keycloak-uncached

Changes

.travis.yml 9(+8 -1)

adapters/pom.xml 2(+1 -1)

authz/client/pom.xml 101(+101 -0)

authz/pom.xml 30(+30 -0)

common/pom.xml 2(+1 -1)

core/pom.xml 2(+1 -1)

distribution/docs-dist/build.xml 139(+0 -139)

docbook/auth-server-docs/pom.xml 159(+0 -159)

docbook/auth-server-docs/reference/en/en-US/master.xml 181(+0 -181)

docbook/auth-server-docs/reference/en/en-US/modules/access-types.xml 71(+0 -71)

docbook/auth-server-docs/reference/en/en-US/modules/adapter_error_handling.xml 75(+0 -75)

docbook/auth-server-docs/reference/en/en-US/modules/adapter-config.xml 421(+0 -421)

docbook/auth-server-docs/reference/en/en-US/modules/adapter-context.xml 12(+0 -12)

docbook/auth-server-docs/reference/en/en-US/modules/admin-permissions.xml 102(+0 -102)

docbook/auth-server-docs/reference/en/en-US/modules/admin-rest-api.xml 35(+0 -35)

docbook/auth-server-docs/reference/en/en-US/modules/application-clustering.xml 253(+0 -253)

docbook/auth-server-docs/reference/en/en-US/modules/auth-spi.xml 1030(+0 -1030)

docbook/auth-server-docs/reference/en/en-US/modules/cache.xml 81(+0 -81)

docbook/auth-server-docs/reference/en/en-US/modules/client-registration.xml 232(+0 -232)

docbook/auth-server-docs/reference/en/en-US/modules/clients.xml 57(+0 -57)

docbook/auth-server-docs/reference/en/en-US/modules/clustering.xml 235(+0 -235)

docbook/auth-server-docs/reference/en/en-US/modules/cors.xml 72(+0 -72)

docbook/auth-server-docs/reference/en/en-US/modules/custom-attributes.xml 167(+0 -167)

docbook/auth-server-docs/reference/en/en-US/modules/direct-access.xml 185(+0 -185)

docbook/auth-server-docs/reference/en/en-US/modules/email.xml 57(+0 -57)

docbook/auth-server-docs/reference/en/en-US/modules/events.xml 120(+0 -120)

docbook/auth-server-docs/reference/en/en-US/modules/export-import.xml 160(+0 -160)

docbook/auth-server-docs/reference/en/en-US/modules/fuse-adapter.xml 69(+0 -69)

docbook/auth-server-docs/reference/en/en-US/modules/groups.xml 48(+0 -48)

docbook/auth-server-docs/reference/en/en-US/modules/identity-broker.xml 1551(+0 -1551)

docbook/auth-server-docs/reference/en/en-US/modules/installed-applications.xml 42(+0 -42)

docbook/auth-server-docs/reference/en/en-US/modules/jaas.xml 59(+0 -59)

docbook/auth-server-docs/reference/en/en-US/modules/javascript-adapter.xml 429(+0 -429)

docbook/auth-server-docs/reference/en/en-US/modules/jboss-adapter.xml 303(+0 -303)

docbook/auth-server-docs/reference/en/en-US/modules/jetty8-adapter.xml 67(+0 -67)

docbook/auth-server-docs/reference/en/en-US/modules/jetty9-adapter.xml 173(+0 -173)

docbook/auth-server-docs/reference/en/en-US/modules/kerberos.xml 297(+0 -297)

docbook/auth-server-docs/reference/en/en-US/modules/MigrationFromOlderVersions.xml 675(+0 -675)

docbook/auth-server-docs/reference/en/en-US/modules/multi-tenancy.xml 73(+0 -73)

docbook/auth-server-docs/reference/en/en-US/modules/openshift.xml 87(+0 -87)

docbook/auth-server-docs/reference/en/en-US/modules/Overview.xml 188(+0 -188)

docbook/auth-server-docs/reference/en/en-US/modules/per-realm-admin-permissions.xml 82(+0 -82)

docbook/auth-server-docs/reference/en/en-US/modules/protocol-mappers.xml 34(+0 -34)

docbook/auth-server-docs/reference/en/en-US/modules/providers.xml 410(+0 -410)

docbook/auth-server-docs/reference/en/en-US/modules/proxy.xml 419(+0 -419)

docbook/auth-server-docs/reference/en/en-US/modules/recaptcha.xml 43(+0 -43)

docbook/auth-server-docs/reference/en/en-US/modules/roles.xml 48(+0 -48)

docbook/auth-server-docs/reference/en/en-US/modules/saml.xml 355(+0 -355)

docbook/auth-server-docs/reference/en/en-US/modules/security-vulnerabilities.xml 194(+0 -194)

docbook/auth-server-docs/reference/en/en-US/modules/server-installation.xml 1001(+0 -1001)

docbook/auth-server-docs/reference/en/en-US/modules/service-accounts.xml 75(+0 -75)

docbook/auth-server-docs/reference/en/en-US/modules/servlet-filter-adapter.xml 77(+0 -77)

docbook/auth-server-docs/reference/en/en-US/modules/social-config.xml 60(+0 -60)

docbook/auth-server-docs/reference/en/en-US/modules/social-facebook.xml 62(+0 -62)

docbook/auth-server-docs/reference/en/en-US/modules/social-github.xml 44(+0 -44)

docbook/auth-server-docs/reference/en/en-US/modules/social-google.xml 67(+0 -67)

docbook/auth-server-docs/reference/en/en-US/modules/social-spi.xml 29(+0 -29)

docbook/auth-server-docs/reference/en/en-US/modules/social-twitter.xml 55(+0 -55)

docbook/auth-server-docs/reference/en/en-US/modules/spring-boot-adapter.xml 89(+0 -89)

docbook/auth-server-docs/reference/en/en-US/modules/spring-security-adapter.xml 312(+0 -312)

docbook/auth-server-docs/reference/en/en-US/modules/themes.xml 318(+0 -318)

docbook/auth-server-docs/reference/en/en-US/modules/timeouts.xml 117(+0 -117)

docbook/auth-server-docs/reference/en/en-US/modules/tomcat-adapter.xml 109(+0 -109)

docbook/auth-server-docs/reference/en/en-US/modules/user-federation.xml 342(+0 -342)

docbook/auth-server-docs/reference/en/images/add-provider-dialog.png 0(+0 -0)

docbook/auth-server-docs/reference/en/images/add-provider-select.png 0(+0 -0)

docbook/auth-server-docs/reference/en/images/domain-mode.png 0(+0 -0)

docbook/auth-server-docs/reference/en/images/email-simple-example.png 0(+0 -0)

docbook/auth-server-docs/reference/en/images/identity_broker_flow.png 0(+0 -0)

docbook/auth-server-docs/reference/en/images/update-server-config-dialog.png 0(+0 -0)

docbook/auth-server-docs/reference/en/images/update-server-config-select.png 0(+0 -0)

docbook/saml-adapter-docs/pom.xml 151(+0 -151)

docbook/saml-adapter-docs/reference/en/en-US/master.xml 84(+0 -84)

docbook/saml-adapter-docs/reference/en/en-US/modules/adapter_error_handling.xml 59(+0 -59)

docbook/saml-adapter-docs/reference/en/en-US/modules/adapter-config.xml 515(+0 -515)

docbook/saml-adapter-docs/reference/en/en-US/modules/assertion-api.xml 126(+0 -126)

docbook/saml-adapter-docs/reference/en/en-US/modules/jboss-adapter.xml 293(+0 -293)

docbook/saml-adapter-docs/reference/en/en-US/modules/jetty8-adapter.xml 66(+0 -66)

docbook/saml-adapter-docs/reference/en/en-US/modules/jetty9-adapter.xml 123(+0 -123)

docbook/saml-adapter-docs/reference/en/en-US/modules/logout.xml 27(+0 -27)

docbook/saml-adapter-docs/reference/en/en-US/modules/MigrationFromOlderVersions.xml 38(+0 -38)

docbook/saml-adapter-docs/reference/en/en-US/modules/multi-tenancy.xml 73(+0 -73)

docbook/saml-adapter-docs/reference/en/en-US/modules/servlet-filter-adapter.xml 84(+0 -84)

docbook/saml-adapter-docs/reference/en/en-US/modules/tomcat-adapter.xml 109(+0 -109)

examples/pom.xml 3(+2 -1)

misc/ReleaseProcess.md 139(+0 -139)

model/jpa/pom.xml 12(+11 -1)

model/pom.xml 2(+1 -1)

pom.xml 71(+68 -3)

proxy/pom.xml 2(+1 -1)

server-spi/pom.xml 12(+11 -1)

server-spi/src/test/java/org/keycloak/models/PasswordPolicyTest.java 168(+0 -168)

services/pom.xml 8(+7 -1)

testsuite/integration/src/test/java/org/keycloak/testsuite/events/AdminEventStoreProviderTest.java 254(+0 -254)

testsuite/integration/src/test/java/org/keycloak/testsuite/events/EventStoreProviderTest.java 251(+0 -251)

testsuite/integration/src/test/java/org/keycloak/testsuite/exportimport/ExportImportTest.java 402(+0 -402)

testsuite/integration/src/test/java/org/keycloak/testsuite/perf/AccessTokenPerfTest.java 272(+0 -272)

testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/LoginLogoutParameters.java 18(+0 -18)

testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/metrics/impl/Results.java 23(+0 -23)

testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/metrics/impl/ResultsWithThroughput.java 48(+0 -48)

testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/PerformanceTestMetrics.java 51(+0 -51)

testsuite/performance/pom.xml 271(+0 -271)

testsuite/performance/README.md 44(+0 -44)

testsuite/performance/src/test/java/org/keycloak/testsuite/performance/BaseJMeterPerformanceTest.java 188(+0 -188)

testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateRealmsWorker.java 104(+0 -104)

testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java 129(+0 -129)

testsuite/performance/src/test/java/org/keycloak/testsuite/performance/ReadUsersWorker.java 146(+0 -146)

testsuite/performance/src/test/java/org/keycloak/testsuite/performance/RemoveUsersWorker.java 88(+0 -88)

testsuite/performance/src/test/jmeter/keycloak_perf_test.jmx 39(+0 -39)

testsuite/performance/src/test/jmeter/system.properties 102(+0 -102)

testsuite/stress/src/main/java/org/keycloak/test/stress/MaxRateExecutor.java 138(+0 -138)

testsuite/stress/src/main/java/org/keycloak/test/stress/StressExecutor.java 65(+0 -65)

testsuite/stress/src/main/java/org/keycloak/test/stress/StressResult.java 62(+0 -62)

testsuite/stress/src/main/java/org/keycloak/test/stress/StressTest.java 37(+0 -37)

testsuite/stress/src/main/java/org/keycloak/test/stress/Test.java 11(+0 -11)

testsuite/stress/src/main/java/org/keycloak/test/stress/TestFactory.java 9(+0 -9)

testsuite/stress/src/main/java/org/keycloak/test/stress/tests/LoginLogout.java 104(+0 -104)

testsuite/stress/src/test/java/org/keycloak/test/LoginLogoutTest.java 96(+0 -96)

themes/pom.xml 2(+1 -1)

util/pom.xml 2(+1 -1)

wildfly/pom.xml 2(+1 -1)

Details

.travis.yml 9(+8 -1)

diff --git a/.travis.yml b/.travis.yml
index c69a2bc..53a9440 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,12 @@
 language: java
 
+cache:
+  directories:
+    - $HOME/.m2
+
+before_cache:
+  - rm -rf $HOME/.m2/repository/org/keycloak
+
 env:
   global:
     - MAVEN_SKIP_RC=true
@@ -12,7 +19,7 @@ before_script:
   - export MAVEN_SKIP_RC=true
 
 install: 
-  - mvn install -Pdistribution -DskipTests=true -B -V -q
+  - travis_wait 30 mvn install -Pdistribution -DskipTests=true -B -V -q
 
 script:
   - mvn test -B
diff --git a/adapters/oidc/adapter-core/pom.xml b/adapters/oidc/adapter-core/pom.xml
index 015fbf4..9077b01 100755
--- a/adapters/oidc/adapter-core/pom.xml
+++ b/adapters/oidc/adapter-core/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
@@ -66,6 +66,11 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-authz-client</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-core</artifactId>
             <scope>provided</scope>
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java
index 7ff049a..d7985b0 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java
@@ -456,6 +456,16 @@ public class AdapterDeploymentContext {
         public void setTurnOffChangeSessionIdOnLogin(boolean turnOffChangeSessionIdOnLogin) {
             delegate.setTurnOffChangeSessionIdOnLogin(turnOffChangeSessionIdOnLogin);
         }
+
+        @Override
+        public int getTokenMinimumTimeToLive() {
+            return delegate.getTokenMinimumTimeToLive();
+        }
+
+        @Override
+        public void setTokenMinimumTimeToLive(final int tokenMinimumTimeToLive) {
+            delegate.setTokenMinimumTimeToLive(tokenMinimumTimeToLive);
+        }
     }
 
     protected KeycloakUriBuilder getBaseBuilder(HttpFacade facade, String base) {
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java
index 18c3f4a..121adf1 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/AuthenticatedActionsHandler.java
@@ -18,10 +18,12 @@
 package org.keycloak.adapters;
 
 import org.jboss.logging.Logger;
+import org.keycloak.AuthorizationContext;
 import org.keycloak.KeycloakSecurityContext;
+import org.keycloak.adapters.authorization.PolicyEnforcer;
+import org.keycloak.common.util.UriUtils;
 import org.keycloak.constants.AdapterConstants;
 import org.keycloak.representations.AccessToken;
-import org.keycloak.common.util.UriUtils;
 
 import java.io.IOException;
 import java.util.Set;
@@ -55,6 +57,9 @@ public class AuthenticatedActionsHandler {
             queryBearerToken();
             return true;
         }
+        if (!isAuthorized()) {
+            return true;
+        }
         return false;
     }
 
@@ -124,4 +129,24 @@ public class AuthenticatedActionsHandler {
         }
         return false;
     }
+
+    private boolean isAuthorized() {
+        PolicyEnforcer policyEnforcer = this.deployment.getPolicyEnforcer();
+
+        if (policyEnforcer == null) {
+            log.debugv("Policy enforcement is disabled.");
+            return true;
+        }
+        try {
+            OIDCHttpFacade facade = (OIDCHttpFacade) this.facade;
+            AuthorizationContext authorizationContext = policyEnforcer.enforce(facade);
+            RefreshableKeycloakSecurityContext session = (RefreshableKeycloakSecurityContext) facade.getSecurityContext();
+
+            session.setAuthorizationContext(authorizationContext);
+
+            return  authorizationContext.isGranted();
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to enforce policy decisions.", e);
+        }
+    }
 }
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authentication/JWTClientCredentialsProvider.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authentication/JWTClientCredentialsProvider.java
index 747137d..2490c0e 100644
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authentication/JWTClientCredentialsProvider.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authentication/JWTClientCredentialsProvider.java
@@ -54,6 +54,10 @@ public class JWTClientCredentialsProvider implements ClientCredentialsProvider {
         this.tokenTimeout = tokenTimeout;
     }
 
+    protected int getTokenTimeout() {
+        return tokenTimeout;
+    }
+
     @Override
     public void init(KeycloakDeployment deployment, Object config) {
         if (config == null || !(config instanceof Map)) {
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/AbstractPolicyEnforcer.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/AbstractPolicyEnforcer.java
new file mode 100644
index 0000000..cfe5ff9
--- /dev/null
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/AbstractPolicyEnforcer.java
@@ -0,0 +1,265 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.adapters.authorization;
+
+import org.jboss.logging.Logger;
+import org.keycloak.AuthorizationContext;
+import org.keycloak.adapters.OIDCHttpFacade;
+import org.keycloak.adapters.spi.HttpFacade.Request;
+import org.keycloak.adapters.spi.HttpFacade.Response;
+import org.keycloak.authorization.client.AuthzClient;
+import org.keycloak.authorization.client.representation.ResourceRepresentation;
+import org.keycloak.authorization.client.resource.ProtectedResource;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
+import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.EnforcementMode;
+import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
+import org.keycloak.representations.idm.authorization.Permission;
+
+import java.net.URI;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public abstract class AbstractPolicyEnforcer {
+
+    private static Logger LOGGER = Logger.getLogger(AbstractPolicyEnforcer.class);
+    private final PolicyEnforcerConfig enforcerConfig;
+    private final PolicyEnforcer policyEnforcer;
+
+    private List<PathConfig> paths;
+    private AuthzClient authzClient;
+    private PathMatcher pathMatcher;
+
+    public AbstractPolicyEnforcer(PolicyEnforcer policyEnforcer) {
+        this.policyEnforcer = policyEnforcer;
+        this.enforcerConfig = policyEnforcer.getEnforcerConfig();
+        this.authzClient = policyEnforcer.getClient();
+        this.pathMatcher = new PathMatcher();
+        this.paths = policyEnforcer.getPaths();
+    }
+
+    public AuthorizationContext authorize(OIDCHttpFacade httpFacade) {
+        EnforcementMode enforcementMode = this.enforcerConfig.getEnforcementMode();
+
+        if (EnforcementMode.DISABLED.equals(enforcementMode)) {
+            return createEmptyAuthorizationContext(true);
+        }
+
+        AccessToken accessToken = httpFacade.getSecurityContext().getToken();
+        Request request = httpFacade.getRequest();
+        Response response = httpFacade.getResponse();
+        String pathInfo = URI.create(request.getURI()).getPath().substring(1);
+        String path = pathInfo.substring(pathInfo.indexOf('/'), pathInfo.length());
+        PathConfig pathConfig = this.pathMatcher.matches(path, this.paths);
+
+        LOGGER.debugf("Checking permissions for path [%s] with config [%s].", request.getURI(), pathConfig);
+
+        if (pathConfig == null) {
+            if (EnforcementMode.PERMISSIVE.equals(enforcementMode)) {
+                return createAuthorizationContext(accessToken);
+            }
+
+            LOGGER.debugf("Could not find a configuration for path [%s]", path);
+            response.sendError(403, "Could not find a configuration for path [" + path + "].");
+
+            return createEmptyAuthorizationContext(false);
+        }
+
+        PathConfig actualPathConfig = resolvePathConfig(pathConfig, request);
+        Set<String> requiredScopes = getRequiredScopes(actualPathConfig, request);
+
+        if (isAuthorized(actualPathConfig, requiredScopes, accessToken, httpFacade)) {
+            try {
+                return createAuthorizationContext(accessToken);
+            } catch (Exception e) {
+                throw new RuntimeException("Error processing path [" + actualPathConfig.getPath() + "].", e);
+            }
+        }
+
+        if (!challenge(actualPathConfig, requiredScopes, httpFacade)) {
+            LOGGER.debugf("Sending challenge to the client. Path [%s]", pathConfig);
+            response.sendError(403, "Authorization failed.");
+        }
+
+        return createEmptyAuthorizationContext(false);
+    }
+
+    protected abstract boolean challenge(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade);
+
+    protected boolean isAuthorized(PathConfig actualPathConfig, Set<String> requiredScopes, AccessToken accessToken, OIDCHttpFacade httpFacade) {
+        Request request = httpFacade.getRequest();
+        PolicyEnforcerConfig enforcerConfig = getEnforcerConfig();
+        String accessDeniedPath = enforcerConfig.getAccessDeniedPath();
+
+        if (accessDeniedPath != null) {
+            if (request.getURI().contains(accessDeniedPath)) {
+                return true;
+            }
+        }
+
+        AccessToken.Authorization authorization = accessToken.getAuthorization();
+
+        if (authorization == null) {
+            return false;
+        }
+
+        List<Permission> permissions = authorization.getPermissions();
+
+        for (Permission permission : permissions) {
+            if (permission.getResourceSetId() != null) {
+                if (isResourcePermission(actualPathConfig, permission)) {
+                    if (actualPathConfig.isInstance() && !matchResourcePermission(actualPathConfig, permission)) {
+                        continue;
+
+                    }
+                    if (hasResourceScopePermission(requiredScopes, permission, actualPathConfig)) {
+                        LOGGER.debugf("Authorization GRANTED for path [%s]. Permissions [%s].", actualPathConfig, permissions);
+                        if (request.getMethod().equalsIgnoreCase("DELETE") && actualPathConfig.isInstance()) {
+                            this.paths.remove(actualPathConfig);
+                        }
+                        return true;
+                    }
+                }
+            } else {
+                if (hasResourceScopePermission(requiredScopes, permission, actualPathConfig)) {
+                    return true;
+                }
+            }
+        }
+
+        LOGGER.debugf("Authorization FAILED for path [%s]. No enough permissions [%s].", actualPathConfig, permissions);
+
+        return false;
+    }
+
+    private boolean hasResourceScopePermission(Set<String> requiredScopes, Permission permission, PathConfig actualPathConfig) {
+        Set<String> allowedScopes = permission.getScopes();
+        return (allowedScopes.containsAll(requiredScopes) || allowedScopes.isEmpty());
+    }
+
+    protected AuthzClient getAuthzClient() {
+        return this.authzClient;
+    }
+
+    protected PolicyEnforcerConfig getEnforcerConfig() {
+        return enforcerConfig;
+    }
+
+    protected PolicyEnforcer getPolicyEnforcer() {
+        return policyEnforcer;
+    }
+
+    private AuthorizationContext createEmptyAuthorizationContext(final boolean granted) {
+        return new AuthorizationContext() {
+            @Override
+            public boolean hasPermission(String resourceName, String scopeName) {
+                return granted;
+            }
+
+            @Override
+            public boolean hasResourcePermission(String resourceName) {
+                return granted;
+            }
+
+            @Override
+            public boolean hasScopePermission(String scopeName) {
+                return granted;
+            }
+
+            @Override
+            public List<Permission> getPermissions() {
+                return Collections.EMPTY_LIST;
+            }
+
+            @Override
+            public boolean isGranted() {
+                return granted;
+            }
+        };
+    }
+
+    private PathConfig resolvePathConfig(PathConfig originalConfig, Request request) {
+        if (originalConfig.hasPattern()) {
+            String pathInfo = URI.create(request.getURI()).getPath().substring(1);
+            String path = pathInfo.substring(pathInfo.indexOf('/'), pathInfo.length());
+            ProtectedResource resource = this.authzClient.protection().resource();
+            Set<String> search = resource.findByFilter("uri=" + path);
+
+            if (!search.isEmpty()) {
+                // resource does exist on the server, cache it
+                ResourceRepresentation targetResource = resource.findById(search.iterator().next()).getResourceDescription();
+                PathConfig config = new PathConfig();
+
+                config.setId(targetResource.getId());
+                config.setName(targetResource.getName());
+                config.setType(targetResource.getType());
+                config.setPath(targetResource.getUri());
+                config.setScopes(originalConfig.getScopes());
+                config.setMethods(originalConfig.getMethods());
+                config.setParentConfig(originalConfig);
+
+                this.paths.add(config);
+
+                return config;
+            }
+        }
+
+        return originalConfig;
+    }
+
+    private Set<String> getRequiredScopes(PathConfig pathConfig, Request request) {
+        Set<String> requiredScopes = new HashSet<>();
+
+        requiredScopes.addAll(pathConfig.getScopes());
+
+        String method = request.getMethod();
+
+        for (PolicyEnforcerConfig.MethodConfig methodConfig : pathConfig.getMethods()) {
+            if (methodConfig.getMethod().equals(method)) {
+                requiredScopes.addAll(methodConfig.getScopes());
+            }
+        }
+
+        return requiredScopes;
+    }
+
+    private AuthorizationContext createAuthorizationContext(AccessToken accessToken) {
+        return new AuthorizationContext(accessToken, this.paths);
+    }
+
+    private boolean isResourcePermission(PathConfig actualPathConfig, Permission permission) {
+        // first we try a match using resource id
+        boolean resourceMatch = matchResourcePermission(actualPathConfig, permission);
+
+        // as a fallback, check if the current path is an instance and if so, check if parent's id matches the permission
+        if (!resourceMatch && actualPathConfig.isInstance()) {
+            resourceMatch = matchResourcePermission(actualPathConfig.getParentConfig(), permission);
+        }
+
+        return resourceMatch;
+    }
+
+    private boolean matchResourcePermission(PathConfig actualPathConfig, Permission permission) {
+        return permission.getResourceSetId().equals(actualPathConfig.getId());
+    }
+}
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/BearerTokenPolicyEnforcer.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/BearerTokenPolicyEnforcer.java
new file mode 100644
index 0000000..efa2b2b
--- /dev/null
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/BearerTokenPolicyEnforcer.java
@@ -0,0 +1,80 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.adapters.authorization;
+
+import org.jboss.logging.Logger;
+import org.keycloak.adapters.OIDCHttpFacade;
+import org.keycloak.adapters.spi.HttpFacade;
+import org.keycloak.authorization.client.AuthzClient;
+import org.keycloak.authorization.client.representation.PermissionRequest;
+import org.keycloak.authorization.client.resource.PermissionResource;
+import org.keycloak.authorization.client.resource.ProtectionResource;
+import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class BearerTokenPolicyEnforcer extends AbstractPolicyEnforcer {
+
+    private static Logger LOGGER = Logger.getLogger(BearerTokenPolicyEnforcer.class);
+
+    public BearerTokenPolicyEnforcer(PolicyEnforcer enforcer) {
+        super(enforcer);
+    }
+
+    @Override
+    protected boolean challenge(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade) {
+        if (getEnforcerConfig().getUmaProtocolConfig() != null) {
+            challengeUmaAuthentication(pathConfig, requiredScopes, facade);
+        } else {
+            challengeEntitlementAuthentication(facade);
+        }
+        return true;
+    }
+
+    private void challengeEntitlementAuthentication(OIDCHttpFacade facade) {
+        HttpFacade.Response response = facade.getResponse();
+        AuthzClient authzClient = getAuthzClient();
+        String clientId = authzClient.getConfiguration().getClientId();
+        String  authorizationServerUri = authzClient.getServerConfiguration().getIssuer().toString() + "/authz/entitlement";
+        response.setStatus(401);
+        response.setHeader("WWW-Authenticate", "KC_ETT realm=\"" + clientId + "\",as_uri=\"" + authorizationServerUri + "\"");
+    }
+
+    private void challengeUmaAuthentication(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade) {
+        HttpFacade.Response response = facade.getResponse();
+        AuthzClient authzClient = getAuthzClient();
+        String ticket = getPermissionTicket(pathConfig, requiredScopes, authzClient);
+        String clientId = authzClient.getConfiguration().getClientId();
+        String authorizationServerUri = authzClient.getServerConfiguration().getIssuer().toString() + "/authz/authorize";
+        response.setStatus(401);
+        response.setHeader("WWW-Authenticate", "UMA realm=\"" + clientId + "\",as_uri=\"" + authorizationServerUri + "\",ticket=\"" + ticket + "\"");
+    }
+
+    private String getPermissionTicket(PathConfig pathConfig, Set<String> requiredScopes, AuthzClient authzClient) {
+        ProtectionResource protection = authzClient.protection();
+        PermissionResource permission = protection.permission();
+        PermissionRequest permissionRequest = new PermissionRequest();
+        permissionRequest.setResourceSetId(pathConfig.getId());
+        permissionRequest.setScopes(requiredScopes);
+        return permission.forResource(permissionRequest).getTicket();
+    }
+}
\ No newline at end of file
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/KeycloakAdapterPolicyEnforcer.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/KeycloakAdapterPolicyEnforcer.java
new file mode 100644
index 0000000..f1be944
--- /dev/null
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/KeycloakAdapterPolicyEnforcer.java
@@ -0,0 +1,151 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.adapters.authorization;
+
+import org.jboss.logging.Logger;
+import org.keycloak.RSATokenVerifier;
+import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.OIDCHttpFacade;
+import org.keycloak.adapters.spi.HttpFacade;
+import org.keycloak.authorization.client.AuthorizationDeniedException;
+import org.keycloak.authorization.client.AuthzClient;
+import org.keycloak.authorization.client.representation.AuthorizationRequest;
+import org.keycloak.authorization.client.representation.AuthorizationResponse;
+import org.keycloak.authorization.client.representation.EntitlementRequest;
+import org.keycloak.authorization.client.representation.EntitlementResponse;
+import org.keycloak.authorization.client.representation.PermissionRequest;
+import org.keycloak.authorization.client.representation.PermissionResponse;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
+import org.keycloak.representations.idm.authorization.Permission;
+import org.keycloak.util.JsonSerialization;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class KeycloakAdapterPolicyEnforcer extends AbstractPolicyEnforcer {
+
+    private static Logger LOGGER = Logger.getLogger(KeycloakAdapterPolicyEnforcer.class);
+
+    public KeycloakAdapterPolicyEnforcer(PolicyEnforcer policyEnforcer) {
+        super(policyEnforcer);
+    }
+
+    @Override
+    protected boolean isAuthorized(PathConfig pathConfig, Set<String> requiredScopes, AccessToken accessToken, OIDCHttpFacade httpFacade) {
+        int retry = 2;
+        AccessToken original = accessToken;
+
+        while (retry > 0) {
+            if (super.isAuthorized(pathConfig, requiredScopes, accessToken, httpFacade)) {
+                return true;
+            }
+
+            accessToken = requestAuthorizationToken(pathConfig, requiredScopes, httpFacade);
+
+            if (accessToken == null) {
+                return false;
+            }
+
+            AccessToken.Authorization authorization = original.getAuthorization();
+
+            if (authorization == null) {
+                authorization = new AccessToken.Authorization();
+                authorization.setPermissions(new ArrayList<Permission>());
+            }
+
+            AccessToken.Authorization newAuthorization = accessToken.getAuthorization();
+
+            if (newAuthorization != null) {
+                authorization.getPermissions().addAll(newAuthorization.getPermissions());
+            }
+
+            original.setAuthorization(authorization);
+
+            retry--;
+        }
+
+        return false;
+    }
+
+    @Override
+    protected boolean challenge(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade facade) {
+        String accessDeniedPath = getEnforcerConfig().getAccessDeniedPath();
+        HttpFacade.Response response = facade.getResponse();
+
+        if (accessDeniedPath != null) {
+            response.setStatus(302);
+            response.setHeader("Location", accessDeniedPath);
+        } else {
+            response.sendError(403);
+        }
+
+        return true;
+    }
+
+    private AccessToken requestAuthorizationToken(PathConfig pathConfig, Set<String> requiredScopes, OIDCHttpFacade httpFacade) {
+        try {
+            String accessToken = httpFacade.getSecurityContext().getTokenString();
+            AuthzClient authzClient = getAuthzClient();
+            KeycloakDeployment deployment = getPolicyEnforcer().getDeployment();
+
+            if (getEnforcerConfig().getUmaProtocolConfig() != null) {
+                LOGGER.debug("Obtaining authorization for  authenticated user.");
+                PermissionRequest permissionRequest = new PermissionRequest();
+
+                permissionRequest.setResourceSetId(pathConfig.getId());
+                permissionRequest.setScopes(requiredScopes);
+
+                PermissionResponse permissionResponse = authzClient.protection().permission().forResource(permissionRequest);
+                AuthorizationRequest authzRequest = new AuthorizationRequest(permissionResponse.getTicket());
+                AuthorizationResponse authzResponse = authzClient.authorization(accessToken).authorize(authzRequest);
+
+                if (authzResponse != null) {
+                    return RSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment.getRealmKey(), deployment.getRealmInfoUrl());
+                }
+
+                return null;
+            } else {
+                LOGGER.debug("Obtaining entitlements for authenticated user.");
+                AccessToken token = httpFacade.getSecurityContext().getToken();
+
+                if (token.getAuthorization() == null) {
+                    EntitlementResponse authzResponse = authzClient.entitlement(accessToken).getAll(authzClient.getConfiguration().getClientId());
+                    return RSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment.getRealmKey(), deployment.getRealmInfoUrl());
+                } else {
+                    EntitlementRequest request = new EntitlementRequest();
+                    PermissionRequest permissionRequest = new PermissionRequest();
+                    permissionRequest.setResourceSetId(pathConfig.getId());
+                    permissionRequest.setResourceSetName(pathConfig.getName());
+                    permissionRequest.setScopes(new HashSet<>(pathConfig.getScopes()));
+                    request.addPermission(permissionRequest);
+                    EntitlementResponse authzResponse = authzClient.entitlement(accessToken).get(authzClient.getConfiguration().getClientId(), request);
+                    return RSATokenVerifier.verifyToken(authzResponse.getRpt(), deployment.getRealmKey(), deployment.getRealmInfoUrl());
+                }
+            }
+        } catch (AuthorizationDeniedException e) {
+            return null;
+        } catch (Exception e) {
+            throw new RuntimeException("Unexpected error during authorization request.", e);
+        }
+    }
+}
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PathMatcher.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PathMatcher.java
new file mode 100644
index 0000000..5ac1b79
--- /dev/null
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PathMatcher.java
@@ -0,0 +1,103 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.adapters.authorization;
+
+import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+class PathMatcher {
+
+    private static final String ANY_RESOURCE_PATTERN = "/*";
+
+    PathConfig matches(final String requestedUri, List<PathConfig> paths) {
+        PathConfig actualConfig = null;
+
+        for (PathConfig entry : paths) {
+            String protectedUri = entry.getPath();
+            String selectedUri = null;
+
+            if (protectedUri.equals(ANY_RESOURCE_PATTERN) && actualConfig == null) {
+                selectedUri = protectedUri;
+            }
+
+            int suffixIndex = protectedUri.indexOf(ANY_RESOURCE_PATTERN + ".");
+
+            if (suffixIndex != -1) {
+                String protectedSuffix = protectedUri.substring(suffixIndex + ANY_RESOURCE_PATTERN.length());
+
+                if (requestedUri.endsWith(protectedSuffix)) {
+                    selectedUri = protectedUri;
+                }
+            }
+
+            if (protectedUri.equals(requestedUri)) {
+                selectedUri = protectedUri;
+            }
+
+            if (protectedUri.endsWith(ANY_RESOURCE_PATTERN)) {
+                String formattedPattern = removeWildCardsFromUri(protectedUri);
+
+                if (!formattedPattern.equals("/") && requestedUri.startsWith(formattedPattern)) {
+                    selectedUri = protectedUri;
+                }
+
+                if (!formattedPattern.equals("/") && formattedPattern.endsWith("/") && formattedPattern.substring(0, formattedPattern.length() - 1).equals(requestedUri)) {
+                    selectedUri = protectedUri;
+                }
+            }
+
+            int startRegex = protectedUri.indexOf('{');
+
+            if (startRegex != -1) {
+                String prefix = protectedUri.substring(0, startRegex);
+
+                if (requestedUri.startsWith(prefix)) {
+                    selectedUri = protectedUri;
+                }
+            }
+
+            if (selectedUri != null) {
+                selectedUri = protectedUri;
+            }
+
+            if (selectedUri != null) {
+                if (actualConfig == null) {
+                    actualConfig = entry;
+                } else {
+                    if (actualConfig.equals(ANY_RESOURCE_PATTERN)) {
+                        actualConfig = entry;
+                    }
+
+                    if (protectedUri.startsWith(removeWildCardsFromUri(actualConfig.getPath()))) {
+                        actualConfig = entry;
+                    }
+                }
+            }
+        }
+
+        return actualConfig;
+    }
+
+    private String removeWildCardsFromUri(String protectedUri) {
+        return protectedUri.replaceAll("/[*]", "/");
+    }
+}
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PolicyEnforcer.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PolicyEnforcer.java
new file mode 100644
index 0000000..aa6d3d2
--- /dev/null
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/authorization/PolicyEnforcer.java
@@ -0,0 +1,203 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.adapters.authorization;
+
+import org.jboss.logging.Logger;
+import org.keycloak.AuthorizationContext;
+import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.OIDCHttpFacade;
+import org.keycloak.authorization.client.AuthzClient;
+import org.keycloak.authorization.client.Configuration;
+import org.keycloak.authorization.client.representation.RegistrationResponse;
+import org.keycloak.authorization.client.representation.ResourceRepresentation;
+import org.keycloak.authorization.client.representation.ScopeRepresentation;
+import org.keycloak.authorization.client.resource.ProtectedResource;
+import org.keycloak.representations.adapters.config.AdapterConfig;
+import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
+import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
+import org.keycloak.representations.idm.authorization.Permission;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class PolicyEnforcer {
+
+    private static Logger LOGGER = Logger.getLogger(PolicyEnforcer.class);
+
+    private final KeycloakDeployment deployment;
+    private final AuthzClient authzClient;
+    private final PolicyEnforcerConfig enforcerConfig;
+    private final List<PathConfig> paths;
+
+    public PolicyEnforcer(KeycloakDeployment deployment, AdapterConfig adapterConfig) {
+        this.deployment = deployment;
+        this.enforcerConfig = adapterConfig.getPolicyEnforcerConfig();
+        this.authzClient = AuthzClient.create(new Configuration(adapterConfig.getAuthServerUrl(), adapterConfig.getRealm(), adapterConfig.getResource(), adapterConfig.getCredentials(), deployment.getClient()));
+        this.paths = configurePaths(this.authzClient.protection().resource(), this.enforcerConfig);
+
+        if (LOGGER.isDebugEnabled()) {
+            LOGGER.debug("Initialization complete. Path configurations:");
+            for (PathConfig pathConfig : this.paths) {
+                LOGGER.debug(pathConfig);
+            }
+        }
+    }
+
+    public AuthorizationContext enforce(OIDCHttpFacade facade) {
+        if (LOGGER.isDebugEnabled()) {
+            LOGGER.debugv("Policy enforcement is enable. Enforcing policy decisions for path [{0}].", facade.getRequest().getURI());
+        }
+
+        AuthorizationContext context;
+
+        if (deployment.isBearerOnly()) {
+            context = new BearerTokenPolicyEnforcer(this).authorize(facade);
+        } else {
+            context = new KeycloakAdapterPolicyEnforcer(this).authorize(facade);
+        }
+
+        if (LOGGER.isDebugEnabled()) {
+            LOGGER.debugv("Policy enforcement result for path [{0}] is : {1}", facade.getRequest().getURI(), context.isGranted() ? "GRANTED" : "DENIED");
+            LOGGER.debugv("Returning authorization context with permissions:");
+            for (Permission permission : context.getPermissions()) {
+                LOGGER.debug(permission);
+            }
+        }
+
+        return context;
+    }
+
+    PolicyEnforcerConfig getEnforcerConfig() {
+        return enforcerConfig;
+    }
+
+    AuthzClient getClient() {
+        return authzClient;
+    }
+
+    List<PathConfig> getPaths() {
+        return paths;
+    }
+
+    KeycloakDeployment getDeployment() {
+        return deployment;
+    }
+
+    private List<PathConfig> configurePaths(ProtectedResource protectedResource, PolicyEnforcerConfig enforcerConfig) {
+        if (enforcerConfig.getPaths().isEmpty()) {
+            LOGGER.info("No path provided in configuration.");
+            return configureAllPathsForResourceServer(protectedResource);
+        } else {
+            LOGGER.info("Paths provided in configuration.");
+            return configureDefinedPaths(protectedResource, enforcerConfig);
+        }
+    }
+
+    private List<PathConfig> configureDefinedPaths(ProtectedResource protectedResource, PolicyEnforcerConfig enforcerConfig) {
+        List<PathConfig> paths = new ArrayList<>();
+
+        for (PathConfig pathConfig : enforcerConfig.getPaths()) {
+            Set<String> search;
+            String resourceName = pathConfig.getName();
+            String path = pathConfig.getPath();
+
+            if (resourceName != null) {
+                LOGGER.debugf("Trying to find resource with name [%s] for path [%s].", resourceName, path);
+                search = protectedResource.findByFilter("name=" + resourceName);
+            } else {
+                LOGGER.debugf("Trying to find resource with uri [%s] for path [%s].", path, path);
+                search = protectedResource.findByFilter("uri=" + path);
+            }
+
+            if (search.isEmpty()) {
+                if (enforcerConfig.isCreateResources()) {
+                    LOGGER.debugf("Creating resource on server for path [%s].", pathConfig);
+                    ResourceRepresentation resource = new ResourceRepresentation();
+
+                    resource.setName(resourceName);
+                    resource.setType(pathConfig.getType());
+                    resource.setUri(path);
+
+                    HashSet<ScopeRepresentation> scopes = new HashSet<>();
+
+                    for (String scopeName : pathConfig.getScopes()) {
+                        ScopeRepresentation scope = new ScopeRepresentation();
+
+                        scope.setName(scopeName);
+
+                        scopes.add(scope);
+                    }
+
+                    resource.setScopes(scopes);
+
+                    RegistrationResponse registrationResponse = protectedResource.create(resource);
+
+                    pathConfig.setId(registrationResponse.getId());
+                } else {
+                    throw new RuntimeException("Could not find matching resource on server with uri [" + path + "] or name [" + resourceName + ". Make sure you have created a resource on the server that matches with the path configuration.");
+                }
+            } else {
+                pathConfig.setId(search.iterator().next());
+            }
+
+            paths.add(pathConfig);
+        }
+
+        return paths;
+    }
+
+    private List<PathConfig> configureAllPathsForResourceServer(ProtectedResource protectedResource) {
+        LOGGER.info("Querying the server for all resources associated with this application.");
+        List<PathConfig> paths = new ArrayList<>();
+
+        for (String id : protectedResource.findAll()) {
+            RegistrationResponse response = protectedResource.findById(id);
+            ResourceRepresentation resourceDescription = response.getResourceDescription();
+
+            if (resourceDescription.getUri() != null) {
+                paths.add(createPathConfig(resourceDescription));
+            }
+        }
+
+        return paths;
+    }
+
+    private PathConfig createPathConfig(ResourceRepresentation resourceDescription) {
+        PathConfig pathConfig = new PathConfig();
+
+        pathConfig.setId(resourceDescription.getId());
+        pathConfig.setName(resourceDescription.getName());
+        pathConfig.setPath(resourceDescription.getUri());
+
+        List<String> scopeNames = new ArrayList<>();
+
+        for (ScopeRepresentation scope : resourceDescription.getScopes()) {
+            scopeNames.add(scope.getName());
+        }
+
+        pathConfig.setScopes(scopeNames);
+        pathConfig.setType(resourceDescription.getType());
+
+        return pathConfig;
+    }
+}
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/jaas/DirectAccessGrantsLoginModule.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/jaas/DirectAccessGrantsLoginModule.java
index ddd1152..78d98e7 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/jaas/DirectAccessGrantsLoginModule.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/jaas/DirectAccessGrantsLoginModule.java
@@ -43,6 +43,7 @@ import org.keycloak.common.VerificationException;
 import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
 import org.keycloak.constants.ServiceUrlConstants;
 import org.keycloak.representations.AccessTokenResponse;
+import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
 import org.keycloak.util.JsonSerialization;
 import org.keycloak.common.util.KeycloakUriBuilder;
 
@@ -102,9 +103,9 @@ public class DirectAccessGrantsLoginModule extends AbstractKeycloakLoginModule {
             StringBuilder errorBuilder = new StringBuilder("Login failed. Invalid status: " + status);
             if (entity != null) {
                 InputStream is = entity.getContent();
-                Map<String, String> errors = (Map<String, String>) JsonSerialization.readValue(is, Map.class);
-                errorBuilder.append(", OAuth2 error. Error: " + errors.get(OAuth2Constants.ERROR))
-                        .append(", Error description: " + errors.get(OAuth2Constants.ERROR_DESCRIPTION));
+                OAuth2ErrorRepresentation errorRep = JsonSerialization.readValue(is, OAuth2ErrorRepresentation.class);
+                errorBuilder.append(", OAuth2 error. Error: " + errorRep.getError())
+                        .append(", Error description: " + errorRep.getErrorDescription());
             }
             String error = errorBuilder.toString();
             log.warn(error);
@@ -161,9 +162,9 @@ public class DirectAccessGrantsLoginModule extends AbstractKeycloakLoginModule {
                     if (entity != null) {
                         InputStream is = entity.getContent();
                         if (status == 400) {
-                            Map<String, String> errors = (Map<String, String>) JsonSerialization.readValue(is, Map.class);
-                            errorBuilder.append(", OAuth2 error. Error: " + errors.get(OAuth2Constants.ERROR))
-                                    .append(", Error description: " + errors.get(OAuth2Constants.ERROR_DESCRIPTION));
+                            OAuth2ErrorRepresentation errorRep = JsonSerialization.readValue(is, OAuth2ErrorRepresentation.class);
+                            errorBuilder.append(", OAuth2 error. Error: " + errorRep.getError())
+                                    .append(", Error description: " + errorRep.getErrorDescription());
 
                         } else {
                             if (is != null) is.close();
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
index cca0adf..901b3ea 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
@@ -20,6 +20,7 @@ package org.keycloak.adapters;
 import org.apache.http.client.HttpClient;
 import org.jboss.logging.Logger;
 import org.keycloak.adapters.authentication.ClientCredentialsProvider;
+import org.keycloak.adapters.authorization.PolicyEnforcer;
 import org.keycloak.constants.ServiceUrlConstants;
 import org.keycloak.common.enums.RelativeUrlsUsed;
 import org.keycloak.common.enums.SslRequired;
@@ -77,6 +78,8 @@ public class KeycloakDeployment {
     protected boolean turnOffChangeSessionIdOnLogin;
 
     protected volatile int notBefore;
+    protected int tokenMinimumTimeToLive;
+    private PolicyEnforcer policyEnforcer;
 
     public KeycloakDeployment() {
     }
@@ -357,4 +360,20 @@ public class KeycloakDeployment {
     public void setTurnOffChangeSessionIdOnLogin(boolean turnOffChangeSessionIdOnLogin) {
         this.turnOffChangeSessionIdOnLogin = turnOffChangeSessionIdOnLogin;
     }
+
+    public int getTokenMinimumTimeToLive() {
+        return tokenMinimumTimeToLive;
+    }
+
+    public void setTokenMinimumTimeToLive(final int tokenMinimumTimeToLive) {
+        this.tokenMinimumTimeToLive = tokenMinimumTimeToLive;
+    }
+
+    public void setPolicyEnforcer(PolicyEnforcer policyEnforcer) {
+        this.policyEnforcer = policyEnforcer;
+    }
+
+    public PolicyEnforcer getPolicyEnforcer() {
+        return policyEnforcer;
+    }
 }
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
index ab77491..5d54df9 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
@@ -21,10 +21,12 @@ import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.jboss.logging.Logger;
 import org.keycloak.adapters.authentication.ClientCredentialsProviderUtils;
+import org.keycloak.adapters.authorization.PolicyEnforcer;
 import org.keycloak.common.enums.SslRequired;
+import org.keycloak.common.util.PemUtils;
 import org.keycloak.enums.TokenStore;
 import org.keycloak.representations.adapters.config.AdapterConfig;
-import org.keycloak.common.util.PemUtils;
+import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
 import org.keycloak.util.SystemPropertiesJsonParserFactory;
 
 import java.io.IOException;
@@ -94,6 +96,7 @@ public class KeycloakDeploymentBuilder {
         deployment.setAlwaysRefreshToken(adapterConfig.isAlwaysRefreshToken());
         deployment.setRegisterNodeAtStartup(adapterConfig.isRegisterNodeAtStartup());
         deployment.setRegisterNodePeriod(adapterConfig.getRegisterNodePeriod());
+        deployment.setTokenMinimumTimeToLive(adapterConfig.getTokenMinimumTimeToLive());
 
         if (realmKeyPem == null && adapterConfig.isBearerOnly() && adapterConfig.getAuthServerUrl() == null) {
             throw new IllegalArgumentException("For bearer auth, you must set the realm-public-key or auth-server-url");
@@ -109,6 +112,12 @@ public class KeycloakDeploymentBuilder {
             deployment.setTurnOffChangeSessionIdOnLogin(adapterConfig.getTurnOffChangeSessionIdOnLogin());
         }
 
+        PolicyEnforcerConfig policyEnforcerConfig = adapterConfig.getPolicyEnforcerConfig();
+
+        if (policyEnforcerConfig != null) {
+            deployment.setPolicyEnforcer(new PolicyEnforcer(deployment, adapterConfig));
+        }
+
         log.debug("Use authServerUrl: " + deployment.getAuthServerBaseUrl() + ", tokenUrl: " + deployment.getTokenUrl() + ", relativeUrls: " + deployment.getRelativeUrls());
         return deployment;
     }
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java
index cf51bdf..73aa0f5 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OAuthRequestAuthenticator.java
@@ -34,6 +34,7 @@ import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.representations.IDToken;
 import org.keycloak.common.util.KeycloakUriBuilder;
 import org.keycloak.common.util.UriUtils;
+import org.keycloak.util.TokenUtil;
 
 import java.io.IOException;
 import java.util.concurrent.atomic.AtomicLong;
@@ -159,6 +160,12 @@ public class OAuthRequestAuthenticator {
         String scope = getQueryParamValue(OAuth2Constants.SCOPE);
         url = UriUtils.stripQueryParam(url, OAuth2Constants.SCOPE);
 
+        String prompt = getQueryParamValue(OAuth2Constants.PROMPT);
+        url = UriUtils.stripQueryParam(url, OAuth2Constants.PROMPT);
+
+        String maxAge = getQueryParamValue(OAuth2Constants.MAX_AGE);
+        url = UriUtils.stripQueryParam(url, OAuth2Constants.MAX_AGE);
+
         KeycloakUriBuilder redirectUriBuilder = deployment.getAuthUrl().clone()
                 .queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE)
                 .queryParam(OAuth2Constants.CLIENT_ID, deployment.getResourceName())
@@ -171,9 +178,15 @@ public class OAuthRequestAuthenticator {
         if (idpHint != null && idpHint.length() > 0) {
             redirectUriBuilder.queryParam(AdapterConstants.KC_IDP_HINT,idpHint);
         }
-        if (scope != null && scope.length() > 0) {
-            redirectUriBuilder.queryParam(OAuth2Constants.SCOPE, scope);
+        if (prompt != null && prompt.length() > 0) {
+            redirectUriBuilder.queryParam(OAuth2Constants.PROMPT, prompt);
         }
+        if (maxAge != null && maxAge.length() > 0) {
+            redirectUriBuilder.queryParam(OAuth2Constants.MAX_AGE, maxAge);
+        }
+
+        scope = TokenUtil.attachOIDCScope(scope);
+        redirectUriBuilder.queryParam(OAuth2Constants.SCOPE, scope);
 
         return redirectUriBuilder.build().toString();
     }
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OIDCAuthenticationError.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OIDCAuthenticationError.java
index 420ae93..a58a05a 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OIDCAuthenticationError.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/OIDCAuthenticationError.java
@@ -35,7 +35,8 @@ public class OIDCAuthenticationError implements AuthenticationError {
         CODE_TO_TOKEN_FAILURE,
         INVALID_TOKEN,
         STALE_TOKEN,
-        NO_AUTHORIZATION_HEADER
+        NO_AUTHORIZATION_HEADER,
+        NO_QUERY_PARAMETER_ACCESS_TOKEN
     }
 
     private Reason reason;
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/QueryParamterTokenRequestAuthenticator.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/QueryParamterTokenRequestAuthenticator.java
new file mode 100644
index 0000000..5ee6662
--- /dev/null
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/QueryParamterTokenRequestAuthenticator.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.adapters;
+
+import org.jboss.logging.Logger;
+import org.keycloak.adapters.spi.AuthOutcome;
+import org.keycloak.adapters.spi.HttpFacade;
+
+/**
+ * @author <a href="mailto:froehlich.ch@gmail.com">Christian Froehlich</a>
+ * @version $Revision: 1 $
+ */
+public class QueryParamterTokenRequestAuthenticator extends BearerTokenRequestAuthenticator {
+    public static final String ACCESS_TOKEN = "access_token";
+    protected Logger log = Logger.getLogger(QueryParamterTokenRequestAuthenticator.class);
+
+    public QueryParamterTokenRequestAuthenticator(KeycloakDeployment deployment) {
+        super(deployment);
+    }
+
+    public AuthOutcome authenticate(HttpFacade exchange) {
+        tokenString = null;
+        tokenString = getAccessTokenFromQueryParamter(exchange);
+        if (tokenString == null || tokenString.trim().isEmpty()) {
+            challenge = challengeResponse(exchange, OIDCAuthenticationError.Reason.NO_QUERY_PARAMETER_ACCESS_TOKEN, null, null);
+            return AuthOutcome.NOT_ATTEMPTED;
+        }
+        return (authenticateToken(exchange, tokenString));
+    }
+
+    String getAccessTokenFromQueryParamter(HttpFacade exchange) {
+        try {
+            if (exchange != null && exchange.getRequest() != null) {
+                return exchange.getRequest().getQueryParamValue(ACCESS_TOKEN);
+            }
+        } catch (Exception ignore) {
+        }
+        return null;
+    }
+}
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java
index bdb5776..7cfc7a6 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java
@@ -18,9 +18,11 @@
 package org.keycloak.adapters;
 
 import org.jboss.logging.Logger;
+import org.keycloak.AuthorizationContext;
 import org.keycloak.KeycloakSecurityContext;
 import org.keycloak.RSATokenVerifier;
 import org.keycloak.common.VerificationException;
+import org.keycloak.common.util.Time;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.representations.IDToken;
@@ -74,7 +76,11 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext 
     }
 
     public boolean isActive() {
-        return token != null && this.token.isActive() && this.token.getIssuedAt() > deployment.getNotBefore();
+        return token != null && this.token.isActive() && deployment!=null && this.token.getIssuedAt() > deployment.getNotBefore();
+    }
+
+    public boolean isTokenTimeToLiveSufficient(AccessToken token) {
+        return token != null && (token.getExpiration() - this.deployment.getTokenMinimumTimeToLive()) > Time.currentTime();
     }
 
     public KeycloakDeployment getDeployment() {
@@ -95,7 +101,7 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext 
             if (log.isTraceEnabled()) {
                 log.trace("checking whether to refresh.");
             }
-            if (isActive()) return true;
+            if (isActive() && isTokenTimeToLiveSufficient(this.token)) return true;
         }
 
         if (this.deployment == null || refreshToken == null) return false; // Might be serialized in HttpSession?
@@ -130,6 +136,13 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext 
             log.error("failed verification of token");
             return false;
         }
+
+        // If the TTL is greater-or-equal to the expire time on the refreshed token, have to abort or go into an infinite refresh loop
+        if (!isTokenTimeToLiveSufficient(token)) {
+            log.error("failed to refresh the token with a longer time-to-live than the minimum");
+            return false;
+        }
+
         if (response.getNotBeforePolicy() > deployment.getNotBefore()) {
             deployment.setNotBefore(response.getNotBeforePolicy());
         }
@@ -145,4 +158,8 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext 
         tokenStore.refreshCallback(this);
         return true;
     }
+
+    public void setAuthorizationContext(AuthorizationContext authorizationContext) {
+        this.authorizationContext = authorizationContext;
+    }
 }
diff --git a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java
index 2cd1261..c04f21c 100755
--- a/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java
+++ b/adapters/oidc/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java
@@ -61,7 +61,7 @@ public abstract class RequestAuthenticator {
         if (log.isTraceEnabled()) {
             log.trace("try bearer");
         }
-        
+
         AuthOutcome outcome = bearer.authenticate(facade);
         if (outcome == AuthOutcome.FAILED) {
             challenge = bearer.getChallenge();
@@ -74,18 +74,36 @@ public abstract class RequestAuthenticator {
             return AuthOutcome.AUTHENTICATED;
         }
 
+        QueryParamterTokenRequestAuthenticator queryParamAuth = createQueryParamterTokenRequestAuthenticator();
+        if (log.isTraceEnabled()) {
+            log.trace("try query paramter auth");
+        }
+
+        outcome = queryParamAuth.authenticate(facade);
+        if (outcome == AuthOutcome.FAILED) {
+            challenge = queryParamAuth.getChallenge();
+            log.debug("QueryParamAuth auth FAILED");
+            return AuthOutcome.FAILED;
+        } else if (outcome == AuthOutcome.AUTHENTICATED) {
+            if (verifySSL()) return AuthOutcome.FAILED;
+            log.debug("QueryParamAuth AUTHENTICATED");
+            completeAuthentication(queryParamAuth, "KEYCLOAK");
+            return AuthOutcome.AUTHENTICATED;
+        }
+
         if (deployment.isEnableBasicAuth()) {
             BasicAuthRequestAuthenticator basicAuth = createBasicAuthAuthenticator();
             if (log.isTraceEnabled()) {
                 log.trace("try basic auth");
             }
-    
+
             outcome = basicAuth.authenticate(facade);
             if (outcome == AuthOutcome.FAILED) {
                 challenge = basicAuth.getChallenge();
                 log.debug("BasicAuth FAILED");
                 return AuthOutcome.FAILED;
             } else if (outcome == AuthOutcome.AUTHENTICATED) {
+                if (verifySSL()) return AuthOutcome.FAILED;
                 log.debug("BasicAuth AUTHENTICATED");
                 completeAuthentication(basicAuth, "BASIC");
                 return AuthOutcome.AUTHENTICATED;
@@ -150,6 +168,10 @@ public abstract class RequestAuthenticator {
         return new BasicAuthRequestAuthenticator(deployment);
     }
 
+    protected QueryParamterTokenRequestAuthenticator createQueryParamterTokenRequestAuthenticator() {
+        return new QueryParamterTokenRequestAuthenticator(deployment);
+    }
+
     protected void completeAuthentication(OAuthRequestAuthenticator oauth) {
         RefreshableKeycloakSecurityContext session = new RefreshableKeycloakSecurityContext(deployment, tokenStore, oauth.getTokenString(), oauth.getToken(), oauth.getIdTokenString(), oauth.getIdToken(), oauth.getRefreshToken());
         final KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal = new KeycloakPrincipal<RefreshableKeycloakSecurityContext>(AdapterUtils.getPrincipalName(deployment, oauth.getToken()), session);
@@ -158,10 +180,12 @@ public abstract class RequestAuthenticator {
     }
 
     protected abstract void completeOAuthAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal);
+
     protected abstract void completeBearerAuthentication(KeycloakPrincipal<RefreshableKeycloakSecurityContext> principal, String method);
 
     /**
      * After code is received, we change the session id if possible to guard against https://www.owasp.org/index.php/Session_Fixation
+     *
      * @param create
      * @return
      */
diff --git a/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java b/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java
index 93d1ea7..4be5110 100644
--- a/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java
+++ b/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/KeycloakDeploymentBuilderTest.java
@@ -61,6 +61,7 @@ public class KeycloakDeploymentBuilderTest {
         assertEquals(1000, deployment.getRegisterNodePeriod());
         assertEquals(TokenStore.COOKIE, deployment.getTokenStore());
         assertEquals("email", deployment.getPrincipalAttribute());
+        assertEquals(10, deployment.getTokenMinimumTimeToLive());
     }
 
     @Test
diff --git a/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/RefreshableKeycloakSecurityContextTest.java b/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/RefreshableKeycloakSecurityContextTest.java
new file mode 100644
index 0000000..2310b21
--- /dev/null
+++ b/adapters/oidc/adapter-core/src/test/java/org/keycloak/adapters/RefreshableKeycloakSecurityContextTest.java
@@ -0,0 +1,23 @@
+package org.keycloak.adapters;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.keycloak.representations.oidc.TokenMetadataRepresentation;
+/**
+ * @author github.com/tubbynl
+ *
+ */
+public class RefreshableKeycloakSecurityContextTest {
+
+	@Test
+	public void isActive() {
+		TokenMetadataRepresentation token = new TokenMetadataRepresentation();
+		token.setActive(true);
+		token.issuedNow();
+		RefreshableKeycloakSecurityContext sut = new RefreshableKeycloakSecurityContext(null,null,null,token,null, null, null);
+		
+		// verify false if null deployment (KEYCLOAK-3050; yielded a npe)
+		assertFalse(sut.isActive());
+	}
+}
diff --git a/adapters/oidc/adapter-core/src/test/resources/keycloak.json b/adapters/oidc/adapter-core/src/test/resources/keycloak.json
index 5a41841..7bf269f 100644
--- a/adapters/oidc/adapter-core/src/test/resources/keycloak.json
+++ b/adapters/oidc/adapter-core/src/test/resources/keycloak.json
@@ -28,5 +28,6 @@
     "register-node-at-startup": true,
     "register-node-period": 1000,
     "token-store": "cookie",
-    "principal-attribute": "email"
+    "principal-attribute": "email",
+    "token-minimum-time-to-live": 10
 }
\ No newline at end of file
diff --git a/adapters/oidc/as7-eap6/as7-adapter/pom.xml b/adapters/oidc/as7-eap6/as7-adapter/pom.xml
index 88625c5..ddf1683 100755
--- a/adapters/oidc/as7-eap6/as7-adapter/pom.xml
+++ b/adapters/oidc/as7-eap6/as7-adapter/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-as7-integration-pom</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/adapters/oidc/as7-eap6/as7-adapter-spi/pom.xml b/adapters/oidc/as7-eap6/as7-adapter-spi/pom.xml
index 03d68cc..15617bc 100755
--- a/adapters/oidc/as7-eap6/as7-adapter-spi/pom.xml
+++ b/adapters/oidc/as7-eap6/as7-adapter-spi/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-as7-integration-pom</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/adapters/oidc/as7-eap6/as7-subsystem/pom.xml b/adapters/oidc/as7-eap6/as7-subsystem/pom.xml
index 35ff17a..743506f 100755
--- a/adapters/oidc/as7-eap6/as7-subsystem/pom.xml
+++ b/adapters/oidc/as7-eap6/as7-subsystem/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak</groupId>
         <artifactId>keycloak-as7-integration-pom</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/adapters/oidc/as7-eap6/as7-subsystem/src/main/java/org/keycloak/subsystem/as7/KeycloakAdapterConfigDeploymentProcessor.java b/adapters/oidc/as7-eap6/as7-subsystem/src/main/java/org/keycloak/subsystem/as7/KeycloakAdapterConfigDeploymentProcessor.java
index 9b60acd..cdaa375 100755
--- a/adapters/oidc/as7-eap6/as7-subsystem/src/main/java/org/keycloak/subsystem/as7/KeycloakAdapterConfigDeploymentProcessor.java
+++ b/adapters/oidc/as7-eap6/as7-subsystem/src/main/java/org/keycloak/subsystem/as7/KeycloakAdapterConfigDeploymentProcessor.java
@@ -49,7 +49,6 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
     @Override
     public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
         DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
-        String deploymentName = deploymentUnit.getName();
 
         // if it's not a web-app there's nothing to secure
         WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
@@ -67,24 +66,24 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
         // otherwise
         LoginConfigMetaData loginConfig = webMetaData.getLoginConfig();
 
-        boolean hasSubsystemConfig = service.isSecureDeployment(deploymentName);
+        boolean hasSubsystemConfig = service.isSecureDeployment(deploymentUnit);
         boolean webRequiresKC = loginConfig != null && "KEYCLOAK".equalsIgnoreCase(loginConfig.getAuthMethod());
 
         if (hasSubsystemConfig || webRequiresKC) {
-            log.debug("Setting up KEYCLOAK auth method for WAR: " + deploymentName);
+            log.debug("Setting up KEYCLOAK auth method for WAR: " + deploymentUnit.getName());
 
             // if secure-deployment configuration exists for web app, we force KEYCLOAK auth method on it
             if (hasSubsystemConfig) {
-                addJSONData(service.getJSON(deploymentName), warMetaData);
+                addJSONData(service.getJSON(deploymentUnit), warMetaData);
                 if (loginConfig != null) {
                     loginConfig.setAuthMethod("KEYCLOAK");
-                    loginConfig.setRealmName(service.getRealmName(deploymentName));
+                    loginConfig.setRealmName(service.getRealmName(deploymentUnit));
                 } else {
-                    log.warn("Failed to set up KEYCLOAK auth method for WAR: " + deploymentName + " (loginConfig == null)");
+                    log.warn("Failed to set up KEYCLOAK auth method for WAR: " + deploymentUnit.getName() + " (loginConfig == null)");
                 }
             }
             addValve(webMetaData);
-            KeycloakLogger.ROOT_LOGGER.deploymentSecured(deploymentName);
+            KeycloakLogger.ROOT_LOGGER.deploymentSecured(deploymentUnit.getName());
         }
     }
 
diff --git a/adapters/oidc/as7-eap6/as7-subsystem/src/main/java/org/keycloak/subsystem/as7/KeycloakAdapterConfigService.java b/adapters/oidc/as7-eap6/as7-subsystem/src/main/java/org/keycloak/subsystem/as7/KeycloakAdapterConfigService.java
index 326862b..0b690c3 100755
--- a/adapters/oidc/as7-eap6/as7-subsystem/src/main/java/org/keycloak/subsystem/as7/KeycloakAdapterConfigService.java
+++ b/adapters/oidc/as7-eap6/as7-subsystem/src/main/java/org/keycloak/subsystem/as7/KeycloakAdapterConfigService.java
@@ -25,6 +25,9 @@ import java.util.HashMap;
 import java.util.Map;
 
 import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADDRESS;
+import org.jboss.as.server.deployment.DeploymentUnit;
+import org.jboss.as.web.deployment.WarMetaData;
+import org.jboss.metadata.web.jboss.JBossWebMetaData;
 
 /**
  * This service keeps track of the entire Keycloak management model so as to provide
@@ -154,13 +157,15 @@ public final class KeycloakAdapterConfigService {
         return null;
     }
 
-    public String getRealmName(String deploymentName) {
+    public String getRealmName(DeploymentUnit deploymentUnit) {
+        String deploymentName = preferredDeploymentName(deploymentUnit);
         ModelNode deployment = this.secureDeployments.get(deploymentName);
         return deployment.get(RealmDefinition.TAG_NAME).asString();
 
     }
 
-    public String getJSON(String deploymentName) {
+    public String getJSON(DeploymentUnit deploymentUnit) {
+        String deploymentName = preferredDeploymentName(deploymentUnit);
         ModelNode deployment = this.secureDeployments.get(deploymentName);
         String realmName = deployment.get(RealmDefinition.TAG_NAME).asString();
         ModelNode realm = this.realms.get(realmName);
@@ -184,9 +189,29 @@ public final class KeycloakAdapterConfigService {
         }
     }
 
-    public boolean isSecureDeployment(String deploymentName) {
+    public boolean isSecureDeployment(DeploymentUnit deploymentUnit) {
         //log.info("********* CHECK KEYCLOAK DEPLOYMENT: deployments.size()" + deployments.size());
 
+        String deploymentName = preferredDeploymentName(deploymentUnit);
         return this.secureDeployments.containsKey(deploymentName);
     }
+    
+    // KEYCLOAK-3273: prefer module name if available
+    private String preferredDeploymentName(DeploymentUnit deploymentUnit) {
+        String deploymentName = deploymentUnit.getName();
+        WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
+        if (warMetaData == null) {
+            return deploymentName;
+        }
+        
+        JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
+        if (webMetaData == null) {
+            return deploymentName;
+        }
+        
+        String moduleName = webMetaData.getModuleName();
+        if (moduleName != null) return moduleName + ".war";
+        
+        return deploymentName;
+    }
 }
diff --git a/adapters/oidc/as7-eap6/as7-subsystem/src/main/java/org/keycloak/subsystem/as7/KeycloakDependencyProcessor.java b/adapters/oidc/as7-eap6/as7-subsystem/src/main/java/org/keycloak/subsystem/as7/KeycloakDependencyProcessor.java
index 8f84a7c..b778dc0 100755
--- a/adapters/oidc/as7-eap6/as7-subsystem/src/main/java/org/keycloak/subsystem/as7/KeycloakDependencyProcessor.java
+++ b/adapters/oidc/as7-eap6/as7-subsystem/src/main/java/org/keycloak/subsystem/as7/KeycloakDependencyProcessor.java
@@ -46,8 +46,7 @@ public abstract class KeycloakDependencyProcessor implements DeploymentUnitProce
     public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
         final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
 
-        String deploymentName = deploymentUnit.getName();
-        if (!KeycloakAdapterConfigService.getInstance().isSecureDeployment(deploymentName)) {
+        if (!KeycloakAdapterConfigService.getInstance().isSecureDeployment(deploymentUnit)) {
             WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
             if (warMetaData == null) {
                 return;
diff --git a/adapters/oidc/as7-eap6/pom.xml b/adapters/oidc/as7-eap6/pom.xml
index edd1761..10a354b 100755
--- a/adapters/oidc/as7-eap6/pom.xml
+++ b/adapters/oidc/as7-eap6/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <name>Keycloak AS7 / JBoss EAP 6 Integration</name>
diff --git a/adapters/oidc/installed/pom.xml b/adapters/oidc/installed/pom.xml
index aede1db..acaf236 100755
--- a/adapters/oidc/installed/pom.xml
+++ b/adapters/oidc/installed/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/adapters/oidc/installed/src/main/java/org/keycloak/adapters/installed/KeycloakInstalled.java b/adapters/oidc/installed/src/main/java/org/keycloak/adapters/installed/KeycloakInstalled.java
index fd8af9f..fc0e47f 100644
--- a/adapters/oidc/installed/src/main/java/org/keycloak/adapters/installed/KeycloakInstalled.java
+++ b/adapters/oidc/installed/src/main/java/org/keycloak/adapters/installed/KeycloakInstalled.java
@@ -119,6 +119,7 @@ public class KeycloakInstalled {
                 .queryParam(OAuth2Constants.CLIENT_ID, deployment.getResourceName())
                 .queryParam(OAuth2Constants.REDIRECT_URI, redirectUri)
                 .queryParam(OAuth2Constants.STATE, state)
+                .queryParam(OAuth2Constants.SCOPE, OAuth2Constants.SCOPE_OPENID)
                 .build().toString();
 
         Desktop.getDesktop().browse(new URI(authUrl));
@@ -175,6 +176,7 @@ public class KeycloakInstalled {
                 .queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE)
                 .queryParam(OAuth2Constants.CLIENT_ID, deployment.getResourceName())
                 .queryParam(OAuth2Constants.REDIRECT_URI, redirectUri)
+                .queryParam(OAuth2Constants.SCOPE, OAuth2Constants.SCOPE_OPENID)
                 .build().toString();
 
         printer.println("Open the following URL in a browser. After login copy/paste the code back and press <enter>");
diff --git a/adapters/oidc/jaxrs-oauth-client/pom.xml b/adapters/oidc/jaxrs-oauth-client/pom.xml
index dd04fd1..b5626c1 100755
--- a/adapters/oidc/jaxrs-oauth-client/pom.xml
+++ b/adapters/oidc/jaxrs-oauth-client/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/adapters/oidc/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsOAuthClient.java b/adapters/oidc/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsOAuthClient.java
index cd2599e..ae305e2 100755
--- a/adapters/oidc/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsOAuthClient.java
+++ b/adapters/oidc/jaxrs-oauth-client/src/main/java/org/keycloak/jaxrs/JaxrsOAuthClient.java
@@ -20,6 +20,7 @@ package org.keycloak.jaxrs;
 import org.keycloak.AbstractOAuthClient;
 import org.keycloak.OAuth2Constants;
 import org.keycloak.representations.AccessTokenResponse;
+import org.keycloak.util.TokenUtil;
 
 import javax.ws.rs.BadRequestException;
 import javax.ws.rs.InternalServerErrorException;
@@ -85,14 +86,13 @@ public class JaxrsOAuthClient extends AbstractOAuthClient {
     }
     public Response redirect(UriInfo uriInfo, String redirectUri) {
         String state = getStateCode();
+        String scopeParam = TokenUtil.attachOIDCScope(scope);
 
         UriBuilder uriBuilder = UriBuilder.fromUri(authUrl)
                 .queryParam(OAuth2Constants.CLIENT_ID, clientId)
                 .queryParam(OAuth2Constants.REDIRECT_URI, redirectUri)
-                .queryParam(OAuth2Constants.STATE, state);
-        if (scope != null) {
-            uriBuilder.queryParam(OAuth2Constants.SCOPE, scope);
-        }
+                .queryParam(OAuth2Constants.STATE, state)
+                .queryParam(OAuth2Constants.SCOPE, scopeParam);
 
         URI url = uriBuilder.build();
 
diff --git a/adapters/oidc/jetty/jetty8.1/pom.xml b/adapters/oidc/jetty/jetty8.1/pom.xml
index 51431bf..4362384 100755
--- a/adapters/oidc/jetty/jetty8.1/pom.xml
+++ b/adapters/oidc/jetty/jetty8.1/pom.xml
@@ -21,7 +21,7 @@
     <parent>
 		<artifactId>keycloak-parent</artifactId>
 		<groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
 		<relativePath>../../../../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
diff --git a/adapters/oidc/jetty/jetty8.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java b/adapters/oidc/jetty/jetty8.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
index ae14931..681f775 100755
--- a/adapters/oidc/jetty/jetty8.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
+++ b/adapters/oidc/jetty/jetty8.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
@@ -50,7 +50,7 @@ public class KeycloakJettyAuthenticator extends AbstractKeycloakJettyAuthenticat
     }
 
     @Override
-    protected Authentication createAuthentication(UserIdentity userIdentity) {
+    protected Authentication createAuthentication(UserIdentity userIdentity, Request request) {
         return new KeycloakAuthentication(getAuthMethod(), userIdentity) {
             @Override
             public void logout() {
diff --git a/adapters/oidc/jetty/jetty9.1/pom.xml b/adapters/oidc/jetty/jetty9.1/pom.xml
index 2263af2..f7cdc36 100755
--- a/adapters/oidc/jetty/jetty9.1/pom.xml
+++ b/adapters/oidc/jetty/jetty9.1/pom.xml
@@ -21,7 +21,7 @@
     <parent>
 		<artifactId>keycloak-parent</artifactId>
 		<groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
 		<relativePath>../../../../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
diff --git a/adapters/oidc/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java b/adapters/oidc/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
index 6ca324e..0df8e73 100755
--- a/adapters/oidc/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
+++ b/adapters/oidc/jetty/jetty9.1/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
@@ -52,7 +52,7 @@ public class KeycloakJettyAuthenticator extends AbstractKeycloakJettyAuthenticat
     }
 
     @Override
-    protected Authentication createAuthentication(UserIdentity userIdentity) {
+    protected Authentication createAuthentication(UserIdentity userIdentity, Request request) {
         return new KeycloakAuthentication(getAuthMethod(), userIdentity) {
             @Override
             public void logout() {
diff --git a/adapters/oidc/jetty/jetty9.2/pom.xml b/adapters/oidc/jetty/jetty9.2/pom.xml
index c090f8f..2e8049c 100755
--- a/adapters/oidc/jetty/jetty9.2/pom.xml
+++ b/adapters/oidc/jetty/jetty9.2/pom.xml
@@ -21,7 +21,7 @@
     <parent>
 		<artifactId>keycloak-parent</artifactId>
 		<groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
 		<relativePath>../../../../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
diff --git a/adapters/oidc/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java b/adapters/oidc/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
index 6986b82..3388483 100755
--- a/adapters/oidc/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
+++ b/adapters/oidc/jetty/jetty9.2/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
@@ -47,7 +47,7 @@ public class KeycloakJettyAuthenticator extends AbstractKeycloakJettyAuthenticat
     }
 
     @Override
-    protected Authentication createAuthentication(UserIdentity userIdentity) {
+    protected Authentication createAuthentication(UserIdentity userIdentity, Request request) {
         return new KeycloakAuthentication(getAuthMethod(), userIdentity) {
             @Override
             public void logout() {
diff --git a/adapters/oidc/jetty/jetty9.3/pom.xml b/adapters/oidc/jetty/jetty9.3/pom.xml
new file mode 100644
index 0000000..1f4e84b
--- /dev/null
+++ b/adapters/oidc/jetty/jetty9.3/pom.xml
@@ -0,0 +1,156 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <parent>
+		<artifactId>keycloak-parent</artifactId>
+		<groupId>org.keycloak</groupId>
+        <version>2.2.0-SNAPSHOT</version>
+		<relativePath>../../../../pom.xml</relativePath>
+	</parent>
+	<modelVersion>4.0.0</modelVersion>
+
+	<artifactId>keycloak-jetty93-adapter</artifactId>
+	<name>Keycloak Jetty 9.3.x Integration</name>
+    <properties>
+        <jetty9.version>9.3.9.v20160517</jetty9.version>
+        <keycloak.osgi.export>
+            org.keycloak.adapters.jetty.*
+        </keycloak.osgi.export>
+        <keycloak.osgi.import>
+            org.eclipse.jetty.*;resolution:=optional,
+            javax.servlet.*;version="[3.0,4)";resolution:=optional,
+            org.keycloak.*;version="${project.version}",
+            *;resolution:=optional
+        </keycloak.osgi.import>
+    </properties>
+	<description />
+
+	<dependencies>
+        <dependency>
+            <groupId>org.jboss.logging</groupId>
+            <artifactId>jboss-logging</artifactId>
+            <version>${jboss.logging.version}</version>
+        </dependency>
+		<dependency>
+			<groupId>org.keycloak</groupId>
+			<artifactId>keycloak-core</artifactId>
+		</dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-adapter-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-jetty-core</artifactId>
+        </dependency>
+		<dependency>
+			<groupId>org.apache.httpcomponents</groupId>
+			<artifactId>httpclient</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.bouncycastle</groupId>
+			<artifactId>bcprov-jdk15on</artifactId>
+		</dependency>
+		<dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-core</artifactId>
+		</dependency>
+		<dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+		</dependency>
+		<dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+		</dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-server</artifactId>
+            <version>${jetty9.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-util</artifactId>
+            <version>${jetty9.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-security</artifactId>
+            <version>${jetty9.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<configuration>
+					<source>1.6</source>
+					<target>1.6</target>
+				</configuration>
+			</plugin>
+
+            <!-- Adding OSGI metadata to the JAR without changing the packaging type. -->
+            <plugin>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+                    </archive>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <executions>
+                    <execution>
+                        <id>bundle-manifest</id>
+                        <phase>process-classes</phase>
+                        <goals>
+                            <goal>manifest</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <instructions>
+                        <Bundle-ClassPath>.</Bundle-ClassPath>
+                        <Bundle-Name>${project.name}</Bundle-Name>
+                        <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+                        <Import-Package>${keycloak.osgi.import}</Import-Package>
+                        <Export-Package>${keycloak.osgi.export}</Export-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+		</plugins>
+	</build>
+
+</project>
diff --git a/adapters/oidc/jetty/jetty9.3/src/main/java/org/keycloak/adapters/jetty/Jetty93RequestAuthenticator.java b/adapters/oidc/jetty/jetty9.3/src/main/java/org/keycloak/adapters/jetty/Jetty93RequestAuthenticator.java
new file mode 100644
index 0000000..e77667b
--- /dev/null
+++ b/adapters/oidc/jetty/jetty9.3/src/main/java/org/keycloak/adapters/jetty/Jetty93RequestAuthenticator.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.adapters.jetty;
+
+import org.eclipse.jetty.server.Request;
+import org.keycloak.adapters.AdapterTokenStore;
+import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.jetty.core.JettyRequestAuthenticator;
+import org.keycloak.adapters.spi.HttpFacade;
+
+import javax.servlet.http.HttpSession;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class Jetty93RequestAuthenticator extends JettyRequestAuthenticator {
+    public Jetty93RequestAuthenticator(HttpFacade facade, KeycloakDeployment deployment, AdapterTokenStore tokenStore, int sslRedirectPort, Request request) {
+        super(facade, deployment, tokenStore, sslRedirectPort, request);
+    }
+
+    @Override
+    protected String changeHttpSessionId(boolean create) {
+        Request request = this.request;
+        HttpSession session = request.getSession(false);
+        if (session == null) {
+            return request.getSession(true).getId();
+        }
+        if (!deployment.isTurnOffChangeSessionIdOnLogin()) return request.changeSessionId();
+        else return session.getId();
+    }
+}
diff --git a/adapters/oidc/jetty/jetty9.3/src/main/java/org/keycloak/adapters/jetty/JettyAdapterSessionStore.java b/adapters/oidc/jetty/jetty9.3/src/main/java/org/keycloak/adapters/jetty/JettyAdapterSessionStore.java
new file mode 100644
index 0000000..f5f6ef8
--- /dev/null
+++ b/adapters/oidc/jetty/jetty9.3/src/main/java/org/keycloak/adapters/jetty/JettyAdapterSessionStore.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.adapters.jetty;
+
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.security.authentication.FormAuthenticator;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.util.MultiMap;
+import org.keycloak.adapters.spi.AdapterSessionStore;
+import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
+import org.keycloak.common.util.MultivaluedHashMap;
+
+import javax.servlet.http.HttpSession;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class JettyAdapterSessionStore implements AdapterSessionStore {
+    public static final String CACHED_FORM_PARAMETERS = "__CACHED_FORM_PARAMETERS";
+    protected Request myRequest;
+
+    public JettyAdapterSessionStore(Request request) {
+        this.myRequest = request; // for IDE/compilation purposes
+    }
+
+    protected MultiMap<String> extractFormParameters(Request base_request) {
+        MultiMap<String> formParameters = new MultiMap<String>();
+        base_request.extractFormParameters(formParameters);
+        return formParameters;
+    }
+    protected void restoreFormParameters(MultiMap<String> j_post, Request base_request) {
+        base_request.setContentParameters(j_post);
+    }
+
+    public boolean restoreRequest() {
+        HttpSession session = myRequest.getSession(false);
+        if (session == null) return false;
+        synchronized (session) {
+            String j_uri = (String) session.getAttribute(FormAuthenticator.__J_URI);
+            if (j_uri != null) {
+                // check if the request is for the same url as the original and restore
+                // params if it was a post
+                StringBuffer buf = myRequest.getRequestURL();
+                if (myRequest.getQueryString() != null)
+                    buf.append("?").append(myRequest.getQueryString());
+                if (j_uri.equals(buf.toString())) {
+                    String method = (String)session.getAttribute(JettyHttpFacade.__J_METHOD);
+                    myRequest.setMethod(method);
+                    MultivaluedHashMap<String, String> j_post = (MultivaluedHashMap<String, String>) session.getAttribute(CACHED_FORM_PARAMETERS);
+                    if (j_post != null) {
+                        myRequest.setContentType("application/x-www-form-urlencoded");
+                        MultiMap<String> map = new MultiMap<String>();
+                        for (String key : j_post.keySet()) {
+                            for (String val : j_post.getList(key)) {
+                                map.add(key, val);
+                            }
+                        }
+                        restoreFormParameters(map, myRequest);
+                    }
+                    session.removeAttribute(FormAuthenticator.__J_URI);
+                    session.removeAttribute(JettyHttpFacade.__J_METHOD);
+                    session.removeAttribute(FormAuthenticator.__J_POST);
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void saveRequest() {
+        // remember the current URI
+        HttpSession session = myRequest.getSession();
+        synchronized (session) {
+            // But only if it is not set already, or we save every uri that leads to a login form redirect
+            if (session.getAttribute(FormAuthenticator.__J_URI) == null) {
+                StringBuffer buf = myRequest.getRequestURL();
+                if (myRequest.getQueryString() != null)
+                    buf.append("?").append(myRequest.getQueryString());
+                session.setAttribute(FormAuthenticator.__J_URI, buf.toString());
+                session.setAttribute(JettyHttpFacade.__J_METHOD, myRequest.getMethod());
+
+                if ("application/x-www-form-urlencoded".equals(myRequest.getContentType()) && "POST".equalsIgnoreCase(myRequest.getMethod())) {
+                    MultiMap<String> formParameters = extractFormParameters(myRequest);
+                    MultivaluedHashMap<String, String> map = new MultivaluedHashMap<String, String>();
+                    for (String key : formParameters.keySet()) {
+                        for (Object value : formParameters.getValues(key)) {
+                            map.add(key, (String) value);
+                        }
+                    }
+                    session.setAttribute(CACHED_FORM_PARAMETERS, map);
+                }
+            }
+        }
+    }
+
+}
diff --git a/adapters/oidc/jetty/jetty9.3/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java b/adapters/oidc/jetty/jetty9.3/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
new file mode 100644
index 0000000..fe9c098
--- /dev/null
+++ b/adapters/oidc/jetty/jetty9.3/src/main/java/org/keycloak/adapters/jetty/KeycloakJettyAuthenticator.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.adapters.jetty;
+
+import org.eclipse.jetty.server.Authentication;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.UserIdentity;
+import org.keycloak.adapters.AdapterTokenStore;
+import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.jetty.core.AbstractKeycloakJettyAuthenticator;
+import org.keycloak.adapters.jetty.core.JettyRequestAuthenticator;
+import org.keycloak.adapters.jetty.core.JettySessionTokenStore;
+import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
+
+import javax.servlet.ServletRequest;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class KeycloakJettyAuthenticator extends AbstractKeycloakJettyAuthenticator {
+
+    public KeycloakJettyAuthenticator() {
+        super();
+    }
+
+
+    @Override
+    protected Request resolveRequest(ServletRequest req) {
+        return Request.getBaseRequest(req);
+    }
+
+    @Override
+    protected Authentication createAuthentication(UserIdentity userIdentity, final Request request) {
+        return new KeycloakAuthentication(getAuthMethod(), userIdentity) {
+            @Override
+            public void logout() {
+                logoutCurrent(request);
+            }
+        };
+    }
+
+    @Override
+    public AdapterTokenStore createSessionTokenStore(Request request, KeycloakDeployment resolvedDeployment) {
+        return new JettySessionTokenStore(request, resolvedDeployment, new JettyAdapterSessionStore(request));
+    }
+
+    @Override
+    protected JettyRequestAuthenticator createRequestAuthenticator(Request request, JettyHttpFacade facade,
+                                                                   KeycloakDeployment deployment, AdapterTokenStore tokenStore) {
+        return new Jetty93RequestAuthenticator(facade, deployment, tokenStore, -1, request);
+    }
+
+}
diff --git a/adapters/oidc/jetty/jetty-core/pom.xml b/adapters/oidc/jetty/jetty-core/pom.xml
index 26ae917..7292547 100755
--- a/adapters/oidc/jetty/jetty-core/pom.xml
+++ b/adapters/oidc/jetty/jetty-core/pom.xml
@@ -21,7 +21,7 @@
     <parent>
 		<artifactId>keycloak-parent</artifactId>
 		<groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
 		<relativePath>../../../../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
diff --git a/adapters/oidc/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/AbstractKeycloakJettyAuthenticator.java b/adapters/oidc/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/AbstractKeycloakJettyAuthenticator.java
index 56d8f51..d732714 100755
--- a/adapters/oidc/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/AbstractKeycloakJettyAuthenticator.java
+++ b/adapters/oidc/jetty/jetty-core/src/main/java/org/keycloak/adapters/jetty/core/AbstractKeycloakJettyAuthenticator.java
@@ -340,13 +340,13 @@ public abstract class AbstractKeycloakJettyAuthenticator extends LoginAuthentica
         Authentication authentication = request.getAuthentication();
         if (!(authentication instanceof KeycloakAuthentication)) {
             UserIdentity userIdentity = createIdentity(principal);
-            authentication = createAuthentication(userIdentity);
+            authentication = createAuthentication(userIdentity, request);
             request.setAuthentication(authentication);
         }
         return authentication;
     }
 
-    protected abstract Authentication createAuthentication(UserIdentity userIdentity);
+    protected abstract Authentication createAuthentication(UserIdentity userIdentity, Request request);
 
     public static abstract class KeycloakAuthentication extends UserAuthentication {
         public KeycloakAuthentication(String method, UserIdentity userIdentity) {
diff --git a/adapters/oidc/jetty/pom.xml b/adapters/oidc/jetty/pom.xml
index 6300953..fa87f8f 100755
--- a/adapters/oidc/jetty/pom.xml
+++ b/adapters/oidc/jetty/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <name>Keycloak Jetty Integration</name>
@@ -33,7 +33,8 @@
     <modules>
         <module>jetty-core</module>
         <module>jetty8.1</module>
-        <module>jetty9.2</module>
         <module>jetty9.1</module>
+        <module>jetty9.2</module>
+        <module>jetty9.3</module>
     </modules>
 </project>
diff --git a/adapters/oidc/js/pom.xml b/adapters/oidc/js/pom.xml
index 315f4b7..54aa16a 100755
--- a/adapters/oidc/js/pom.xml
+++ b/adapters/oidc/js/pom.xml
@@ -21,7 +21,7 @@
 	<parent>
 		<artifactId>keycloak-parent</artifactId>
 		<groupId>org.keycloak</groupId>
-		<version>2.0.0.CR1-SNAPSHOT</version>
+		<version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
@@ -58,6 +58,25 @@
                             <goal>minify</goal>
                         </goals>
                     </execution>
+                    <execution>
+                        <id>min-authz-js</id>
+                        <phase>compile</phase>
+                        <configuration>
+                            <charset>utf-8</charset>
+                            <webappSourceDir>${basedir}/src/main/resources</webappSourceDir>
+                            <jsSourceDir>.</jsSourceDir>
+                            <jsSourceFiles>
+                                <jsSourceFile>keycloak-authz.js</jsSourceFile>
+                            </jsSourceFiles>
+
+                            <webappTargetDir>${project.build.directory}/classes</webappTargetDir>
+                            <jsTargetDir>.</jsTargetDir>
+                            <jsFinalFile>keycloak-authz.js</jsFinalFile>
+                        </configuration>
+                        <goals>
+                            <goal>minify</goal>
+                        </goals>
+                    </execution>
                 </executions>
             </plugin>
 		</plugins>
diff --git a/adapters/oidc/js/src/main/resources/keycloak.js b/adapters/oidc/js/src/main/resources/keycloak.js
index 44151e6..563f7ca 100755
--- a/adapters/oidc/js/src/main/resources/keycloak.js
+++ b/adapters/oidc/js/src/main/resources/keycloak.js
@@ -25,7 +25,7 @@
         var kc = this;
         var adapter;
         var refreshQueue = [];
-        var storage;
+        var callbackStorage;
 
         var loginIframe = {
             enable: true,
@@ -36,10 +36,10 @@
         kc.init = function (initOptions) {
             kc.authenticated = false;
 
-            storage = new PersistentStorage();
+            callbackStorage = createCallbackStorage();
 
             if (initOptions && initOptions.adapter === 'cordova') {
-               adapter = loadAdapter('cordova');
+                adapter = loadAdapter('cordova');
             } else if (initOptions && initOptions.adapter === 'default') {
                 adapter = loadAdapter();
             } else {
@@ -103,8 +103,8 @@
             initPromise.promise.success(function() {
                 kc.onReady && kc.onReady(kc.authenticated);
                 promise.setSuccess(kc.authenticated);
-            }).error(function() {
-                promise.setError();
+            }).error(function(errorData) {
+                promise.setError(errorData);
             });
 
             var configPromise = loadConfig(config);
@@ -201,13 +201,15 @@
                 redirectUri += (redirectUri.indexOf('?') == -1 ? '?' : '&') + 'prompt=' + options.prompt;
             }
 
-            storage.setItem('oauthState', JSON.stringify({ state: state, nonce: nonce, redirectUri: encodeURIComponent(redirectUri) }));
+            callbackStorage.add({ state: state, nonce: nonce, redirectUri: encodeURIComponent(redirectUri) });
 
             var action = 'auth';
             if (options && options.action == 'register') {
                 action = 'registrations';
             }
 
+            var scope = (options && options.scope) ? "openid " + options.scope : "openid";
+
             var url = getRealmUrl()
                 + '/protocol/openid-connect/' + action
                 + '?client_id=' + encodeURIComponent(kc.clientId)
@@ -215,12 +217,17 @@
                 + '&state=' + encodeURIComponent(state)
                 + '&nonce=' + encodeURIComponent(nonce)
                 + '&response_mode=' + encodeURIComponent(kc.responseMode)
-                + '&response_type=' + encodeURIComponent(kc.responseType);
+                + '&response_type=' + encodeURIComponent(kc.responseType)
+                + '&scope=' + encodeURIComponent(scope);
 
             if (options && options.prompt) {
                 url += '&prompt=' + encodeURIComponent(options.prompt);
             }
 
+            if (options && options.maxAge) {
+                url += '&max_age=' + encodeURIComponent(options.maxAge);
+            }
+
             if (options && options.loginHint) {
                 url += '&login_hint=' + encodeURIComponent(options.loginHint);
             }
@@ -229,10 +236,6 @@
                 url += '&kc_idp_hint=' + encodeURIComponent(options.idpHint);
             }
 
-            if (options && options.scope) {
-                url += '&scope=' + encodeURIComponent(options.scope);
-            }
-
             if (options && options.locale) {
                 url += '&ui_locales=' + encodeURIComponent(options.locale);
             }
@@ -463,8 +466,9 @@
 
             if (error) {
                 if (prompt != 'none') {
-                    kc.onAuthError && kc.onAuthError();
-                    promise && promise.setError();
+                    var errorData = { error: error, error_description: oauth.error_description };
+                    kc.onAuthError && kc.onAuthError(errorData);
+                    promise && promise.setError(errorData);
                 } else {
                     promise && promise.setSuccess();
                 }
@@ -697,15 +701,11 @@
 
         function parseCallback(url) {
             var oauth = new CallbackParser(url, kc.responseMode).parseUri();
+            var oauthState = callbackStorage.get(oauth.state);
 
-            var oauthState = storage.getItem('oauthState');
-            var sessionState = oauthState && JSON.parse(oauthState);
-
-            if (sessionState && (oauth.code || oauth.error || oauth.access_token || oauth.id_token) && oauth.state && oauth.state == sessionState.state) {
-                storage.removeItem('oauthState');
-
-                oauth.redirectUri = sessionState.redirectUri;
-                oauth.storedNonce = sessionState.nonce;
+            if (oauthState && (oauth.code || oauth.error || oauth.access_token || oauth.id_token)) {
+                oauth.redirectUri = oauthState.redirectUri;
+                oauth.storedNonce = oauthState.nonce;
 
                 if (oauth.fragment) {
                     oauth.newUrl += '#' + oauth.fragment;
@@ -792,8 +792,22 @@
                 if (event.origin !== loginIframe.iframeOrigin) {
                     return;
                 }
-                var data = JSON.parse(event.data);
+
+                try {
+                    var data = JSON.parse(event.data);
+                } catch (err) {
+                    return;
+                }
+
+                if (!data.callbackId) {
+                    return;
+                }
+
                 var promise = loginIframe.callbackMap[data.callbackId];
+                if (!promise) {
+                    return;
+                }
+
                 delete loginIframe.callbackMap[data.callbackId];
 
                 if ((!kc.sessionId || kc.sessionId == data.session) && data.loggedIn) {
@@ -982,60 +996,93 @@
             throw 'invalid adapter type: ' + type;
         }
 
+        var LocalStorage = function() {
+            if (!(this instanceof LocalStorage)) {
+                return new LocalStorage();
+            }
 
-        var PersistentStorage = function() {
-            if (!(this instanceof PersistentStorage)) {
-                return new PersistentStorage();
+            localStorage.setItem('kc-test', 'test');
+            localStorage.removeItem('kc-test');
+
+            var cs = this;
+
+            function clearExpired() {
+                var time = new Date().getTime();
+                for (var i = 1; i <= localStorage.length; i++)  {
+                    var key = localStorage.key(i);
+                    if (key && key.indexOf('kc-callback-') == 0) {
+                        var value = localStorage.getItem(key);
+                        if (value) {
+                            try {
+                                var expires = JSON.parse(value).expires;
+                                if (!expires || expires < time) {
+                                    localStorage.removeItem(key);
+                                }
+                            } catch (err) {
+                                localStorage.removeItem(key);
+                            }
+                        }
+                    }
+                }
             }
-            var ps = this;
-            var useCookieStorage = function () {
-                if (typeof localStorage === "undefined") {
-                    return true;
+
+            cs.get = function(state) {
+                if (!state) {
+                    return;
                 }
-                try {
-                    var key = '@@keycloak-session-storage/test';
-                    localStorage.setItem(key, 'test');
+
+                var key = 'kc-callback-' + state;
+                var value = localStorage.getItem(key);
+                if (value) {
                     localStorage.removeItem(key);
-                    return false;
-                } catch (err) {
-                    // Probably in Safari "private mode" where localStorage
-                    // quota is 0, or quota exceeded. Switching to cookie
-                    // storage.
-                    return true;
+                    value = JSON.parse(value);
                 }
-            }
 
-            ps.setItem = function(key, value) {
-                if (useCookieStorage()) {
-                    setCookie(key, value, cookieExpiration(5));
-                } else {
-                    localStorage.setItem(key, value);
-                }
+                clearExpired();
+                return value;
+            };
+
+            cs.add = function(state) {
+                clearExpired();
+
+                var key = 'kc-callback-' + state.state;
+                state.expires = new Date().getTime() + (60 * 60 * 1000);
+                localStorage.setItem(key, JSON.stringify(state));
+            };
+        };
+
+        var CookieStorage = function() {
+            if (!(this instanceof CookieStorage)) {
+                return new CookieStorage();
             }
+            
+            var cs = this;
 
-            ps.getItem = function(key) {
-                if (useCookieStorage()) {
-                    return getCookie(key);
+            cs.get = function(state) {
+                if (!state) {
+                    return;
                 }
-                return localStorage.getItem(key);
-            }
 
-            ps.removeItem = function(key) {
-                if (typeof localStorage !== "undefined") {
-                    try {
-                        // Always try to delete from localStorage.
-                        localStorage.removeItem(key);
-                    } catch (err) { }
+                var value = getCookie('kc-callback-' + state);
+                setCookie('kc-callback-' + state, '', cookieExpiration(-100));
+                if (value) {
+                    return JSON.parse(value);
                 }
-                // Always remove the cookie.
+            };
+
+            cs.add = function(state) {
+                setCookie('kc-callback-' + state.state, JSON.stringify(state), cookieExpiration(60));
+            };
+
+            cs.removeItem = function(key) {
                 setCookie(key, '', cookieExpiration(-100));
-            }
+            };
 
             var cookieExpiration = function (minutes) {
                 var exp = new Date();
                 exp.setTime(exp.getTime() + (minutes*60*1000));
                 return exp;
-            }
+            };
 
             var getCookie = function (key) {
                 var name = key + '=';
@@ -1050,13 +1097,22 @@
                     }
                 }
                 return '';
-            }
+            };
 
             var setCookie = function (key, value, expirationDate) {
                 var cookie = key + '=' + value + '; '
                     + 'expires=' + expirationDate.toUTCString() + '; ';
                 document.cookie = cookie;
             }
+        };
+
+        function createCallbackStorage() {
+            try {
+                return new LocalStorage();
+            } catch (err) {
+            }
+
+            return new CookieStorage();
         }
 
         var CallbackParser = function(uriToParse, responseMode) {
@@ -1103,7 +1159,7 @@
             }
 
             var handleQueryParam = function(paramName, paramValue, oauth) {
-                var supportedOAuthParams = [ 'code', 'error', 'state' ];
+                var supportedOAuthParams = [ 'code', 'state', 'error', 'error_description' ];
 
                 for (var i = 0 ; i< supportedOAuthParams.length ; i++) {
                     if (paramName === supportedOAuthParams[i]) {
diff --git a/adapters/oidc/js/src/main/resources/keycloak-authz.js b/adapters/oidc/js/src/main/resources/keycloak-authz.js
new file mode 100644
index 0000000..dd18477
--- /dev/null
+++ b/adapters/oidc/js/src/main/resources/keycloak-authz.js
@@ -0,0 +1,170 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+(function( window, undefined ) {
+    
+    var KeycloakAuthorization = function (keycloak) {
+        var _instance = this;
+        this.rpt = null;
+
+        this.init = function () {
+            var request = new XMLHttpRequest();
+
+            request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/.well-known/uma-configuration');
+            request.onreadystatechange = function () {
+                if (request.readyState == 4) {
+                    if (request.status == 200) {
+                        _instance.config = JSON.parse(request.responseText);
+                    } else {
+                        console.error('Could not obtain configuration from server.');
+                    }
+                }
+            }
+
+            request.send(null);
+        };
+
+        /**
+         * This method enables client applications to better integrate with resource servers protected by a Keycloak
+         * policy enforcer.
+         *
+         * In this case, the resource server will respond with a 401 status code and a WWW-Authenticate header holding the
+         * necessary information to ask a Keycloak server for authorization data using both UMA and Entitlement protocol,
+         * depending on how the policy enforcer at the resource server was configured.
+         */
+        this.authorize = function (wwwAuthenticateHeader) {
+            this.then = function (onGrant, onDeny, onError) {
+                if (wwwAuthenticateHeader.indexOf('UMA') != -1) {
+                    var params = wwwAuthenticateHeader.split(',');
+
+                    for (i = 0; i < params.length; i++) {
+                        var param = params[i].split('=');
+
+                        if (param[0] == 'ticket') {
+                            var request = new XMLHttpRequest();
+
+                            request.open('POST', _instance.config.rpt_endpoint, true);
+                            request.setRequestHeader('Content-Type', 'application/json')
+                            request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token)
+
+                            request.onreadystatechange = function () {
+                                if (request.readyState == 4) {
+                                    var status = request.status;
+
+                                    if (status >= 200 && status < 300) {
+                                        var rpt = JSON.parse(request.responseText).rpt;
+                                        _instance.rpt = rpt;
+                                        onGrant(rpt);
+                                    } else if (status == 403) {
+                                        if (onDeny) {
+                                            onDeny();
+                                        } else {
+                                            console.error('Authorization request was denied by the server.');
+                                        }
+                                    } else {
+                                        if (onError) {
+                                            onError();
+                                        } else {
+                                            console.error('Could not obtain authorization data from server.');
+                                        }
+                                    }
+                                }
+                            };
+
+                            var ticket = param[1].substring(1, param[1].length - 1).trim();
+
+                            request.send(JSON.stringify(
+                                {
+                                    ticket: ticket,
+                                    rpt: _instance.rpt
+                                }
+                            ));
+                        }
+                    }
+                } else if (wwwAuthenticateHeader.indexOf('KC_ETT') != -1) {
+                    var params = wwwAuthenticateHeader.substring('KC_ETT'.length).trim().split(',');
+                    var clientId = null;
+
+                    for (i = 0; i < params.length; i++) {
+                        var param = params[i].split('=');
+
+                        if (param[0] == 'realm') {
+                            clientId = param[1].substring(1, param[1].length - 1).trim();
+                        }
+                    }
+
+                    _instance.entitlement(clientId).then(onGrant, onDeny, onError);
+                }
+            };
+
+            /**
+             * Obtains all entitlements from a Keycloak Server based on a give resourceServerId.
+             */
+            this.entitlement = function (resourceSeververId) {
+                this.then = function (onGrant, onDeny, onError) {
+                    var request = new XMLHttpRequest();
+
+                    request.open('GET', keycloak.authServerUrl + '/realms/' + keycloak.realm + '/authz/entitlement/' + resourceSeververId, true);
+                    request.setRequestHeader('Authorization', 'Bearer ' + keycloak.token)
+
+                    request.onreadystatechange = function () {
+                        if (request.readyState == 4) {
+                            var status = request.status;
+
+                            if (status >= 200 && status < 300) {
+                                var rpt = JSON.parse(request.responseText).rpt;
+                                _instance.rpt = rpt;
+                                onGrant(rpt);
+                            } else if (status == 403) {
+                                if (onDeny) {
+                                    onDeny();
+                                } else {
+                                    console.error('Authorization request was denied by the server.');
+                                }
+                            } else {
+                                if (onError) {
+                                    onError();
+                                } else {
+                                    console.error('Could not obtain authorization data from server.');
+                                }
+                            }
+                        }
+                    };
+
+                    request.send(null);
+                };
+
+                return this;
+            };
+
+            return this;
+        };
+
+        this.init(this);
+    };
+
+    if ( typeof module === "object" && module && typeof module.exports === "object" ) {
+        module.exports = KeycloakAuthorization;
+    } else {
+        window.KeycloakAuthorization = KeycloakAuthorization;
+
+        if ( typeof define === "function" && define.amd ) {
+            define( "keycloak-authorization", [], function () { return KeycloakAuthorization; } );
+        }
+    }
+})( window );
\ No newline at end of file
diff --git a/adapters/oidc/osgi-adapter/pom.xml b/adapters/oidc/osgi-adapter/pom.xml
index 59ca855..1f6b19f 100755
--- a/adapters/oidc/osgi-adapter/pom.xml
+++ b/adapters/oidc/osgi-adapter/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/adapters/oidc/pom.xml b/adapters/oidc/pom.xml
index 1398672..f525a63 100755
--- a/adapters/oidc/pom.xml
+++ b/adapters/oidc/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <name>Keycloak OIDC Client Adapter Modules</name>
diff --git a/adapters/oidc/servlet-filter/pom.xml b/adapters/oidc/servlet-filter/pom.xml
index 2e607c2..98f907a 100755
--- a/adapters/oidc/servlet-filter/pom.xml
+++ b/adapters/oidc/servlet-filter/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/adapters/oidc/servlet-filter/src/main/java/org/keycloak/adapters/servlet/KeycloakOIDCFilter.java b/adapters/oidc/servlet-filter/src/main/java/org/keycloak/adapters/servlet/KeycloakOIDCFilter.java
index dab7501..fc13616 100755
--- a/adapters/oidc/servlet-filter/src/main/java/org/keycloak/adapters/servlet/KeycloakOIDCFilter.java
+++ b/adapters/oidc/servlet-filter/src/main/java/org/keycloak/adapters/servlet/KeycloakOIDCFilter.java
@@ -47,6 +47,7 @@ import java.io.InputStream;
 import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+import java.util.regex.Pattern;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -56,10 +57,18 @@ public class KeycloakOIDCFilter implements Filter {
     protected AdapterDeploymentContext deploymentContext;
     protected SessionIdMapper idMapper = new InMemorySessionIdMapper();
     protected NodesRegistrationManagement nodesRegistrationManagement;
+    protected Pattern skipPattern;
+
     private final static Logger log = Logger.getLogger(""+KeycloakOIDCFilter.class);
 
     @Override
     public void init(final FilterConfig filterConfig) throws ServletException {
+
+        String skipPatternDefinition = filterConfig.getInitParameter("keycloak.config.skipPattern");
+        if (skipPatternDefinition != null) {
+            skipPattern = Pattern.compile(skipPatternDefinition, Pattern.DOTALL);
+        }
+
         String configResolverClass = filterConfig.getInitParameter("keycloak.config.resolver");
         if (configResolverClass != null) {
             try {
@@ -85,13 +94,7 @@ public class KeycloakOIDCFilter implements Filter {
                 if (pathParam != null) path = pathParam;
                 is = filterConfig.getServletContext().getResourceAsStream(path);
             }
-            KeycloakDeployment kd;
-            if (is == null) {
-                log.fine("No adapter configuration. Keycloak is unconfigured and will deny all requests.");
-                kd = new KeycloakDeployment();
-            } else {
-                kd = KeycloakDeploymentBuilder.build(is);
-            }
+            KeycloakDeployment kd = createKeycloakDeploymentFrom(is);
             deploymentContext = new AdapterDeploymentContext(kd);
             log.fine("Keycloak is using a per-deployment configuration.");
         }
@@ -99,13 +102,30 @@ public class KeycloakOIDCFilter implements Filter {
         nodesRegistrationManagement = new NodesRegistrationManagement();
     }
 
+    private KeycloakDeployment createKeycloakDeploymentFrom(InputStream is) {
+
+        if (is == null) {
+            log.fine("No adapter configuration. Keycloak is unconfigured and will deny all requests.");
+            return new KeycloakDeployment();
+        }
+
+        return KeycloakDeploymentBuilder.build(is);
+    }
+
 
     @Override
     public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
+
         log.fine("Keycloak OIDC Filter");
         //System.err.println("Keycloak OIDC Filter: " + ((HttpServletRequest)req).getRequestURL().toString());
         HttpServletRequest request = (HttpServletRequest) req;
         HttpServletResponse response = (HttpServletResponse) res;
+
+        if (shouldSkip(request)) {
+            chain.doFilter(req, res);
+            return;
+        }
+
         OIDCServletHttpFacade facade = new OIDCServletHttpFacade(request, response);
         KeycloakDeployment deployment = deploymentContext.resolveDeployment(facade);
         if (deployment == null || !deployment.isConfigured()) {
@@ -171,6 +191,26 @@ public class KeycloakOIDCFilter implements Filter {
 
     }
 
+    /**
+     * Decides whether this {@link Filter} should skip the given {@link HttpServletRequest} based on the configured {@link KeycloakOIDCFilter#skipPattern}.
+     * Patterns are matched against the {@link HttpServletRequest#getRequestURI() requestURI} of a request without the context-path.
+     * A request for {@code /myapp/index.html} would be tested with {@code /index.html} against the skip pattern.
+     * Skipped requests will not be processed further by {@link KeycloakOIDCFilter} and immediately delegated to the {@link FilterChain}.
+     *
+     * @param request the request to check
+     * @return {@code true} if the request should not be handled,
+     *         {@code false} otherwise.
+     */
+    private boolean shouldSkip(HttpServletRequest request) {
+
+        if (skipPattern == null) {
+            return false;
+        }
+
+        String requestPath = request.getRequestURI().substring(request.getContextPath().length());
+        return skipPattern.matcher(requestPath).matches();
+    }
+
     @Override
     public void destroy() {
 
diff --git a/adapters/oidc/servlet-oauth-client/pom.xml b/adapters/oidc/servlet-oauth-client/pom.xml
index c3f9a9a..237c385 100755
--- a/adapters/oidc/servlet-oauth-client/pom.xml
+++ b/adapters/oidc/servlet-oauth-client/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/adapters/oidc/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java b/adapters/oidc/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
index f3dbcdc..64099e6 100755
--- a/adapters/oidc/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
+++ b/adapters/oidc/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
@@ -30,6 +30,7 @@ import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.representations.IDToken;
 import org.keycloak.common.util.KeycloakUriBuilder;
+import org.keycloak.util.TokenUtil;
 
 import javax.security.cert.X509Certificate;
 import javax.servlet.http.Cookie;
@@ -91,15 +92,15 @@ public class ServletOAuthClient extends KeycloakDeploymentDelegateOAuthClient {
         String state = getStateCode();
         KeycloakDeployment resolvedDeployment = resolveDeployment(getDeployment(), request);
         String authUrl = resolvedDeployment.getAuthUrl().clone().build().toString();
+        String scopeParam = TokenUtil.attachOIDCScope(scope);
 
         KeycloakUriBuilder uriBuilder =  KeycloakUriBuilder.fromUri(authUrl)
                 .queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE)
                 .queryParam(OAuth2Constants.CLIENT_ID, getClientId())
                 .queryParam(OAuth2Constants.REDIRECT_URI, redirectUri)
-                .queryParam(OAuth2Constants.STATE, state);
-        if (scope != null) {
-            uriBuilder.queryParam(OAuth2Constants.SCOPE, scope);
-        }
+                .queryParam(OAuth2Constants.STATE, state)
+                .queryParam(OAuth2Constants.SCOPE, scopeParam);
+
         URI url = uriBuilder.build();
 
         String stateCookiePath = this.stateCookiePath;
diff --git a/adapters/oidc/spring-boot/pom.xml b/adapters/oidc/spring-boot/pom.xml
index e06f6ef..e6096bf 100755
--- a/adapters/oidc/spring-boot/pom.xml
+++ b/adapters/oidc/spring-boot/pom.xml
@@ -21,7 +21,7 @@
   <parent>
     <artifactId>keycloak-parent</artifactId>
     <groupId>org.keycloak</groupId>
-    <version>2.0.0.CR1-SNAPSHOT</version>
+    <version>2.2.0-SNAPSHOT</version>
     <relativePath>../../../pom.xml</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
@@ -68,6 +68,45 @@
     </dependency>
 
     <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-server</artifactId>
+      <version>${jetty9.version}</version>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-security</artifactId>
+      <version>${jetty9.version}</version>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-webapp</artifactId>
+      <version>${jetty9.version}</version>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>io.undertow</groupId>
+      <artifactId>undertow-servlet</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>io.undertow</groupId>
+      <artifactId>undertow-core</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.keycloak</groupId>
+      <artifactId>keycloak-undertow-adapter-spi</artifactId>
+      <scope>provided</scope>
+    </dependency>
+
+    <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
       <scope>test</scope>
diff --git a/adapters/oidc/spring-boot/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootConfiguration.java b/adapters/oidc/spring-boot/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootConfiguration.java
index ec847c0..5c1b546 100755
--- a/adapters/oidc/spring-boot/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootConfiguration.java
+++ b/adapters/oidc/spring-boot/src/main/java/org/keycloak/adapters/springboot/KeycloakSpringBootConfiguration.java
@@ -17,24 +17,38 @@
 
 package org.keycloak.adapters.springboot;
 
+import io.undertow.servlet.api.DeploymentInfo;
+import io.undertow.servlet.api.WebResourceCollection;
 import org.apache.catalina.Context;
 import org.apache.tomcat.util.descriptor.web.LoginConfig;
 import org.apache.tomcat.util.descriptor.web.SecurityCollection;
 import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
+import org.eclipse.jetty.security.ConstraintMapping;
+import org.eclipse.jetty.security.ConstraintSecurityHandler;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.util.security.Constraint;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.keycloak.adapters.jetty.KeycloakJettyAuthenticator;
 import org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve;
+import org.keycloak.adapters.undertow.KeycloakServletExtension;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
 import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
 import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
 import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
+import org.springframework.boot.context.embedded.jetty.JettyServerCustomizer;
 import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer;
 import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
+import org.springframework.boot.context.embedded.undertow.UndertowDeploymentInfoCustomizer;
 import org.springframework.boot.context.embedded.undertow.UndertowEmbeddedServletContainerFactory;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
+import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -61,80 +75,212 @@ public class KeycloakSpringBootConfiguration {
         return new EmbeddedServletContainerCustomizer() {
             @Override
             public void customize(ConfigurableEmbeddedServletContainer configurableEmbeddedServletContainer) {
+
                 if (configurableEmbeddedServletContainer instanceof TomcatEmbeddedServletContainerFactory) {
-                    TomcatEmbeddedServletContainerFactory container = (TomcatEmbeddedServletContainerFactory) configurableEmbeddedServletContainer;
 
+                    TomcatEmbeddedServletContainerFactory container = (TomcatEmbeddedServletContainerFactory) configurableEmbeddedServletContainer;
                     container.addContextValves(new KeycloakAuthenticatorValve());
+                    container.addContextCustomizers(tomcatKeycloakContextCustomizer());
 
-                    container.addContextCustomizers(getTomcatKeycloakContextCustomizer());
                 } else if (configurableEmbeddedServletContainer instanceof UndertowEmbeddedServletContainerFactory) {
-                    throw new IllegalArgumentException("Undertow Keycloak integration is not yet implemented");
+
+                    UndertowEmbeddedServletContainerFactory container = (UndertowEmbeddedServletContainerFactory) configurableEmbeddedServletContainer;
+                    container.addDeploymentInfoCustomizers(undertowKeycloakContextCustomizer());
+
                 } else if (configurableEmbeddedServletContainer instanceof JettyEmbeddedServletContainerFactory) {
-                    throw new IllegalArgumentException("Jetty Keycloak integration is not yet implemented");
+
+                    JettyEmbeddedServletContainerFactory container = (JettyEmbeddedServletContainerFactory) configurableEmbeddedServletContainer;
+                    container.addServerCustomizers(jettyKeycloakServerCustomizer());
                 }
             }
         };
     }
 
     @Bean
-    public TomcatContextCustomizer getTomcatKeycloakContextCustomizer() {
-        return new TomcatContextCustomizer() {
-            @Override
-            public void customize(Context context) {
-                LoginConfig loginConfig = new LoginConfig();
-                loginConfig.setAuthMethod("KEYCLOAK");
-                context.setLoginConfig(loginConfig);
-
-                Set<String> authRoles = new HashSet<String>();
-                for (KeycloakSpringBootProperties.SecurityConstraint constraint : keycloakProperties.getSecurityConstraints()) {
-                    for (KeycloakSpringBootProperties.SecurityCollection collection : constraint.getSecurityCollections()) {
-                        for (String authRole : collection.getAuthRoles()) {
-                            if (!authRoles.contains(authRole)) {
-                                context.addSecurityRole(authRole);
-                                authRoles.add(authRole);
-                            }
-                        }
+    @ConditionalOnClass(name = {"org.eclipse.jetty.webapp.WebAppContext"})
+    public JettyServerCustomizer jettyKeycloakServerCustomizer() {
+        return new KeycloakJettyServerCustomizer(keycloakProperties);
+    }
+
+    @Bean
+    @ConditionalOnClass(name = {"org.apache.catalina.startup.Tomcat"})
+    public TomcatContextCustomizer tomcatKeycloakContextCustomizer() {
+        return new KeycloakTomcatContextCustomizer(keycloakProperties);
+    }
+
+    @Bean
+    @ConditionalOnClass(name = {"io.undertow.Undertow"})
+    public UndertowDeploymentInfoCustomizer undertowKeycloakContextCustomizer() {
+        return new KeycloakUndertowDeploymentInfoCustomizer(keycloakProperties);
+    }
+
+    static class KeycloakUndertowDeploymentInfoCustomizer implements UndertowDeploymentInfoCustomizer {
+
+        private final KeycloakSpringBootProperties keycloakProperties;
+
+        public KeycloakUndertowDeploymentInfoCustomizer(KeycloakSpringBootProperties keycloakProperties) {
+            this.keycloakProperties = keycloakProperties;
+        }
+
+        @Override
+        public void customize(DeploymentInfo deploymentInfo) {
+
+            io.undertow.servlet.api.LoginConfig loginConfig = new io.undertow.servlet.api.LoginConfig(keycloakProperties.getRealm());
+            loginConfig.addFirstAuthMethod("KEYCLOAK");
+
+            deploymentInfo.setLoginConfig(loginConfig);
+
+            deploymentInfo.addInitParameter("keycloak.config.resolver", KeycloakSpringBootConfigResolver.class.getName());
+            deploymentInfo.addSecurityConstraints(getSecurityConstraints());
+
+            deploymentInfo.addServletExtension(new KeycloakServletExtension());
+        }
+
+        private List<io.undertow.servlet.api.SecurityConstraint> getSecurityConstraints() {
+
+            List<io.undertow.servlet.api.SecurityConstraint> undertowSecurityConstraints = new ArrayList<io.undertow.servlet.api.SecurityConstraint>();
+            for (KeycloakSpringBootProperties.SecurityConstraint constraintDefinition : keycloakProperties.getSecurityConstraints()) {
+
+                for (KeycloakSpringBootProperties.SecurityCollection collectionDefinition : constraintDefinition.getSecurityCollections()) {
+
+                    io.undertow.servlet.api.SecurityConstraint undertowSecurityConstraint = new io.undertow.servlet.api.SecurityConstraint();
+                    undertowSecurityConstraint.addRolesAllowed(collectionDefinition.getAuthRoles());
+
+                    WebResourceCollection webResourceCollection = new WebResourceCollection();
+                    webResourceCollection.addHttpMethods(collectionDefinition.getMethods());
+                    webResourceCollection.addHttpMethodOmissions(collectionDefinition.getOmittedMethods());
+                    webResourceCollection.addUrlPatterns(collectionDefinition.getPatterns());
+
+                    undertowSecurityConstraint.addWebResourceCollections(webResourceCollection);
+
+                    undertowSecurityConstraints.add(undertowSecurityConstraint);
+                }
+            }
+            return undertowSecurityConstraints;
+        }
+    }
+
+    static class KeycloakJettyServerCustomizer implements JettyServerCustomizer {
+
+        private final KeycloakSpringBootProperties keycloakProperties;
+
+        public KeycloakJettyServerCustomizer(KeycloakSpringBootProperties keycloakProperties) {
+            this.keycloakProperties = keycloakProperties;
+        }
+
+        @Override
+        public void customize(Server server) {
+
+            KeycloakJettyAuthenticator keycloakJettyAuthenticator = new KeycloakJettyAuthenticator();
+            keycloakJettyAuthenticator.setConfigResolver(new KeycloakSpringBootConfigResolver());
+
+            List<ConstraintMapping> jettyConstraintMappings = new ArrayList<ConstraintMapping>();
+            for (KeycloakSpringBootProperties.SecurityConstraint constraintDefinition : keycloakProperties.getSecurityConstraints()) {
+
+                for (KeycloakSpringBootProperties.SecurityCollection securityCollectionDefinition : constraintDefinition
+                        .getSecurityCollections()) {
+
+                    Constraint jettyConstraint = new Constraint();
+                    jettyConstraint.setName(securityCollectionDefinition.getName());
+                    jettyConstraint.setAuthenticate(true);
+
+                    if (securityCollectionDefinition.getName() != null) {
+                        jettyConstraint.setName(securityCollectionDefinition.getName());
+                    }
+
+                    jettyConstraint.setRoles(securityCollectionDefinition.getAuthRoles().toArray(new String[0]));
+
+                    ConstraintMapping jettyConstraintMapping = new ConstraintMapping();
+                    if (securityCollectionDefinition.getPatterns().size() > 0) {
+                        //First pattern wins
+                        jettyConstraintMapping.setPathSpec(securityCollectionDefinition.getPatterns().get(0));
+                        jettyConstraintMapping.setConstraint(jettyConstraint);
+                    }
+
+                    if (securityCollectionDefinition.getMethods().size() > 0) {
+                        //First method wins
+                        jettyConstraintMapping.setMethod(securityCollectionDefinition.getMethods().get(0));
                     }
+
+                    jettyConstraintMapping.setMethodOmissions(
+                            securityCollectionDefinition.getOmittedMethods().toArray(new String[0]));
+
+                    jettyConstraintMappings.add(jettyConstraintMapping);
                 }
+            }
 
-                for (KeycloakSpringBootProperties.SecurityConstraint constraint : keycloakProperties.getSecurityConstraints()) {
-                    SecurityConstraint tomcatConstraint = new SecurityConstraint();
+            WebAppContext webAppContext = server.getBean(WebAppContext.class);
 
-                    for (KeycloakSpringBootProperties.SecurityCollection collection : constraint.getSecurityCollections()) {
-                        SecurityCollection tomcatSecCollection = new SecurityCollection();
+            ConstraintSecurityHandler securityHandler = new ConstraintSecurityHandler();
+            securityHandler.setConstraintMappings(jettyConstraintMappings);
+            securityHandler.setAuthenticator(keycloakJettyAuthenticator);
 
-                        if (collection.getName() != null) {
-                            tomcatSecCollection.setName(collection.getName());
-                        }
-                        if (collection.getDescription() != null) {
-                            tomcatSecCollection.setDescription(collection.getDescription());
-                        }
+            webAppContext.setHandler(securityHandler);
+        }
+    }
 
-                        for (String authRole : collection.getAuthRoles()) {
-                            tomcatConstraint.addAuthRole(authRole);
-                        }
+    static class KeycloakTomcatContextCustomizer implements TomcatContextCustomizer {
 
-                        for (String pattern : collection.getPatterns()) {
-                            tomcatSecCollection.addPattern(pattern);
-                        }
+        private final KeycloakSpringBootProperties keycloakProperties;
 
-                        for (String method : collection.getMethods()) {
-                            tomcatSecCollection.addMethod(method);
-                        }
+        public KeycloakTomcatContextCustomizer(KeycloakSpringBootProperties keycloakProperties) {
+            this.keycloakProperties = keycloakProperties;
+        }
 
-                        for (String method : collection.getOmittedMethods()) {
-                            tomcatSecCollection.addOmittedMethod(method);
+        @Override
+        public void customize(Context context) {
+            LoginConfig loginConfig = new LoginConfig();
+            loginConfig.setAuthMethod("KEYCLOAK");
+            context.setLoginConfig(loginConfig);
+
+            Set<String> authRoles = new HashSet<String>();
+            for (KeycloakSpringBootProperties.SecurityConstraint constraint : keycloakProperties.getSecurityConstraints()) {
+                for (KeycloakSpringBootProperties.SecurityCollection collection : constraint.getSecurityCollections()) {
+                    for (String authRole : collection.getAuthRoles()) {
+                        if (!authRoles.contains(authRole)) {
+                            context.addSecurityRole(authRole);
+                            authRoles.add(authRole);
                         }
+                    }
+                }
+            }
+
+            for (KeycloakSpringBootProperties.SecurityConstraint constraint : keycloakProperties.getSecurityConstraints()) {
+                SecurityConstraint tomcatConstraint = new SecurityConstraint();
+
+                for (KeycloakSpringBootProperties.SecurityCollection collection : constraint.getSecurityCollections()) {
+                    SecurityCollection tomcatSecCollection = new SecurityCollection();
+
+                    if (collection.getName() != null) {
+                        tomcatSecCollection.setName(collection.getName());
+                    }
+                    if (collection.getDescription() != null) {
+                        tomcatSecCollection.setDescription(collection.getDescription());
+                    }
 
-                        tomcatConstraint.addCollection(tomcatSecCollection);
+                    for (String authRole : collection.getAuthRoles()) {
+                        tomcatConstraint.addAuthRole(authRole);
                     }
 
-                    context.addConstraint(tomcatConstraint);
+                    for (String pattern : collection.getPatterns()) {
+                        tomcatSecCollection.addPattern(pattern);
+                    }
+
+                    for (String method : collection.getMethods()) {
+                        tomcatSecCollection.addMethod(method);
+                    }
+
+                    for (String method : collection.getOmittedMethods()) {
+                        tomcatSecCollection.addOmittedMethod(method);
+                    }
+
+                    tomcatConstraint.addCollection(tomcatSecCollection);
                 }
 
-                context.addParameter("keycloak.config.resolver", KeycloakSpringBootConfigResolver.class.getName());
+                context.addConstraint(tomcatConstraint);
             }
-        };
-    }
 
+            context.addParameter("keycloak.config.resolver", KeycloakSpringBootConfigResolver.class.getName());
+        }
+    }
 }
diff --git a/adapters/oidc/spring-security/pom.xml b/adapters/oidc/spring-security/pom.xml
index 5644c0f..5025a0b 100755
--- a/adapters/oidc/spring-security/pom.xml
+++ b/adapters/oidc/spring-security/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
@@ -71,6 +71,13 @@
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
             <version>${slf4j.version}</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.logging</groupId>
+            <artifactId>jboss-logging</artifactId>
+            <version>${jboss.logging.version}</version>
+            <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.httpcomponents</groupId>
@@ -121,12 +128,6 @@
             <version>${slf4j.version}</version>
             <scope>test</scope>
         </dependency>
-        <dependency>
-            <groupId>org.jboss.logging</groupId>
-            <artifactId>jboss-logging</artifactId>
-            <version>${jboss.logging.version}</version>
-            <scope>test</scope>
-        </dependency>
     </dependencies>
     <build>
         <plugins>
diff --git a/adapters/oidc/tomcat/pom.xml b/adapters/oidc/tomcat/pom.xml
index a3b172a..037af6e 100755
--- a/adapters/oidc/tomcat/pom.xml
+++ b/adapters/oidc/tomcat/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <name>Keycloak Tomcat Integration</name>
diff --git a/adapters/oidc/tomcat/tomcat6/pom.xml b/adapters/oidc/tomcat/tomcat6/pom.xml
index bd3c479..1f8e5be 100755
--- a/adapters/oidc/tomcat/tomcat6/pom.xml
+++ b/adapters/oidc/tomcat/tomcat6/pom.xml
@@ -21,7 +21,7 @@
     <parent>
 		<artifactId>keycloak-tomcat-integration-pom</artifactId>
 		<groupId>org.keycloak</groupId>
-		<version>2.0.0.CR1-SNAPSHOT</version>
+		<version>2.2.0-SNAPSHOT</version>
 		<relativePath>../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
diff --git a/adapters/oidc/tomcat/tomcat7/pom.xml b/adapters/oidc/tomcat/tomcat7/pom.xml
index 6faec4b..eb60fe6 100755
--- a/adapters/oidc/tomcat/tomcat7/pom.xml
+++ b/adapters/oidc/tomcat/tomcat7/pom.xml
@@ -21,7 +21,7 @@
     <parent>
 		<artifactId>keycloak-tomcat-integration-pom</artifactId>
 		<groupId>org.keycloak</groupId>
-		<version>2.0.0.CR1-SNAPSHOT</version>
+		<version>2.2.0-SNAPSHOT</version>
 		<relativePath>../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
diff --git a/adapters/oidc/tomcat/tomcat8/pom.xml b/adapters/oidc/tomcat/tomcat8/pom.xml
index ee1ef8d..4beff8a 100755
--- a/adapters/oidc/tomcat/tomcat8/pom.xml
+++ b/adapters/oidc/tomcat/tomcat8/pom.xml
@@ -21,7 +21,7 @@
     <parent>
 		<artifactId>keycloak-tomcat-integration-pom</artifactId>
 		<groupId>org.keycloak</groupId>
-		<version>2.0.0.CR1-SNAPSHOT</version>
+		<version>2.2.0-SNAPSHOT</version>
 		<relativePath>../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
diff --git a/adapters/oidc/tomcat/tomcat-core/pom.xml b/adapters/oidc/tomcat/tomcat-core/pom.xml
index 62761fb..5f541f5 100755
--- a/adapters/oidc/tomcat/tomcat-core/pom.xml
+++ b/adapters/oidc/tomcat/tomcat-core/pom.xml
@@ -21,7 +21,7 @@
     <parent>
 		<artifactId>keycloak-tomcat-integration-pom</artifactId>
 		<groupId>org.keycloak</groupId>
-		<version>2.0.0.CR1-SNAPSHOT</version>
+		<version>2.2.0-SNAPSHOT</version>
 		<relativePath>../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
@@ -77,6 +77,13 @@
 			<groupId>com.fasterxml.jackson.core</groupId>
 			<artifactId>jackson-annotations</artifactId>
 		</dependency>
+
+		<!-- Authorization -->
+		<dependency>
+			<groupId>org.keycloak</groupId>
+			<artifactId>keycloak-authz-client</artifactId>
+		</dependency>
+
         <!--
 		<dependency>
 			<groupId>org.apache.tomcat</groupId>
diff --git a/adapters/oidc/undertow/pom.xml b/adapters/oidc/undertow/pom.xml
index 4a4df89..2677e83 100755
--- a/adapters/oidc/undertow/pom.xml
+++ b/adapters/oidc/undertow/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/adapters/oidc/undertow/src/main/java/org/keycloak/adapters/undertow/OIDCServletUndertowHttpFacade.java b/adapters/oidc/undertow/src/main/java/org/keycloak/adapters/undertow/OIDCServletUndertowHttpFacade.java
index 3dc705f..27ddae8 100755
--- a/adapters/oidc/undertow/src/main/java/org/keycloak/adapters/undertow/OIDCServletUndertowHttpFacade.java
+++ b/adapters/oidc/undertow/src/main/java/org/keycloak/adapters/undertow/OIDCServletUndertowHttpFacade.java
@@ -17,16 +17,16 @@
 package org.keycloak.adapters.undertow;
 
 import io.undertow.server.HttpServerExchange;
-import io.undertow.util.AttachmentKey;
 import org.keycloak.KeycloakSecurityContext;
 import org.keycloak.adapters.OIDCHttpFacade;
 
+import static org.keycloak.adapters.undertow.OIDCUndertowHttpFacade.KEYCLOAK_SECURITY_CONTEXT_KEY;
+
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
 public class OIDCServletUndertowHttpFacade extends ServletHttpFacade implements OIDCHttpFacade {
-    public static final AttachmentKey<KeycloakSecurityContext> KEYCLOAK_SECURITY_CONTEXT_KEY = AttachmentKey.create(KeycloakSecurityContext.class);
 
     public OIDCServletUndertowHttpFacade(HttpServerExchange exchange) {
         super(exchange);
diff --git a/adapters/oidc/wildfly/pom.xml b/adapters/oidc/wildfly/pom.xml
index 69d41aa..c2b61de 100755
--- a/adapters/oidc/wildfly/pom.xml
+++ b/adapters/oidc/wildfly/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <name>Keycloak WildFly Integration</name>
diff --git a/adapters/oidc/wildfly/wf8-subsystem/pom.xml b/adapters/oidc/wildfly/wf8-subsystem/pom.xml
index edddfed..ec5676d 100755
--- a/adapters/oidc/wildfly/wf8-subsystem/pom.xml
+++ b/adapters/oidc/wildfly/wf8-subsystem/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak</groupId>
         <artifactId>keycloak-parent</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../../pom.xml</relativePath>
     </parent>
 
diff --git a/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/KeycloakAdapterConfigDeploymentProcessor.java b/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/KeycloakAdapterConfigDeploymentProcessor.java
index 6facc2c..0ec9335 100755
--- a/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/KeycloakAdapterConfigDeploymentProcessor.java
+++ b/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/KeycloakAdapterConfigDeploymentProcessor.java
@@ -46,8 +46,7 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
 
     // not sure if we need this yet, keeping here just in case
     protected void addSecurityDomain(DeploymentUnit deploymentUnit, KeycloakAdapterConfigService service) {
-        String deploymentName = deploymentUnit.getName();
-        if (!service.isSecureDeployment(deploymentName)) {
+        if (!service.isSecureDeployment(deploymentUnit)) {
             return;
         }
         WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
@@ -67,10 +66,9 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
     public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
         DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
 
-        String deploymentName = deploymentUnit.getName();
         KeycloakAdapterConfigService service = KeycloakAdapterConfigService.getInstance();
-        if (service.isSecureDeployment(deploymentName)) {
-            addKeycloakAuthData(phaseContext, deploymentName, service);
+        if (service.isSecureDeployment(deploymentUnit)) {
+            addKeycloakAuthData(phaseContext, service);
         }
 
         // FYI, Undertow Extension will find deployments that have auth-method set to KEYCLOAK
@@ -79,14 +77,14 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
         // addSecurityDomain(deploymentUnit, service);
     }
 
-    private void addKeycloakAuthData(DeploymentPhaseContext phaseContext, String deploymentName, KeycloakAdapterConfigService service) throws DeploymentUnitProcessingException {
+    private void addKeycloakAuthData(DeploymentPhaseContext phaseContext, KeycloakAdapterConfigService service) throws DeploymentUnitProcessingException {
         DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
         WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
         if (warMetaData == null) {
-            throw new DeploymentUnitProcessingException("WarMetaData not found for " + deploymentName + ".  Make sure you have specified a WAR as your secure-deployment in the Keycloak subsystem.");
+            throw new DeploymentUnitProcessingException("WarMetaData not found for " + deploymentUnit.getName() + ".  Make sure you have specified a WAR as your secure-deployment in the Keycloak subsystem.");
         }
 
-        addJSONData(service.getJSON(deploymentName), warMetaData);
+        addJSONData(service.getJSON(deploymentUnit), warMetaData);
         JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
         if (webMetaData == null) {
             webMetaData = new JBossWebMetaData();
@@ -99,8 +97,8 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
             webMetaData.setLoginConfig(loginConfig);
         }
         loginConfig.setAuthMethod("KEYCLOAK");
-        loginConfig.setRealmName(service.getRealmName(deploymentName));
-        KeycloakLogger.ROOT_LOGGER.deploymentSecured(deploymentName);
+        loginConfig.setRealmName(service.getRealmName(deploymentUnit));
+        KeycloakLogger.ROOT_LOGGER.deploymentSecured(deploymentUnit.getName());
     }
 
     private void addJSONData(String json, WarMetaData warMetaData) {
diff --git a/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/KeycloakAdapterConfigService.java b/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/KeycloakAdapterConfigService.java
index c9251f9..5d15b70 100755
--- a/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/KeycloakAdapterConfigService.java
+++ b/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/KeycloakAdapterConfigService.java
@@ -24,6 +24,9 @@ import java.util.HashMap;
 import java.util.Map;
 
 import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADDRESS;
+import org.jboss.as.server.deployment.DeploymentUnit;
+import org.jboss.as.web.common.WarMetaData;
+import org.jboss.metadata.web.jboss.JBossWebMetaData;
 
 /**
  * This service keeps track of the entire Keycloak management model so as to provide
@@ -153,13 +156,15 @@ public final class KeycloakAdapterConfigService {
         return null;
     }
 
-    public String getRealmName(String deploymentName) {
+    public String getRealmName(DeploymentUnit deploymentUnit) {
+        String deploymentName = preferredDeploymentName(deploymentUnit);
         ModelNode deployment = this.secureDeployments.get(deploymentName);
         return deployment.get(RealmDefinition.TAG_NAME).asString();
 
     }
 
-    public String getJSON(String deploymentName) {
+    public String getJSON(DeploymentUnit deploymentUnit) {
+        String deploymentName = preferredDeploymentName(deploymentUnit);
         ModelNode deployment = this.secureDeployments.get(deploymentName);
         String realmName = deployment.get(RealmDefinition.TAG_NAME).asString();
         ModelNode realm = this.realms.get(realmName);
@@ -183,9 +188,29 @@ public final class KeycloakAdapterConfigService {
         }
     }
 
-    public boolean isSecureDeployment(String deploymentName) {
+    public boolean isSecureDeployment(DeploymentUnit deploymentUnit) {
         //log.info("********* CHECK KEYCLOAK DEPLOYMENT: deployments.size()" + deployments.size());
 
+        String deploymentName = preferredDeploymentName(deploymentUnit);
         return this.secureDeployments.containsKey(deploymentName);
     }
+    
+    // KEYCLOAK-3273: prefer module name if available
+    private String preferredDeploymentName(DeploymentUnit deploymentUnit) {
+        String deploymentName = deploymentUnit.getName();
+        WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
+        if (warMetaData == null) {
+            return deploymentName;
+        }
+        
+        JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
+        if (webMetaData == null) {
+            return deploymentName;
+        }
+        
+        String moduleName = webMetaData.getModuleName();
+        if (moduleName != null) return moduleName + ".war";
+        
+        return deploymentName;
+    }
 }
diff --git a/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/KeycloakDependencyProcessor.java b/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/KeycloakDependencyProcessor.java
index 26a9723..60d0856 100755
--- a/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/KeycloakDependencyProcessor.java
+++ b/adapters/oidc/wildfly/wf8-subsystem/src/main/java/org/keycloak/subsystem/wf8/extension/KeycloakDependencyProcessor.java
@@ -46,8 +46,7 @@ public abstract class KeycloakDependencyProcessor implements DeploymentUnitProce
     public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
         final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
 
-        String deploymentName = deploymentUnit.getName();
-        if (!KeycloakAdapterConfigService.getInstance().isSecureDeployment(deploymentName)) {
+        if (!KeycloakAdapterConfigService.getInstance().isSecureDeployment(deploymentUnit)) {
             WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
             if (warMetaData == null) {
                 return;
diff --git a/adapters/oidc/wildfly/wf8-subsystem/src/test/java/org/keycloak/subsystem/wf8/extension/SubsystemParsingTestCase.java b/adapters/oidc/wildfly/wf8-subsystem/src/test/java/org/keycloak/subsystem/wf8/extension/SubsystemParsingTestCase.java
index 48dcc92..2daec3c 100755
--- a/adapters/oidc/wildfly/wf8-subsystem/src/test/java/org/keycloak/subsystem/wf8/extension/SubsystemParsingTestCase.java
+++ b/adapters/oidc/wildfly/wf8-subsystem/src/test/java/org/keycloak/subsystem/wf8/extension/SubsystemParsingTestCase.java
@@ -78,8 +78,6 @@ public class SubsystemParsingTestCase extends AbstractSubsystemBaseTest {
         addCredential(addr, service, "secret", "secret1");
         addCredential(addr, service, "jwt.client-keystore-file", "/tmp/foo.jks");
         addCredential(addr, service, "jwt.token-timeout", "10");
-
-        System.out.println("Deployment: " + service.getJSON("foo"));
     }
 
     private void addCredential(PathAddress parent, KeycloakAdapterConfigService service, String key, String value) {
diff --git a/adapters/oidc/wildfly/wildfly-adapter/pom.xml b/adapters/oidc/wildfly/wildfly-adapter/pom.xml
index 7a6de07..1f0522c 100755
--- a/adapters/oidc/wildfly/wildfly-adapter/pom.xml
+++ b/adapters/oidc/wildfly/wildfly-adapter/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/pom.xml b/adapters/oidc/wildfly/wildfly-subsystem/pom.xml
index 5d36bb8..30e26d5 100755
--- a/adapters/oidc/wildfly/wildfly-subsystem/pom.xml
+++ b/adapters/oidc/wildfly/wildfly-subsystem/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak</groupId>
         <artifactId>keycloak-parent</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../../pom.xml</relativePath>
     </parent>
 
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakAdapterConfigDeploymentProcessor.java b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakAdapterConfigDeploymentProcessor.java
index 00343df..9f52c41 100755
--- a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakAdapterConfigDeploymentProcessor.java
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakAdapterConfigDeploymentProcessor.java
@@ -46,8 +46,7 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
 
     // not sure if we need this yet, keeping here just in case
     protected void addSecurityDomain(DeploymentUnit deploymentUnit, KeycloakAdapterConfigService service) {
-        String deploymentName = deploymentUnit.getName();
-        if (!service.isSecureDeployment(deploymentName)) {
+        if (!service.isSecureDeployment(deploymentUnit)) {
             return;
         }
         WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
@@ -67,10 +66,9 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
     public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
         DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
 
-        String deploymentName = deploymentUnit.getName();
         KeycloakAdapterConfigService service = KeycloakAdapterConfigService.getInstance();
-        if (service.isSecureDeployment(deploymentName)) {
-            addKeycloakAuthData(phaseContext, deploymentName, service);
+        if (service.isSecureDeployment(deploymentUnit)) {
+            addKeycloakAuthData(phaseContext, service);
         }
 
         // FYI, Undertow Extension will find deployments that have auth-method set to KEYCLOAK
@@ -79,14 +77,14 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
         // addSecurityDomain(deploymentUnit, service);
     }
 
-    private void addKeycloakAuthData(DeploymentPhaseContext phaseContext, String deploymentName, KeycloakAdapterConfigService service) throws DeploymentUnitProcessingException {
+    private void addKeycloakAuthData(DeploymentPhaseContext phaseContext, KeycloakAdapterConfigService service) throws DeploymentUnitProcessingException {
         DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
         WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
         if (warMetaData == null) {
-            throw new DeploymentUnitProcessingException("WarMetaData not found for " + deploymentName + ".  Make sure you have specified a WAR as your secure-deployment in the Keycloak subsystem.");
+            throw new DeploymentUnitProcessingException("WarMetaData not found for " + deploymentUnit.getName() + ".  Make sure you have specified a WAR as your secure-deployment in the Keycloak subsystem.");
         }
 
-        addJSONData(service.getJSON(deploymentName), warMetaData);
+        addJSONData(service.getJSON(deploymentUnit), warMetaData);
         JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
         if (webMetaData == null) {
             webMetaData = new JBossWebMetaData();
@@ -99,8 +97,8 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
             webMetaData.setLoginConfig(loginConfig);
         }
         loginConfig.setAuthMethod("KEYCLOAK");
-        loginConfig.setRealmName(service.getRealmName(deploymentName));
-        KeycloakLogger.ROOT_LOGGER.deploymentSecured(deploymentName);
+        loginConfig.setRealmName(service.getRealmName(deploymentUnit));
+        KeycloakLogger.ROOT_LOGGER.deploymentSecured(deploymentUnit.getName());
     }
 
     private void addJSONData(String json, WarMetaData warMetaData) {
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakAdapterConfigService.java b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakAdapterConfigService.java
index 854544f..86c9e7e 100755
--- a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakAdapterConfigService.java
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakAdapterConfigService.java
@@ -24,6 +24,9 @@ import java.util.HashMap;
 import java.util.Map;
 
 import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADDRESS;
+import org.jboss.as.server.deployment.DeploymentUnit;
+import org.jboss.as.web.common.WarMetaData;
+import org.jboss.metadata.web.jboss.JBossWebMetaData;
 
 /**
  * This service keeps track of the entire Keycloak management model so as to provide
@@ -153,13 +156,15 @@ public final class KeycloakAdapterConfigService {
         return null;
     }
 
-    public String getRealmName(String deploymentName) {
+    public String getRealmName(DeploymentUnit deploymentUnit) {
+        String deploymentName = preferredDeploymentName(deploymentUnit);
         ModelNode deployment = this.secureDeployments.get(deploymentName);
         return deployment.get(RealmDefinition.TAG_NAME).asString();
 
     }
 
-    public String getJSON(String deploymentName) {
+    public String getJSON(DeploymentUnit deploymentUnit) {
+        String deploymentName = preferredDeploymentName(deploymentUnit);
         ModelNode deployment = this.secureDeployments.get(deploymentName);
         String realmName = deployment.get(RealmDefinition.TAG_NAME).asString();
         ModelNode realm = this.realms.get(realmName);
@@ -183,9 +188,29 @@ public final class KeycloakAdapterConfigService {
         }
     }
 
-    public boolean isSecureDeployment(String deploymentName) {
+    public boolean isSecureDeployment(DeploymentUnit deploymentUnit) {
         //log.info("********* CHECK KEYCLOAK DEPLOYMENT: deployments.size()" + deployments.size());
 
+        String deploymentName = preferredDeploymentName(deploymentUnit);
         return this.secureDeployments.containsKey(deploymentName);
     }
+    
+    // KEYCLOAK-3273: prefer module name if available
+    private String preferredDeploymentName(DeploymentUnit deploymentUnit) {
+        String deploymentName = deploymentUnit.getName();
+        WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
+        if (warMetaData == null) {
+            return deploymentName;
+        }
+        
+        JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
+        if (webMetaData == null) {
+            return deploymentName;
+        }
+        
+        String moduleName = webMetaData.getModuleName();
+        if (moduleName != null) return moduleName + ".war";
+        
+        return deploymentName;
+    }
 }
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakDependencyProcessor.java b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakDependencyProcessor.java
index 373f57a..e918a47 100755
--- a/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakDependencyProcessor.java
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/extension/KeycloakDependencyProcessor.java
@@ -45,9 +45,7 @@ public abstract class KeycloakDependencyProcessor implements DeploymentUnitProce
     @Override
     public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
         final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
-
-        String deploymentName = deploymentUnit.getName();
-        if (!KeycloakAdapterConfigService.getInstance().isSecureDeployment(deploymentName)) {
+        if (!KeycloakAdapterConfigService.getInstance().isSecureDeployment(deploymentUnit)) {
             WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
             if (warMetaData == null) {
                 return;
@@ -67,7 +65,7 @@ public abstract class KeycloakDependencyProcessor implements DeploymentUnitProce
         addCommonModules(moduleSpecification, moduleLoader);
         addPlatformSpecificModules(moduleSpecification, moduleLoader);
     }
-
+    
     private void addCommonModules(ModuleSpecification moduleSpecification, ModuleLoader moduleLoader) {
         // ModuleDependency(ModuleLoader moduleLoader, ModuleIdentifier identifier, boolean optional, boolean export, boolean importServices, boolean userSpecified)
         moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_JBOSS_CORE_ADAPTER, false, false, false, false));
diff --git a/adapters/oidc/wildfly/wildfly-subsystem/src/test/java/org/keycloak/subsystem/adapter/extension/SubsystemParsingTestCase.java b/adapters/oidc/wildfly/wildfly-subsystem/src/test/java/org/keycloak/subsystem/adapter/extension/SubsystemParsingTestCase.java
index 6ff643a..9d5f87a 100755
--- a/adapters/oidc/wildfly/wildfly-subsystem/src/test/java/org/keycloak/subsystem/adapter/extension/SubsystemParsingTestCase.java
+++ b/adapters/oidc/wildfly/wildfly-subsystem/src/test/java/org/keycloak/subsystem/adapter/extension/SubsystemParsingTestCase.java
@@ -78,8 +78,6 @@ public class SubsystemParsingTestCase extends AbstractSubsystemBaseTest {
         addCredential(addr, service, "secret", "secret1");
         addCredential(addr, service, "jwt.client-keystore-file", "/tmp/foo.jks");
         addCredential(addr, service, "jwt.token-timeout", "10");
-
-        System.out.println("Deployment: " + service.getJSON("foo"));
     }
 
     private void addCredential(PathAddress parent, KeycloakAdapterConfigService service, String key, String value) {

adapters/pom.xml 2(+1 -1)

diff --git a/adapters/pom.xml b/adapters/pom.xml
index 060978e..28811ad 100755
--- a/adapters/pom.xml
+++ b/adapters/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <name>Keycloak Integration</name>
diff --git a/adapters/saml/as7-eap6/adapter/pom.xml b/adapters/saml/as7-eap6/adapter/pom.xml
index a99d957..0bf41d4 100755
--- a/adapters/saml/as7-eap6/adapter/pom.xml
+++ b/adapters/saml/as7-eap6/adapter/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-saml-eap-integration-pom</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/adapters/saml/as7-eap6/pom.xml b/adapters/saml/as7-eap6/pom.xml
index 265a1f8..e67baab 100755
--- a/adapters/saml/as7-eap6/pom.xml
+++ b/adapters/saml/as7-eap6/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <name>Keycloak SAML EAP Integration</name>
diff --git a/adapters/saml/as7-eap6/subsystem/pom.xml b/adapters/saml/as7-eap6/subsystem/pom.xml
index 4c92714..37afc21 100755
--- a/adapters/saml/as7-eap6/subsystem/pom.xml
+++ b/adapters/saml/as7-eap6/subsystem/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak</groupId>
         <artifactId>keycloak-saml-eap-integration-pom</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/Configuration.java b/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/Configuration.java
index 07c32f8..4534cf4 100644
--- a/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/Configuration.java
+++ b/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/Configuration.java
@@ -16,8 +16,11 @@
  */
 package org.keycloak.subsystem.saml.as7;
 
+import org.jboss.as.server.deployment.DeploymentUnit;
+import org.jboss.as.web.deployment.WarMetaData;
 import org.jboss.dmr.ModelNode;
 import org.jboss.dmr.Property;
+import org.jboss.metadata.web.jboss.JBossWebMetaData;
 
 /**
  * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
@@ -46,7 +49,8 @@ public class Configuration {
         return keymodel.get(key);
     }
 
-    public ModelNode getSecureDeployment(String name) {
+    public ModelNode getSecureDeployment(DeploymentUnit deploymentUnit) {
+        String name = preferredDeploymentName(deploymentUnit);
         ModelNode secureDeployment = config.get("subsystem").get("keycloak-saml").get(Constants.Model.SECURE_DEPLOYMENT);
         if (secureDeployment.hasDefined(name)) {
             return secureDeployment.get(name);
@@ -54,7 +58,26 @@ public class Configuration {
         return null;
     }
 
-    public boolean isSecureDeployment(String name) {
-        return getSecureDeployment(name) != null;
+    public boolean isSecureDeployment(DeploymentUnit deploymentUnit) {
+        return getSecureDeployment(deploymentUnit) != null;
+    }
+    
+    // KEYCLOAK-3273: prefer module name if available
+    private String preferredDeploymentName(DeploymentUnit deploymentUnit) {
+        String deploymentName = deploymentUnit.getName();
+        WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
+        if (warMetaData == null) {
+            return deploymentName;
+        }
+        
+        JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
+        if (webMetaData == null) {
+            return deploymentName;
+        }
+        
+        String moduleName = webMetaData.getModuleName();
+        if (moduleName != null) return moduleName + ".war";
+        
+        return deploymentName;
     }
 }
diff --git a/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/Constants.java b/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/Constants.java
index 81c697a..7d30f7f 100755
--- a/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/Constants.java
+++ b/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/Constants.java
@@ -45,6 +45,7 @@ public class Constants {
         static final String KEY_STORE = "KeyStore";
         static final String SIGN_REQUEST = "signRequest";
         static final String VALIDATE_RESPONSE_SIGNATURE = "validateResponseSignature";
+        static final String VALIDATE_ASSERTION_SIGNATURE = "validateAssertionSignature";
         static final String REQUEST_BINDING = "requestBinding";
         static final String BINDING_URL = "bindingUrl";
         static final String VALIDATE_REQUEST_SIGNATURE = "validateRequestSignature";
@@ -97,6 +98,7 @@ public class Constants {
         static final String CERTIFICATE_ALIAS = "alias";
         static final String SIGN_REQUEST = "signRequest";
         static final String VALIDATE_RESPONSE_SIGNATURE = "validateResponseSignature";
+        static final String VALIDATE_ASSERTION_SIGNATURE = "validateAssertionSignature";
         static final String REQUEST_BINDING = "requestBinding";
         static final String BINDING_URL = "bindingUrl";
         static final String VALIDATE_REQUEST_SIGNATURE = "validateRequestSignature";
diff --git a/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakAdapterConfigDeploymentProcessor.java b/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakAdapterConfigDeploymentProcessor.java
index 54fc1e2..48ab715 100755
--- a/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakAdapterConfigDeploymentProcessor.java
+++ b/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakAdapterConfigDeploymentProcessor.java
@@ -51,7 +51,6 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
     @Override
     public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
         DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
-        String deploymentName = deploymentUnit.getName();
 
         WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
         if (warMetaData == null) {
@@ -69,30 +68,30 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
 
         try {
             boolean webRequiresKC = loginConfig != null && "KEYCLOAK-SAML".equalsIgnoreCase(loginConfig.getAuthMethod());
-            boolean hasSubsystemConfig = Configuration.INSTANCE.isSecureDeployment(deploymentName);
+            boolean hasSubsystemConfig = Configuration.INSTANCE.isSecureDeployment(deploymentUnit);
             if (hasSubsystemConfig || webRequiresKC) {
-                log.debug("Setting up KEYCLOAK-SAML auth method for WAR: " + deploymentName);
+                log.debug("Setting up KEYCLOAK-SAML auth method for WAR: " + deploymentUnit.getName());
 
                 // if secure-deployment configuration exists for web app, we force KEYCLOAK-SAML auth method on it
                 if (hasSubsystemConfig) {
-                    addXMLData(getXML(deploymentName), warMetaData);
+                    addXMLData(getXML(deploymentUnit), warMetaData);
                     if (loginConfig != null) {
                         loginConfig.setAuthMethod("KEYCLOAK-SAML");
                         //loginConfig.setRealmName(service.getRealmName(deploymentName));
                     } else {
-                        log.warn("Failed to set up KEYCLOAK-SAML auth method for WAR: " + deploymentName + " (loginConfig == null)");
+                        log.warn("Failed to set up KEYCLOAK-SAML auth method for WAR: " + deploymentUnit.getName() + " (loginConfig == null)");
                     }
                 }
                 addValve(webMetaData);
-                KeycloakLogger.ROOT_LOGGER.deploymentSecured(deploymentName);
+                KeycloakLogger.ROOT_LOGGER.deploymentSecured(deploymentUnit.getName());
             }
         } catch (Exception e) {
             throw new DeploymentUnitProcessingException("Failed to configure KeycloakSamlExtension from subsystem model", e);
         }
     }
 
-    private String getXML(String deploymentName) throws XMLStreamException {
-        ModelNode node = Configuration.INSTANCE.getSecureDeployment(deploymentName);
+    private String getXML(DeploymentUnit deploymentUnit) throws XMLStreamException {
+        ModelNode node = Configuration.INSTANCE.getSecureDeployment(deploymentUnit);
         if (node != null) {
             KeycloakSubsystemParser writer = new KeycloakSubsystemParser();
             ByteArrayOutputStream output = new ByteArrayOutputStream();
diff --git a/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakDependencyProcessor.java b/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakDependencyProcessor.java
index 851052d..51988b2 100755
--- a/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakDependencyProcessor.java
+++ b/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/KeycloakDependencyProcessor.java
@@ -46,8 +46,7 @@ public abstract class KeycloakDependencyProcessor implements DeploymentUnitProce
     public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
         final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
 
-        String deploymentName = deploymentUnit.getName();
-        if (Configuration.INSTANCE.getSecureDeployment(deploymentName) == null) {
+        if (Configuration.INSTANCE.getSecureDeployment(deploymentUnit) == null) {
             WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
             if (warMetaData == null) {
                 return;
diff --git a/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/SingleSignOnDefinition.java b/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/SingleSignOnDefinition.java
index 9f7732a..61c55d8 100644
--- a/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/SingleSignOnDefinition.java
+++ b/adapters/saml/as7-eap6/subsystem/src/main/java/org/keycloak/subsystem/saml/as7/SingleSignOnDefinition.java
@@ -37,6 +37,11 @@ abstract class SingleSignOnDefinition {
                     .setXmlName(Constants.XML.VALIDATE_RESPONSE_SIGNATURE)
                     .build();
 
+    static final SimpleAttributeDefinition VALIDATE_ASSERTION_SIGNATURE =
+            new SimpleAttributeDefinitionBuilder(Constants.Model.VALIDATE_ASSERTION_SIGNATURE, ModelType.BOOLEAN, true)
+                    .setXmlName(Constants.XML.VALIDATE_ASSERTION_SIGNATURE)
+                    .build();
+
     static final SimpleAttributeDefinition REQUEST_BINDING =
             new SimpleAttributeDefinitionBuilder(Constants.Model.REQUEST_BINDING, ModelType.STRING, true)
                     .setXmlName(Constants.XML.REQUEST_BINDING)
@@ -52,7 +57,7 @@ abstract class SingleSignOnDefinition {
                     .setXmlName(Constants.XML.BINDING_URL)
                     .build();
 
-    static final SimpleAttributeDefinition[] ATTRIBUTES = {SIGN_REQUEST, VALIDATE_RESPONSE_SIGNATURE, REQUEST_BINDING, RESPONSE_BINDING, BINDING_URL};
+    static final SimpleAttributeDefinition[] ATTRIBUTES = {SIGN_REQUEST, VALIDATE_RESPONSE_SIGNATURE, VALIDATE_ASSERTION_SIGNATURE, REQUEST_BINDING, RESPONSE_BINDING, BINDING_URL};
 
     static final HashMap<String, SimpleAttributeDefinition> ATTRIBUTE_MAP = new HashMap<>();
 
diff --git a/adapters/saml/as7-eap6/subsystem/src/main/resources/org/keycloak/subsystem/saml/as7/LocalDescriptions.properties b/adapters/saml/as7-eap6/subsystem/src/main/resources/org/keycloak/subsystem/saml/as7/LocalDescriptions.properties
index 6add1e4..8196235 100755
--- a/adapters/saml/as7-eap6/subsystem/src/main/resources/org/keycloak/subsystem/saml/as7/LocalDescriptions.properties
+++ b/adapters/saml/as7-eap6/subsystem/src/main/resources/org/keycloak/subsystem/saml/as7/LocalDescriptions.properties
@@ -67,6 +67,7 @@ keycloak-saml.IDP.signatureCanonicalizationMethod=Signature canonicalization met
 keycloak-saml.IDP.SingleSignOnService=Single sign-on configuration
 keycloak-saml.IDP.SingleSignOnService.signRequest=Sign SSO requests
 keycloak-saml.IDP.SingleSignOnService.validateResponseSignature=Validate an SSO response signature
+keycloak-saml.IDP.SingleSignOnService.validateAssertionSignature=Validate an SSO assertion signature
 keycloak-saml.IDP.SingleSignOnService.requestBinding=HTTP method to use for requests
 keycloak-saml.IDP.SingleSignOnService.responseBinding=HTTP method to use for responses
 keycloak-saml.IDP.SingleSignOnService.bindingUrl=SSO endpoint URL
diff --git a/adapters/saml/as7-eap6/subsystem/src/main/resources/schema/wildfly-keycloak-saml_1_1.xsd b/adapters/saml/as7-eap6/subsystem/src/main/resources/schema/wildfly-keycloak-saml_1_1.xsd
index fb893dd..0494a1e 100755
--- a/adapters/saml/as7-eap6/subsystem/src/main/resources/schema/wildfly-keycloak-saml_1_1.xsd
+++ b/adapters/saml/as7-eap6/subsystem/src/main/resources/schema/wildfly-keycloak-saml_1_1.xsd
@@ -132,6 +132,11 @@
                 <xs:documentation>Validate the SSO response signature</xs:documentation>
             </xs:annotation>
         </xs:attribute>
+        <xs:attribute name="validateAssertionSignature" type="xs:boolean" use="optional">
+            <xs:annotation>
+                <xs:documentation>Validate the SSO assertion signature</xs:documentation>
+            </xs:annotation>
+        </xs:attribute>
         <xs:attribute name="requestBinding" type="xs:string" use="optional">
             <xs:annotation>
                 <xs:documentation>HTTP method to use for requests</xs:documentation>
diff --git a/adapters/saml/as7-eap6/subsystem/src/test/resources/org/keycloak/subsystem/saml/as7/keycloak-saml-1.1.xml b/adapters/saml/as7-eap6/subsystem/src/test/resources/org/keycloak/subsystem/saml/as7/keycloak-saml-1.1.xml
index 31ed630..2380642 100644
--- a/adapters/saml/as7-eap6/subsystem/src/test/resources/org/keycloak/subsystem/saml/as7/keycloak-saml-1.1.xml
+++ b/adapters/saml/as7-eap6/subsystem/src/test/resources/org/keycloak/subsystem/saml/as7/keycloak-saml-1.1.xml
@@ -42,6 +42,7 @@
             <IDP entityID="idp">
                 <SingleSignOnService signRequest="true"
                                      validateResponseSignature="true"
+                                     validateAssertionSignature="true"
                                      requestBinding="POST"
                                      bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
                 <SingleLogoutService
diff --git a/adapters/saml/core/pom.xml b/adapters/saml/core/pom.xml
index f02e3a9..8c1ff3a 100755
--- a/adapters/saml/core/pom.xml
+++ b/adapters/saml/core/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/IDP.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/IDP.java
index 73c14a2..7502e5d 100755
--- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/IDP.java
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/IDP.java
@@ -33,6 +33,7 @@ public class IDP implements Serializable {
         private String requestBinding;
         private String responseBinding;
         private String bindingUrl;
+        private boolean validateAssertionSignature;
 
         public boolean isSignRequest() {
             return signRequest;
@@ -50,6 +51,14 @@ public class IDP implements Serializable {
             this.validateResponseSignature = validateResponseSignature;
         }
 
+        public boolean isValidateAssertionSignature() {
+            return validateAssertionSignature;
+        }
+
+        public void setValidateAssertionSignature(boolean validateAssertionSignature) {
+            this.validateAssertionSignature = validateAssertionSignature;
+        }
+
         public String getRequestBinding() {
             return requestBinding;
         }
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/ConfigXmlConstants.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/ConfigXmlConstants.java
index 8866203..0085a6a 100755
--- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/ConfigXmlConstants.java
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/ConfigXmlConstants.java
@@ -68,6 +68,7 @@ public class ConfigXmlConstants {
     public static final String RESPONSE_BINDING_ATTR = "responseBinding";
     public static final String BINDING_URL_ATTR = "bindingUrl";
     public static final String VALIDATE_RESPONSE_SIGNATURE_ATTR = "validateResponseSignature";
+    public static final String VALIDATE_ASSERTION_SIGNATURE_ATTR = "validateAssertionSignature";
     public static final String VALIDATE_REQUEST_SIGNATURE_ATTR = "validateRequestSignature";
     public static final String POST_BINDING_URL_ATTR = "postBindingUrl";
     public static final String REDIRECT_BINDING_URL_ATTR = "redirectBindingUrl";
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/DeploymentBuilder.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/DeploymentBuilder.java
index 356b79b..e5a6ead 100755
--- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/DeploymentBuilder.java
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/DeploymentBuilder.java
@@ -149,6 +149,7 @@ public class DeploymentBuilder {
         }
         sso.setSignRequest(sp.getIdp().getSingleSignOnService().isSignRequest());
         sso.setValidateResponseSignature(sp.getIdp().getSingleSignOnService().isValidateResponseSignature());
+        sso.setValidateAssertionSignature(sp.getIdp().getSingleSignOnService().isValidateAssertionSignature());
 
         slo.setSignRequest(sp.getIdp().getSingleLogoutService().isSignRequest());
         slo.setSignResponse(sp.getIdp().getSingleLogoutService().isSignResponse());
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IDPXmlParser.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IDPXmlParser.java
index b65f830..e649d1c 100755
--- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IDPXmlParser.java
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/config/parsers/IDPXmlParser.java
@@ -106,6 +106,7 @@ public class IDPXmlParser extends AbstractParser {
         StartElement element = StaxParserUtil.getNextStartElement(xmlEventReader);
         sso.setSignRequest(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.SIGN_REQUEST_ATTR, signaturesRequired));
         sso.setValidateResponseSignature(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_RESPONSE_SIGNATURE_ATTR, signaturesRequired));
+        sso.setValidateAssertionSignature(SPXmlParser.getBooleanAttributeValue(element, ConfigXmlConstants.VALIDATE_ASSERTION_SIGNATURE_ATTR));
         sso.setRequestBinding(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.REQUEST_BINDING_ATTR));
         sso.setResponseBinding(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.RESPONSE_BINDING_ATTR));
         sso.setBindingUrl(SPXmlParser.getAttributeValue(element, ConfigXmlConstants.BINDING_URL_ATTR));
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/DefaultSamlDeployment.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/DefaultSamlDeployment.java
index 4d55f38..9e12f48 100755
--- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/DefaultSamlDeployment.java
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/DefaultSamlDeployment.java
@@ -34,6 +34,7 @@ public class DefaultSamlDeployment implements SamlDeployment {
     public static class DefaultSingleSignOnService implements IDP.SingleSignOnService {
         private boolean signRequest;
         private boolean validateResponseSignature;
+        private boolean validateAssertionSignature;
         private Binding requestBinding;
         private Binding responseBinding;
         private String requestBindingUrl;
@@ -49,6 +50,11 @@ public class DefaultSamlDeployment implements SamlDeployment {
         }
 
         @Override
+        public boolean validateAssertionSignature() {
+            return validateAssertionSignature;
+        }
+
+        @Override
         public Binding getRequestBinding() {
             return requestBinding;
         }
@@ -71,6 +77,10 @@ public class DefaultSamlDeployment implements SamlDeployment {
             this.validateResponseSignature = validateResponseSignature;
         }
 
+        public void setValidateAssertionSignature(boolean validateAssertionSignature) {
+            this.validateAssertionSignature = validateAssertionSignature;
+        }
+
         public void setRequestBinding(Binding requestBinding) {
             this.requestBinding = requestBinding;
         }
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/profile/AbstractSamlAuthenticationHandler.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/profile/AbstractSamlAuthenticationHandler.java
index 1c3766f..e9247b3 100644
--- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/profile/AbstractSamlAuthenticationHandler.java
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/profile/AbstractSamlAuthenticationHandler.java
@@ -201,7 +201,7 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
                         return AuthOutcome.FAILED;
                     }
                 }
-                return handleLoginResponse((ResponseType) statusResponse, onCreateSession);
+                return handleLoginResponse((ResponseType) statusResponse, postBinding, onCreateSession);
             } finally {
                 sessionStore.setCurrentAction(SamlSessionStore.CurrentAction.NONE);
             }
@@ -272,8 +272,7 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
         return false;
     }
 
-    protected AuthOutcome handleLoginResponse(ResponseType responseType, OnSessionCreated onCreateSession) {
-
+    protected AuthOutcome handleLoginResponse(ResponseType responseType, boolean postBinding, OnSessionCreated onCreateSession) {
         AssertionType assertion = null;
         try {
             assertion = AssertionUtil.getAssertion(responseType, deployment.getDecryptionKey());
@@ -298,6 +297,32 @@ public abstract class AbstractSamlAuthenticationHandler implements SamlAuthentic
             };
         }
 
+        if (deployment.getIDP().getSingleSignOnService().validateAssertionSignature()) {
+            try {
+                validateSamlSignature(new SAMLDocumentHolder(AssertionUtil.asDocument(assertion)), postBinding, GeneralConstants.SAML_RESPONSE_KEY);
+            } catch (VerificationException e) {
+                log.error("Failed to verify saml assertion signature", e);
+
+                challenge = new AuthChallenge() {
+                    @Override
+                    public boolean challenge(HttpFacade exchange) {
+                        SamlAuthenticationError error = new SamlAuthenticationError(SamlAuthenticationError.Reason.INVALID_SIGNATURE);
+                        exchange.getRequest().setError(error);
+                        exchange.getResponse().sendError(403);
+                        return true;
+                    }
+
+                    @Override
+                    public int getResponseCode() {
+                        return 403;
+                    }
+                };
+                return AuthOutcome.FAILED;
+            } catch (ProcessingException e) {
+                e.printStackTrace();
+            }
+        }
+
         SubjectType subject = assertion.getSubject();
         SubjectType.STSubType subType = subject.getSubType();
         NameIDType subjectNameID = (NameIDType) subType.getBaseID();
diff --git a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/SamlDeployment.java b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/SamlDeployment.java
index 5f60f34..0b82ff2 100755
--- a/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/SamlDeployment.java
+++ b/adapters/saml/core/src/main/java/org/keycloak/adapters/saml/SamlDeployment.java
@@ -50,6 +50,7 @@ public interface SamlDeployment {
         public interface SingleSignOnService {
             boolean signRequest();
             boolean validateResponseSignature();
+            boolean validateAssertionSignature();
             Binding getRequestBinding();
             Binding getResponseBinding();
             String getRequestBindingUrl();
diff --git a/adapters/saml/core/src/main/resources/schema/keycloak_saml_adapter_1_6.xsd b/adapters/saml/core/src/main/resources/schema/keycloak_saml_adapter_1_6.xsd
index 843c865..1ca774b 100755
--- a/adapters/saml/core/src/main/resources/schema/keycloak_saml_adapter_1_6.xsd
+++ b/adapters/saml/core/src/main/resources/schema/keycloak_saml_adapter_1_6.xsd
@@ -112,6 +112,7 @@
     <xs:complexType name="sign-on-type">
         <xs:attribute name="signRequest" type="xs:boolean" use="optional"/>
         <xs:attribute name="validateResponseSignature" type="xs:boolean" use="optional"/>
+        <xs:attribute name="validateAssertionSignature" type="xs:boolean" use="optional"/>
         <xs:attribute name="requestBinding" type="xs:string" use="optional"/>
         <xs:attribute name="responseBinding" type="xs:string" use="optional"/>
         <xs:attribute name="bindingUrl" type="xs:string" use="optional"/>
diff --git a/adapters/saml/core-public/pom.xml b/adapters/saml/core-public/pom.xml
index f479e3c..7493f24 100755
--- a/adapters/saml/core-public/pom.xml
+++ b/adapters/saml/core-public/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/adapters/saml/jetty/jetty8.1/pom.xml b/adapters/saml/jetty/jetty8.1/pom.xml
index a622c05..76e1479 100755
--- a/adapters/saml/jetty/jetty8.1/pom.xml
+++ b/adapters/saml/jetty/jetty8.1/pom.xml
@@ -21,7 +21,7 @@
     <parent>
 		<artifactId>keycloak-parent</artifactId>
 		<groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
 		<relativePath>../../../../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
diff --git a/adapters/saml/jetty/jetty8.1/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java b/adapters/saml/jetty/jetty8.1/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java
index e236056..870f986 100755
--- a/adapters/saml/jetty/jetty8.1/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java
+++ b/adapters/saml/jetty/jetty8.1/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java
@@ -17,6 +17,7 @@
 
 package org.keycloak.adapters.saml.jetty;
 
+import org.bouncycastle.cert.ocsp.Req;
 import org.eclipse.jetty.server.AbstractHttpConnection;
 import org.eclipse.jetty.server.Authentication;
 import org.eclipse.jetty.server.Request;
@@ -48,7 +49,7 @@ public class KeycloakSamlAuthenticator extends AbstractSamlAuthenticator {
     }
 
     @Override
-    public Authentication createAuthentication(UserIdentity userIdentity) {
+    public Authentication createAuthentication(UserIdentity userIdentity, Request request) {
         return new KeycloakAuthentication(getAuthMethod(), userIdentity) {
             @Override
             public void logout() {
diff --git a/adapters/saml/jetty/jetty9.1/pom.xml b/adapters/saml/jetty/jetty9.1/pom.xml
index 60a7080..ec12888 100755
--- a/adapters/saml/jetty/jetty9.1/pom.xml
+++ b/adapters/saml/jetty/jetty9.1/pom.xml
@@ -21,7 +21,7 @@
     <parent>
 		<artifactId>keycloak-parent</artifactId>
 		<groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
 		<relativePath>../../../../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
diff --git a/adapters/saml/jetty/jetty9.1/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java b/adapters/saml/jetty/jetty9.1/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java
index ca89f50..8696801 100755
--- a/adapters/saml/jetty/jetty9.1/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java
+++ b/adapters/saml/jetty/jetty9.1/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java
@@ -17,6 +17,7 @@
 
 package org.keycloak.adapters.saml.jetty;
 
+import org.bouncycastle.cert.ocsp.Req;
 import org.eclipse.jetty.server.Authentication;
 import org.eclipse.jetty.server.HttpChannel;
 import org.eclipse.jetty.server.Request;
@@ -50,7 +51,7 @@ public class KeycloakSamlAuthenticator extends AbstractSamlAuthenticator {
     }
 
     @Override
-    public Authentication createAuthentication(UserIdentity userIdentity) {
+    public Authentication createAuthentication(UserIdentity userIdentity, Request request) {
         return new KeycloakAuthentication(getAuthMethod(), userIdentity) {
             @Override
             public void logout() {
diff --git a/adapters/saml/jetty/jetty9.2/pom.xml b/adapters/saml/jetty/jetty9.2/pom.xml
index 147182f..13e74bb 100755
--- a/adapters/saml/jetty/jetty9.2/pom.xml
+++ b/adapters/saml/jetty/jetty9.2/pom.xml
@@ -21,7 +21,7 @@
     <parent>
 		<artifactId>keycloak-parent</artifactId>
 		<groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
 		<relativePath>../../../../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
diff --git a/adapters/saml/jetty/jetty9.2/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java b/adapters/saml/jetty/jetty9.2/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java
index 3285059..3491ab2 100755
--- a/adapters/saml/jetty/jetty9.2/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java
+++ b/adapters/saml/jetty/jetty9.2/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java
@@ -45,7 +45,7 @@ public class KeycloakSamlAuthenticator extends AbstractSamlAuthenticator {
     }
 
     @Override
-    public Authentication createAuthentication(UserIdentity userIdentity) {
+    public Authentication createAuthentication(UserIdentity userIdentity, Request request) {
         return new KeycloakAuthentication(getAuthMethod(), userIdentity) {
             @Override
             public void logout() {
diff --git a/adapters/saml/jetty/jetty9.3/pom.xml b/adapters/saml/jetty/jetty9.3/pom.xml
new file mode 100644
index 0000000..5082f28
--- /dev/null
+++ b/adapters/saml/jetty/jetty9.3/pom.xml
@@ -0,0 +1,162 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <parent>
+		<artifactId>keycloak-parent</artifactId>
+		<groupId>org.keycloak</groupId>
+        <version>2.2.0-SNAPSHOT</version>
+		<relativePath>../../../../pom.xml</relativePath>
+	</parent>
+	<modelVersion>4.0.0</modelVersion>
+
+	<artifactId>keycloak-saml-jetty93-adapter</artifactId>
+	<name>Keycloak Jetty 9.3.x SAML Integration</name>
+    <properties>
+        <jetty9.version>9.3.9.v20160517</jetty9.version>
+        <keycloak.osgi.export>
+            org.keycloak.adapters.jetty.*
+        </keycloak.osgi.export>
+        <keycloak.osgi.import>
+            org.eclipse.jetty.*;resolution:=optional,
+            javax.servlet.*;version="[3.0,4)";resolution:=optional,
+            org.keycloak.*;version="${project.version}",
+            *;resolution:=optional
+        </keycloak.osgi.import>
+    </properties>
+	<description />
+
+	<dependencies>
+        <dependency>
+            <groupId>org.jboss.logging</groupId>
+            <artifactId>jboss-logging</artifactId>
+            <version>${jboss.logging.version}</version>
+        </dependency>
+		<dependency>
+			<groupId>org.keycloak</groupId>
+			<artifactId>keycloak-common</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.bouncycastle</groupId>
+			<artifactId>bcprov-jdk15on</artifactId>
+		</dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-saml-adapter-api-public</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-saml-adapter-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-adapter-spi</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-saml-jetty-adapter-core</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.eclipse.jetty</groupId>
+                    <artifactId>jetty-server</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.eclipse.jetty</groupId>
+                    <artifactId>jetty-util</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.eclipse.jetty</groupId>
+                    <artifactId>jetty-security</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-server</artifactId>
+            <version>${jetty9.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-util</artifactId>
+            <version>${jetty9.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-security</artifactId>
+            <version>${jetty9.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<configuration>
+					<source>1.6</source>
+					<target>1.6</target>
+				</configuration>
+			</plugin>
+
+            <!-- Adding OSGI metadata to the JAR without changing the packaging type. -->
+            <plugin>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+                    </archive>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <executions>
+                    <execution>
+                        <id>bundle-manifest</id>
+                        <phase>process-classes</phase>
+                        <goals>
+                            <goal>manifest</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <instructions>
+                        <Bundle-ClassPath>.</Bundle-ClassPath>
+                        <Bundle-Name>${project.name}</Bundle-Name>
+                        <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+                        <Import-Package>${keycloak.osgi.import}</Import-Package>
+                        <Export-Package>${keycloak.osgi.export}</Export-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+		</plugins>
+	</build>
+
+</project>
diff --git a/adapters/saml/jetty/jetty9.3/src/main/java/org/keycloak/adapters/saml/jetty/Jetty9SamlSessionStore.java b/adapters/saml/jetty/jetty9.3/src/main/java/org/keycloak/adapters/saml/jetty/Jetty9SamlSessionStore.java
new file mode 100644
index 0000000..fa618cb
--- /dev/null
+++ b/adapters/saml/jetty/jetty9.3/src/main/java/org/keycloak/adapters/saml/jetty/Jetty9SamlSessionStore.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.adapters.saml.jetty;
+
+import org.eclipse.jetty.server.Request;
+import org.keycloak.adapters.jetty.spi.JettyUserSessionManagement;
+import org.keycloak.adapters.saml.SamlDeployment;
+import org.keycloak.adapters.spi.AdapterSessionStore;
+import org.keycloak.adapters.spi.HttpFacade;
+import org.keycloak.adapters.spi.SessionIdMapper;
+
+import javax.servlet.http.HttpSession;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class Jetty9SamlSessionStore extends JettySamlSessionStore {
+    public Jetty9SamlSessionStore(Request request, AdapterSessionStore sessionStore, HttpFacade facade, SessionIdMapper idMapper, JettyUserSessionManagement sessionManagement, SamlDeployment deployment) {
+        super(request, sessionStore, facade, idMapper, sessionManagement, deployment);
+    }
+
+    @Override
+    protected String changeSessionId(HttpSession session) {
+        Request request = this.request;
+        if (!deployment.turnOffChangeSessionIdOnLogin()) return request.changeSessionId();
+        else return session.getId();
+    }
+}
diff --git a/adapters/saml/jetty/jetty9.3/src/main/java/org/keycloak/adapters/saml/jetty/JettyAdapterSessionStore.java b/adapters/saml/jetty/jetty9.3/src/main/java/org/keycloak/adapters/saml/jetty/JettyAdapterSessionStore.java
new file mode 100644
index 0000000..2259086
--- /dev/null
+++ b/adapters/saml/jetty/jetty9.3/src/main/java/org/keycloak/adapters/saml/jetty/JettyAdapterSessionStore.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.adapters.saml.jetty;
+
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.security.authentication.FormAuthenticator;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.util.MultiMap;
+import org.keycloak.adapters.spi.AdapterSessionStore;
+import org.keycloak.adapters.jetty.spi.JettyHttpFacade;
+import org.keycloak.common.util.MultivaluedHashMap;
+
+import javax.servlet.http.HttpSession;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class JettyAdapterSessionStore implements AdapterSessionStore {
+    public static final String CACHED_FORM_PARAMETERS = "__CACHED_FORM_PARAMETERS";
+    protected Request myRequest;
+
+    public JettyAdapterSessionStore(Request request) {
+        this.myRequest = request; // for IDE/compilation purposes
+    }
+
+    protected MultiMap<String> extractFormParameters(Request base_request) {
+        MultiMap<String> formParameters = new MultiMap<String>();
+        base_request.extractFormParameters(formParameters);
+        return formParameters;
+    }
+    protected void restoreFormParameters(MultiMap<String> j_post, Request base_request) {
+        base_request.setContentParameters(j_post);
+    }
+
+    public boolean restoreRequest() {
+        HttpSession session = myRequest.getSession(false);
+        if (session == null) return false;
+        synchronized (session) {
+            String j_uri = (String) session.getAttribute(FormAuthenticator.__J_URI);
+            if (j_uri != null) {
+                // check if the request is for the same url as the original and restore
+                // params if it was a post
+                StringBuffer buf = myRequest.getRequestURL();
+                if (myRequest.getQueryString() != null)
+                    buf.append("?").append(myRequest.getQueryString());
+                if (j_uri.equals(buf.toString())) {
+                    String method = (String)session.getAttribute(JettyHttpFacade.__J_METHOD);
+                    myRequest.setMethod(method);
+                    MultivaluedHashMap<String, String> j_post = (MultivaluedHashMap<String, String>) session.getAttribute(CACHED_FORM_PARAMETERS);
+                    if (j_post != null) {
+                        myRequest.setContentType("application/x-www-form-urlencoded");
+                        MultiMap<String> map = new MultiMap<String>();
+                        for (String key : j_post.keySet()) {
+                            for (String val : j_post.getList(key)) {
+                                map.add(key, val);
+                            }
+                        }
+                        restoreFormParameters(map, myRequest);
+                    }
+                    session.removeAttribute(FormAuthenticator.__J_URI);
+                    session.removeAttribute(JettyHttpFacade.__J_METHOD);
+                    session.removeAttribute(FormAuthenticator.__J_POST);
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void saveRequest() {
+        // remember the current URI
+        HttpSession session = myRequest.getSession();
+        synchronized (session) {
+            // But only if it is not set already, or we save every uri that leads to a login form redirect
+            if (session.getAttribute(FormAuthenticator.__J_URI) == null) {
+                StringBuffer buf = myRequest.getRequestURL();
+                if (myRequest.getQueryString() != null)
+                    buf.append("?").append(myRequest.getQueryString());
+                session.setAttribute(FormAuthenticator.__J_URI, buf.toString());
+                session.setAttribute(JettyHttpFacade.__J_METHOD, myRequest.getMethod());
+
+                if ("application/x-www-form-urlencoded".equals(myRequest.getContentType()) && "POST".equalsIgnoreCase(myRequest.getMethod())) {
+                    MultiMap<String> formParameters = extractFormParameters(myRequest);
+                    MultivaluedHashMap<String, String> map = new MultivaluedHashMap<String, String>();
+                    for (String key : formParameters.keySet()) {
+                        for (Object value : formParameters.getValues(key)) {
+                            map.add(key, (String) value);
+                        }
+                    }
+                    session.setAttribute(CACHED_FORM_PARAMETERS, map);
+                }
+            }
+        }
+    }
+
+}
diff --git a/adapters/saml/jetty/jetty9.3/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java b/adapters/saml/jetty/jetty9.3/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java
new file mode 100644
index 0000000..0d4268f
--- /dev/null
+++ b/adapters/saml/jetty/jetty9.3/src/main/java/org/keycloak/adapters/saml/jetty/KeycloakSamlAuthenticator.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.adapters.saml.jetty;
+
+import org.eclipse.jetty.server.Authentication;
+import org.eclipse.jetty.server.HttpChannel;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.UserIdentity;
+import org.keycloak.adapters.jetty.spi.JettyUserSessionManagement;
+import org.keycloak.adapters.spi.AdapterSessionStore;
+import org.keycloak.adapters.saml.SamlDeployment;
+import org.keycloak.adapters.spi.HttpFacade;
+
+import javax.servlet.ServletRequest;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class KeycloakSamlAuthenticator extends AbstractSamlAuthenticator {
+
+    public KeycloakSamlAuthenticator() {
+        super();
+    }
+
+
+   @Override
+    protected Request resolveRequest(ServletRequest req) {
+       return Request.getBaseRequest(req);
+    }
+
+    @Override
+    public Authentication createAuthentication(UserIdentity userIdentity, final Request request) {
+        return new KeycloakAuthentication(getAuthMethod(), userIdentity) {
+            @Override
+            public void logout() {
+                logoutCurrent(request);
+            }
+        };
+    }
+
+    @Override
+    public AdapterSessionStore createSessionTokenStore(Request request, SamlDeployment resolvedDeployment) {
+        return new JettyAdapterSessionStore(request);
+    }
+
+    @Override
+    protected JettySamlSessionStore createJettySamlSessionStore(Request request, HttpFacade facade, SamlDeployment resolvedDeployment) {
+        JettySamlSessionStore store;
+        store = new Jetty9SamlSessionStore(request, createSessionTokenStore(request, resolvedDeployment), facade, idMapper, new JettyUserSessionManagement(request.getSessionManager()), resolvedDeployment);
+        return store;
+    }
+}
diff --git a/adapters/saml/jetty/jetty-core/pom.xml b/adapters/saml/jetty/jetty-core/pom.xml
index 89ae21d..fbd5a83 100755
--- a/adapters/saml/jetty/jetty-core/pom.xml
+++ b/adapters/saml/jetty/jetty-core/pom.xml
@@ -21,7 +21,7 @@
     <parent>
 		<artifactId>keycloak-parent</artifactId>
 		<groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
 		<relativePath>../../../../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
diff --git a/adapters/saml/jetty/jetty-core/src/main/java/org/keycloak/adapters/saml/jetty/AbstractSamlAuthenticator.java b/adapters/saml/jetty/jetty-core/src/main/java/org/keycloak/adapters/saml/jetty/AbstractSamlAuthenticator.java
index bfa7d59..4ef67f8 100755
--- a/adapters/saml/jetty/jetty-core/src/main/java/org/keycloak/adapters/saml/jetty/AbstractSamlAuthenticator.java
+++ b/adapters/saml/jetty/jetty-core/src/main/java/org/keycloak/adapters/saml/jetty/AbstractSamlAuthenticator.java
@@ -370,13 +370,13 @@ public abstract class AbstractSamlAuthenticator extends LoginAuthenticator {
         Authentication authentication = request.getAuthentication();
         if (!(authentication instanceof KeycloakAuthentication)) {
             UserIdentity userIdentity = createIdentity(samlSession);
-            authentication = createAuthentication(userIdentity);
+            authentication = createAuthentication(userIdentity, request);
             request.setAuthentication(authentication);
         }
         return authentication;
     }
 
-    public abstract Authentication createAuthentication(UserIdentity userIdentity);
+    public abstract Authentication createAuthentication(UserIdentity userIdentity, Request request);
 
     public static abstract class KeycloakAuthentication extends UserAuthentication {
         public KeycloakAuthentication(String method, UserIdentity userIdentity) {
diff --git a/adapters/saml/jetty/pom.xml b/adapters/saml/jetty/pom.xml
index 62b951e..2531a32 100755
--- a/adapters/saml/jetty/pom.xml
+++ b/adapters/saml/jetty/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <name>Keycloak SAML Jetty Integration</name>
@@ -35,5 +35,6 @@
         <module>jetty8.1</module>
         <module>jetty9.1</module>
         <module>jetty9.2</module>
+        <module>jetty9.3</module>
     </modules>
 </project>
diff --git a/adapters/saml/pom.xml b/adapters/saml/pom.xml
index e2e0fe5..a958624 100755
--- a/adapters/saml/pom.xml
+++ b/adapters/saml/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <name>Keycloak SAML Client Adapter Modules</name>
diff --git a/adapters/saml/servlet-filter/pom.xml b/adapters/saml/servlet-filter/pom.xml
index 4edd8ab..42807f7 100755
--- a/adapters/saml/servlet-filter/pom.xml
+++ b/adapters/saml/servlet-filter/pom.xml
@@ -21,7 +21,7 @@
     <parent>
 		<artifactId>keycloak-parent</artifactId>
 		<groupId>org.keycloak</groupId>
-		<version>2.0.0.CR1-SNAPSHOT</version>
+		<version>2.2.0-SNAPSHOT</version>
 		<relativePath>../../../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
diff --git a/adapters/saml/tomcat/pom.xml b/adapters/saml/tomcat/pom.xml
index e863a45..56b5272 100755
--- a/adapters/saml/tomcat/pom.xml
+++ b/adapters/saml/tomcat/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <name>Keycloak SAML Tomcat Integration</name>
diff --git a/adapters/saml/tomcat/tomcat6/pom.xml b/adapters/saml/tomcat/tomcat6/pom.xml
index edac214..d9f6b87 100755
--- a/adapters/saml/tomcat/tomcat6/pom.xml
+++ b/adapters/saml/tomcat/tomcat6/pom.xml
@@ -21,7 +21,7 @@
     <parent>
 		<artifactId>keycloak-saml-tomcat-integration-pom</artifactId>
 		<groupId>org.keycloak</groupId>
-		<version>2.0.0.CR1-SNAPSHOT</version>
+		<version>2.2.0-SNAPSHOT</version>
 		<relativePath>../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
diff --git a/adapters/saml/tomcat/tomcat7/pom.xml b/adapters/saml/tomcat/tomcat7/pom.xml
index 1278ec2..680b64b 100755
--- a/adapters/saml/tomcat/tomcat7/pom.xml
+++ b/adapters/saml/tomcat/tomcat7/pom.xml
@@ -21,7 +21,7 @@
     <parent>
 		<artifactId>keycloak-saml-tomcat-integration-pom</artifactId>
 		<groupId>org.keycloak</groupId>
-		<version>2.0.0.CR1-SNAPSHOT</version>
+		<version>2.2.0-SNAPSHOT</version>
 		<relativePath>../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
diff --git a/adapters/saml/tomcat/tomcat8/pom.xml b/adapters/saml/tomcat/tomcat8/pom.xml
index 038d499..4e80f5f 100755
--- a/adapters/saml/tomcat/tomcat8/pom.xml
+++ b/adapters/saml/tomcat/tomcat8/pom.xml
@@ -21,7 +21,7 @@
     <parent>
 		<artifactId>keycloak-saml-tomcat-integration-pom</artifactId>
 		<groupId>org.keycloak</groupId>
-		<version>2.0.0.CR1-SNAPSHOT</version>
+		<version>2.2.0-SNAPSHOT</version>
 		<relativePath>../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
diff --git a/adapters/saml/tomcat/tomcat-core/pom.xml b/adapters/saml/tomcat/tomcat-core/pom.xml
index f2b8481..ff5227d 100755
--- a/adapters/saml/tomcat/tomcat-core/pom.xml
+++ b/adapters/saml/tomcat/tomcat-core/pom.xml
@@ -21,7 +21,7 @@
     <parent>
 		<artifactId>keycloak-saml-tomcat-integration-pom</artifactId>
 		<groupId>org.keycloak</groupId>
-		<version>2.0.0.CR1-SNAPSHOT</version>
+		<version>2.2.0-SNAPSHOT</version>
 		<relativePath>../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
diff --git a/adapters/saml/undertow/pom.xml b/adapters/saml/undertow/pom.xml
index 23ebbeb..3e3a4d0 100755
--- a/adapters/saml/undertow/pom.xml
+++ b/adapters/saml/undertow/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/adapters/saml/wildfly/pom.xml b/adapters/saml/wildfly/pom.xml
index 708a4c8..357ed49 100755
--- a/adapters/saml/wildfly/pom.xml
+++ b/adapters/saml/wildfly/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <name>Keycloak SAML Wildfly Integration</name>
diff --git a/adapters/saml/wildfly/wildfly-adapter/pom.xml b/adapters/saml/wildfly/wildfly-adapter/pom.xml
index dd0837d..15dcdcf 100755
--- a/adapters/saml/wildfly/wildfly-adapter/pom.xml
+++ b/adapters/saml/wildfly/wildfly-adapter/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/adapters/saml/wildfly/wildfly-subsystem/pom.xml b/adapters/saml/wildfly/wildfly-subsystem/pom.xml
index 7861150..b8c5cc3 100755
--- a/adapters/saml/wildfly/wildfly-subsystem/pom.xml
+++ b/adapters/saml/wildfly/wildfly-subsystem/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak</groupId>
         <artifactId>keycloak-parent</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../../pom.xml</relativePath>
     </parent>
 
diff --git a/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/Configuration.java b/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/Configuration.java
index d3990a4..e81b05d 100644
--- a/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/Configuration.java
+++ b/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/Configuration.java
@@ -16,8 +16,11 @@
  */
 package org.keycloak.subsystem.adapter.saml.extension;
 
+import org.jboss.as.server.deployment.DeploymentUnit;
+import org.jboss.as.web.common.WarMetaData;
 import org.jboss.dmr.ModelNode;
 import org.jboss.dmr.Property;
+import org.jboss.metadata.web.jboss.JBossWebMetaData;
 
 /**
  * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
@@ -46,11 +49,31 @@ public class Configuration {
         return keymodel.get(key);
     }
 
-    public ModelNode getSecureDeployment(String name) {
+    public ModelNode getSecureDeployment(DeploymentUnit deploymentUnit) {
+        String name = preferredDeploymentName(deploymentUnit);
         ModelNode secureDeployment = config.get("subsystem").get("keycloak-saml").get(Constants.Model.SECURE_DEPLOYMENT);
         if (secureDeployment.hasDefined(name)) {
             return secureDeployment.get(name);
         }
         return null;
     }
+    
+    // KEYCLOAK-3273: prefer module name if available
+    private String preferredDeploymentName(DeploymentUnit deploymentUnit) {
+        String deploymentName = deploymentUnit.getName();
+        WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
+        if (warMetaData == null) {
+            return deploymentName;
+        }
+        
+        JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
+        if (webMetaData == null) {
+            return deploymentName;
+        }
+        
+        String moduleName = webMetaData.getModuleName();
+        if (moduleName != null) return moduleName + ".war";
+        
+        return deploymentName;
+    }
 }
diff --git a/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/Constants.java b/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/Constants.java
index c7d5acc..46bfaed 100755
--- a/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/Constants.java
+++ b/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/Constants.java
@@ -45,6 +45,7 @@ public class Constants {
         static final String KEY_STORE = "KeyStore";
         static final String SIGN_REQUEST = "signRequest";
         static final String VALIDATE_RESPONSE_SIGNATURE = "validateResponseSignature";
+        static final String VALIDATE_ASSERTION_SIGNATURE = "validateAssertionSignature";
         static final String REQUEST_BINDING = "requestBinding";
         static final String BINDING_URL = "bindingUrl";
         static final String VALIDATE_REQUEST_SIGNATURE = "validateRequestSignature";
@@ -97,6 +98,7 @@ public class Constants {
         static final String CERTIFICATE_ALIAS = "alias";
         static final String SIGN_REQUEST = "signRequest";
         static final String VALIDATE_RESPONSE_SIGNATURE = "validateResponseSignature";
+        static final String VALIDATE_ASSERTION_SIGNATURE = "validateAssertionSignature";
         static final String REQUEST_BINDING = "requestBinding";
         static final String BINDING_URL = "bindingUrl";
         static final String VALIDATE_REQUEST_SIGNATURE = "validateRequestSignature";
diff --git a/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakAdapterConfigDeploymentProcessor.java b/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakAdapterConfigDeploymentProcessor.java
index cd3cf17..c23d77f 100755
--- a/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakAdapterConfigDeploymentProcessor.java
+++ b/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakAdapterConfigDeploymentProcessor.java
@@ -49,21 +49,20 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
     public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
         DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
 
-        String deploymentName = deploymentUnit.getName();
-        if (Configuration.INSTANCE.getSecureDeployment(deploymentName) != null) {
-            addKeycloakSamlAuthData(phaseContext, deploymentName);
+        if (Configuration.INSTANCE.getSecureDeployment(deploymentUnit) != null) {
+            addKeycloakSamlAuthData(phaseContext);
         }
     }
 
-    private void addKeycloakSamlAuthData(DeploymentPhaseContext phaseContext, String deploymentName) throws DeploymentUnitProcessingException {
+    private void addKeycloakSamlAuthData(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
         DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
         WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
         if (warMetaData == null) {
-            throw new DeploymentUnitProcessingException("WarMetaData not found for " + deploymentName + ".  Make sure you have specified a WAR as your secure-deployment in the Keycloak subsystem.");
+            throw new DeploymentUnitProcessingException("WarMetaData not found for " + deploymentUnit.getName() + ".  Make sure you have specified a WAR as your secure-deployment in the Keycloak subsystem.");
         }
 
         try {
-            addXMLData(getXML(deploymentName), warMetaData);
+            addXMLData(getXML(deploymentUnit), warMetaData);
         } catch (Exception e) {
             throw new DeploymentUnitProcessingException("Failed to configure KeycloakSamlExtension from subsystem model", e);
         }
@@ -80,11 +79,11 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
         }
         loginConfig.setAuthMethod("KEYCLOAK-SAML");
 
-        KeycloakLogger.ROOT_LOGGER.deploymentSecured(deploymentName);
+        KeycloakLogger.ROOT_LOGGER.deploymentSecured(deploymentUnit.getName());
     }
 
-    private String getXML(String deploymentName) throws XMLStreamException {
-        ModelNode node = Configuration.INSTANCE.getSecureDeployment(deploymentName);
+    private String getXML(DeploymentUnit deploymentUnit) throws XMLStreamException {
+        ModelNode node = Configuration.INSTANCE.getSecureDeployment(deploymentUnit);
         if (node != null) {
             KeycloakSubsystemParser writer = new KeycloakSubsystemParser();
             ByteArrayOutputStream output = new ByteArrayOutputStream();
diff --git a/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakDependencyProcessor.java b/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakDependencyProcessor.java
index a53eedc..677eda2 100755
--- a/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakDependencyProcessor.java
+++ b/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/KeycloakDependencyProcessor.java
@@ -45,8 +45,7 @@ public abstract class KeycloakDependencyProcessor implements DeploymentUnitProce
     public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
         final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
 
-        String deploymentName = deploymentUnit.getName();
-        if (Configuration.INSTANCE.getSecureDeployment(deploymentName) == null) {
+        if (Configuration.INSTANCE.getSecureDeployment(deploymentUnit) == null) {
             WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
             if (warMetaData == null) {
                 return;
diff --git a/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/SingleSignOnDefinition.java b/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/SingleSignOnDefinition.java
index 8a565a3..d0d95b1 100644
--- a/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/SingleSignOnDefinition.java
+++ b/adapters/saml/wildfly/wildfly-subsystem/src/main/java/org/keycloak/subsystem/adapter/saml/extension/SingleSignOnDefinition.java
@@ -37,6 +37,11 @@ abstract class SingleSignOnDefinition {
                     .setXmlName(Constants.XML.VALIDATE_RESPONSE_SIGNATURE)
                     .build();
 
+    static final SimpleAttributeDefinition VALIDATE_ASSERTION_SIGNATURE =
+            new SimpleAttributeDefinitionBuilder(Constants.Model.VALIDATE_ASSERTION_SIGNATURE, ModelType.BOOLEAN, true)
+                    .setXmlName(Constants.XML.VALIDATE_ASSERTION_SIGNATURE)
+                    .build();
+
     static final SimpleAttributeDefinition REQUEST_BINDING =
             new SimpleAttributeDefinitionBuilder(Constants.Model.REQUEST_BINDING, ModelType.STRING, true)
                     .setXmlName(Constants.XML.REQUEST_BINDING)
@@ -52,7 +57,7 @@ abstract class SingleSignOnDefinition {
                     .setXmlName(Constants.XML.BINDING_URL)
                     .build();
 
-    static final SimpleAttributeDefinition[] ATTRIBUTES = {SIGN_REQUEST, VALIDATE_RESPONSE_SIGNATURE, REQUEST_BINDING, RESPONSE_BINDING, BINDING_URL};
+    static final SimpleAttributeDefinition[] ATTRIBUTES = {SIGN_REQUEST, VALIDATE_RESPONSE_SIGNATURE, VALIDATE_ASSERTION_SIGNATURE, REQUEST_BINDING, RESPONSE_BINDING, BINDING_URL};
 
     static final HashMap<String, SimpleAttributeDefinition> ATTRIBUTE_MAP = new HashMap<>();
 
diff --git a/adapters/saml/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/saml/extension/LocalDescriptions.properties b/adapters/saml/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/saml/extension/LocalDescriptions.properties
index 6add1e4..8196235 100755
--- a/adapters/saml/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/saml/extension/LocalDescriptions.properties
+++ b/adapters/saml/wildfly/wildfly-subsystem/src/main/resources/org/keycloak/subsystem/adapter/saml/extension/LocalDescriptions.properties
@@ -67,6 +67,7 @@ keycloak-saml.IDP.signatureCanonicalizationMethod=Signature canonicalization met
 keycloak-saml.IDP.SingleSignOnService=Single sign-on configuration
 keycloak-saml.IDP.SingleSignOnService.signRequest=Sign SSO requests
 keycloak-saml.IDP.SingleSignOnService.validateResponseSignature=Validate an SSO response signature
+keycloak-saml.IDP.SingleSignOnService.validateAssertionSignature=Validate an SSO assertion signature
 keycloak-saml.IDP.SingleSignOnService.requestBinding=HTTP method to use for requests
 keycloak-saml.IDP.SingleSignOnService.responseBinding=HTTP method to use for responses
 keycloak-saml.IDP.SingleSignOnService.bindingUrl=SSO endpoint URL
diff --git a/adapters/saml/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak-saml_1_1.xsd b/adapters/saml/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak-saml_1_1.xsd
index fb893dd..0494a1e 100755
--- a/adapters/saml/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak-saml_1_1.xsd
+++ b/adapters/saml/wildfly/wildfly-subsystem/src/main/resources/schema/wildfly-keycloak-saml_1_1.xsd
@@ -132,6 +132,11 @@
                 <xs:documentation>Validate the SSO response signature</xs:documentation>
             </xs:annotation>
         </xs:attribute>
+        <xs:attribute name="validateAssertionSignature" type="xs:boolean" use="optional">
+            <xs:annotation>
+                <xs:documentation>Validate the SSO assertion signature</xs:documentation>
+            </xs:annotation>
+        </xs:attribute>
         <xs:attribute name="requestBinding" type="xs:string" use="optional">
             <xs:annotation>
                 <xs:documentation>HTTP method to use for requests</xs:documentation>
diff --git a/adapters/saml/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/saml/extension/keycloak-saml-1.1.xml b/adapters/saml/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/saml/extension/keycloak-saml-1.1.xml
index d818308..f703c58 100755
--- a/adapters/saml/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/saml/extension/keycloak-saml-1.1.xml
+++ b/adapters/saml/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/saml/extension/keycloak-saml-1.1.xml
@@ -44,6 +44,7 @@
             <IDP entityID="idp" signaturesRequired="true" signatureAlgorithm="test" signatureCanonicalizationMethod="test">
                 <SingleSignOnService signRequest="true"
                                      validateResponseSignature="true"
+                                     validateAssertionSignature="true"
                                      requestBinding="POST"
                                      responseBinding="POST"
                                      bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
diff --git a/adapters/saml/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/saml/extension/keycloak-saml-1.1-err.xml b/adapters/saml/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/saml/extension/keycloak-saml-1.1-err.xml
index ed56ccc..5afd0bf 100644
--- a/adapters/saml/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/saml/extension/keycloak-saml-1.1-err.xml
+++ b/adapters/saml/wildfly/wildfly-subsystem/src/test/resources/org/keycloak/subsystem/adapter/saml/extension/keycloak-saml-1.1-err.xml
@@ -42,6 +42,7 @@
             <IDP entityID="idp" signaturesRequired="true" signatureAlgorithm="test" signatureCanonicalizationMethod="test" encryption="test">
                 <SingleSignOnService signRequest="true"
                                      validateResponseSignature="true"
+                                     validateAssertionSignature="true"
                                      requestBinding="POST"
                                      responseBinding="POST"
                                      bindingUrl="http://localhost:8080/auth/realms/saml-demo/protocol/saml"/>
diff --git a/adapters/spi/adapter-spi/pom.xml b/adapters/spi/adapter-spi/pom.xml
index d0f2837..d61f55b 100755
--- a/adapters/spi/adapter-spi/pom.xml
+++ b/adapters/spi/adapter-spi/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/adapters/spi/jboss-adapter-core/pom.xml b/adapters/spi/jboss-adapter-core/pom.xml
index 503ca08..1b4902f 100755
--- a/adapters/spi/jboss-adapter-core/pom.xml
+++ b/adapters/spi/jboss-adapter-core/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/adapters/spi/jetty-adapter-spi/pom.xml b/adapters/spi/jetty-adapter-spi/pom.xml
index 568d718..a18aed7 100755
--- a/adapters/spi/jetty-adapter-spi/pom.xml
+++ b/adapters/spi/jetty-adapter-spi/pom.xml
@@ -21,7 +21,7 @@
     <parent>
 		<artifactId>keycloak-parent</artifactId>
 		<groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
 		<relativePath>../../../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
diff --git a/adapters/spi/pom.xml b/adapters/spi/pom.xml
index 362a249..682a803 100755
--- a/adapters/spi/pom.xml
+++ b/adapters/spi/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <name>Keycloak Client Adapter SPI Modules</name>
diff --git a/adapters/spi/servlet-adapter-spi/pom.xml b/adapters/spi/servlet-adapter-spi/pom.xml
index dbe6e96..025ee7e 100755
--- a/adapters/spi/servlet-adapter-spi/pom.xml
+++ b/adapters/spi/servlet-adapter-spi/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/adapters/spi/servlet-adapter-spi/src/main/java/org/keycloak/adapters/servlet/FilterSessionStore.java b/adapters/spi/servlet-adapter-spi/src/main/java/org/keycloak/adapters/servlet/FilterSessionStore.java
index 5d1eb51..243ab33 100755
--- a/adapters/spi/servlet-adapter-spi/src/main/java/org/keycloak/adapters/servlet/FilterSessionStore.java
+++ b/adapters/spi/servlet-adapter-spi/src/main/java/org/keycloak/adapters/servlet/FilterSessionStore.java
@@ -192,7 +192,7 @@ public class FilterSessionStore implements AdapterSessionStore {
                 @Override
                 public long getDateHeader(String name) {
                    if (!needRequestRestore) return super.getDateHeader(name);
-                   throw new RuntimeException("This method is not supported in a restored authenticated request");
+                   return -1;
                 }
 
                 @Override
diff --git a/adapters/spi/tomcat-adapter-spi/pom.xml b/adapters/spi/tomcat-adapter-spi/pom.xml
index 93767a1..13b7752 100755
--- a/adapters/spi/tomcat-adapter-spi/pom.xml
+++ b/adapters/spi/tomcat-adapter-spi/pom.xml
@@ -21,7 +21,7 @@
     <parent>
 		<artifactId>keycloak-parent</artifactId>
 		<groupId>org.keycloak</groupId>
-		<version>2.0.0.CR1-SNAPSHOT</version>
+		<version>2.2.0-SNAPSHOT</version>
 		<relativePath>../../../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
diff --git a/adapters/spi/undertow-adapter-spi/pom.xml b/adapters/spi/undertow-adapter-spi/pom.xml
index e057685..5f1d5f5 100755
--- a/adapters/spi/undertow-adapter-spi/pom.xml
+++ b/adapters/spi/undertow-adapter-spi/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>

authz/client/pom.xml 101(+101 -0)

diff --git a/authz/client/pom.xml b/authz/client/pom.xml
new file mode 100644
index 0000000..594624b
--- /dev/null
+++ b/authz/client/pom.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.keycloak</groupId>
+        <artifactId>keycloak-authz-parent</artifactId>
+        <version>2.2.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>keycloak-authz-client</artifactId>
+    <packaging>jar</packaging>
+
+    <name>KeyCloak Authz: Client API</name>
+    <description>KeyCloak AuthZ: Client API</description>
+
+    <properties>
+        <keycloak.osgi.export>
+            org.keycloak.authorization.client.*
+        </keycloak.osgi.export>
+        <keycloak.osgi.import>
+            org.keycloak.*;version="${project.version}",
+            org.apache.http.*;version=${apache.httpcomponents.version},
+            *;resolution:=optional
+        </keycloak.osgi.import>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.logging</groupId>
+            <artifactId>jboss-logging</artifactId>
+            <version>${jboss.logging.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <!-- Adding OSGI metadata to the JAR without changing the packaging type. -->
+            <plugin>
+                <artifactId>maven-jar-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+                    </archive>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <executions>
+                    <execution>
+                        <id>bundle-manifest</id>
+                        <phase>process-classes</phase>
+                        <goals>
+                            <goal>manifest</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <instructions>
+                        <Bundle-ClassPath>.</Bundle-ClassPath>
+                        <Bundle-Name>${project.name}</Bundle-Name>
+                        <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+                        <Import-Package>${keycloak.osgi.import}</Import-Package>
+                        <Export-Package>${keycloak.osgi.export}</Export-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/AuthorizationDeniedException.java b/authz/client/src/main/java/org/keycloak/authorization/client/AuthorizationDeniedException.java
new file mode 100644
index 0000000..ffab2b5
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/AuthorizationDeniedException.java
@@ -0,0 +1,29 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.authorization.client;
+
+import org.keycloak.authorization.client.util.HttpResponseException;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AuthorizationDeniedException extends RuntimeException {
+    public AuthorizationDeniedException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/AuthzClient.java b/authz/client/src/main/java/org/keycloak/authorization/client/AuthzClient.java
new file mode 100644
index 0000000..0221af6
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/AuthzClient.java
@@ -0,0 +1,131 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.client;
+
+import org.keycloak.authorization.client.representation.ServerConfiguration;
+import org.keycloak.authorization.client.resource.AuthorizationResource;
+import org.keycloak.authorization.client.resource.EntitlementResource;
+import org.keycloak.authorization.client.resource.ProtectionResource;
+import org.keycloak.authorization.client.util.Http;
+import org.keycloak.representations.AccessTokenResponse;
+import org.keycloak.util.JsonSerialization;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+
+/**
+ * <p>This is class serves as an entry point for clients looking for access to Keycloak Authorization Services.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AuthzClient {
+
+    private final Http http;
+
+    public static AuthzClient create() {
+        InputStream configStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("keycloak.json");
+
+        if (configStream == null) {
+            throw new RuntimeException("Could not find any keycloak.json file in classpath.");
+        }
+
+        try {
+            return create(JsonSerialization.readValue(configStream, Configuration.class));
+        } catch (IOException e) {
+            throw new RuntimeException("Could not parse configuration.", e);
+        }
+    }
+
+    public static AuthzClient create(Configuration configuration) {
+        return new AuthzClient(configuration);
+    }
+
+    private final ServerConfiguration serverConfiguration;
+    private final Configuration deployment;
+
+    private AuthzClient(Configuration configuration) {
+        if (configuration == null) {
+            throw new IllegalArgumentException("Client configuration can not be null.");
+        }
+
+        String configurationUrl = configuration.getAuthServerUrl();
+
+        if (configurationUrl == null) {
+            throw new IllegalArgumentException("Configuration URL can not be null.");
+        }
+
+        configurationUrl += "/realms/" + configuration.getRealm() + "/.well-known/uma-configuration";
+
+        this.http = new Http(configuration);
+
+        try {
+            this.serverConfiguration = this.http.<ServerConfiguration>get(URI.create(configurationUrl))
+                    .response().json(ServerConfiguration.class)
+                    .execute();
+        } catch (Exception e) {
+            throw new RuntimeException("Could not obtain configuration from server [" + configurationUrl + "].", e);
+        }
+
+        this.http.setServerConfiguration(this.serverConfiguration);
+
+        this.deployment = configuration;
+    }
+
+    public ProtectionResource protection() {
+        return new ProtectionResource(this.http, obtainAccessToken().getToken());
+    }
+
+    public AuthorizationResource authorization(String accesstoken) {
+        return new AuthorizationResource(this.http, accesstoken);
+    }
+
+    public AuthorizationResource authorization(String userName, String password) {
+        return new AuthorizationResource(this.http, obtainAccessToken(userName, password).getToken());
+    }
+
+    public EntitlementResource entitlement(String eat) {
+        return new EntitlementResource(this.http, eat);
+    }
+
+    public AccessTokenResponse obtainAccessToken() {
+        return this.http.<AccessTokenResponse>post(this.serverConfiguration.getTokenEndpoint())
+                .authentication()
+                    .oauth2ClientCredentials()
+                .response()
+                    .json(AccessTokenResponse.class)
+                .execute();
+    }
+
+    public AccessTokenResponse obtainAccessToken(String userName, String password) {
+        return this.http.<AccessTokenResponse>post(this.serverConfiguration.getTokenEndpoint())
+                .authentication()
+                    .oauth2ResourceOwnerPassword(userName, password)
+                .response()
+                    .json(AccessTokenResponse.class)
+                .execute();
+    }
+
+    public ServerConfiguration getServerConfiguration() {
+        return this.serverConfiguration;
+    }
+
+    public Configuration getConfiguration() {
+        return this.deployment;
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/ClientAuthenticator.java b/authz/client/src/main/java/org/keycloak/authorization/client/ClientAuthenticator.java
new file mode 100644
index 0000000..076c2db
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/ClientAuthenticator.java
@@ -0,0 +1,27 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.authorization.client;
+
+import java.util.HashMap;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface ClientAuthenticator {
+    void configureClientCredentials(HashMap<String, String> requestParams, HashMap<String, String> requestHeaders);
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/Configuration.java b/authz/client/src/main/java/org/keycloak/authorization/client/Configuration.java
new file mode 100644
index 0000000..835c830
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/Configuration.java
@@ -0,0 +1,102 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.authorization.client;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.apache.http.client.HttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.keycloak.util.BasicAuthHelper;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class Configuration {
+
+    @JsonIgnore
+    private HttpClient httpClient;
+
+    @JsonProperty("auth-server-url")
+    protected String authServerUrl;
+
+    @JsonProperty("realm")
+    protected String realm;
+
+    @JsonProperty("resource")
+    protected String clientId;
+
+    @JsonProperty("credentials")
+    protected Map<String, Object> clientCredentials = new HashMap<>();
+
+    public Configuration() {
+
+    }
+
+    public Configuration(String authServerUrl, String realm, String clientId, Map<String, Object> clientCredentials, HttpClient httpClient) {
+        this.authServerUrl = authServerUrl;
+        this.realm = realm;
+        this.clientId = clientId;
+        this.clientCredentials = clientCredentials;
+        this.httpClient = httpClient;
+    }
+
+    @JsonIgnore
+    private ClientAuthenticator clientAuthenticator = new ClientAuthenticator() {
+        @Override
+        public void configureClientCredentials(HashMap<String, String> requestParams, HashMap<String, String> requestHeaders) {
+            String secret = (String) clientCredentials.get("secret");
+
+            if (secret == null) {
+                throw new RuntimeException("Client secret not provided.");
+            }
+
+            requestHeaders.put("Authorization", BasicAuthHelper.createHeader(clientId, secret));
+        }
+    };
+
+    public HttpClient getHttpClient() {
+        if (this.httpClient == null) {
+            this.httpClient = HttpClients.createDefault();
+        }
+
+        return httpClient;
+    }
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    public String getAuthServerUrl() {
+        return authServerUrl;
+    }
+
+    public ClientAuthenticator getClientAuthenticator() {
+        return this.clientAuthenticator;
+    }
+
+    public Map<String, Object> getClientCredentials() {
+        return clientCredentials;
+    }
+
+    public String getRealm() {
+        return realm;
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/representation/AuthorizationRequest.java b/authz/client/src/main/java/org/keycloak/authorization/client/representation/AuthorizationRequest.java
new file mode 100644
index 0000000..ef53586
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/representation/AuthorizationRequest.java
@@ -0,0 +1,48 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.client.representation;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AuthorizationRequest {
+
+    private String ticket;
+    private String rpt;
+
+    public AuthorizationRequest(String ticket, String rpt) {
+        this.ticket = ticket;
+        this.rpt = rpt;
+    }
+
+    public AuthorizationRequest(String ticket) {
+        this(ticket, null);
+    }
+
+    public AuthorizationRequest() {
+        this(null, null);
+    }
+
+    public String getTicket() {
+        return this.ticket;
+    }
+
+    public String getRpt() {
+        return this.rpt;
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/representation/AuthorizationResponse.java b/authz/client/src/main/java/org/keycloak/authorization/client/representation/AuthorizationResponse.java
new file mode 100644
index 0000000..472c89a
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/representation/AuthorizationResponse.java
@@ -0,0 +1,42 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.client.representation;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AuthorizationResponse {
+
+    private String rpt;
+
+    public AuthorizationResponse(String rpt) {
+        this.rpt = rpt;
+    }
+
+    public AuthorizationResponse() {
+        this(null);
+    }
+
+    public String getRpt() {
+        return this.rpt;
+    }
+
+    public void setRpt(final String rpt) {
+        this.rpt = rpt;
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/representation/EntitlementRequest.java b/authz/client/src/main/java/org/keycloak/authorization/client/representation/EntitlementRequest.java
new file mode 100644
index 0000000..daec233
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/representation/EntitlementRequest.java
@@ -0,0 +1,34 @@
+package org.keycloak.authorization.client.representation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class EntitlementRequest {
+
+    private String rpt;
+
+    private List<PermissionRequest> permissions = new ArrayList<>();
+
+    public List<PermissionRequest> getPermissions() {
+        return permissions;
+    }
+
+    public String getRpt() {
+        return rpt;
+    }
+
+    public void setRpt(String rpt) {
+        this.rpt = rpt;
+    }
+
+    public void setPermissions(List<PermissionRequest> permissions) {
+        this.permissions = permissions;
+    }
+
+    public void addPermission(PermissionRequest request) {
+        getPermissions().add(request);
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/representation/EntitlementResponse.java b/authz/client/src/main/java/org/keycloak/authorization/client/representation/EntitlementResponse.java
new file mode 100644
index 0000000..747c144
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/representation/EntitlementResponse.java
@@ -0,0 +1,42 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.client.representation;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class EntitlementResponse {
+
+    private String rpt;
+
+    public EntitlementResponse(String rpt) {
+        this.rpt = rpt;
+    }
+
+    public EntitlementResponse() {
+        this(null);
+    }
+
+    public String getRpt() {
+        return this.rpt;
+    }
+
+    public void setRpt(final String rpt) {
+        this.rpt = rpt;
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/representation/ErrorResponse.java b/authz/client/src/main/java/org/keycloak/authorization/client/representation/ErrorResponse.java
new file mode 100644
index 0000000..fd3dc63
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/representation/ErrorResponse.java
@@ -0,0 +1,60 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.client.representation;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ErrorResponse {
+
+    private String error;
+
+    @JsonProperty("error_description")
+    private String description;
+
+    @JsonProperty("error_uri")
+    private String uri;
+
+    public ErrorResponse(final String error, final String description, final String uri) {
+        this.error = error;
+        this.description = description;
+        this.uri = uri;
+    }
+
+    public ErrorResponse(final String error) {
+        this(error, null, null);
+    }
+
+    public ErrorResponse() {
+        this(null, null, null);
+    }
+
+    public String getError() {
+        return this.error;
+    }
+
+    public String getDescription() {
+        return this.description;
+    }
+
+    public String getUri() {
+        return this.uri;
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/representation/PermissionRequest.java b/authz/client/src/main/java/org/keycloak/authorization/client/representation/PermissionRequest.java
new file mode 100644
index 0000000..bc9037e
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/representation/PermissionRequest.java
@@ -0,0 +1,62 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.client.representation;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class PermissionRequest {
+
+    @JsonProperty("resource_set_id")
+    private String resourceSetId;
+
+    @JsonProperty("resource_set_name")
+    private String resourceSetName;
+
+    private Set<String> scopes;
+
+    public String getResourceSetId() {
+        return this.resourceSetId;
+    }
+
+    public void setResourceSetId(String resourceSetId) {
+        this.resourceSetId = resourceSetId;
+    }
+
+    public Set<String> getScopes() {
+        return this.scopes;
+    }
+
+    public void setScopes(Set<String> scopes) {
+        this.scopes = scopes;
+    }
+
+    public String getResourceSetName() {
+        return this.resourceSetName;
+    }
+
+    public void setResourceSetName(String resourceSetName) {
+        this.resourceSetName = resourceSetName;
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/representation/PermissionResponse.java b/authz/client/src/main/java/org/keycloak/authorization/client/representation/PermissionResponse.java
new file mode 100644
index 0000000..1002bb5
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/representation/PermissionResponse.java
@@ -0,0 +1,38 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.client.representation;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class PermissionResponse {
+
+    private final String ticket;
+
+    public PermissionResponse(String ticket) {
+        this.ticket = ticket;
+    }
+
+    public PermissionResponse() {
+        this(null);
+    }
+
+    public String getTicket() {
+        return this.ticket;
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/representation/RegistrationResponse.java b/authz/client/src/main/java/org/keycloak/authorization/client/representation/RegistrationResponse.java
new file mode 100644
index 0000000..0f279bc
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/representation/RegistrationResponse.java
@@ -0,0 +1,49 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.client.representation;
+
+import com.fasterxml.jackson.annotation.JsonUnwrapped;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class RegistrationResponse {
+
+    private final ResourceRepresentation resourceDescription;
+
+    public RegistrationResponse(ResourceRepresentation resourceDescription) {
+        this.resourceDescription = resourceDescription;
+    }
+
+    public RegistrationResponse() {
+        this(null);
+    }
+
+    @JsonUnwrapped
+    public ResourceRepresentation getResourceDescription() {
+        return this.resourceDescription;
+    }
+
+    public String getId() {
+        if (this.resourceDescription != null) {
+            return this.resourceDescription.getId();
+        }
+
+        return null;
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/representation/ResourceRepresentation.java b/authz/client/src/main/java/org/keycloak/authorization/client/representation/ResourceRepresentation.java
new file mode 100644
index 0000000..b0b6948
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/representation/ResourceRepresentation.java
@@ -0,0 +1,184 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.client.representation;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.net.URI;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * <p>One or more resources that the resource server manages as a set of protected resources.
+ *
+ * <p>For more details, <a href="https://docs.kantarainitiative.org/uma/draft-oauth-resource-reg.html#rfc.section.2.2">OAuth-resource-reg</a>.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ResourceRepresentation {
+
+    @JsonProperty("_id")
+    private String id;
+
+    private String name;
+    private String uri;
+    private String type;
+    private Set<ScopeRepresentation> scopes;
+
+    @JsonProperty("icon_uri")
+    private String iconUri;
+    private String owner;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param name a human-readable string describing a set of one or more resources
+     * @param uri a {@link URI} that provides the network location for the resource set being registered
+     * @param type a string uniquely identifying the semantics of the resource set
+     * @param scopes the available scopes for this resource set
+     * @param iconUri a {@link URI} for a graphic icon representing the resource set
+     */
+    public ResourceRepresentation(String name, Set<ScopeRepresentation> scopes, String uri, String type, String iconUri) {
+        this.name = name;
+        this.scopes = scopes;
+        this.uri = uri;
+        this.type = type;
+        this.iconUri = iconUri;
+    }
+
+    /**
+     * Creates a new instance.
+     *
+     * @param name a human-readable string describing a set of one or more resources
+     * @param uri a {@link URI} that provides the network location for the resource set being registered
+     * @param type a string uniquely identifying the semantics of the resource set
+     * @param scopes the available scopes for this resource set
+     */
+    public ResourceRepresentation(String name, Set<ScopeRepresentation> scopes, String uri, String type) {
+        this(name, scopes, uri, type, null);
+    }
+
+    /**
+     * Creates a new instance.
+     *
+     * @param name a human-readable string describing a set of one or more resources
+     * @param serverUri a {@link URI} that identifies this resource server
+     * @param scopes the available scopes for this resource set
+     */
+    public ResourceRepresentation(String name, Set<ScopeRepresentation> scopes) {
+        this(name, scopes, null, null, null);
+    }
+
+    /**
+     * Creates a new instance.
+     *
+     */
+    public ResourceRepresentation() {
+        this(null, null, null, null, null);
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getId() {
+        return this.id;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public String getUri() {
+        return this.uri;
+    }
+
+    public String getType() {
+        return this.type;
+    }
+
+    public Set<ScopeRepresentation> getScopes() {
+        return Collections.unmodifiableSet(this.scopes);
+    }
+
+    public String getIconUri() {
+        return this.iconUri;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setUri(String uri) {
+        this.uri = uri;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public void setScopes(Set<ScopeRepresentation> scopes) {
+        this.scopes = scopes;
+    }
+
+    public void setIconUri(String iconUri) {
+        this.iconUri = iconUri;
+    }
+
+    public String getOwner() {
+        return owner;
+    }
+
+    public void setOwner(String owner) {
+        this.owner = owner;
+    }
+
+    public void addScope(ScopeRepresentation scopeRepresentation) {
+        if (this.scopes == null) {
+            this.scopes = new HashSet<>();
+        }
+        this.scopes.add(scopeRepresentation);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        ResourceRepresentation that = (ResourceRepresentation) o;
+        return Objects.equals(id, that.id);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(id);
+    }
+
+    @Override
+    public String toString() {
+        return "ResourceRepresentation{" +
+                "id='" + id + '\'' +
+                ", name='" + name + '\'' +
+                ", uri='" + uri + '\'' +
+                ", type='" + type + '\'' +
+                ", owner='" + owner + '\'' +
+                ", scopes=" + scopes +
+                '}';
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/representation/ScopeRepresentation.java b/authz/client/src/main/java/org/keycloak/authorization/client/representation/ScopeRepresentation.java
new file mode 100644
index 0000000..4fcfc35
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/representation/ScopeRepresentation.java
@@ -0,0 +1,98 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.client.representation;
+
+import java.net.URI;
+import java.util.Objects;
+
+/**
+ * <p>A bounded extent of access that is possible to perform on a resource set. In authorization policy terminology,
+ * a scope is one of the potentially many "verbs" that can logically apply to a resource set ("object").
+ *
+ * <p>For more details, <a href="https://docs.kantarainitiative.org/uma/draft-oauth-resource-reg.html#rfc.section.2.1">OAuth-resource-reg</a>.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ScopeRepresentation {
+
+    private String id;
+    private String name;
+    private String iconUri;
+
+    /**
+     * Creates an instance.
+     *
+     * @param name the a human-readable string describing some scope (extent) of access
+     * @param iconUri a {@link URI} for a graphic icon representing the scope
+     */
+    public ScopeRepresentation(String name, String iconUri) {
+        this.name = name;
+        this.iconUri = iconUri;
+    }
+
+    /**
+     * Creates an instance.
+     *
+     * @param name the a human-readable string describing some scope (extent) of access
+     */
+    public ScopeRepresentation(String name) {
+        this(name, null);
+    }
+
+    /**
+     * Creates an instance.
+     */
+    public ScopeRepresentation() {
+        this(null, null);
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public String getIconUri() {
+        return this.iconUri;
+    }
+
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        ScopeRepresentation scope = (ScopeRepresentation) o;
+        return Objects.equals(getName(), scope.getName());
+    }
+
+    public int hashCode() {
+        return Objects.hash(getName());
+    }
+
+    public String getId() {
+        return this.id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setIconUri(String iconUri) {
+        this.iconUri = iconUri;
+    }
+}
\ No newline at end of file
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/representation/ServerConfiguration.java b/authz/client/src/main/java/org/keycloak/authorization/client/representation/ServerConfiguration.java
new file mode 100644
index 0000000..6716165
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/representation/ServerConfiguration.java
@@ -0,0 +1,235 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.client.representation;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.net.URI;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ServerConfiguration {
+
+    private String version;
+    private URI issuer;
+
+    @JsonProperty("pat_profiles_supported")
+    private Set<String> patProfiles;
+
+    @JsonProperty("pat_grant_types_supported")
+    private Set<String> patGrantTypes;
+
+    @JsonProperty("aat_profiles_supported")
+    private Set<String> aatProfiles;
+
+    @JsonProperty("aat_grant_types_supported")
+    private Set<String> aatGrantTypes;
+
+    @JsonProperty("rpt_profiles_supported")
+    private Set<String> rptProfiles;
+
+    @JsonProperty("claim_token_profiles_supported")
+    private Set<String> claimTokenProfiles;
+
+    @JsonProperty("dynamic_client_endpoint")
+    private URI dynamicClientEndpoint;
+
+    @JsonProperty("token_endpoint")
+    private URI tokenEndpoint;
+
+    @JsonProperty("authorization_endpoint")
+    private URI authorizationEndpoint;
+
+    @JsonProperty("requesting_party_claims_endpoint")
+    private URI requestingPartyClaimsEndpoint;
+
+    @JsonProperty("resource_set_registration_endpoint")
+    private URI resourceSetRegistrationEndpoint;
+
+    @JsonProperty("introspection_endpoint")
+    private URI introspectionEndpoint;
+
+    @JsonProperty("permission_registration_endpoint")
+    private URI permissionRegistrationEndpoint;
+
+    @JsonProperty("rpt_endpoint")
+    private URI rptEndpoint;
+
+    /**
+     * Non-standard, Keycloak specific configuration options
+     */
+    private String realm;
+
+    private String realmPublicKey;
+
+    private URI serverUrl;
+
+    public String getVersion() {
+        return this.version;
+    }
+
+    void setVersion(final String version) {
+        this.version = version;
+    }
+
+    public URI getIssuer() {
+        return this.issuer;
+    }
+
+    void setIssuer(final URI issuer) {
+        this.issuer = issuer;
+    }
+
+    public Set<String> getPatProfiles() {
+        return this.patProfiles;
+    }
+
+    void setPatProfiles(final Set<String> patProfiles) {
+        this.patProfiles = patProfiles;
+    }
+
+    public Set<String> getPatGrantTypes() {
+        return this.patGrantTypes;
+    }
+
+    void setPatGrantTypes(final Set<String> patGrantTypes) {
+        this.patGrantTypes = patGrantTypes;
+    }
+
+    public Set<String> getAatProfiles() {
+        return this.aatProfiles;
+    }
+
+    void setAatProfiles(final Set<String> aatProfiles) {
+        this.aatProfiles = aatProfiles;
+    }
+
+    public Set<String> getAatGrantTypes() {
+        return this.aatGrantTypes;
+    }
+
+    void setAatGrantTypes(final Set<String> aatGrantTypes) {
+        this.aatGrantTypes = aatGrantTypes;
+    }
+
+    public Set<String> getRptProfiles() {
+        return this.rptProfiles;
+    }
+
+    void setRptProfiles(final Set<String> rptProfiles) {
+        this.rptProfiles = rptProfiles;
+    }
+
+    public Set<String> getClaimTokenProfiles() {
+        return this.claimTokenProfiles;
+    }
+
+    void setClaimTokenProfiles(final Set<String> claimTokenProfiles) {
+        this.claimTokenProfiles = claimTokenProfiles;
+    }
+
+    public URI getDynamicClientEndpoint() {
+        return this.dynamicClientEndpoint;
+    }
+
+    void setDynamicClientEndpoint(final URI dynamicClientEndpoint) {
+        this.dynamicClientEndpoint = dynamicClientEndpoint;
+    }
+
+    public URI getTokenEndpoint() {
+        return this.tokenEndpoint;
+    }
+
+    void setTokenEndpoint(final URI tokenEndpoint) {
+        this.tokenEndpoint = tokenEndpoint;
+    }
+
+    public URI getAuthorizationEndpoint() {
+        return this.authorizationEndpoint;
+    }
+
+    void setAuthorizationEndpoint(final URI authorizationEndpoint) {
+        this.authorizationEndpoint = authorizationEndpoint;
+    }
+
+    public URI getRequestingPartyClaimsEndpoint() {
+        return this.requestingPartyClaimsEndpoint;
+    }
+
+    void setRequestingPartyClaimsEndpoint(final URI requestingPartyClaimsEndpoint) {
+        this.requestingPartyClaimsEndpoint = requestingPartyClaimsEndpoint;
+    }
+
+    public URI getResourceSetRegistrationEndpoint() {
+        return this.resourceSetRegistrationEndpoint;
+    }
+
+    void setResourceSetRegistrationEndpoint(final URI resourceSetRegistrationEndpoint) {
+        this.resourceSetRegistrationEndpoint = resourceSetRegistrationEndpoint;
+    }
+
+    public URI getIntrospectionEndpoint() {
+        return this.introspectionEndpoint;
+    }
+
+    void setIntrospectionEndpoint(final URI introspectionEndpoint) {
+        this.introspectionEndpoint = introspectionEndpoint;
+    }
+
+    public URI getPermissionRegistrationEndpoint() {
+        return this.permissionRegistrationEndpoint;
+    }
+
+    void setPermissionRegistrationEndpoint(final URI permissionRegistrationEndpoint) {
+        this.permissionRegistrationEndpoint = permissionRegistrationEndpoint;
+    }
+
+    public URI getRptEndpoint() {
+        return this.rptEndpoint;
+    }
+
+    void setRptEndpoint(final URI rptEndpoint) {
+        this.rptEndpoint = rptEndpoint;
+    }
+
+    public String getRealm() {
+        return this.realm;
+    }
+
+    public void setRealm(final String realm) {
+        this.realm = realm;
+    }
+
+    public String getRealmPublicKey() {
+        return this.realmPublicKey;
+    }
+
+    public void setRealmPublicKey(String realmPublicKey) {
+        this.realmPublicKey = realmPublicKey;
+    }
+
+    public URI getServerUrl() {
+        return this.serverUrl;
+    }
+
+    public void setServerUrl(URI serverUrl) {
+        this.serverUrl = serverUrl;
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/representation/TokenIntrospectionResponse.java b/authz/client/src/main/java/org/keycloak/authorization/client/representation/TokenIntrospectionResponse.java
new file mode 100644
index 0000000..8fcc6f3
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/representation/TokenIntrospectionResponse.java
@@ -0,0 +1,43 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.authorization.client.representation;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.keycloak.representations.JsonWebToken;
+import org.keycloak.representations.idm.authorization.Permission;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class TokenIntrospectionResponse extends JsonWebToken {
+
+    @JsonProperty
+    private Boolean active;
+
+    private List<Permission> permissions;
+
+    public Boolean getActive() {
+        return this.active;
+    }
+
+    public List<Permission> getPermissions() {
+        return this.permissions;
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/resource/AuthorizationResource.java b/authz/client/src/main/java/org/keycloak/authorization/client/resource/AuthorizationResource.java
new file mode 100644
index 0000000..49b6d2d
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/resource/AuthorizationResource.java
@@ -0,0 +1,58 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.client.resource;
+
+
+import org.keycloak.authorization.client.AuthorizationDeniedException;
+import org.keycloak.authorization.client.representation.AuthorizationRequest;
+import org.keycloak.authorization.client.representation.AuthorizationResponse;
+import org.keycloak.authorization.client.util.Http;
+import org.keycloak.authorization.client.util.HttpResponseException;
+import org.keycloak.util.JsonSerialization;
+
+import java.io.IOException;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AuthorizationResource {
+
+    private final Http http;
+    private final String accessToken;
+
+    public AuthorizationResource(Http http, String aat) {
+        this.http = http;
+        this.accessToken = aat;
+    }
+
+    public AuthorizationResponse authorize(AuthorizationRequest request) {
+        try {
+            return this.http.<AuthorizationResponse>post("/authz/authorize")
+                    .authorizationBearer(this.accessToken)
+                    .json(JsonSerialization.writeValueAsBytes(request))
+                    .response().json(AuthorizationResponse.class).execute();
+        } catch (HttpResponseException e) {
+            if (403 == e.getStatusCode()) {
+                throw new AuthorizationDeniedException(e);
+            }
+            throw new RuntimeException("Failed to obtain authorization data.", e);
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to obtain authorization data.", e);
+        }
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/resource/EntitlementResource.java b/authz/client/src/main/java/org/keycloak/authorization/client/resource/EntitlementResource.java
new file mode 100644
index 0000000..55c0abd
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/resource/EntitlementResource.java
@@ -0,0 +1,54 @@
+package org.keycloak.authorization.client.resource;
+
+import org.keycloak.authorization.client.AuthorizationDeniedException;
+import org.keycloak.authorization.client.representation.EntitlementRequest;
+import org.keycloak.authorization.client.representation.EntitlementResponse;
+import org.keycloak.authorization.client.util.Http;
+import org.keycloak.authorization.client.util.HttpResponseException;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class EntitlementResource {
+
+    private final Http http;
+    private final String eat;
+
+    public EntitlementResource(Http http, String eat) {
+        this.http = http;
+        this.eat = eat;
+    }
+
+    public EntitlementResponse getAll(String resourceServerId) {
+        try {
+            return this.http.<EntitlementResponse>get("/authz/entitlement/" + resourceServerId)
+                    .authorizationBearer(this.eat)
+                    .response()
+                        .json(EntitlementResponse.class).execute();
+        } catch (HttpResponseException e) {
+            if (403 == e.getStatusCode()) {
+                throw new AuthorizationDeniedException(e);
+            }
+            throw new RuntimeException("Failed to obtain entitlements.", e);
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to obtain entitlements.", e);
+        }
+    }
+
+    public EntitlementResponse get(String resourceServerId, EntitlementRequest request) {
+        try {
+            return this.http.<EntitlementResponse>post("/authz/entitlement/" + resourceServerId)
+                    .authorizationBearer(this.eat)
+                    .json(JsonSerialization.writeValueAsBytes(request))
+                    .response().json(EntitlementResponse.class).execute();
+        } catch (HttpResponseException e) {
+            if (403 == e.getStatusCode()) {
+                throw new AuthorizationDeniedException(e);
+            }
+            throw new RuntimeException("Failed to obtain entitlements.", e);
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to obtain entitlements.", e);
+        }
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/resource/PermissionResource.java b/authz/client/src/main/java/org/keycloak/authorization/client/resource/PermissionResource.java
new file mode 100644
index 0000000..72247b2
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/resource/PermissionResource.java
@@ -0,0 +1,50 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.client.resource;
+
+import org.keycloak.authorization.client.representation.PermissionRequest;
+import org.keycloak.authorization.client.representation.PermissionResponse;
+import org.keycloak.authorization.client.util.Http;
+import org.keycloak.util.JsonSerialization;
+
+import java.io.IOException;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class PermissionResource {
+
+    private final Http http;
+    private final String pat;
+
+    public PermissionResource(Http http, String pat) {
+        this.http = http;
+        this.pat = pat;
+    }
+
+    public PermissionResponse forResource(PermissionRequest request) {
+        try {
+            return this.http.<PermissionResponse>post("/authz/protection/permission")
+                    .authorizationBearer(this.pat)
+                    .json(JsonSerialization.writeValueAsBytes(request))
+                    .response().json(PermissionResponse.class).execute();
+        } catch (IOException e) {
+            throw new RuntimeException("Error obtaining permission ticket.", e);
+        }
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectedResource.java b/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectedResource.java
new file mode 100644
index 0000000..e237642
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectedResource.java
@@ -0,0 +1,91 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.client.resource;
+
+import org.keycloak.authorization.client.representation.RegistrationResponse;
+import org.keycloak.authorization.client.representation.ResourceRepresentation;
+import org.keycloak.authorization.client.util.Http;
+import org.keycloak.util.JsonSerialization;
+
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ProtectedResource {
+
+    private final Http http;
+    private final String pat;
+
+    public ProtectedResource(Http http, String pat) {
+        this.http = http;
+        this.pat = pat;
+    }
+
+    public RegistrationResponse create(ResourceRepresentation resource) {
+        try {
+            return this.http.<RegistrationResponse>post("/authz/protection/resource_set")
+                    .authorizationBearer(this.pat)
+                    .json(JsonSerialization.writeValueAsBytes(resource))
+                    .response().json(RegistrationResponse.class).execute();
+        } catch (Exception e) {
+            throw new RuntimeException("Could not create resource.", e);
+        }
+    }
+
+    public RegistrationResponse findById(String id) {
+        try {
+            return this.http.<RegistrationResponse>get("/authz/protection/resource_set/" + id)
+                    .authorizationBearer(this.pat)
+                    .response().json(RegistrationResponse.class).execute();
+        } catch (Exception e) {
+            throw new RuntimeException("Could not find resource.", e);
+        }
+    }
+
+    public Set<String> findByFilter(String filter) {
+        try {
+            return this.http.<Set>get("/authz/protection/resource_set")
+                    .authorizationBearer(this.pat)
+                    .param("filter", filter)
+                    .response().json(Set.class).execute();
+        } catch (Exception e) {
+            throw new RuntimeException("Could not find resource.", e);
+        }
+    }
+
+    public Set<String> findAll() {
+        try {
+            return this.http.<Set>get("/authz/protection/resource_set")
+                    .authorizationBearer(this.pat)
+                    .response().json(Set.class).execute();
+        } catch (Exception e) {
+            throw new RuntimeException("Could not find resource.", e);
+        }
+    }
+
+    public void delete(String id) {
+        try {
+            this.http.delete("/authz/protection/resource_set/" + id)
+                    .authorizationBearer(this.pat)
+                    .execute();
+        } catch (Exception e) {
+            throw new RuntimeException("Could not delete resource.", e);
+        }
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectionResource.java b/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectionResource.java
new file mode 100644
index 0000000..536b188
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/resource/ProtectionResource.java
@@ -0,0 +1,57 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.authorization.client.resource;
+
+import org.keycloak.authorization.client.representation.TokenIntrospectionResponse;
+import org.keycloak.authorization.client.util.Http;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ProtectionResource {
+
+    private final String pat;
+    private final Http http;
+
+    public ProtectionResource(Http http, String pat) {
+        if (pat == null) {
+            throw new RuntimeException("No access token was provided when creating client for Protection API.");
+        }
+
+        this.http = http;
+        this.pat = pat;
+    }
+
+    public ProtectedResource resource() {
+        return new ProtectedResource(http, pat);
+    }
+
+    public PermissionResource permission() {
+        return new PermissionResource(http, pat);
+    }
+
+    public TokenIntrospectionResponse introspectRequestingPartyToken(String rpt) {
+        return this.http.<TokenIntrospectionResponse>post("/protocol/openid-connect/token/introspect")
+                .authentication()
+                    .oauth2ClientCredentials()
+                .form()
+                    .param("token_type_hint", "requesting_party_token")
+                    .param("token", rpt)
+                .response().json(TokenIntrospectionResponse.class).execute();
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/util/Http.java b/authz/client/src/main/java/org/keycloak/authorization/client/util/Http.java
new file mode 100644
index 0000000..503772f
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/util/Http.java
@@ -0,0 +1,65 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.authorization.client.util;
+
+import org.apache.http.client.methods.RequestBuilder;
+import org.keycloak.authorization.client.Configuration;
+import org.keycloak.authorization.client.representation.ServerConfiguration;
+
+import java.net.URI;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class Http {
+
+    private final Configuration configuration;
+    private ServerConfiguration serverConfiguration;
+
+    public Http(Configuration configuration) {
+        this.configuration = configuration;
+    }
+
+    public <R> HttpMethod<R> get(String path) {
+        return method(RequestBuilder.get(this.serverConfiguration.getIssuer() + path));
+    }
+
+    public <R> HttpMethod<R> get(URI path) {
+        return method(RequestBuilder.get(path));
+    }
+
+    public <R> HttpMethod<R> post(URI path) {
+        return method(RequestBuilder.post(path));
+    }
+
+    public <R> HttpMethod<R> post(String path) {
+        return method(RequestBuilder.post(this.serverConfiguration.getIssuer() + path));
+    }
+
+    public <R> HttpMethod<R> delete(String path) {
+        return method(RequestBuilder.delete(this.serverConfiguration.getIssuer() + path));
+    }
+
+    private <R> HttpMethod<R> method(RequestBuilder builder) {
+        return new HttpMethod(this.configuration, builder);
+    }
+
+    public void setServerConfiguration(ServerConfiguration serverConfiguration) {
+        this.serverConfiguration = serverConfiguration;
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpMethod.java b/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpMethod.java
new file mode 100644
index 0000000..be83987
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpMethod.java
@@ -0,0 +1,158 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.authorization.client.util;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.StatusLine;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.RequestBuilder;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+import org.keycloak.authorization.client.Configuration;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class HttpMethod<R> {
+
+    private final HttpClient httpClient;
+    private final RequestBuilder builder;
+    protected final Configuration configuration;
+    protected final HashMap<String, String> headers;
+    protected final HashMap<String, String> params;
+    private HttpMethodResponse<R> response;
+
+    public HttpMethod(Configuration configuration, RequestBuilder builder) {
+        this(configuration, builder, new HashMap<>(), new HashMap<>());
+    }
+
+    public HttpMethod(Configuration configuration, RequestBuilder builder, HashMap<String, String> params, HashMap<String, String> headers) {
+        this.configuration = configuration;
+        this.httpClient = configuration.getHttpClient();
+        this.builder = builder;
+        this.params = params;
+        this.headers = headers;
+    }
+
+    public void execute() {
+        execute(new HttpResponseProcessor<R>() {
+            @Override
+            public R process(byte[] entity) {
+                return null;
+            }
+        });
+    }
+
+    public R execute(HttpResponseProcessor<R> responseProcessor) {
+        byte[] bytes = null;
+
+        try {
+            for (Map.Entry<String, String> header : this.headers.entrySet()) {
+                this.builder.setHeader(header.getKey(), header.getValue());
+            }
+
+            preExecute(this.builder);
+
+            HttpResponse response = this.httpClient.execute(this.builder.build());
+            HttpEntity entity = response.getEntity();
+
+            if (entity != null) {
+                bytes = EntityUtils.toByteArray(entity);
+            }
+
+            StatusLine statusLine = response.getStatusLine();
+            int statusCode = statusLine.getStatusCode();
+
+            if (statusCode < 200 || statusCode >= 300) {
+                throw new HttpResponseException("Unexpected response from server: " + statusCode + " / " + statusLine.getReasonPhrase(), statusCode, statusLine.getReasonPhrase(), bytes);
+            }
+
+            if (bytes == null) {
+                return null;
+            }
+
+            return responseProcessor.process(bytes);
+        } catch (HttpResponseException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new RuntimeException("Error executing http method [" + builder + "]. Response : " + new String(bytes), e);
+        }
+    }
+
+    protected void preExecute(RequestBuilder builder) {
+        for (Map.Entry<String, String> param : params.entrySet()) {
+            builder.addParameter(param.getKey(), param.getValue());
+        }
+    }
+
+    public HttpMethod<R> authorizationBearer(String bearer) {
+        this.builder.addHeader("Authorization", "Bearer " + bearer);
+        return this;
+    }
+
+    public HttpMethodResponse<R> response() {
+        this.response = new HttpMethodResponse(this);
+        return this.response;
+    }
+
+    public HttpMethodAuthenticator<R> authentication() {
+        return new HttpMethodAuthenticator<R>(this);
+    }
+
+    public HttpMethod<R> param(String name, String value) {
+        this.params.put(name, value);
+        return this;
+    }
+
+    public HttpMethod<R> json(byte[] entity) {
+        this.builder.addHeader("Content-Type", "application/json");
+        this.builder.setEntity(new ByteArrayEntity(entity));
+        return this;
+    }
+
+    public HttpMethod<R> form() {
+        return new HttpMethod<R>(this.configuration, this.builder, this.params, this.headers) {
+            @Override
+            protected void preExecute(RequestBuilder builder) {
+                if (params != null) {
+                    List<NameValuePair> formparams = new ArrayList<>();
+
+                    for (Map.Entry<String, String> param : params.entrySet()) {
+                        formparams.add(new BasicNameValuePair(param.getKey(), param.getValue()));
+                    }
+
+                    try {
+                        builder.setEntity(new UrlEncodedFormEntity(formparams, "UTF-8"));
+                    } catch (UnsupportedEncodingException e) {
+                        throw new RuntimeException("Error creating form parameters");
+                    }
+                }
+            }
+        };
+    }
+}
\ No newline at end of file
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpMethodAuthenticator.java b/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpMethodAuthenticator.java
new file mode 100644
index 0000000..d67090a
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpMethodAuthenticator.java
@@ -0,0 +1,50 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.authorization.client.util;
+
+import org.keycloak.OAuth2Constants;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class HttpMethodAuthenticator<R> {
+
+    private final HttpMethod<R> method;
+
+    public HttpMethodAuthenticator(HttpMethod<R> method) {
+        this.method = method;
+    }
+
+    public HttpMethod<R> oauth2ClientCredentials() {
+        this.method.params.put(OAuth2Constants.GRANT_TYPE, OAuth2Constants.CLIENT_CREDENTIALS);
+        configureClientCredentials();
+        return this.method;
+    }
+
+    public HttpMethod<R> oauth2ResourceOwnerPassword(String userName, String password) {
+        this.method.params.put(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD);
+        this.method.params.put("username", userName);
+        this.method.params.put("password", password);
+        configureClientCredentials();
+        return this.method;
+    }
+
+    private void configureClientCredentials() {
+        this.method.configuration.getClientAuthenticator().configureClientCredentials(this.method.params, this.method.headers);
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpMethodResponse.java b/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpMethodResponse.java
new file mode 100644
index 0000000..4155240
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpMethodResponse.java
@@ -0,0 +1,61 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.authorization.client.util;
+
+import org.keycloak.util.JsonSerialization;
+
+import java.io.IOException;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class HttpMethodResponse<R> {
+
+    private final HttpMethod<R> method;
+
+    public HttpMethodResponse(HttpMethod method) {
+        this.method = method;
+    }
+
+    public R execute() {
+        return this.method.execute(new HttpResponseProcessor<R>() {
+            @Override
+            public R process(byte[] entity) {
+                return null;
+            }
+        });
+    }
+
+    public HttpMethodResponse<R> json(Class<R> responseType) {
+        return new HttpMethodResponse<R>(this.method) {
+            @Override
+            public R execute() {
+                return method.execute(new HttpResponseProcessor<R>() {
+                    @Override
+                    public R process(byte[] entity) {
+                        try {
+                            return JsonSerialization.readValue(entity, responseType);
+                        } catch (IOException e) {
+                            throw new RuntimeException("Error parsing JSON response.", e);
+                        }
+                    }
+                });
+            }
+        };
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpResponseException.java b/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpResponseException.java
new file mode 100644
index 0000000..3531f40
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpResponseException.java
@@ -0,0 +1,47 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.authorization.client.util;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class HttpResponseException extends RuntimeException {
+
+    private final int statusCode;
+    private final String reasonPhrase;
+    private final byte[] bytes;
+
+    public HttpResponseException(String message, int statusCode, String reasonPhrase, byte[] bytes) {
+        super(message);
+        this.statusCode = statusCode;
+        this.reasonPhrase = reasonPhrase;
+        this.bytes = bytes;
+    }
+
+    public int getStatusCode() {
+        return statusCode;
+    }
+
+    public String getReasonPhrase() {
+        return reasonPhrase;
+    }
+
+    public byte[] getBytes() {
+        return bytes;
+    }
+}
diff --git a/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpResponseProcessor.java b/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpResponseProcessor.java
new file mode 100644
index 0000000..72eba04
--- /dev/null
+++ b/authz/client/src/main/java/org/keycloak/authorization/client/util/HttpResponseProcessor.java
@@ -0,0 +1,26 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.authorization.client.util;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface HttpResponseProcessor<R> {
+
+    R process(byte[] entity);
+}
diff --git a/authz/policy/common/pom.xml b/authz/policy/common/pom.xml
new file mode 100644
index 0000000..77b0965
--- /dev/null
+++ b/authz/policy/common/pom.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~  Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~  and other contributors as indicated by the @author tags.
+  ~
+  ~  Licensed under the Apache License, Version 2.0 (the "License");
+  ~  you may not use this file except in compliance with the License.
+  ~  You may obtain a copy of the License at
+  ~
+  ~  http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing, software
+  ~  distributed under the License is distributed on an "AS IS" BASIS,
+  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  See the License for the specific language governing permissions and
+  ~  limitations under the License.
+  ~
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.keycloak</groupId>
+        <artifactId>keycloak-authz-provider-parent</artifactId>
+        <version>2.2.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>keycloak-authz-policy-common</artifactId>
+    <packaging>jar</packaging>
+
+    <name>KeyCloak AuthZ: Common Policy Providers</name>
+    <description>KeyCloak AuthZ: Common Policy Providers</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/aggregated/AggregatePolicyAdminResource.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/aggregated/AggregatePolicyAdminResource.java
new file mode 100644
index 0000000..0cfb0f9
--- /dev/null
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/aggregated/AggregatePolicyAdminResource.java
@@ -0,0 +1,69 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.keycloak.authorization.policy.provider.aggregated;
+
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AggregatePolicyAdminResource implements PolicyProviderAdminService {
+
+    private final ResourceServer resourceServer;
+
+    public AggregatePolicyAdminResource(ResourceServer resourceServer) {
+        this.resourceServer = resourceServer;
+    }
+
+    @Override
+    public void onCreate(Policy policy) {
+        verifyCircularReference(policy, new ArrayList<>());
+    }
+
+    @Override
+    public void onUpdate(Policy policy) {
+        verifyCircularReference(policy, new ArrayList<>());
+    }
+
+    private void verifyCircularReference(Policy policy, List<String> ids) {
+        if (!policy.getType().equals("aggregate")) {
+            return;
+        }
+
+        if (ids.contains(policy.getId())) {
+            throw new RuntimeException("Circular reference found [" + policy.getName() + "].");
+        }
+
+        ids.add(policy.getId());
+
+        for (Policy associated : policy.getAssociatedPolicies()) {
+            verifyCircularReference(associated, ids);
+        }
+    }
+
+    @Override
+    public void onRemove(Policy policy) {
+
+    }
+}
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/aggregated/AggregatePolicyProvider.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/aggregated/AggregatePolicyProvider.java
new file mode 100644
index 0000000..b1e668a
--- /dev/null
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/aggregated/AggregatePolicyProvider.java
@@ -0,0 +1,75 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.authorization.policy.provider.aggregated;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.policy.evaluation.DecisionResultCollector;
+import org.keycloak.authorization.policy.evaluation.DefaultEvaluation;
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+import org.keycloak.authorization.policy.evaluation.Result;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AggregatePolicyProvider implements PolicyProvider {
+
+    private final Policy policy;
+    private final AuthorizationProvider authorization;
+
+    public AggregatePolicyProvider(Policy policy, AuthorizationProvider authorization) {
+        this.policy = policy;
+        this.authorization = authorization;
+    }
+
+    @Override
+    public void evaluate(Evaluation evaluation) {
+        //TODO: need to detect deep recursions
+        DecisionResultCollector decision = new DecisionResultCollector() {
+            @Override
+            protected void onComplete(List<Result> results) {
+                if (results.isEmpty()) {
+                    evaluation.deny();
+                } else {
+                    Result result = results.iterator().next();
+
+                    if (Effect.PERMIT.equals(result.getEffect())) {
+                        evaluation.grant();
+                    }
+                }
+            }
+        };
+
+        this.policy.getAssociatedPolicies().forEach(associatedPolicy -> {
+            PolicyProviderFactory providerFactory = authorization.getProviderFactory(associatedPolicy.getType());
+            PolicyProvider policyProvider = providerFactory.create(associatedPolicy, authorization);
+            policyProvider.evaluate(new DefaultEvaluation(evaluation.getPermission(), evaluation.getContext(), policy, associatedPolicy, decision));
+        });
+
+        decision.onComplete();
+    }
+
+    @Override
+    public void close() {
+
+    }
+}
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/aggregated/AggregatePolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/aggregated/AggregatePolicyProviderFactory.java
new file mode 100644
index 0000000..9c7faad
--- /dev/null
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/aggregated/AggregatePolicyProviderFactory.java
@@ -0,0 +1,79 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.authorization.policy.provider.aggregated;
+
+import org.keycloak.Config;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
+import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AggregatePolicyProviderFactory implements PolicyProviderFactory {
+
+    @Override
+    public String getName() {
+        return "Aggregated";
+    }
+
+    @Override
+    public String getGroup() {
+        return "Others";
+    }
+
+    @Override
+    public PolicyProvider create(Policy policy, AuthorizationProvider authorization) {
+        return new AggregatePolicyProvider(policy, authorization);
+    }
+
+    @Override
+    public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
+        return new AggregatePolicyAdminResource(resourceServer);
+    }
+
+    @Override
+    public PolicyProvider create(KeycloakSession session) {
+        return null;
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "aggregate";
+    }
+}
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/js/JSPolicyProvider.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/js/JSPolicyProvider.java
new file mode 100644
index 0000000..eeeb3ea
--- /dev/null
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/js/JSPolicyProvider.java
@@ -0,0 +1,57 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.policy.provider.js;
+
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class JSPolicyProvider implements PolicyProvider {
+
+    private final Policy policy;
+
+    public JSPolicyProvider(Policy policy) {
+        this.policy = policy;
+    }
+
+    @Override
+    public void evaluate(Evaluation evaluation) {
+        ScriptEngineManager manager = new ScriptEngineManager();
+        ScriptEngine engine = manager.getEngineByName("nashorn");
+
+        engine.put("$evaluation", evaluation);
+
+        try {
+            engine.eval(policy.getConfig().get("code"));
+        } catch (ScriptException e) {
+            throw new RuntimeException("Error evaluating JS Policy [" + policy.getName() + "].", e);
+        }
+    }
+
+    @Override
+    public void close() {
+
+    }
+}
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/js/JSPolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/js/JSPolicyProviderFactory.java
new file mode 100644
index 0000000..8134d95
--- /dev/null
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/js/JSPolicyProviderFactory.java
@@ -0,0 +1,62 @@
+package org.keycloak.authorization.policy.provider.js;
+
+import org.keycloak.Config;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
+import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class JSPolicyProviderFactory implements PolicyProviderFactory {
+
+    @Override
+    public String getName() {
+        return "JavaScript";
+    }
+
+    @Override
+    public String getGroup() {
+        return "Rule Based";
+    }
+
+    @Override
+    public PolicyProvider create(Policy policy, AuthorizationProvider authorization) {
+        return new JSPolicyProvider(policy);
+    }
+
+    @Override
+    public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
+        return null;
+    }
+
+    @Override
+    public PolicyProvider create(KeycloakSession session) {
+        return null;
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "js";
+    }
+}
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/resource/ResourcePolicyProvider.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/resource/ResourcePolicyProvider.java
new file mode 100644
index 0000000..c76a989
--- /dev/null
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/resource/ResourcePolicyProvider.java
@@ -0,0 +1,41 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.policy.provider.resource;
+
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ResourcePolicyProvider implements PolicyProvider {
+
+    public ResourcePolicyProvider(Policy policy) {
+
+    }
+
+    @Override
+    public void evaluate(Evaluation evaluation) {
+    }
+
+    @Override
+    public void close() {
+
+    }
+}
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/resource/ResourcePolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/resource/ResourcePolicyProviderFactory.java
new file mode 100644
index 0000000..8ea4800
--- /dev/null
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/resource/ResourcePolicyProviderFactory.java
@@ -0,0 +1,62 @@
+package org.keycloak.authorization.policy.provider.resource;
+
+import org.keycloak.Config;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
+import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ResourcePolicyProviderFactory implements PolicyProviderFactory {
+
+    @Override
+    public String getName() {
+        return "Resource-Based";
+    }
+
+    @Override
+    public String getGroup() {
+        return "Permission";
+    }
+
+    @Override
+    public PolicyProvider create(Policy policy, AuthorizationProvider authorization) {
+        return new ResourcePolicyProvider(policy);
+    }
+
+    @Override
+    public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
+        return null;
+    }
+
+    @Override
+    public PolicyProvider create(KeycloakSession session) {
+        return null;
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "resource";
+    }
+}
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProvider.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProvider.java
new file mode 100644
index 0000000..c8a99fe
--- /dev/null
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProvider.java
@@ -0,0 +1,96 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.authorization.policy.provider.role;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.identity.Identity;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+import org.keycloak.authorization.policy.evaluation.EvaluationContext;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+
+import java.util.Map;
+
+import static org.keycloak.authorization.policy.provider.role.RolePolicyProviderFactory.getRoles;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class RolePolicyProvider implements PolicyProvider {
+
+    private final Policy policy;
+    private final AuthorizationProvider authorization;
+
+    public RolePolicyProvider(Policy policy, AuthorizationProvider authorization) {
+        this.policy = policy;
+        this.authorization = authorization;
+    }
+
+    public RolePolicyProvider() {
+        this(null, null);
+    }
+
+    @Override
+    public void evaluate(Evaluation evaluation) {
+        Map<String, Object>[] roleIds = getRoles(this.policy);
+
+        if (roleIds.length > 0) {
+            Identity identity = evaluation.getContext().getIdentity();
+
+            for (Map<String, Object> current : roleIds) {
+                RoleModel role = getCurrentRealm().getRoleById((String) current.get("id"));
+
+                if (role != null) {
+                    boolean hasRole = hasRole(identity, role);
+
+                    if (!hasRole && Boolean.valueOf(isRequired(current))) {
+                        evaluation.deny();
+                        return;
+                    } else if (hasRole) {
+                        evaluation.grant();
+                    }
+                }
+            }
+        }
+    }
+
+    private boolean isRequired(Map<String, Object> current) {
+        return (boolean) current.getOrDefault("required", false);
+    }
+
+    private boolean hasRole(Identity identity, RoleModel role) {
+        String roleName = role.getName();
+        if (role.isClientRole()) {
+            ClientModel clientModel = getCurrentRealm().getClientById(role.getContainerId());
+            return identity.hasClientRole(clientModel.getClientId(), roleName);
+        }
+        return identity.hasRealmRole(roleName);
+    }
+
+    private RealmModel getCurrentRealm() {
+        return this.authorization.getKeycloakSession().getContext().getRealm();
+    }
+
+    @Override
+    public void close() {
+
+    }
+}
\ No newline at end of file
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProviderFactory.java
new file mode 100644
index 0000000..301bb7b
--- /dev/null
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/role/RolePolicyProviderFactory.java
@@ -0,0 +1,142 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.keycloak.authorization.policy.provider.role;
+
+import org.keycloak.Config;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
+import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
+import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RoleContainerModel.RoleRemovedEvent;
+import org.keycloak.models.RoleModel;
+import org.keycloak.util.JsonSerialization;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class RolePolicyProviderFactory implements PolicyProviderFactory {
+
+    @Override
+    public String getName() {
+        return "Role-Based";
+    }
+
+    @Override
+    public String getGroup() {
+        return "Identity Based";
+    }
+
+    @Override
+    public PolicyProvider create(Policy policy, AuthorizationProvider authorization) {
+        return new RolePolicyProvider(policy, authorization);
+    }
+
+    @Override
+    public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
+        return null;
+    }
+
+    @Override
+    public PolicyProvider create(KeycloakSession session) {
+        return new RolePolicyProvider();
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+        factory.register(event -> {
+            if (event instanceof RoleRemovedEvent) {
+                KeycloakSession keycloakSession = ((RoleRemovedEvent) event).getKeycloakSession();
+                AuthorizationProvider provider = keycloakSession.getProvider(AuthorizationProvider.class);
+                PolicyStore policyStore = provider.getStoreFactory().getPolicyStore();
+                RoleModel removedRole = ((RoleRemovedEvent) event).getRole();
+
+                policyStore.findByType(getId()).forEach(policy -> {
+                    List<Map> roles = new ArrayList<>();
+
+                    for (Map<String,Object> role : getRoles(policy)) {
+                        if (!role.get("id").equals(removedRole.getId())) {
+                            Map updated = new HashMap();
+                            updated.put("id", role.get("id"));
+                            Object required = role.get("required");
+                            if (required != null) {
+                                updated.put("required", required);
+                            }
+                            roles.add(updated);
+                        }
+                    }
+
+                    try {
+                        if (roles.isEmpty()) {
+                            policyStore.findDependentPolicies(policy.getId()).forEach(dependentPolicy -> {
+                                dependentPolicy.removeAssociatedPolicy(policy);
+                            });
+                            policyStore.delete(policy.getId());
+                        } else {
+                            Map<String, String> config = policy.getConfig();
+                            config.put("roles", JsonSerialization.writeValueAsString(roles));
+                            policy.setConfig(config);
+                        }
+                    } catch (IOException e) {
+                        throw new RuntimeException("Error while synchronizing roles with policy [" + policy.getName() + "].", e);
+                    }
+                });
+            }
+        });
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "role";
+    }
+
+    static Map<String, Object>[] getRoles(Policy policy) {
+        String roles = policy.getConfig().get("roles");
+
+        if (roles != null) {
+            try {
+                return JsonSerialization.readValue(roles.getBytes(), Map[].class);
+            } catch (IOException e) {
+                throw new RuntimeException("Could not parse roles [" + roles + "] from policy config [" + policy.getName() + ".", e);
+            }
+        }
+
+        return new Map[] {};
+    }
+}
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/scope/ScopePolicyProvider.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/scope/ScopePolicyProvider.java
new file mode 100644
index 0000000..5c10cc3
--- /dev/null
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/scope/ScopePolicyProvider.java
@@ -0,0 +1,43 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.policy.provider.scope;
+
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ScopePolicyProvider implements PolicyProvider {
+
+    private final Policy policy;
+
+    public ScopePolicyProvider(Policy policy) {
+        this.policy = policy;
+    }
+
+    @Override
+    public void evaluate(Evaluation evaluation) {
+    }
+
+    @Override
+    public void close() {
+
+    }
+}
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/scope/ScopePolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/scope/ScopePolicyProviderFactory.java
new file mode 100644
index 0000000..6ed0cd5
--- /dev/null
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/scope/ScopePolicyProviderFactory.java
@@ -0,0 +1,62 @@
+package org.keycloak.authorization.policy.provider.scope;
+
+import org.keycloak.Config;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
+import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ScopePolicyProviderFactory implements PolicyProviderFactory {
+
+    @Override
+    public String getName() {
+        return "Scope-Based";
+    }
+
+    @Override
+    public String getGroup() {
+        return "Permission";
+    }
+
+    @Override
+    public PolicyProvider create(Policy policy, AuthorizationProvider authorization) {
+        return new ScopePolicyProvider(policy);
+    }
+
+    @Override
+    public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
+        return null;
+    }
+
+    @Override
+    public PolicyProvider create(KeycloakSession session) {
+        return null;
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "scope";
+    }
+}
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyAdminResource.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyAdminResource.java
new file mode 100644
index 0000000..75de911
--- /dev/null
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyAdminResource.java
@@ -0,0 +1,64 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.policy.provider.time;
+
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
+
+import java.text.SimpleDateFormat;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class TimePolicyAdminResource implements PolicyProviderAdminService {
+
+    @Override
+    public void onCreate(Policy policy) {
+        validateConfig(policy);
+    }
+
+    private void validateConfig(Policy policy) {
+        String nbf = policy.getConfig().get("nbf");
+        String noa = policy.getConfig().get("noa");
+
+        if (nbf == null && noa == null) {
+            throw new RuntimeException("You must provide NotBefore, NotOnOrAfter or both.");
+        }
+
+        validateFormat(nbf);
+        validateFormat(noa);
+    }
+
+    @Override
+    public void onUpdate(Policy policy) {
+        validateConfig(policy);
+    }
+
+    @Override
+    public void onRemove(Policy policy) {
+    }
+
+    private void validateFormat(String date) {
+        try {
+            new SimpleDateFormat(TimePolicyProvider.DEFAULT_DATE_PATTERN).parse(TimePolicyProvider.format(date));
+        } catch (Exception e) {
+            throw new RuntimeException("Could not parse a date using format [" + date + "]");
+        }
+    }
+}
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProvider.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProvider.java
new file mode 100644
index 0000000..dc6af9f
--- /dev/null
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProvider.java
@@ -0,0 +1,86 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.policy.provider.time;
+
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class TimePolicyProvider implements PolicyProvider {
+
+    static String DEFAULT_DATE_PATTERN = "yyyy-MM-dd hh:mm:ss";
+
+    private final Policy policy;
+    private final SimpleDateFormat dateFormat;
+    private final Date currentDate;
+
+    public TimePolicyProvider(Policy policy) {
+        this.policy = policy;
+        this.dateFormat = new SimpleDateFormat(DEFAULT_DATE_PATTERN);
+        this.currentDate = new Date();
+    }
+
+    @Override
+    public void evaluate(Evaluation evaluation) {
+        try {
+            String notBefore = this.policy.getConfig().get("nbf");
+
+            if (notBefore != null) {
+
+                if (this.currentDate.before(this.dateFormat.parse(format(notBefore)))) {
+                    evaluation.deny();
+                    return;
+                }
+            }
+
+            String notOnOrAfter = this.policy.getConfig().get("noa");
+
+            if (notOnOrAfter != null) {
+                if (this.currentDate.after(this.dateFormat.parse(format(notOnOrAfter)))) {
+                    evaluation.deny();
+                    return;
+                }
+            }
+
+            evaluation.grant();
+        } catch (Exception e) {
+            throw new RuntimeException("Could not evaluate time-based policy [" + this.policy.getName() + "].", e);
+        }
+    }
+
+    static String format(String notBefore) {
+        String trimmed = notBefore.trim();
+
+        if (trimmed.length() == 10) {
+            notBefore = trimmed + " 00:00:00";
+        }
+
+        return notBefore;
+    }
+
+    @Override
+    public void close() {
+
+    }
+}
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProviderFactory.java
new file mode 100644
index 0000000..efe3cd2
--- /dev/null
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/time/TimePolicyProviderFactory.java
@@ -0,0 +1,62 @@
+package org.keycloak.authorization.policy.provider.time;
+
+import org.keycloak.Config;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
+import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class TimePolicyProviderFactory implements PolicyProviderFactory {
+
+    @Override
+    public String getName() {
+        return "Time";
+    }
+
+    @Override
+    public String getGroup() {
+        return "Time Based";
+    }
+
+    @Override
+    public PolicyProvider create(Policy policy, AuthorizationProvider authorization) {
+        return new TimePolicyProvider(policy);
+    }
+
+    @Override
+    public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
+        return new TimePolicyAdminResource();
+    }
+
+    @Override
+    public PolicyProvider create(KeycloakSession session) {
+        return null;
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "time";
+    }
+}
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/user/UserPolicyProvider.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/user/UserPolicyProvider.java
new file mode 100644
index 0000000..a6fc0a4
--- /dev/null
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/user/UserPolicyProvider.java
@@ -0,0 +1,57 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.authorization.policy.provider.user;
+
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+import org.keycloak.authorization.policy.evaluation.EvaluationContext;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+
+import static org.keycloak.authorization.policy.provider.user.UserPolicyProviderFactory.getUsers;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class UserPolicyProvider implements PolicyProvider {
+
+    private final Policy policy;
+
+    public UserPolicyProvider(Policy policy) {
+        this.policy = policy;
+    }
+
+    @Override
+    public void evaluate(Evaluation evaluation) {
+        EvaluationContext context = evaluation.getContext();
+        String[] userIds = getUsers(this.policy);
+
+        if (userIds.length > 0) {
+            for (String userId : userIds) {
+                if (context.getIdentity().getId().equals(userId)) {
+                    evaluation.grant();
+                    break;
+                }
+            }
+        }
+    }
+
+    @Override
+    public void close() {
+
+    }
+}
diff --git a/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/user/UserPolicyProviderFactory.java b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/user/UserPolicyProviderFactory.java
new file mode 100644
index 0000000..9461474
--- /dev/null
+++ b/authz/policy/common/src/main/java/org/keycloak/authorization/policy/provider/user/UserPolicyProviderFactory.java
@@ -0,0 +1,132 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.keycloak.authorization.policy.provider.user;
+
+import org.keycloak.Config;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
+import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
+import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserModel.UserRemovedEvent;
+import org.keycloak.util.JsonSerialization;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class UserPolicyProviderFactory implements PolicyProviderFactory {
+
+    @Override
+    public String getName() {
+        return "User-Based";
+    }
+
+    @Override
+    public String getGroup() {
+        return "Identity Based";
+    }
+
+    @Override
+    public PolicyProvider create(Policy policy, AuthorizationProvider authorization) {
+        return new UserPolicyProvider(policy);
+    }
+
+    @Override
+    public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
+        return null;
+    }
+
+    @Override
+    public PolicyProvider create(KeycloakSession session) {
+        return null;
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+        factory.register(event -> {
+            if (event instanceof UserRemovedEvent) {
+                KeycloakSession keycloakSession = ((UserRemovedEvent) event).getKeycloakSession();
+                AuthorizationProvider provider = keycloakSession.getProvider(AuthorizationProvider.class);
+                PolicyStore policyStore = provider.getStoreFactory().getPolicyStore();
+                UserModel removedUser = ((UserRemovedEvent) event).getUser();
+
+                policyStore.findByType(getId()).forEach(policy -> {
+                    List<String> users = new ArrayList<>();
+
+                    for (String userId : getUsers(policy)) {
+                        if (!userId.equals(removedUser.getId())) {
+                            users.add(userId);
+                        }
+                    }
+
+                    try {
+                        if (users.isEmpty()) {
+                            policyStore.findDependentPolicies(policy.getId()).forEach(dependentPolicy -> {
+                                dependentPolicy.removeAssociatedPolicy(policy);
+                            });
+                            policyStore.delete(policy.getId());
+                        } else {
+                            policy.getConfig().put("users", JsonSerialization.writeValueAsString(users));
+                        }
+                    } catch (IOException e) {
+                        throw new RuntimeException("Error while synchronizing users with policy [" + policy.getName() + "].", e);
+                    }
+                });
+            }
+        });
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "user";
+    }
+
+    static String[] getUsers(Policy policy) {
+        String roles = policy.getConfig().get("users");
+
+        if (roles != null) {
+            try {
+                return JsonSerialization.readValue(roles.getBytes(), String[].class);
+            } catch (IOException e) {
+                throw new RuntimeException("Could not parse roles [" + roles + "] from policy config [" + policy.getName() + ".", e);
+            }
+        }
+
+        return new String[]{};
+    }
+}
diff --git a/authz/policy/common/src/main/resources/META-INF/services/org.keycloak.authorization.policy.provider.PolicyProviderFactory b/authz/policy/common/src/main/resources/META-INF/services/org.keycloak.authorization.policy.provider.PolicyProviderFactory
new file mode 100644
index 0000000..1e8dfd2
--- /dev/null
+++ b/authz/policy/common/src/main/resources/META-INF/services/org.keycloak.authorization.policy.provider.PolicyProviderFactory
@@ -0,0 +1,43 @@
+#
+#  Copyright 2016 Red Hat, Inc. and/or its affiliates
+#  and other contributors as indicated by the @author tags.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#
+
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2016 Red Hat, Inc., and individual contributors
+# as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.keycloak.authorization.policy.provider.aggregated.AggregatePolicyProviderFactory
+org.keycloak.authorization.policy.provider.js.JSPolicyProviderFactory
+org.keycloak.authorization.policy.provider.resource.ResourcePolicyProviderFactory
+org.keycloak.authorization.policy.provider.role.RolePolicyProviderFactory
+org.keycloak.authorization.policy.provider.scope.ScopePolicyProviderFactory
+org.keycloak.authorization.policy.provider.time.TimePolicyProviderFactory
+org.keycloak.authorization.policy.provider.user.UserPolicyProviderFactory
\ No newline at end of file
diff --git a/authz/policy/drools/pom.xml b/authz/policy/drools/pom.xml
new file mode 100644
index 0000000..4e7c005
--- /dev/null
+++ b/authz/policy/drools/pom.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.keycloak</groupId>
+        <artifactId>keycloak-authz-provider-parent</artifactId>
+        <version>2.2.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>keycloak-authz-policy-drools</artifactId>
+    <packaging>jar</packaging>
+
+    <name>KeyCloak AuthZ: Drools Policy Provider</name>
+    <description>KeyCloak AuthZ: Drools Policy Provider</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-services</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.drools</groupId>
+            <artifactId>drools-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.jboss.spec.javax.ws.rs</groupId>
+            <artifactId>jboss-jaxrs-api_2.0_spec</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicy.java b/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicy.java
new file mode 100644
index 0000000..c8848c1
--- /dev/null
+++ b/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicy.java
@@ -0,0 +1,71 @@
+package org.keycloak.authorization.policy.provider.drools;
+
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+import org.kie.api.KieServices;
+import org.kie.api.builder.KieScanner;
+import org.kie.api.runtime.KieContainer;
+import org.kie.api.runtime.KieSession;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+class DroolsPolicy {
+
+    private static final int SESSION_POOL_SIZE = 10;
+
+    private final KieContainer kc;
+    private final KieScanner kcs;
+    private final String sessionName;
+
+    DroolsPolicy(KieServices ks, Policy associatedPolicy) {
+        String groupId = associatedPolicy.getConfig().get("mavenArtifactGroupId");
+        String artifactId = associatedPolicy.getConfig().get("mavenArtifactId");
+        String version = associatedPolicy.getConfig().get("mavenArtifactVersion");
+        String scannerPeriod = associatedPolicy.getConfig().get("scannerPeriod");
+        String scannerPeriodUnit = associatedPolicy.getConfig().get("scannerPeriodUnit");
+        this.sessionName = associatedPolicy.getConfig().get("sessionName");
+
+        this.kc = ks.newKieContainer(ks.newReleaseId(groupId, artifactId, version));
+        this.kcs = ks.newKieScanner(this.kc);
+        this.kcs.start(toMillis(scannerPeriod, scannerPeriodUnit));
+
+        KieSession session = this.kc.newKieSession(this.sessionName);
+
+        if (session == null) {
+            throw new RuntimeException("Could not obtain session with name [" + this.sessionName + "].");
+        }
+
+        session.dispose();
+    }
+
+    void evaluate(Evaluation evaluation) {
+        KieSession session = this.kc.newKieSession(this.sessionName);
+
+        session.insert(evaluation);
+        session.fireAllRules();
+
+        session.dispose();
+    }
+
+    void dispose() {
+        this.kcs.stop();
+    }
+
+    private long toMillis(final String scannerPeriod, final String scannerPeriodUnit) {
+        switch (scannerPeriodUnit) {
+            case "Seconds":
+                return TimeUnit.SECONDS.toMillis(Integer.valueOf(scannerPeriod));
+            case "Minutes":
+                return TimeUnit.MINUTES.toMillis(Integer.valueOf(scannerPeriod));
+            case "Hours":
+                return TimeUnit.HOURS.toMillis(Integer.valueOf(scannerPeriod));
+            case "Days":
+                return TimeUnit.DAYS.toMillis(Integer.valueOf(scannerPeriod));
+        }
+
+        throw new RuntimeException("Invalid time period [" + scannerPeriodUnit + "].");
+    }
+}
diff --git a/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyAdminResource.java b/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyAdminResource.java
new file mode 100644
index 0000000..c6e5701
--- /dev/null
+++ b/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyAdminResource.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.policy.provider.drools;
+
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.kie.api.runtime.KieContainer;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class DroolsPolicyAdminResource implements PolicyProviderAdminService {
+
+    private final ResourceServer resourceServer;
+    private final DroolsPolicyProviderFactory factory;
+
+    public DroolsPolicyAdminResource(ResourceServer resourceServer, DroolsPolicyProviderFactory factory) {
+        this.resourceServer = resourceServer;
+        this.factory = factory;
+    }
+
+    @Override
+    public void onCreate(Policy policy) {
+        this.factory.update(policy);
+    }
+
+    @Override
+    public void onUpdate(Policy policy) {
+        this.factory.update(policy);
+    }
+
+    @Override
+    public void onRemove(Policy policy) {
+        this.factory.remove(policy);
+    }
+
+    @Path("/resolveModules")
+    @POST
+    @Consumes("application/json")
+    @Produces("application/json")
+    public Response resolveModules(PolicyRepresentation policy) {
+        return Response.ok(getContainer(policy).getKieBaseNames()).build();
+    }
+
+    @Path("/resolveSessions")
+    @POST
+    @Consumes("application/json")
+    @Produces("application/json")
+    public Response resolveSessions(PolicyRepresentation policy) {
+        return Response.ok(getContainer(policy).getKieSessionNamesInKieBase(policy.getConfig().get("moduleName"))).build();
+    }
+
+    private KieContainer getContainer(PolicyRepresentation policy) {
+        String groupId = policy.getConfig().get("mavenArtifactGroupId");
+        String artifactId = policy.getConfig().get("mavenArtifactId");
+        String version = policy.getConfig().get("mavenArtifactVersion");
+        return this.factory.getKieContainer(groupId, artifactId, version);
+    }
+}
diff --git a/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyProvider.java b/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyProvider.java
new file mode 100644
index 0000000..c53e361
--- /dev/null
+++ b/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyProvider.java
@@ -0,0 +1,43 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.policy.provider.drools;
+
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class DroolsPolicyProvider implements PolicyProvider {
+
+    private final DroolsPolicy policy;
+
+    public DroolsPolicyProvider(DroolsPolicy policy) {
+        this.policy = policy;
+    }
+
+    @Override
+    public void evaluate(Evaluation evaluationt) {
+        this.policy.evaluate(evaluationt);
+    }
+
+    @Override
+    public void close() {
+
+    }
+}
diff --git a/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyProviderFactory.java b/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyProviderFactory.java
new file mode 100644
index 0000000..0e1e208
--- /dev/null
+++ b/authz/policy/drools/src/main/java/org/keycloak/authorization/policy/provider/drools/DroolsPolicyProviderFactory.java
@@ -0,0 +1,109 @@
+package org.keycloak.authorization.policy.provider.drools;
+
+import org.keycloak.Config;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
+import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.utils.PostMigrationEvent;
+import org.keycloak.provider.ProviderEvent;
+import org.keycloak.provider.ProviderEventListener;
+import org.keycloak.provider.ProviderFactory;
+import org.kie.api.KieServices;
+import org.kie.api.KieServices.Factory;
+import org.kie.api.runtime.KieContainer;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class DroolsPolicyProviderFactory implements PolicyProviderFactory {
+
+    private KieServices ks;
+    private final Map<String, DroolsPolicy> containers = new HashMap<>();
+
+    @Override
+    public String getName() {
+        return "Drools";
+    }
+
+    @Override
+    public String getGroup() {
+        return "Rule Based";
+    }
+
+    @Override
+    public PolicyProvider create(Policy policy, AuthorizationProvider authorization) {
+        if (!this.containers.containsKey(policy.getId())) {
+            update(policy);
+        }
+
+        return new DroolsPolicyProvider(this.containers.get(policy.getId()));
+    }
+
+    @Override
+    public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
+        return new DroolsPolicyAdminResource(resourceServer, this);
+    }
+
+    @Override
+    public PolicyProvider create(KeycloakSession session) {
+        return null;
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+        this.ks = Factory.get();
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+        factory.register(new ProviderEventListener() {
+
+            @Override
+            public void onEvent(ProviderEvent event) {
+                // Ensure the initialization is done after DB upgrade is finished
+                if (event instanceof PostMigrationEvent) {
+                    ProviderFactory<AuthorizationProvider> providerFactory = factory.getProviderFactory(AuthorizationProvider.class);
+                    AuthorizationProvider authorization = providerFactory.create(factory.create());
+                    authorization.getStoreFactory().getPolicyStore().findByType(getId()).forEach(DroolsPolicyProviderFactory.this::update);
+                }
+            }
+
+        });
+    }
+
+    @Override
+    public void close() {
+        this.containers.values().forEach(DroolsPolicy::dispose);
+        this.containers.clear();
+    }
+
+    @Override
+    public String getId() {
+        return "drools";
+    }
+
+    void update(Policy policy) {
+        remove(policy);
+        this.containers.put(policy.getId(), new DroolsPolicy(this.ks, policy));
+    }
+
+    void remove(Policy policy) {
+        DroolsPolicy holder = this.containers.remove(policy.getId());
+
+        if (holder != null) {
+            holder.dispose();
+        }
+    }
+
+    KieContainer getKieContainer(String groupId, String artifactId, String version) {
+        return this.ks.newKieContainer(this.ks.newReleaseId(groupId, artifactId, version));
+    }
+}
diff --git a/authz/policy/drools/src/main/resources/META-INF/services/org.keycloak.authorization.policy.provider.PolicyProviderFactory b/authz/policy/drools/src/main/resources/META-INF/services/org.keycloak.authorization.policy.provider.PolicyProviderFactory
new file mode 100644
index 0000000..512e334
--- /dev/null
+++ b/authz/policy/drools/src/main/resources/META-INF/services/org.keycloak.authorization.policy.provider.PolicyProviderFactory
@@ -0,0 +1,19 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2016 Red Hat, Inc., and individual contributors
+# as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.keycloak.authorization.policy.provider.drools.DroolsPolicyProviderFactory
\ No newline at end of file
diff --git a/authz/policy/pom.xml b/authz/policy/pom.xml
new file mode 100644
index 0000000..ee9bd87
--- /dev/null
+++ b/authz/policy/pom.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.keycloak</groupId>
+        <artifactId>keycloak-authz-parent</artifactId>
+        <version>2.2.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>keycloak-authz-provider-parent</artifactId>
+    <packaging>pom</packaging>
+
+    <name>KeyCloak AuthZ: Provider Parent</name>
+    <description>KeyCloak AuthZ: Provider Parent</description>
+
+    <modules>
+        <module>common</module>
+        <module>drools</module>
+    </modules>
+
+</project>
\ No newline at end of file

authz/pom.xml 30(+30 -0)

diff --git a/authz/pom.xml b/authz/pom.xml
new file mode 100644
index 0000000..3c10f0e
--- /dev/null
+++ b/authz/pom.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.keycloak</groupId>
+        <artifactId>keycloak-parent</artifactId>
+        <version>2.2.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>keycloak-authz-parent</artifactId>
+    <packaging>pom</packaging>
+
+    <name>KeyCloak Authz: Parent</name>
+    <description>KeyCloak AuthZ: Parent</description>
+
+    <modules>
+        <module>policy</module>
+        <module>client</module>
+    </modules>
+
+    <properties>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+    </properties>
+
+</project>
\ No newline at end of file

common/pom.xml 2(+1 -1)

diff --git a/common/pom.xml b/common/pom.xml
index ad165ad..8f6cc17 100755
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/common/src/main/java/org/keycloak/common/util/reflections/Types.java b/common/src/main/java/org/keycloak/common/util/reflections/Types.java
index e6787be..adf8626 100644
--- a/common/src/main/java/org/keycloak/common/util/reflections/Types.java
+++ b/common/src/main/java/org/keycloak/common/util/reflections/Types.java
@@ -17,7 +17,14 @@
 
 package org.keycloak.common.util.reflections;
 
+import java.lang.reflect.Array;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * Utility class for Types
@@ -68,4 +75,564 @@ public class Types {
             return type;
         }
     }
+
+    /**
+     * Is the genericType of a certain class?
+     */
+    public static boolean isA(Class clazz, ParameterizedType pType)
+    {
+        return clazz.isAssignableFrom((Class) pType.getRawType());
+    }
+
+    /**
+     * Gets the index-th type argument.
+     */
+    public static Class getArgumentType(ParameterizedType pType, int index)
+    {
+        return (Class) pType.getActualTypeArguments()[index];
+    }
+
+    public static Class getTemplateParameterOfInterface(Class base, Class desiredInterface)
+    {
+        Object rtn = searchForInterfaceTemplateParameter(base, desiredInterface);
+        if (rtn != null && rtn instanceof Class) return (Class) rtn;
+        return null;
+    }
+
+
+    private static Object searchForInterfaceTemplateParameter(Class base, Class desiredInterface)
+    {
+        for (int i = 0; i < base.getInterfaces().length; i++)
+        {
+            Class intf = base.getInterfaces()[i];
+            if (intf.equals(desiredInterface))
+            {
+                Type generic = base.getGenericInterfaces()[i];
+                if (generic instanceof ParameterizedType)
+                {
+                    ParameterizedType p = (ParameterizedType) generic;
+                    Type type = p.getActualTypeArguments()[0];
+                    Class rtn = getRawTypeNoException(type);
+                    if (rtn != null) return rtn;
+                    return type;
+                }
+                else
+                {
+                    return null;
+                }
+            }
+        }
+        if (base.getSuperclass() == null || base.getSuperclass().equals(Object.class)) return null;
+        Object rtn = searchForInterfaceTemplateParameter(base.getSuperclass(), desiredInterface);
+        if (rtn == null || rtn instanceof Class) return rtn;
+        if (!(rtn instanceof TypeVariable)) return null;
+
+        String name = ((TypeVariable) rtn).getName();
+        int index = -1;
+        TypeVariable[] variables = base.getSuperclass().getTypeParameters();
+        if (variables == null || variables.length < 1) return null;
+
+        for (int i = 0; i < variables.length; i++)
+        {
+            if (variables[i].getName().equals(name)) index = i;
+        }
+        if (index == -1) return null;
+
+
+        Type genericSuperclass = base.getGenericSuperclass();
+        if (!(genericSuperclass instanceof ParameterizedType)) return null;
+
+        ParameterizedType pt = (ParameterizedType) genericSuperclass;
+        Type type = pt.getActualTypeArguments()[index];
+
+        Class clazz = getRawTypeNoException(type);
+        if (clazz != null) return clazz;
+        return type;
+    }
+
+
+    /**
+     * See if the two methods are compatible, that is they have the same relative signature
+     *
+     * @param method
+     * @param intfMethod
+     * @return
+     */
+    public static boolean isCompatible(Method method, Method intfMethod)
+    {
+        if (method == intfMethod) return true;
+
+        if (!method.getName().equals(intfMethod.getName())) return false;
+        if (method.getParameterTypes().length != intfMethod.getParameterTypes().length) return false;
+
+        for (int i = 0; i < method.getParameterTypes().length; i++)
+        {
+            Class rootParam = method.getParameterTypes()[i];
+            Class intfParam = intfMethod.getParameterTypes()[i];
+            if (!intfParam.isAssignableFrom(rootParam)) return false;
+        }
+        return true;
+    }
+
+    /**
+     * Given a method and a root class, find the actual method declared in the root that implements the method.
+     *
+     * @param clazz
+     * @param intfMethod
+     * @return
+     */
+    public static Method getImplementingMethod(Class clazz, Method intfMethod)
+    {
+        Class<?> declaringClass = intfMethod.getDeclaringClass();
+        if (declaringClass.equals(clazz)) return intfMethod;
+
+        Class[] paramTypes = intfMethod.getParameterTypes();
+
+        if (declaringClass.getTypeParameters().length > 0 && paramTypes.length > 0)
+        {
+            Type[] intfTypes = findParameterizedTypes(clazz, declaringClass);
+            Map<String, Type> typeVarMap = new HashMap<String, Type>();
+            TypeVariable<? extends Class<?>>[] vars = declaringClass.getTypeParameters();
+            for (int i = 0; i < vars.length; i++)
+            {
+                if (intfTypes != null && i < intfTypes.length)
+                {
+                    typeVarMap.put(vars[i].getName(), intfTypes[i]);
+                }
+                else
+                {
+                    // Interface type parameters may not have been filled out
+                    typeVarMap.put(vars[i].getName(), vars[i].getGenericDeclaration());
+                }
+            }
+            Type[] paramGenericTypes = intfMethod.getGenericParameterTypes();
+            paramTypes = new Class[paramTypes.length];
+
+            for (int i = 0; i < paramTypes.length; i++)
+            {
+                if (paramGenericTypes[i] instanceof TypeVariable)
+                {
+                    TypeVariable tv = (TypeVariable)paramGenericTypes[i];
+                    Type t = typeVarMap.get(tv.getName());
+                    if (t == null)
+                    {
+                        throw new RuntimeException("Unable to resolve type variable");
+                    }
+                    paramTypes[i] = getRawType(t);
+                }
+                else
+                {
+                    paramTypes[i] = getRawType(paramGenericTypes[i]);
+                }
+            }
+
+        }
+
+        try
+        {
+            return clazz.getMethod(intfMethod.getName(), paramTypes);
+        }
+        catch (NoSuchMethodException e)
+        {
+        }
+
+        try
+        {
+            Method tmp = clazz.getMethod(intfMethod.getName(), intfMethod.getParameterTypes());
+            return tmp;
+        }
+        catch (NoSuchMethodException e)
+        {
+
+        }
+        return intfMethod;
+    }
+
+
+    public static Class<?> getRawType(Type type)
+    {
+        if (type instanceof Class<?>)
+        {
+            // type is a normal class.
+            return (Class<?>) type;
+
+        }
+        else if (type instanceof ParameterizedType)
+        {
+            ParameterizedType parameterizedType = (ParameterizedType) type;
+            Type rawType = parameterizedType.getRawType();
+            return (Class<?>) rawType;
+        }
+        else if (type instanceof GenericArrayType)
+        {
+            final GenericArrayType genericArrayType = (GenericArrayType) type;
+            final Class<?> componentRawType = getRawType(genericArrayType.getGenericComponentType());
+            return Array.newInstance(componentRawType, 0).getClass();
+        }
+        else if (type instanceof TypeVariable)
+        {
+            final TypeVariable typeVar = (TypeVariable) type;
+            if (typeVar.getBounds() != null && typeVar.getBounds().length > 0)
+            {
+                return getRawType(typeVar.getBounds()[0]);
+            }
+        }
+        throw new RuntimeException("unable to determine base class");
+    }
+
+
+    public static Class<?> getRawTypeNoException(Type type)
+    {
+        if (type instanceof Class<?>)
+        {
+            // type is a normal class.
+            return (Class<?>) type;
+
+        }
+        else if (type instanceof ParameterizedType)
+        {
+            ParameterizedType parameterizedType = (ParameterizedType) type;
+            Type rawType = parameterizedType.getRawType();
+            return (Class<?>) rawType;
+        }
+        else if (type instanceof GenericArrayType)
+        {
+            final GenericArrayType genericArrayType = (GenericArrayType) type;
+            final Class<?> componentRawType = getRawType(genericArrayType.getGenericComponentType());
+            return Array.newInstance(componentRawType, 0).getClass();
+        }
+        return null;
+    }
+
+    /**
+     * Returns the type argument from a parameterized type
+     *
+     * @param genericType
+     * @return null if there is no type parameter
+     */
+    public static Class<?> getTypeArgument(Type genericType)
+    {
+        if (!(genericType instanceof ParameterizedType)) return null;
+        ParameterizedType parameterizedType = (ParameterizedType) genericType;
+        Class<?> typeArg = (Class<?>) parameterizedType.getActualTypeArguments()[0];
+        return typeArg;
+    }
+
+
+    public static Class getCollectionBaseType(Class type, Type genericType)
+    {
+        if (genericType instanceof ParameterizedType)
+        {
+            ParameterizedType parameterizedType = (ParameterizedType) genericType;
+            Type componentGenericType = parameterizedType.getActualTypeArguments()[0];
+            return getRawType(componentGenericType);
+        }
+        else if (genericType instanceof GenericArrayType)
+        {
+            final GenericArrayType genericArrayType = (GenericArrayType) genericType;
+            Type componentGenericType = genericArrayType.getGenericComponentType();
+            return getRawType(componentGenericType);
+        }
+        else if (type.isArray())
+        {
+            return type.getComponentType();
+        }
+        return null;
+    }
+
+
+    public static Class getMapKeyType(Type genericType)
+    {
+        if (genericType instanceof ParameterizedType)
+        {
+            ParameterizedType parameterizedType = (ParameterizedType) genericType;
+            Type componentGenericType = parameterizedType.getActualTypeArguments()[0];
+            return getRawType(componentGenericType);
+        }
+        return null;
+    }
+
+    public static Class getMapValueType(Type genericType)
+    {
+        if (genericType instanceof ParameterizedType)
+        {
+            ParameterizedType parameterizedType = (ParameterizedType) genericType;
+            Type componentGenericType = parameterizedType.getActualTypeArguments()[1];
+            return getRawType(componentGenericType);
+        }
+        return null;
+    }
+
+    public static Type resolveTypeVariables(Class<?> root, Type type)
+    {
+        if (type instanceof TypeVariable)
+        {
+            Type newType = resolveTypeVariable(root, (TypeVariable)type);
+            return (newType == null) ? type : newType;
+        }
+        else if (type instanceof ParameterizedType)
+        {
+            final ParameterizedType param = (ParameterizedType)type;
+            final Type[] actuals = new Type[param.getActualTypeArguments().length];
+            for (int i = 0; i < actuals.length; i++)
+            {
+                Type newType = resolveTypeVariables(root, param.getActualTypeArguments()[i]);
+                actuals[i] = newType == null ? param.getActualTypeArguments()[i] : newType;
+            }
+            return new ParameterizedType() {
+                @Override
+                public Type[] getActualTypeArguments()
+                {
+                    return actuals;
+                }
+
+                @Override
+                public Type getRawType()
+                {
+                    return param.getRawType();
+                }
+
+                @Override
+                public Type getOwnerType()
+                {
+                    return param.getOwnerType();
+                }
+            };
+        }
+        else if (type instanceof GenericArrayType)
+        {
+            GenericArrayType arrayType = (GenericArrayType)type;
+            final Type componentType = resolveTypeVariables(root, arrayType.getGenericComponentType());
+            if (componentType == null) return type;
+            return new GenericArrayType()
+            {
+                @Override
+                public Type getGenericComponentType()
+                {
+                    return componentType;
+                }
+            };
+        }
+        else
+        {
+            return type;
+        }
+    }
+
+
+    /**
+     * Finds an actual value of a type variable. The method looks in a class hierarchy for a class defining the variable
+     * and returns the value if present.
+     *
+     * @param root
+     * @param typeVariable
+     * @return actual type of the type variable
+     */
+    public static Type resolveTypeVariable(Class<?> root, TypeVariable<?> typeVariable)
+    {
+        if (typeVariable.getGenericDeclaration() instanceof Class<?>)
+        {
+            Class<?> classDeclaringTypeVariable = (Class<?>) typeVariable.getGenericDeclaration();
+            Type[] types = findParameterizedTypes(root, classDeclaringTypeVariable);
+            if (types == null) return  null;
+            for (int i = 0; i < types.length; i++)
+            {
+                TypeVariable<?> tv = classDeclaringTypeVariable.getTypeParameters()[i];
+                if (tv.equals(typeVariable))
+                {
+                    return types[i];
+                }
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     * Given a class and an interfaces, go through the class hierarchy to find the interface and return its type arguments.
+     *
+     * @param classToSearch
+     * @param interfaceToFind
+     * @return type arguments of the interface
+     */
+    public static Type[] getActualTypeArgumentsOfAnInterface(Class<?> classToSearch, Class<?> interfaceToFind)
+    {
+        Type[] types = findParameterizedTypes(classToSearch, interfaceToFind);
+        if (types == null) throw new RuntimeException("Unable to find type arguments");
+        return types;
+    }
+
+    private static final Type[] EMPTY_TYPE_ARRAY = {};
+
+    /**
+     * Search for the given interface or class within the root's class/interface hierarchy.
+     * If the searched for class/interface is a generic return an array of real types that fill it out.
+     *
+     * @param root
+     * @param searchedFor
+     * @return
+     */
+    public static Type[] findParameterizedTypes(Class<?> root, Class<?> searchedFor)
+    {
+        if (searchedFor.isInterface())
+        {
+            return findInterfaceParameterizedTypes(root, null, searchedFor);
+        }
+        return findClassParameterizedTypes(root, null, searchedFor);
+    }
+
+    public static Type[] findClassParameterizedTypes(Class<?> root, ParameterizedType rootType, Class<?> searchedForClass)
+    {
+        if (Object.class.equals(root)) return null;
+
+        Map<String, Type> typeVarMap = populateParameterizedMap(root, rootType);
+
+        Class<?> superclass = root.getSuperclass();
+        Type genericSuper = root.getGenericSuperclass();
+
+        if (superclass.equals(searchedForClass))
+        {
+            return extractTypes(typeVarMap, genericSuper);
+        }
+
+
+        if (genericSuper instanceof ParameterizedType)
+        {
+            ParameterizedType intfParam = (ParameterizedType) genericSuper;
+            Type[] types = findClassParameterizedTypes(superclass, intfParam, searchedForClass);
+            if (types != null)
+            {
+                return extractTypeVariables(typeVarMap, types);
+            }
+        }
+        else
+        {
+            Type[] types = findClassParameterizedTypes(superclass, null, searchedForClass);
+            if (types != null)
+            {
+                return types;
+            }
+        }
+        return null;
+    }
+
+    private static Map<String, Type> populateParameterizedMap(Class<?> root, ParameterizedType rootType)
+    {
+        Map<String, Type> typeVarMap = new HashMap<String, Type>();
+        if (rootType != null)
+        {
+            TypeVariable<? extends Class<?>>[] vars = root.getTypeParameters();
+            for (int i = 0; i < vars.length; i++)
+            {
+                typeVarMap.put(vars[i].getName(), rootType.getActualTypeArguments()[i]);
+            }
+        }
+        return typeVarMap;
+    }
+
+
+    public static Type[] findInterfaceParameterizedTypes(Class<?> root, ParameterizedType rootType, Class<?> searchedForInterface)
+    {
+        Map<String, Type> typeVarMap = populateParameterizedMap(root, rootType);
+
+        for (int i = 0; i < root.getInterfaces().length; i++)
+        {
+            Class<?> sub = root.getInterfaces()[i];
+            Type genericSub = root.getGenericInterfaces()[i];
+            if (sub.equals(searchedForInterface))
+            {
+                return extractTypes(typeVarMap, genericSub);
+            }
+        }
+
+        for (int i = 0; i < root.getInterfaces().length; i++)
+        {
+            Type genericSub = root.getGenericInterfaces()[i];
+            Class<?> sub = root.getInterfaces()[i];
+
+            Type[] types = recurseSuperclassForInterface(searchedForInterface, typeVarMap, genericSub, sub);
+            if (types != null) return types;
+        }
+        if (root.isInterface()) return null;
+
+        Class<?> superclass = root.getSuperclass();
+        Type genericSuper = root.getGenericSuperclass();
+
+
+        return recurseSuperclassForInterface(searchedForInterface, typeVarMap, genericSuper, superclass);
+    }
+
+    private static Type[] recurseSuperclassForInterface(Class<?> searchedForInterface, Map<String, Type> typeVarMap, Type genericSub, Class<?> sub)
+    {
+        if (genericSub instanceof ParameterizedType)
+        {
+            ParameterizedType intfParam = (ParameterizedType) genericSub;
+            Type[] types = findInterfaceParameterizedTypes(sub, intfParam, searchedForInterface);
+            if (types != null)
+            {
+                return extractTypeVariables(typeVarMap, types);
+            }
+        }
+        else
+        {
+            Type[] types = findInterfaceParameterizedTypes(sub, null, searchedForInterface);
+            if (types != null)
+            {
+                return types;
+            }
+        }
+        return null;
+    }
+
+    private static Type[] extractTypeVariables(Map<String, Type> typeVarMap, Type[] types)
+    {
+        for (int j = 0; j < types.length; j++)
+        {
+            if (types[j] instanceof TypeVariable)
+            {
+                TypeVariable tv = (TypeVariable) types[j];
+                types[j] = typeVarMap.get(tv.getName());
+            }
+            else
+            {
+                types[j] = types[j];
+            }
+        }
+        return types;
+    }
+
+    private static Type[] extractTypes(Map<String, Type> typeVarMap, Type genericSub)
+    {
+        if (genericSub instanceof ParameterizedType)
+        {
+            ParameterizedType param = (ParameterizedType) genericSub;
+            Type[] types = param.getActualTypeArguments();
+            Type[] returnTypes = new Type[types.length];
+            System.arraycopy(types, 0, returnTypes, 0, types.length);
+            extractTypeVariables(typeVarMap, returnTypes);
+            return returnTypes;
+        }
+        else
+        {
+            return EMPTY_TYPE_ARRAY;
+        }
+    }
+
+    /**
+     * Grabs the parameterized type of fromInterface
+     * that object implements and sees if it is assignable from type.
+     *
+     * @param type
+     * @param object
+     * @param fromInterface
+     * @param <T>
+     * @return
+     */
+    public static <T> boolean supports(Class<T> type, Object object, Class<?> fromInterface) {
+        Type providerType = getActualTypeArgumentsOfAnInterface(object.getClass(), fromInterface)[0];
+        Class providerClass = getRawType(providerType);
+        return type.isAssignableFrom(providerClass);
+    }
+
+
 }
\ No newline at end of file

core/pom.xml 2(+1 -1)

diff --git a/core/pom.xml b/core/pom.xml
index 3bcd9ef..3f43522 100755
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/core/src/main/java/org/keycloak/AuthorizationContext.java b/core/src/main/java/org/keycloak/AuthorizationContext.java
new file mode 100644
index 0000000..05bb97d
--- /dev/null
+++ b/core/src/main/java/org/keycloak/AuthorizationContext.java
@@ -0,0 +1,93 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak;
+
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.adapters.config.PolicyEnforcerConfig.PathConfig;
+import org.keycloak.representations.idm.authorization.Permission;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AuthorizationContext {
+
+    private final AccessToken authzToken;
+    private final List<PathConfig> paths;
+    private boolean granted;
+
+    public AuthorizationContext(AccessToken authzToken, List<PathConfig> paths) {
+        this.authzToken = authzToken;
+        this.paths = paths;
+        this.granted = true;
+    }
+
+    public AuthorizationContext() {
+        this(null, null);
+        this.granted = false;
+    }
+
+    public boolean hasPermission(String resourceName, String scopeName) {
+        for (Permission permission : authzToken.getAuthorization().getPermissions()) {
+            for (PathConfig pathHolder : this.paths) {
+                if (pathHolder.getName().equals(resourceName)) {
+                    if (pathHolder.getId().equals(permission.getResourceSetId())) {
+                        if (permission.getScopes().contains(scopeName)) {
+                            return true;
+                        }
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    public boolean hasResourcePermission(String resourceName) {
+        for (Permission permission : authzToken.getAuthorization().getPermissions()) {
+            for (PathConfig pathHolder : this.paths) {
+                if (pathHolder.getName().equals(resourceName)) {
+                    if (pathHolder.getId().equals(permission.getResourceSetId())) {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
+    public boolean hasScopePermission(String scopeName) {
+        for (Permission permission : authzToken.getAuthorization().getPermissions()) {
+            if (permission.getScopes().contains(scopeName)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public List<Permission> getPermissions() {
+        return this.authzToken.getAuthorization().getPermissions();
+    }
+
+    public boolean isGranted() {
+        return granted;
+    }
+}
diff --git a/core/src/main/java/org/keycloak/jose/jwk/JWK.java b/core/src/main/java/org/keycloak/jose/jwk/JWK.java
index ce153a4..e75963a 100755
--- a/core/src/main/java/org/keycloak/jose/jwk/JWK.java
+++ b/core/src/main/java/org/keycloak/jose/jwk/JWK.java
@@ -37,8 +37,20 @@ public class JWK {
 
     public static final String PUBLIC_KEY_USE = "use";
 
-    public static final String SIG_USE = "sig";
-    public static final String ENCRYPTION_USE = "enc";
+    public enum Use {
+        SIG("sig"),
+        ENCRYPTION("enc");
+
+        private String str;
+
+        Use(String str) {
+            this.str = str;
+        }
+
+        public String asString() {
+            return str;
+        }
+    }
 
     @JsonProperty(KEY_ID)
     private String keyId;
diff --git a/core/src/main/java/org/keycloak/jose/jwk/JWKParser.java b/core/src/main/java/org/keycloak/jose/jwk/JWKParser.java
index a503a3c..7a31f72 100755
--- a/core/src/main/java/org/keycloak/jose/jwk/JWKParser.java
+++ b/core/src/main/java/org/keycloak/jose/jwk/JWKParser.java
@@ -21,6 +21,7 @@ import com.fasterxml.jackson.core.type.TypeReference;
 import org.keycloak.common.util.Base64Url;
 import org.keycloak.util.JsonSerialization;
 
+import java.io.InputStream;
 import java.math.BigInteger;
 import java.security.KeyFactory;
 import java.security.PublicKey;
@@ -66,7 +67,7 @@ public class JWKParser {
 
     public PublicKey toPublicKey() {
         String algorithm = jwk.getKeyType();
-        if (RSAPublicJWK.RSA.equals(algorithm)) {
+        if (isAlgorithmSupported(algorithm)) {
             BigInteger modulus = new BigInteger(1, Base64Url.decode(jwk.getOtherClaims().get(RSAPublicJWK.MODULUS).toString()));
             BigInteger publicExponent = new BigInteger(1, Base64Url.decode(jwk.getOtherClaims().get(RSAPublicJWK.PUBLIC_EXPONENT).toString()));
 
@@ -80,4 +81,8 @@ public class JWKParser {
         }
     }
 
+    public boolean isAlgorithmSupported(String algorithm) {
+        return RSAPublicJWK.RSA.equals(algorithm);
+    }
+
 }
diff --git a/core/src/main/java/org/keycloak/jose/jws/crypto/HashProvider.java b/core/src/main/java/org/keycloak/jose/jws/crypto/HashProvider.java
new file mode 100644
index 0000000..c8fa714
--- /dev/null
+++ b/core/src/main/java/org/keycloak/jose/jws/crypto/HashProvider.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.jose.jws.crypto;
+
+import java.security.MessageDigest;
+import java.util.Arrays;
+
+import org.keycloak.common.util.Base64Url;
+import org.keycloak.jose.jws.Algorithm;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class HashProvider {
+
+    // See "at_hash" and "c_hash" in OIDC specification
+    public static String oidcHash(Algorithm jwtAlgorithm, String input) {
+        byte[] digest = digest(jwtAlgorithm, input);
+
+        int hashLength = digest.length / 2;
+        byte[] hashInput = Arrays.copyOf(digest, hashLength);
+
+        return Base64Url.encode(hashInput);
+    }
+
+    private static byte[] digest(Algorithm algorithm, String input) {
+        String digestAlg = getJavaDigestAlgorithm(algorithm);
+
+        try {
+            MessageDigest md = MessageDigest.getInstance(digestAlg);
+            md.update(input.getBytes("UTF-8"));
+            return md.digest();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static String getJavaDigestAlgorithm(Algorithm alg) {
+        switch (alg) {
+            case RS256:
+                return "SHA-256";
+            case RS384:
+                return "SHA-384";
+            case RS512:
+                return "SHA-512";
+            default:
+                throw new IllegalArgumentException("Not an RSA Algorithm");
+        }
+    }
+
+}
diff --git a/core/src/main/java/org/keycloak/jose/jws/JWSBuilder.java b/core/src/main/java/org/keycloak/jose/jws/JWSBuilder.java
index e344389..68ee65d 100755
--- a/core/src/main/java/org/keycloak/jose/jws/JWSBuilder.java
+++ b/core/src/main/java/org/keycloak/jose/jws/JWSBuilder.java
@@ -33,6 +33,7 @@ import java.security.PrivateKey;
  */
 public class JWSBuilder {
     String type;
+    String kid;
     String contentType;
     byte[] contentBytes;
 
@@ -41,6 +42,11 @@ public class JWSBuilder {
         return this;
     }
 
+    public JWSBuilder kid(String kid) {
+        this.kid = kid;
+        return this;
+    }
+
     public JWSBuilder contentType(String type) {
         this.contentType = type;
         return this;
@@ -66,6 +72,7 @@ public class JWSBuilder {
         builder.append("\"alg\":\"").append(alg.toString()).append("\"");
 
         if (type != null) builder.append(",\"typ\" : \"").append(type).append("\"");
+        if (kid != null) builder.append(",\"kid\" : \"").append(kid).append("\"");
         if (contentType != null) builder.append(",\"cty\":\"").append(contentType).append("\"");
         builder.append("}");
         try {
@@ -101,43 +108,29 @@ public class JWSBuilder {
             return encodeAll(buffer, null);
         }
 
-        public String rsa256(PrivateKey privateKey) {
+        public String sign(Algorithm algorithm, PrivateKey privateKey) {
             StringBuffer buffer = new StringBuffer();
             byte[] data = marshalContent();
-            encode(Algorithm.RS256, data, buffer);
+            encode(algorithm, data, buffer);
             byte[] signature = null;
             try {
-                signature = RSAProvider.sign(buffer.toString().getBytes("UTF-8"), Algorithm.RS256, privateKey);
+                signature = RSAProvider.sign(buffer.toString().getBytes("UTF-8"), algorithm, privateKey);
             } catch (UnsupportedEncodingException e) {
                 throw new RuntimeException(e);
             }
             return encodeAll(buffer, signature);
         }
 
+        public String rsa256(PrivateKey privateKey) {
+            return sign(Algorithm.RS256, privateKey);
+        }
+
         public String rsa384(PrivateKey privateKey) {
-            StringBuffer buffer = new StringBuffer();
-            byte[] data = marshalContent();
-            encode(Algorithm.RS384, data, buffer);
-            byte[] signature = null;
-            try {
-                signature = RSAProvider.sign(buffer.toString().getBytes("UTF-8"), Algorithm.RS384, privateKey);
-            } catch (UnsupportedEncodingException e) {
-                throw new RuntimeException(e);
-            }
-            return encodeAll(buffer, signature);
+            return sign(Algorithm.RS384, privateKey);
         }
 
         public String rsa512(PrivateKey privateKey) {
-            StringBuffer buffer = new StringBuffer();
-            byte[] data = marshalContent();
-            encode(Algorithm.RS512, data, buffer);
-            byte[] signature = null;
-            try {
-                signature = RSAProvider.sign(buffer.toString().getBytes("UTF-8"), Algorithm.RS512, privateKey);
-            } catch (UnsupportedEncodingException e) {
-                throw new RuntimeException(e);
-            }
-            return encodeAll(buffer, signature);
+            return sign(Algorithm.RS512, privateKey);
         }
 
 
diff --git a/core/src/main/java/org/keycloak/KeycloakSecurityContext.java b/core/src/main/java/org/keycloak/KeycloakSecurityContext.java
index 118fd1b..68ac957 100755
--- a/core/src/main/java/org/keycloak/KeycloakSecurityContext.java
+++ b/core/src/main/java/org/keycloak/KeycloakSecurityContext.java
@@ -41,6 +41,7 @@ public class KeycloakSecurityContext implements Serializable {
     // Don't store parsed tokens into HTTP session
     protected transient AccessToken token;
     protected transient IDToken idToken;
+    protected transient AuthorizationContext authorizationContext;
 
     public KeycloakSecurityContext() {
     }
@@ -60,6 +61,10 @@ public class KeycloakSecurityContext implements Serializable {
         return tokenString;
     }
 
+    public AuthorizationContext getAuthorizationContext() {
+        return authorizationContext;
+    }
+
     public IDToken getIdToken() {
         return idToken;
     }
diff --git a/core/src/main/java/org/keycloak/OAuth2Constants.java b/core/src/main/java/org/keycloak/OAuth2Constants.java
index bb3ccd7..2a7d37b 100644
--- a/core/src/main/java/org/keycloak/OAuth2Constants.java
+++ b/core/src/main/java/org/keycloak/OAuth2Constants.java
@@ -26,6 +26,8 @@ public interface OAuth2Constants {
 
     String CLIENT_ID = "client_id";
 
+    String CLIENT_SECRET = "client_secret";
+
     String ERROR = "error";
 
     String ERROR_DESCRIPTION = "error_description";
@@ -40,6 +42,10 @@ public interface OAuth2Constants {
 
     String RESPONSE_TYPE = "response_type";
 
+    String ACCESS_TOKEN = "access_token";
+
+    String ID_TOKEN = "id_token";
+
     String REFRESH_TOKEN = "refresh_token";
 
     String AUTHORIZATION_CODE = "authorization_code";
@@ -60,8 +66,21 @@ public interface OAuth2Constants {
     // http://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess
     String OFFLINE_ACCESS = "offline_access";
 
+    // http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
+    String SCOPE_OPENID = "openid";
+
+    // http://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims
+    String SCOPE_PROFILE = "profile";
+    String SCOPE_EMAIL = "email";
+    String SCOPE_ADDRESS = "address";
+    String SCOPE_PHONE = "phone";
+
     String UI_LOCALES_PARAM = "ui_locales";
 
+    String PROMPT = "prompt";
+
+    String MAX_AGE = "max_age";
+
 
 }
 
diff --git a/core/src/main/java/org/keycloak/OAuthErrorException.java b/core/src/main/java/org/keycloak/OAuthErrorException.java
index c5f0173..940d434 100755
--- a/core/src/main/java/org/keycloak/OAuthErrorException.java
+++ b/core/src/main/java/org/keycloak/OAuthErrorException.java
@@ -22,11 +22,32 @@ package org.keycloak;
  * @version $Revision: 1 $
  */
 public class OAuthErrorException extends Exception {
+    // OAuth2
     public static final String INVALID_REQUEST = "invalid_request";
+    public static final String INVALID_SCOPE = "invalid_scope";
+    public static final String UNAUTHORIZED_CLIENT = "unauthorized_client";
+    public static final String ACCESS_DENIED = "access_denied";
+    public static final String UNSUPPORTED_RESPONSE_TYPE = "unsupported_response_type";
+    public static final String SERVER_ERROR = "server_error";
+    public static final String TEMPORARILY_UNAVAILABLE = "temporarily_unavailable";
+
+    // OpenID Connect 1
+    public static final String INTERACTION_REQUIRED = "interaction_required";
+    public static final String LOGIN_REQUIRED = "login_required";
+    public static final String REQUEST_NOT_SUPPORTED = "request_not_supported";
+    public static final String REQUEST_URI_NOT_SUPPORTED = "request_uri_not_supported";
+
+    // OAuth2 Bearer Token Usage
+    public static final String INVALID_TOKEN = "invalid_token";
+    public static final String INSUFFICIENT_SCOPE = "insufficient_scope";
+
+    // OIDC Dynamic Client Registration
+    public static final String INVALID_REDIRECT_URI = "invalid_redirect_uri";
+    public static final String INVALID_CLIENT_METADATA = "invalid_client_metadata";
+
+    // Others
     public static final String INVALID_CLIENT = "invalid_client";
     public static final String INVALID_GRANT = "invalid_grant";
-    public static final String INVALID_SCOPE = "invalid_grant";
-    public static final String UNAUTHORIZED_CLIENT = "unauthorized_client";
     public static final String UNSUPPORTED_GRANT_TYPE = "unsupported_grant_type";
 
     public OAuthErrorException(String error, String description, String message, Throwable cause) {
diff --git a/core/src/main/java/org/keycloak/representations/AccessToken.java b/core/src/main/java/org/keycloak/representations/AccessToken.java
index ac800cd..4ef6831 100755
--- a/core/src/main/java/org/keycloak/representations/AccessToken.java
+++ b/core/src/main/java/org/keycloak/representations/AccessToken.java
@@ -19,10 +19,12 @@ package org.keycloak.representations;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import org.keycloak.representations.idm.authorization.Permission;
 
 import java.io.Serializable;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -81,6 +83,20 @@ public class AccessToken extends IDToken {
         }
     }
 
+    public static class Authorization implements Serializable {
+
+        @JsonProperty("permissions")
+        private List<Permission> permissions;
+
+        public List<Permission> getPermissions() {
+            return permissions;
+        }
+
+        public void setPermissions(List<Permission> permissions) {
+            this.permissions = permissions;
+        }
+    }
+
     @JsonProperty("client_session")
     protected String clientSession;
 
@@ -96,6 +112,9 @@ public class AccessToken extends IDToken {
     @JsonProperty("resource_access")
     protected Map<String, Access> resourceAccess = new HashMap<String, Access>();
 
+    @JsonProperty("authorization")
+    protected Authorization authorization;
+
     public Map<String, Access> getResourceAccess() {
         return resourceAccess;
     }
@@ -219,5 +238,11 @@ public class AccessToken extends IDToken {
         return (AccessToken)super.issuedFor(issuedFor);
     }
 
+    public Authorization getAuthorization() {
+        return authorization;
+    }
 
+    public void setAuthorization(Authorization authorization) {
+        this.authorization = authorization;
+    }
 }
diff --git a/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java
index 87b3ab2..91fb5f0 100755
--- a/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java
+++ b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java
@@ -36,7 +36,8 @@ import com.fasterxml.jackson.annotation.JsonPropertyOrder;
         "client-keystore", "client-keystore-password", "client-key-password",
         "always-refresh-token",
         "register-node-at-startup", "register-node-period", "token-store", "principal-attribute",
-        "proxy-url"
+        "proxy-url", "turn-off-change-session-id-on-login", "token-minimum-time-to-live",
+        "policy-enforcer"
 })
 public class AdapterConfig extends BaseAdapterConfig {
 
@@ -68,6 +69,10 @@ public class AdapterConfig extends BaseAdapterConfig {
     protected String principalAttribute;
     @JsonProperty("turn-off-change-session-id-on-login")
     protected Boolean turnOffChangeSessionIdOnLogin;
+    @JsonProperty("token-minimum-time-to-live")
+    protected int tokenMinimumTimeToLive = 0;
+    @JsonProperty("policy-enforcer")
+    protected PolicyEnforcerConfig policyEnforcerConfig;
 
     /**
      * The Proxy url to use for requests to the auth-server, configurable via the adapter config property {@code proxy-url}.
@@ -187,6 +192,14 @@ public class AdapterConfig extends BaseAdapterConfig {
         this.turnOffChangeSessionIdOnLogin = turnOffChangeSessionIdOnLogin;
     }
 
+    public PolicyEnforcerConfig getPolicyEnforcerConfig() {
+        return policyEnforcerConfig;
+    }
+
+    public void setPolicyEnforcerConfig(PolicyEnforcerConfig policyEnforcerConfig) {
+        this.policyEnforcerConfig = policyEnforcerConfig;
+    }
+
     public String getProxyUrl() {
         return proxyUrl;
     }
@@ -194,4 +207,13 @@ public class AdapterConfig extends BaseAdapterConfig {
     public void setProxyUrl(String proxyUrl) {
         this.proxyUrl = proxyUrl;
     }
+
+    public int getTokenMinimumTimeToLive() {
+        return tokenMinimumTimeToLive;
+    }
+
+    public void setTokenMinimumTimeToLive(final int tokenMinimumTimeToLive) {
+        this.tokenMinimumTimeToLive = tokenMinimumTimeToLive;
+    }
+
 }
diff --git a/core/src/main/java/org/keycloak/representations/adapters/config/PolicyEnforcerConfig.java b/core/src/main/java/org/keycloak/representations/adapters/config/PolicyEnforcerConfig.java
new file mode 100644
index 0000000..9cf710a
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/adapters/config/PolicyEnforcerConfig.java
@@ -0,0 +1,227 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.representations.adapters.config;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class PolicyEnforcerConfig {
+
+    @JsonProperty("create-resources")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Boolean createResources = Boolean.FALSE;
+
+    @JsonProperty("enforcement-mode")
+    private EnforcementMode enforcementMode = EnforcementMode.ENFORCING;
+
+    @JsonProperty("user-managed-access")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private UmaProtocolConfig umaProtocolConfig;
+
+    @JsonProperty("entitlement")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private EntitlementProtocolConfig entitlementProtocolConfig;
+
+    @JsonProperty("paths")
+    @JsonInclude(JsonInclude.Include.NON_EMPTY)
+    private List<PathConfig> paths = new ArrayList<>();
+
+    @JsonProperty("online-introspection")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Boolean onlineIntrospection = Boolean.FALSE;
+
+    @JsonProperty("on-deny-redirect-to")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private String accessDeniedPath;
+
+    public Boolean isCreateResources() {
+        return this.createResources;
+    }
+
+    public List<PathConfig> getPaths() {
+        return Collections.unmodifiableList(this.paths);
+    }
+
+    public EnforcementMode getEnforcementMode() {
+        return this.enforcementMode;
+    }
+
+    public void setEnforcementMode(EnforcementMode enforcementMode) {
+        this.enforcementMode = enforcementMode;
+    }
+
+    public UmaProtocolConfig getUmaProtocolConfig() {
+        return this.umaProtocolConfig;
+    }
+
+    public EntitlementProtocolConfig getEntitlementProtocolConfig() {
+        return this.entitlementProtocolConfig;
+    }
+
+    public Boolean isOnlineIntrospection() {
+        return onlineIntrospection;
+    }
+
+    public void setCreateResources(Boolean createResources) {
+        this.createResources = createResources;
+    }
+
+    public void setOnlineIntrospection(Boolean onlineIntrospection) {
+        this.onlineIntrospection = onlineIntrospection;
+    }
+
+    public void setPaths(List<PathConfig> paths) {
+        this.paths = paths;
+    }
+
+    public String getAccessDeniedPath() {
+        return accessDeniedPath;
+    }
+
+    public static class PathConfig {
+
+        private String name;
+        private String type;
+        private String path;
+        private List<MethodConfig> methods = new ArrayList<>();
+        private List<String> scopes = Collections.emptyList();
+        private String id;
+
+        @JsonIgnore
+        private PathConfig parentConfig;
+
+        public String getPath() {
+            return this.path;
+        }
+
+        public void setPath(String path) {
+            this.path = path;
+        }
+
+        public List<String> getScopes() {
+            return this.scopes;
+        }
+
+        public void setScopes(List<String> scopes) {
+            this.scopes = scopes;
+        }
+
+        public List<MethodConfig> getMethods() {
+            return methods;
+        }
+
+        public void setMethods(List<MethodConfig> methods) {
+            this.methods = methods;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public String getType() {
+            return type;
+        }
+
+        public void setType(String type) {
+            this.type = type;
+        }
+
+        public void setId(String id) {
+            this.id = id;
+        }
+
+        public String getId() {
+            return id;
+        }
+
+        @Override
+        public String toString() {
+            return "PathConfig{" +
+                    "name='" + name + '\'' +
+                    ", type='" + type + '\'' +
+                    ", path='" + path + '\'' +
+                    ", scopes=" + scopes +
+                    ", id='" + id + '\'' +
+                    '}';
+        }
+
+        public boolean hasPattern() {
+            return getPath().indexOf("{") != -1;
+        }
+
+        public boolean isInstance() {
+            return this.parentConfig != null;
+        }
+
+        public void setParentConfig(PathConfig parentConfig) {
+            this.parentConfig = parentConfig;
+        }
+
+        public PathConfig getParentConfig() {
+            return parentConfig;
+        }
+    }
+
+    public static class MethodConfig {
+
+        private String method;
+        private List<String> scopes = Collections.emptyList();
+
+        public String getMethod() {
+            return method;
+        }
+
+        public void setMethod(String method) {
+            this.method = method;
+        }
+
+        public List<String> getScopes() {
+            return scopes;
+        }
+
+        public void setScopes(List<String> scopes) {
+            this.scopes = scopes;
+        }
+    }
+
+    public enum EnforcementMode {
+        PERMISSIVE,
+        ENFORCING,
+        DISABLED
+    }
+
+    public static class UmaProtocolConfig {
+
+    }
+
+    public static class EntitlementProtocolConfig {
+
+    }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/AdminEventRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/AdminEventRepresentation.java
index f615cbd..9aa1e16 100644
--- a/core/src/main/java/org/keycloak/representations/idm/AdminEventRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/AdminEventRepresentation.java
@@ -18,7 +18,6 @@
 package org.keycloak.representations.idm;
 
 /**
- *
  * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
  */
 public class AdminEventRepresentation {
@@ -27,6 +26,7 @@ public class AdminEventRepresentation {
     private String realmId;
     private AuthDetailsRepresentation authDetails;
     private String operationType;
+    private String resourceType;
     private String resourcePath;
     private String representation;
     private String error;
@@ -63,6 +63,14 @@ public class AdminEventRepresentation {
         this.operationType = operationType;
     }
 
+    public String getResourceType() {
+        return resourceType;
+    }
+
+    public void setResourceType(String resourceType) {
+        this.resourceType = resourceType;
+    }
+
     public String getResourcePath() {
         return resourcePath;
     }
@@ -86,5 +94,4 @@ public class AdminEventRepresentation {
     public void setError(String error) {
         this.error = error;
     }
-
 }
diff --git a/core/src/main/java/org/keycloak/representations/idm/AuthenticationExecutionInfoRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/AuthenticationExecutionInfoRepresentation.java
index 1ff76a6..7ff1fa1 100755
--- a/core/src/main/java/org/keycloak/representations/idm/AuthenticationExecutionInfoRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/AuthenticationExecutionInfoRepresentation.java
@@ -29,6 +29,7 @@ public class AuthenticationExecutionInfoRepresentation implements Serializable {
     protected String id;
     protected String requirement;
     protected String displayName;
+    protected String alias;
     protected List<String> requirementChoices;
     protected Boolean configurable;
     protected Boolean authenticationFlow;
@@ -54,6 +55,14 @@ public class AuthenticationExecutionInfoRepresentation implements Serializable {
         this.displayName = displayName;
     }
 
+    public String getAlias() {
+        return alias;
+    }
+
+    public void setAlias(String alias) {
+        this.alias = alias;
+    }
+
     public String getRequirement() {
         return requirement;
     }
diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/DecisionStrategy.java b/core/src/main/java/org/keycloak/representations/idm/authorization/DecisionStrategy.java
new file mode 100644
index 0000000..bd66bea
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/authorization/DecisionStrategy.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.representations.idm.authorization;
+
+/**
+ * The decision strategy dictates how the policies associated with a given policy are evaluated and how a final decision
+ * is obtained.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public enum DecisionStrategy {
+
+    /**
+     * Defines that at least one policy must evaluate to a positive decision in order to the overall decision be also positive.
+     */
+    AFFIRMATIVE,
+
+    /**
+     * Defines that all policies must evaluate to a positive decision in order to the overall decision be also positive.
+     */
+    UNANIMOUS,
+
+    /**
+     * Defines that the number of positive decisions must be greater than the number of negative decisions. If the number of positive and negative is the same,
+     * the final decision will be negative.
+     */
+    CONSENSUS
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/Logic.java b/core/src/main/java/org/keycloak/representations/idm/authorization/Logic.java
new file mode 100644
index 0000000..70c382e
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/authorization/Logic.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.representations.idm.authorization;
+
+/**
+ * The decision strategy dictates how the policies associated with a given policy are evaluated and how a final decision
+ * is obtained.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public enum Logic {
+
+    /**
+     * Defines that this policy follows a positive logic. In other words, the final decision is the policy outcome.
+     */
+    POSITIVE,
+
+    /**
+     * Defines that this policy uses a logical negation. In other words, the final decision would be a negative of the policy outcome.
+     */
+    NEGATIVE,
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/Permission.java b/core/src/main/java/org/keycloak/representations/idm/authorization/Permission.java
new file mode 100644
index 0000000..7e865cd
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/authorization/Permission.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.representations.idm.authorization;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class Permission {
+
+    @JsonProperty("resource_set_id")
+    private String resourceSetId;
+
+    @JsonProperty("resource_set_name")
+    private final String resourceSetName;
+
+    @JsonInclude(JsonInclude.Include.NON_EMPTY)
+    private Set<String> scopes;
+
+    public Permission() {
+        this(null, null, null);
+    }
+
+    public Permission(final String resourceSetId, String resourceSetName, final Set<String> scopes) {
+        this.resourceSetId = resourceSetId;
+        this.resourceSetName = resourceSetName;
+        this.scopes = scopes;
+    }
+
+    public String getResourceSetId() {
+        return this.resourceSetId;
+    }
+
+    public String getResourceSetName() {
+        return this.resourceSetName;
+    }
+
+    public Set<String> getScopes() {
+        if (this.scopes == null) {
+            this.scopes = new HashSet<>();
+        }
+
+        return this.scopes;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+
+        builder.append("Permission {").append("id=").append(resourceSetId).append(", name=").append(resourceSetName)
+                .append(", scopes=").append(scopes).append("}");
+
+        return builder.toString();
+    }
+
+    public void setScopes(Set<String> scopes) {
+        this.scopes = scopes;
+    }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/PolicyEnforcementMode.java b/core/src/main/java/org/keycloak/representations/idm/authorization/PolicyEnforcementMode.java
new file mode 100644
index 0000000..4d1eef6
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/authorization/PolicyEnforcementMode.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.representations.idm.authorization;
+
+/**
+ * The policy enforcement mode dictates how authorization requests are handled by the server.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public enum PolicyEnforcementMode {
+
+    /**
+     * Requests are denied by default even when there is no policy associated with a given resource.
+     */
+    ENFORCING,
+
+    /**
+     * Requests are allowed even when there is no policy associated with a given resource.
+     */
+    PERMISSIVE,
+
+    /**
+     * Completely disables the evaluation of policies and allow access to any resource.
+     */
+    DISABLED
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/PolicyRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/authorization/PolicyRepresentation.java
new file mode 100644
index 0000000..9a51031
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/authorization/PolicyRepresentation.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.representations.idm.authorization;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class PolicyRepresentation {
+
+    private String id;
+    private String name;
+    private String description;
+    private String type;
+    private Logic logic = Logic.POSITIVE;
+    private DecisionStrategy decisionStrategy = DecisionStrategy.UNANIMOUS;
+    private Map<String, String> config = new HashMap();
+    private List<PolicyRepresentation> dependentPolicies;
+    @JsonInclude(JsonInclude.Include.NON_EMPTY)
+    private List<PolicyRepresentation> associatedPolicies = new ArrayList<>();
+
+    public String getId() {
+        return this.id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getType() {
+        return this.type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public DecisionStrategy getDecisionStrategy() {
+        return this.decisionStrategy;
+    }
+
+    public void setDecisionStrategy(DecisionStrategy decisionStrategy) {
+        this.decisionStrategy = decisionStrategy;
+    }
+
+    public Logic getLogic() {
+        return logic;
+    }
+
+    public void setLogic(Logic logic) {
+        this.logic = logic;
+    }
+
+    public Map<String, String> getConfig() {
+        return this.config;
+    }
+
+    public void setConfig(Map<String, String> config) {
+        this.config = config;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return this.description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public List<PolicyRepresentation> getAssociatedPolicies() {
+        return associatedPolicies;
+    }
+
+    public void setAssociatedPolicies(List<PolicyRepresentation> associatedPolicies) {
+        this.associatedPolicies = associatedPolicies;
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        final PolicyRepresentation policy = (PolicyRepresentation) o;
+        return Objects.equals(getId(), policy.getId());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(getId());
+    }
+
+    public void setDependentPolicies(List<PolicyRepresentation> dependentPolicies) {
+        this.dependentPolicies = dependentPolicies;
+    }
+
+    public List<PolicyRepresentation> getDependentPolicies() {
+        return this.dependentPolicies;
+    }
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/ResourceOwnerRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/authorization/ResourceOwnerRepresentation.java
new file mode 100644
index 0000000..c058b9d
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/authorization/ResourceOwnerRepresentation.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.representations.idm.authorization;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ResourceOwnerRepresentation {
+
+    private String id;
+    private String name;
+
+    public String getId() {
+        return this.id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/ResourceRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/authorization/ResourceRepresentation.java
new file mode 100644
index 0000000..c89a2d6
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/authorization/ResourceRepresentation.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.representations.idm.authorization;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Predicate;
+
+/**
+ * <p>One or more resources that the resource server manages as a set of protected resources.
+ *
+ * <p>For more details, <a href="https://docs.kantarainitiative.org/uma/draft-oauth-resource-reg.html#rfc.section.2.2">OAuth-resource-reg</a>.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ResourceRepresentation {
+
+    @JsonProperty("_id")
+    private String id;
+
+    private String name;
+    private String uri;
+    private String type;
+    @JsonInclude(JsonInclude.Include.NON_EMPTY)
+    private Set<ScopeRepresentation> scopes;
+
+    @JsonProperty("icon_uri")
+    private String iconUri;
+    private ResourceOwnerRepresentation owner;
+
+    @JsonInclude(JsonInclude.Include.NON_EMPTY)
+    private List<PolicyRepresentation> policies;
+    private List<ScopeRepresentation> typedScopes;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param name a human-readable string describing a set of one or more resources
+     * @param uri a {@link URI} that provides the network location for the resource set being registered
+     * @param type a string uniquely identifying the semantics of the resource set
+     * @param scopes the available scopes for this resource set
+     * @param iconUri a {@link URI} for a graphic icon representing the resource set
+     */
+    public ResourceRepresentation(String name, Set<ScopeRepresentation> scopes, String uri, String type, String iconUri) {
+        this.name = name;
+        this.scopes = scopes;
+        this.uri = uri;
+        this.type = type;
+        this.iconUri = iconUri;
+    }
+
+    /**
+     * Creates a new instance.
+     *
+     * @param name a human-readable string describing a set of one or more resources
+     * @param uri a {@link URI} that provides the network location for the resource set being registered
+     * @param type a string uniquely identifying the semantics of the resource set
+     * @param scopes the available scopes for this resource set
+     */
+    public ResourceRepresentation(String name, Set<ScopeRepresentation> scopes, String uri, String type) {
+        this(name, scopes, uri, type, null);
+    }
+
+    /**
+     * Creates a new instance.
+     *
+     * @param name a human-readable string describing a set of one or more resources
+     * @param serverUri a {@link URI} that identifies this resource server
+     * @param scopes the available scopes for this resource set
+     */
+    public ResourceRepresentation(String name, Set<ScopeRepresentation> scopes) {
+        this(name, scopes, null, null, null);
+    }
+
+    /**
+     * Creates a new instance.
+     *
+     */
+    public ResourceRepresentation() {
+        this(null, null, null, null, null);
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getId() {
+        return this.id;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public String getUri() {
+        return this.uri;
+    }
+
+    public String getType() {
+        return this.type;
+    }
+
+    public Set<ScopeRepresentation> getScopes() {
+        if (this.scopes == null) {
+            return Collections.emptySet();
+        }
+
+        return Collections.unmodifiableSet(this.scopes);
+    }
+
+    public String getIconUri() {
+        return this.iconUri;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setUri(String uri) {
+        this.uri = uri;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public void setScopes(Set<ScopeRepresentation> scopes) {
+        this.scopes = scopes;
+    }
+
+    public void setIconUri(String iconUri) {
+        this.iconUri = iconUri;
+    }
+
+    public ResourceOwnerRepresentation getOwner() {
+        return this.owner;
+    }
+
+    public void setOwner(ResourceOwnerRepresentation owner) {
+        this.owner = owner;
+    }
+
+    public List<PolicyRepresentation> getPolicies() {
+        return this.policies;
+    }
+
+    public void setPolicies(List<PolicyRepresentation> policies) {
+        this.policies = policies;
+    }
+
+    <T> T test(Predicate<T> t) {
+        return null;
+    }
+
+    public void setTypedScopes(List<ScopeRepresentation> typedScopes) {
+        this.typedScopes = typedScopes;
+    }
+
+    public List<ScopeRepresentation> getTypedScopes() {
+        return typedScopes;
+    }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/ResourceServerRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/authorization/ResourceServerRepresentation.java
new file mode 100644
index 0000000..230cf76
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/authorization/ResourceServerRepresentation.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.representations.idm.authorization;
+
+import java.util.List;
+
+import static java.util.Collections.emptyList;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ResourceServerRepresentation {
+
+    private String id;
+
+    private String clientId;
+    private String name;
+    private boolean allowRemoteResourceManagement = true;
+    private PolicyEnforcementMode policyEnforcementMode = PolicyEnforcementMode.ENFORCING;
+    private List<ResourceRepresentation> resources = emptyList();
+    private List<PolicyRepresentation> policies = emptyList();
+    private List<ScopeRepresentation> scopes = emptyList();
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getId() {
+        return this.id;
+    }
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public boolean isAllowRemoteResourceManagement() {
+        return this.allowRemoteResourceManagement;
+    }
+
+    public void setAllowRemoteResourceManagement(boolean allowRemoteResourceManagement) {
+        this.allowRemoteResourceManagement = allowRemoteResourceManagement;
+    }
+
+    public PolicyEnforcementMode getPolicyEnforcementMode() {
+        return this.policyEnforcementMode;
+    }
+
+    public void setPolicyEnforcementMode(PolicyEnforcementMode policyEnforcementMode) {
+        this.policyEnforcementMode = policyEnforcementMode;
+    }
+
+    public void setResources(List<ResourceRepresentation> resources) {
+        this.resources = resources;
+    }
+
+    public List<ResourceRepresentation> getResources() {
+        return resources;
+    }
+
+    public void setPolicies(List<PolicyRepresentation> policies) {
+        this.policies = policies;
+    }
+
+    public List<PolicyRepresentation> getPolicies() {
+        return policies;
+    }
+
+    public void setScopes(List<ScopeRepresentation> scopes) {
+        this.scopes = scopes;
+    }
+
+    public List<ScopeRepresentation> getScopes() {
+        return scopes;
+    }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/authorization/ScopeRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/authorization/ScopeRepresentation.java
new file mode 100644
index 0000000..3a1f252
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/authorization/ScopeRepresentation.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.representations.idm.authorization;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * <p>A bounded extent of access that is possible to perform on a resource set. In authorization policy terminology,
+ * a scope is one of the potentially many "verbs" that can logically apply to a resource set ("object").
+ *
+ * <p>For more details, <a href="https://docs.kantarainitiative.org/uma/draft-oauth-resource-reg.html#rfc.section.2.1">OAuth-resource-reg</a>.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ScopeRepresentation {
+
+    private String id;
+    private String name;
+    private String iconUri;
+    private List<PolicyRepresentation> policies;
+    private List<ResourceRepresentation> resources;
+
+    /**
+     * Creates an instance.
+     *
+     * @param name the a human-readable string describing some scope (extent) of access
+     * @param iconUri a {@link URI} for a graphic icon representing the scope
+     */
+    public ScopeRepresentation(String name, String iconUri) {
+        this.name = name;
+        this.iconUri = iconUri;
+    }
+
+    /**
+     * Creates an instance.
+     *
+     * @param name the a human-readable string describing some scope (extent) of access
+     */
+    public ScopeRepresentation(String name) {
+        this(name, null);
+    }
+
+    /**
+     * Creates an instance.
+     */
+    public ScopeRepresentation() {
+        this(null, null);
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public String getIconUri() {
+        return this.iconUri;
+    }
+
+    public String getId() {
+        return this.id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setIconUri(String iconUri) {
+        this.iconUri = iconUri;
+    }
+
+    public List<PolicyRepresentation> getPolicies() {
+        return this.policies;
+    }
+
+    public void setPolicies(List<PolicyRepresentation> policies) {
+        this.policies = policies;
+    }
+
+    public List<ResourceRepresentation> getResources() {
+        return this.resources;
+    }
+
+    public void setResources(List<ResourceRepresentation> resources) {
+        this.resources = resources;
+    }
+
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        ScopeRepresentation scope = (ScopeRepresentation) o;
+        return Objects.equals(getName(), scope.getName());
+    }
+
+    public int hashCode() {
+        return Objects.hash(getName());
+    }
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/keycloak/representations/idm/CertificateRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/CertificateRepresentation.java
index ee8e102..03539ff 100755
--- a/core/src/main/java/org/keycloak/representations/idm/CertificateRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/CertificateRepresentation.java
@@ -25,6 +25,7 @@ package org.keycloak.representations.idm;
 public class CertificateRepresentation {
 
     protected String privateKey;
+    protected String publicKey;
     protected String certificate;
 
     public String getPrivateKey() {
@@ -35,6 +36,14 @@ public class CertificateRepresentation {
         this.privateKey = privateKey;
     }
 
+    public String getPublicKey() {
+        return publicKey;
+    }
+
+    public void setPublicKey(String publicKey) {
+        this.publicKey = publicKey;
+    }
+
     public String getCertificate() {
         return certificate;
     }
diff --git a/core/src/main/java/org/keycloak/representations/idm/ClientRegistrationTrustedHostRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ClientRegistrationTrustedHostRepresentation.java
new file mode 100644
index 0000000..1df7ab4
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/ClientRegistrationTrustedHostRepresentation.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.representations.idm;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ClientRegistrationTrustedHostRepresentation {
+
+    String hostName;
+    Integer count;
+    Integer remainingCount;
+
+    public static ClientRegistrationTrustedHostRepresentation create(String hostName, int count, int remainingCount) {
+        ClientRegistrationTrustedHostRepresentation rep = new ClientRegistrationTrustedHostRepresentation();
+        rep.setHostName(hostName);
+        rep.setCount(count);
+        rep.setRemainingCount(remainingCount);
+        return rep;
+    }
+
+    public String getHostName() {
+        return hostName;
+    }
+
+    public void setHostName(String hostName) {
+        this.hostName = hostName;
+    }
+
+    public Integer getCount() {
+        return count;
+    }
+
+    public void setCount(Integer count) {
+        this.count = count;
+    }
+
+    public Integer getRemainingCount() {
+        return remainingCount;
+    }
+
+    public void setRemainingCount(Integer remainingCount) {
+        this.remainingCount = remainingCount;
+    }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java
index a5b3802..cc9e54b 100755
--- a/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/ClientRepresentation.java
@@ -17,6 +17,8 @@
 
 package org.keycloak.representations.idm;
 
+import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
+
 import java.util.List;
 import java.util.Map;
 
@@ -47,6 +49,7 @@ public class ClientRepresentation {
     protected Boolean implicitFlowEnabled;
     protected Boolean directAccessGrantsEnabled;
     protected Boolean serviceAccountsEnabled;
+    protected Boolean authorizationServicesEnabled;
     @Deprecated
     protected Boolean directGrantsOnly;
     protected Boolean publicClient;
@@ -61,6 +64,7 @@ public class ClientRepresentation {
     private Boolean useTemplateConfig;
     private Boolean useTemplateScope;
     private Boolean useTemplateMappers;
+    private ResourceServerRepresentation authorizationSettings;
 
 
     public String getId() {
@@ -239,6 +243,17 @@ public class ClientRepresentation {
         this.serviceAccountsEnabled = serviceAccountsEnabled;
     }
 
+    public Boolean getAuthorizationServicesEnabled() {
+        if (authorizationSettings != null) {
+            return true;
+        }
+        return authorizationServicesEnabled;
+    }
+
+    public void setAuthorizationServicesEnabled(Boolean authorizationServicesEnabled) {
+        this.authorizationServicesEnabled = authorizationServicesEnabled;
+    }
+
     @Deprecated
     public Boolean isDirectGrantsOnly() {
         return directGrantsOnly;
@@ -344,4 +359,11 @@ public class ClientRepresentation {
         this.useTemplateMappers = useTemplateMappers;
     }
 
+    public ResourceServerRepresentation getAuthorizationSettings() {
+        return authorizationSettings;
+    }
+
+    public void setAuthorizationSettings(ResourceServerRepresentation authorizationSettings) {
+        this.authorizationSettings = authorizationSettings;
+    }
 }
diff --git a/core/src/main/java/org/keycloak/representations/idm/ComponentExportRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ComponentExportRepresentation.java
new file mode 100755
index 0000000..7f834c3
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/ComponentExportRepresentation.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.representations.idm;
+
+import org.keycloak.common.util.MultivaluedHashMap;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ComponentExportRepresentation {
+
+    private String id;
+    private String name;
+    private String providerId;
+    private MultivaluedHashMap<String, ComponentExportRepresentation> subComponents = new MultivaluedHashMap<>();
+    private MultivaluedHashMap<String, String> config = new MultivaluedHashMap<>();
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getProviderId() {
+        return providerId;
+    }
+
+    public void setProviderId(String providerId) {
+        this.providerId = providerId;
+    }
+
+    public MultivaluedHashMap<String, String> getConfig() {
+        return config;
+    }
+
+    public void setConfig(MultivaluedHashMap<String, String> config) {
+        this.config = config;
+    }
+
+    public MultivaluedHashMap<String, ComponentExportRepresentation> getSubComponents() {
+        return subComponents;
+    }
+
+    public void setSubComponents(MultivaluedHashMap<String, ComponentExportRepresentation> subComponents) {
+        this.subComponents = subComponents;
+    }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/ComponentRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ComponentRepresentation.java
new file mode 100755
index 0000000..bbc4a42
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/ComponentRepresentation.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.representations.idm;
+
+import org.keycloak.common.util.MultivaluedHashMap;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ComponentRepresentation {
+
+    private String id;
+    private String name;
+    private String providerId;
+    private String providerType;
+    private String parentId;
+    private MultivaluedHashMap<String, String> config;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getProviderId() {
+        return providerId;
+    }
+
+    public void setProviderId(String providerId) {
+        this.providerId = providerId;
+    }
+
+    public String getProviderType() {
+        return providerType;
+    }
+
+    public void setProviderType(String providerType) {
+        this.providerType = providerType;
+    }
+
+    public String getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(String parentId) {
+        this.parentId = parentId;
+    }
+
+    public MultivaluedHashMap<String, String> getConfig() {
+        return config;
+    }
+
+    public void setConfig(MultivaluedHashMap<String, String> config) {
+        this.config = config;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        ComponentRepresentation that = (ComponentRepresentation) o;
+
+        if (!id.equals(that.id)) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return id.hashCode();
+    }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/ComponentTypeRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ComponentTypeRepresentation.java
new file mode 100644
index 0000000..8ba0da6
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/ComponentTypeRepresentation.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.representations.idm;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ComponentTypeRepresentation {
+    protected String id;
+    protected String helpText;
+    protected List<ConfigPropertyRepresentation> properties;
+
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getHelpText() {
+        return helpText;
+    }
+
+    public void setHelpText(String helpText) {
+        this.helpText = helpText;
+    }
+
+    public List<ConfigPropertyRepresentation> getProperties() {
+        return properties;
+    }
+
+    public void setProperties(List<ConfigPropertyRepresentation> properties) {
+        this.properties = properties;
+    }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/OAuth2ErrorRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/OAuth2ErrorRepresentation.java
new file mode 100644
index 0000000..f988013
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/OAuth2ErrorRepresentation.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.representations.idm;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.keycloak.OAuth2Constants;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OAuth2ErrorRepresentation {
+
+    private String error;
+    private String errorDescription;
+
+    public OAuth2ErrorRepresentation() {
+    }
+
+    public OAuth2ErrorRepresentation(String error, String errorDescription) {
+        this.error = error;
+        this.errorDescription = errorDescription;
+    }
+
+    @JsonProperty(OAuth2Constants.ERROR)
+    public String getError() {
+        return error;
+    }
+
+    public void setError(String error) {
+        this.error = error;
+    }
+
+    @JsonProperty(OAuth2Constants.ERROR_DESCRIPTION)
+    public String getErrorDescription() {
+        return errorDescription;
+    }
+
+    public void setErrorDescription(String errorDescription) {
+        this.errorDescription = errorDescription;
+    }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/PasswordPolicyTypeRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/PasswordPolicyTypeRepresentation.java
new file mode 100644
index 0000000..5a5a1f9
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/PasswordPolicyTypeRepresentation.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.representations.idm;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class PasswordPolicyTypeRepresentation {
+
+    private String id;
+    private String displayName;
+    private String configType;
+    private String defaultValue;
+    private boolean multipleSupported;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getDisplayName() {
+        return displayName;
+    }
+
+    public void setDisplayName(String displayName) {
+        this.displayName = displayName;
+    }
+
+    public String getConfigType() {
+        return configType;
+    }
+
+    public void setConfigType(String configType) {
+        this.configType = configType;
+    }
+
+    public String getDefaultValue() {
+        return defaultValue;
+    }
+
+    public void setDefaultValue(String defaultValue) {
+        this.defaultValue = defaultValue;
+    }
+
+    public boolean isMultipleSupported() {
+        return multipleSupported;
+    }
+
+    public void setMultipleSupported(boolean multipleSupported) {
+        this.multipleSupported = multipleSupported;
+    }
+}
diff --git a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
index cb6aa32..67c1678 100755
--- a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
@@ -18,6 +18,7 @@
 package org.keycloak.representations.idm;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.keycloak.common.util.MultivaluedHashMap;
 
 import java.util.*;
 
@@ -109,6 +110,7 @@ public class RealmRepresentation {
     private List<IdentityProviderRepresentation> identityProviders;
     private List<IdentityProviderMapperRepresentation> identityProviderMappers;
     private List<ProtocolMapperRepresentation> protocolMappers;
+    private MultivaluedHashMap<String, ComponentExportRepresentation> components;
     protected Boolean internationalizationEnabled;
     protected Set<String> supportedLocales;
     protected String defaultLocale;
@@ -849,6 +851,14 @@ public class RealmRepresentation {
         this.clientTemplates = clientTemplates;
     }
 
+    public MultivaluedHashMap<String, ComponentExportRepresentation> getComponents() {
+        return components;
+    }
+
+    public void setComponents(MultivaluedHashMap<String, ComponentExportRepresentation> components) {
+        this.components = components;
+    }
+
     @JsonIgnore
     public boolean isIdentityFederationEnabled() {
         return identityProviders != null && !identityProviders.isEmpty();
diff --git a/core/src/main/java/org/keycloak/representations/idm/RoleRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RoleRepresentation.java
index e9b470a..9614ca3 100755
--- a/core/src/main/java/org/keycloak/representations/idm/RoleRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/RoleRepresentation.java
@@ -32,6 +32,8 @@ public class RoleRepresentation {
     protected Boolean scopeParamRequired;
     protected boolean composite;
     protected Composites composites;
+    private Boolean clientRole;
+    private String containerId;
 
     public static class Composites {
         protected Set<String> realm;
@@ -122,4 +124,20 @@ public class RoleRepresentation {
     public void setComposite(boolean composite) {
         this.composite = composite;
     }
+
+    public Boolean getClientRole() {
+        return clientRole;
+    }
+
+    public void setClientRole(Boolean clientRole) {
+        this.clientRole = clientRole;
+    }
+
+    public String getContainerId() {
+        return containerId;
+    }
+
+    public void setContainerId(String containerId) {
+        this.containerId = containerId;
+    }
 }
diff --git a/core/src/main/java/org/keycloak/representations/idm/StorageProviderRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/StorageProviderRepresentation.java
new file mode 100755
index 0000000..04bf174
--- /dev/null
+++ b/core/src/main/java/org/keycloak/representations/idm/StorageProviderRepresentation.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.representations.idm;
+
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class StorageProviderRepresentation {
+
+    private String id;
+    private String displayName;
+    private String providerName;
+    private Map<String, String> config;
+    private int priority;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getDisplayName() {
+        return displayName;
+    }
+
+    public void setDisplayName(String displayName) {
+        this.displayName = displayName;
+    }
+
+    public String getProviderName() {
+        return providerName;
+    }
+
+    public void setProviderName(String providerName) {
+        this.providerName = providerName;
+    }
+
+
+    public Map<String, String> getConfig() {
+        return config;
+    }
+
+    public void setConfig(Map<String, String> config) {
+        this.config = config;
+    }
+
+    public int getPriority() {
+        return priority;
+    }
+
+    public void setPriority(int priority) {
+        this.priority = priority;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        StorageProviderRepresentation that = (StorageProviderRepresentation) o;
+
+        if (!id.equals(that.id)) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return id.hashCode();
+    }
+}
diff --git a/core/src/main/java/org/keycloak/representations/IDToken.java b/core/src/main/java/org/keycloak/representations/IDToken.java
index f11b866..51776f0 100755
--- a/core/src/main/java/org/keycloak/representations/IDToken.java
+++ b/core/src/main/java/org/keycloak/representations/IDToken.java
@@ -25,7 +25,10 @@ import com.fasterxml.jackson.annotation.JsonProperty;
  */
 public class IDToken extends JsonWebToken {
     public static final String NONCE = "nonce";
+    public static final String AUTH_TIME = "auth_time";
     public static final String SESSION_STATE = "session_state";
+    public static final String AT_HASH = "at_hash";
+    public static final String C_HASH = "c_hash";
     public static final String NAME = "name";
     public static final String GIVEN_NAME = "given_name";
     public static final String FAMILY_NAME = "family_name";
@@ -46,14 +49,25 @@ public class IDToken extends JsonWebToken {
     public static final String ADDRESS = "address";
     public static final String UPDATED_AT = "updated_at";
     public static final String CLAIMS_LOCALES = "claims_locales";
+    public static final String ACR = "acr";
+
     // NOTE!!!  WE used to use @JsonUnwrapped on a UserClaimSet object.  This screws up otherClaims and the won't work
     // anymore.  So don't have any @JsonUnwrapped!
     @JsonProperty(NONCE)
     protected String nonce;
 
+    @JsonProperty(AUTH_TIME)
+    protected int authTime;
+
     @JsonProperty(SESSION_STATE)
     protected String sessionState;
 
+    @JsonProperty(AT_HASH)
+    protected String accessTokenHash;
+
+    @JsonProperty(C_HASH)
+    protected String codeHash;
+
     @JsonProperty(NAME)
     protected String name;
 
@@ -114,6 +128,9 @@ public class IDToken extends JsonWebToken {
     @JsonProperty(CLAIMS_LOCALES)
     protected String claimsLocales;
 
+    @JsonProperty(ACR)
+    protected String acr;
+
     public String getNonce() {
         return nonce;
     }
@@ -122,6 +139,14 @@ public class IDToken extends JsonWebToken {
         this.nonce = nonce;
     }
 
+    public int getAuthTime() {
+        return authTime;
+    }
+
+    public void setAuthTime(int authTime) {
+        this.authTime = authTime;
+    }
+
     public String getSessionState() {
         return sessionState;
     }
@@ -130,6 +155,22 @@ public class IDToken extends JsonWebToken {
         this.sessionState = sessionState;
     }
 
+    public String getAccessTokenHash() {
+        return accessTokenHash;
+    }
+
+    public void setAccessTokenHash(String accessTokenHash) {
+        this.accessTokenHash = accessTokenHash;
+    }
+
+    public String getCodeHash() {
+        return codeHash;
+    }
+
+    public void setCodeHash(String codeHash) {
+        this.codeHash = codeHash;
+    }
+
     public String getName() {
         return this.name;
     }
@@ -290,4 +331,11 @@ public class IDToken extends JsonWebToken {
         this.claimsLocales = claimsLocales;
     }
 
+    public String getAcr() {
+        return acr;
+    }
+
+    public void setAcr(String acr) {
+        this.acr = acr;
+    }
 }
diff --git a/core/src/main/java/org/keycloak/representations/info/ServerInfoRepresentation.java b/core/src/main/java/org/keycloak/representations/info/ServerInfoRepresentation.java
index 5510bb2..59d400e 100755
--- a/core/src/main/java/org/keycloak/representations/info/ServerInfoRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/info/ServerInfoRepresentation.java
@@ -17,6 +17,8 @@
 
 package org.keycloak.representations.info;
 
+import org.keycloak.representations.idm.ComponentTypeRepresentation;
+import org.keycloak.representations.idm.PasswordPolicyTypeRepresentation;
 import org.keycloak.representations.idm.ProtocolMapperRepresentation;
 import org.keycloak.representations.idm.ProtocolMapperTypeRepresentation;
 
@@ -42,6 +44,9 @@ public class ServerInfoRepresentation {
     private Map<String, List<ProtocolMapperTypeRepresentation>> protocolMapperTypes;
     private Map<String, List<ProtocolMapperRepresentation>> builtinProtocolMappers;
     private Map<String, List<ClientInstallationRepresentation>> clientInstallations;
+    private Map<String, List<ComponentTypeRepresentation>> componentTypes;
+
+    private List<PasswordPolicyTypeRepresentation> passwordPolicies;
 
     private Map<String, List<String>> enums;
 
@@ -132,4 +137,20 @@ public class ServerInfoRepresentation {
     public void setClientInstallations(Map<String, List<ClientInstallationRepresentation>> clientInstallations) {
         this.clientInstallations = clientInstallations;
     }
+
+    public List<PasswordPolicyTypeRepresentation> getPasswordPolicies() {
+        return passwordPolicies;
+    }
+
+    public void setPasswordPolicies(List<PasswordPolicyTypeRepresentation> passwordPolicies) {
+        this.passwordPolicies = passwordPolicies;
+    }
+
+    public Map<String, List<ComponentTypeRepresentation>> getComponentTypes() {
+        return componentTypes;
+    }
+
+    public void setComponentTypes(Map<String, List<ComponentTypeRepresentation>> componentTypes) {
+        this.componentTypes = componentTypes;
+    }
 }
diff --git a/core/src/main/java/org/keycloak/representations/oidc/OIDCClientRepresentation.java b/core/src/main/java/org/keycloak/representations/oidc/OIDCClientRepresentation.java
index fc2973d..d7f9939 100644
--- a/core/src/main/java/org/keycloak/representations/oidc/OIDCClientRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/oidc/OIDCClientRepresentation.java
@@ -18,6 +18,7 @@
 package org.keycloak.representations.oidc;
 
 import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import org.keycloak.jose.jwk.JSONWebKeySet;
 
 import java.util.List;
 
@@ -27,14 +28,20 @@ import java.util.List;
 @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
 public class OIDCClientRepresentation {
 
+    // OIDC Dynamic client registration properties
+
     private List<String> redirect_uris;
 
     private String token_endpoint_auth_method;
 
+    private String token_endpoint_auth_signing_alg;
+
     private List<String> grant_types;
 
     private List<String> response_types;
 
+    private String application_type;
+
     private String client_id;
 
     private String client_secret;
@@ -47,7 +54,7 @@ public class OIDCClientRepresentation {
 
     private String scope;
 
-    private String contacts;
+    private List<String> contacts;
 
     private String tos_uri;
 
@@ -55,12 +62,49 @@ public class OIDCClientRepresentation {
 
     private String jwks_uri;
 
-    private String jwks;
+    private JSONWebKeySet jwks;
+
+    private String sector_identifier_uri;
+
+    private String subject_type;
+
+    private String id_token_signed_response_alg;
+
+    private String id_token_encrypted_response_alg;
+
+    private String id_token_encrypted_response_enc;
+
+    private String userinfo_signed_response_alg;
+
+    private String userinfo_encrypted_response_alg;
+
+    private String userinfo_encrypted_response_enc;
+
+    private String request_object_signing_alg;
 
+    private String request_object_encryption_alg;
+
+    private String request_object_encryption_enc;
+
+    private Integer default_max_age;
+
+    private Boolean require_auth_time;
+
+    private List<String> default_acr_values;
+
+    private String initiate_login_uri;
+
+    private List<String> request_uris;
+
+    // OIDC Session Management
+    private List<String> post_logout_redirect_uris;
+
+    // Not sure from which specs this comes
     private String software_id;
 
     private String software_version;
 
+    // OIDC Dynamic Client Registration Response
     private Integer client_id_issued_at;
 
     private Integer client_secret_expires_at;
@@ -85,6 +129,14 @@ public class OIDCClientRepresentation {
         this.token_endpoint_auth_method = token_endpoint_auth_method;
     }
 
+    public String getTokenEndpointAuthSigningAlg() {
+        return token_endpoint_auth_signing_alg;
+    }
+
+    public void setTokenEndpointAuthSigningAlg(String token_endpoint_auth_signing_alg) {
+        this.token_endpoint_auth_signing_alg = token_endpoint_auth_signing_alg;
+    }
+
     public List<String> getGrantTypes() {
         return grant_types;
     }
@@ -101,6 +153,14 @@ public class OIDCClientRepresentation {
         this.response_types = responseTypes;
     }
 
+    public String getApplicationType() {
+        return application_type;
+    }
+
+    public void setApplicationType(String applicationType) {
+        this.application_type = applicationType;
+    }
+
     public String getClientId() {
         return client_id;
     }
@@ -149,11 +209,11 @@ public class OIDCClientRepresentation {
         this.scope = scope;
     }
 
-    public String getContacts() {
+    public List<String> getContacts() {
         return contacts;
     }
 
-    public void setContacts(String contacts) {
+    public void setContacts(List<String> contacts) {
         this.contacts = contacts;
     }
 
@@ -181,14 +241,150 @@ public class OIDCClientRepresentation {
         this.jwks_uri = jwks_uri;
     }
 
-    public String getJwks() {
+    public JSONWebKeySet getJwks() {
         return jwks;
     }
 
-    public void setJwks(String jwks) {
+    public void setJwks(JSONWebKeySet jwks) {
         this.jwks = jwks;
     }
 
+    public String getSectorIdentifierUri() {
+        return sector_identifier_uri;
+    }
+
+    public void setSectorIdentifierUri(String sectorIdentifierUri) {
+        this.sector_identifier_uri = sectorIdentifierUri;
+    }
+
+    public String getSubjectType() {
+        return subject_type;
+    }
+
+    public void setSubjectType(String subjectType) {
+        this.subject_type = subjectType;
+    }
+
+    public String getIdTokenSignedResponseAlg() {
+        return id_token_signed_response_alg;
+    }
+
+    public void setIdTokenSignedResponseAlg(String idTokenSignedResponseAlg) {
+        this.id_token_signed_response_alg = idTokenSignedResponseAlg;
+    }
+
+    public String getIdTokenEncryptedResponseAlg() {
+        return id_token_encrypted_response_alg;
+    }
+
+    public void setIdTokenEncryptedResponseAlg(String idTokenEncryptedResponseAlg) {
+        this.id_token_encrypted_response_alg = idTokenEncryptedResponseAlg;
+    }
+
+    public String getIdTokenEncryptedResponseEnc() {
+        return id_token_encrypted_response_enc;
+    }
+
+    public void setIdTokenEncryptedResponseEnc(String idTokenEncryptedResponseEnc) {
+        this.id_token_encrypted_response_enc = idTokenEncryptedResponseEnc;
+    }
+
+    public String getUserinfoSignedResponseAlg() {
+        return userinfo_signed_response_alg;
+    }
+
+    public void setUserinfoSignedResponseAlg(String userinfo_signed_response_alg) {
+        this.userinfo_signed_response_alg = userinfo_signed_response_alg;
+    }
+
+    public String getUserinfoEncryptedResponseAlg() {
+        return userinfo_encrypted_response_alg;
+    }
+
+    public void setUserinfoEncryptedResponseAlg(String userinfo_encrypted_response_alg) {
+        this.userinfo_encrypted_response_alg = userinfo_encrypted_response_alg;
+    }
+
+    public String getUserinfoEncryptedResponseEnc() {
+        return userinfo_encrypted_response_enc;
+    }
+
+    public void setUserinfoEncryptedResponseEnc(String userinfo_encrypted_response_enc) {
+        this.userinfo_encrypted_response_enc = userinfo_encrypted_response_enc;
+    }
+
+    public String getRequestObjectSigningAlg() {
+        return request_object_signing_alg;
+    }
+
+    public void setRequestObjectSigningAlg(String request_object_signing_alg) {
+        this.request_object_signing_alg = request_object_signing_alg;
+    }
+
+    public String getRequestObjectEncryptionAlg() {
+        return request_object_encryption_alg;
+    }
+
+    public void setRequestObjectEncryptionAlg(String request_object_encryption_alg) {
+        this.request_object_encryption_alg = request_object_encryption_alg;
+    }
+
+    public String getRequestObjectEncryptionEnc() {
+        return request_object_encryption_enc;
+    }
+
+    public void setRequestObjectEncryptionEnc(String request_object_encryption_enc) {
+        this.request_object_encryption_enc = request_object_encryption_enc;
+    }
+
+    public Integer getDefaultMaxAge() {
+        return default_max_age;
+    }
+
+    public void setDefaultMaxAge(Integer default_max_age) {
+        this.default_max_age = default_max_age;
+    }
+
+    public Boolean getRequireAuthTime() {
+        return require_auth_time;
+    }
+
+    public void setRequireAuthTime(Boolean require_auth_time) {
+        this.require_auth_time = require_auth_time;
+    }
+
+    public List<String> getDefaultAcrValues() {
+        return default_acr_values;
+    }
+
+    public void setDefaultAcrValues(List<String> default_acr_values) {
+        this.default_acr_values = default_acr_values;
+    }
+
+    public String getInitiateLoginUri() {
+        return initiate_login_uri;
+    }
+
+    public void setInitiateLoginUri(String initiate_login_uri) {
+        this.initiate_login_uri = initiate_login_uri;
+    }
+
+    public List<String> getRequestUris() {
+        return request_uris;
+    }
+
+    public void setRequestUris(List<String> requestUris) {
+        this.request_uris = requestUris;
+    }
+
+    public List<String> getPostLogoutRedirectUris() {
+        return post_logout_redirect_uris;
+    }
+
+    public void setPostLogoutRedirectUris(List<String> post_logout_redirect_uris) {
+        this.post_logout_redirect_uris = post_logout_redirect_uris;
+    }
+
     public String getSoftwareId() {
         return software_id;
     }
diff --git a/core/src/main/java/org/keycloak/util/TokenUtil.java b/core/src/main/java/org/keycloak/util/TokenUtil.java
index eb28943..f649b5e 100644
--- a/core/src/main/java/org/keycloak/util/TokenUtil.java
+++ b/core/src/main/java/org/keycloak/util/TokenUtil.java
@@ -38,14 +38,45 @@ public class TokenUtil {
     public static final String TOKEN_TYPE_OFFLINE = "Offline";
 
 
+    public static String attachOIDCScope(String scopeParam) {
+        if (scopeParam == null || scopeParam.isEmpty()) {
+            return OAuth2Constants.SCOPE_OPENID;
+        } else {
+            return OAuth2Constants.SCOPE_OPENID + " " + scopeParam;
+        }
+    }
+
+    public static boolean isOIDCRequest(String scopeParam) {
+        return hasScope(scopeParam, OAuth2Constants.SCOPE_OPENID);
+    }
+
     public static boolean isOfflineTokenRequested(String scopeParam) {
-        if (scopeParam == null) {
+        return hasScope(scopeParam, OAuth2Constants.OFFLINE_ACCESS);
+    }
+
+    public static boolean hasScope(String scopeParam, String targetScope) {
+        if (scopeParam == null || targetScope == null) {
             return false;
         }
 
         String[] scopes = scopeParam.split(" ");
         for (String scope : scopes) {
-            if (OAuth2Constants.OFFLINE_ACCESS.equals(scope)) {
+            if (targetScope.equals(scope)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    public static boolean hasPrompt(String promptParam, String targetPrompt) {
+        if (promptParam == null || targetPrompt == null) {
+            return false;
+        }
+
+        String[] prompts = promptParam.split(" ");
+        for (String prompt : prompts) {
+            if (targetPrompt.equals(prompt)) {
                 return true;
             }
         }
@@ -53,6 +84,7 @@ public class TokenUtil {
     }
 
 
+
     /**
      * Return refresh token or offline token
      *
diff --git a/core/src/test/java/org/keycloak/AtHashTest.java b/core/src/test/java/org/keycloak/AtHashTest.java
new file mode 100644
index 0000000..7015e7a
--- /dev/null
+++ b/core/src/test/java/org/keycloak/AtHashTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak;
+
+import java.security.Security;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.junit.Assert;
+import org.junit.Test;
+import org.keycloak.jose.jws.Algorithm;
+import org.keycloak.jose.jws.crypto.HashProvider;
+
+/**
+ * See "at_hash" in OIDC specification
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class AtHashTest {
+
+    static {
+        if (Security.getProvider("BC") == null) Security.addProvider(new BouncyCastleProvider());
+    }
+
+    @Test
+    public void testAtHash() throws Exception {
+        verifyHash("jHkWEdUXMU1BwAsC4vtUsZwnNvTIxEl0z9K3vx5KF0Y", "77QmUPtjPfzWtF2AnpK9RQ");
+        verifyHash("ya29.eQETFbFOkAs8nWHcmYXKwEi0Zz46NfsrUU_KuQLOLTwWS40y6Fb99aVzEXC0U14m61lcPMIr1hEIBA", "aUAkJG-u6x4RTWuILWy-CA");
+    }
+
+    private void verifyHash(String accessToken, String expectedAtHash) {
+        String atHash = HashProvider.oidcHash(Algorithm.RS256, accessToken);
+        Assert.assertEquals(expectedAtHash, atHash);
+    }
+}
diff --git a/core/src/test/java/org/keycloak/JsonParserTest.java b/core/src/test/java/org/keycloak/JsonParserTest.java
index 69416b7..e346fe6 100755
--- a/core/src/test/java/org/keycloak/JsonParserTest.java
+++ b/core/src/test/java/org/keycloak/JsonParserTest.java
@@ -33,6 +33,7 @@ import org.junit.Test;
 import org.keycloak.representations.IDToken;
 import org.keycloak.representations.JsonWebToken;
 import org.keycloak.representations.adapters.config.AdapterConfig;
+import org.keycloak.representations.oidc.OIDCClientRepresentation;
 import org.keycloak.util.JsonSerialization;
 
 /**
@@ -125,4 +126,23 @@ public class JsonParserTest {
         System.out.println(sb.toString());
     }
 
+    @Test
+    public void testReadOIDCClientRep() throws IOException {
+        String stringRep = "{\"subject_type\": \"public\", \"jwks_uri\": \"https://op.certification.openid.net:60720/export/jwk_60720.json\", \"contacts\": [\"roland.hedberg@umu.se\"], \"application_type\": \"web\", \"grant_types\": [\"authorization_code\"], \"post_logout_redirect_uris\": [\"https://op.certification.openid.net:60720/logout\"], \"redirect_uris\": [\"https://op.certification.openid.net:60720/authz_cb\"], \"response_types\": [\"code\"], \"require_auth_time\": true, \"default_max_age\": 3600}";
+        OIDCClientRepresentation clientRep = JsonSerialization.readValue(stringRep, OIDCClientRepresentation.class);
+        Assert.assertEquals("public", clientRep.getSubjectType());
+        Assert.assertTrue(clientRep.getRequireAuthTime());
+        Assert.assertEquals(3600, clientRep.getDefaultMaxAge().intValue());
+        Assert.assertEquals(1, clientRep.getRedirectUris().size());
+        Assert.assertEquals("https://op.certification.openid.net:60720/authz_cb", clientRep.getRedirectUris().get(0));
+        Assert.assertNull(clientRep.getJwks());
+    }
+
+    @Test
+    public void testReadOIDCClientRepWithJWKS() throws IOException {
+        String stringRep = "{\"token_endpoint_auth_method\": \"private_key_jwt\", \"subject_type\": \"public\", \"jwks_uri\": null, \"jwks\": {\"keys\": [{\"use\": \"enc\", \"e\": \"AQAB\", \"d\": \"lZQv0_81euRLeUYU84Aodh0ar7ymDlzWP5NMra4Jklkb-lTBWkI-u4RMsPqGYyW3KHRoL_pgzZXSzQx8RLQfER6timRWb--NxMMKllZubByU3RqH2ooNuocJurspYiXkznPW1Mg9DaNXL0C2hwWPQHTeUVISpjgi5TCOV1ccWVyksFruya_VNL1CIByB-L0GL1rqbKv32cDwi2A3_jJa61cpzfLSIBe-lvCO6tuiDsR4qgJnUwnndQFwEI_4mLmD3iNWXrc8N-poleV8mBfMqBB5fWwy_ZTFCpmQ5AywGmctaik_wNhMoWuA4tUfY6_1LdKld-5Cjq55eLtuJjtvuQ\", \"n\": \"tx3Hjdbc19lkTiohbJrNj4jf2_90MEE122CRrwtFu6saDywKcG7Bi7w2FMAK2oTkuWfqhWRb5BEGmnSXdiCEPO5d-ytqP3nwlZXHaCDYscpP8bB4YLhvCn7R8Efw6gwQle24QPRP3lYoFeuUbDUq7GKA5SfaZUvWoeWjqyLIaBspKQsC26_Umx1E4IXLrMSL6nkRnrYcVZBAXrYCeTP1XtsV38_lZVJfHSaJaUy4PKaj3yvgm93EV2CXybPti7CCMXZ34VqqWiF64pQjZsPu3ZTr7ha_TTQq499-zYRQNDvIVsBDLQQIgrbctuGqj6lrXb31Jj3JIEYqH_4h5X9d0Q\", \"q\": \"1q-r-bmMFbIzrLK2U3elksZq8CqUqZxlSfkGMZuVkxgYMS-e4FPzEp2iirG-eO11aa0cpMMoBdTnVdGJ_ZUR93w0lGf9XnQAJqxP7eOsrUoiW4VWlWH4WfOiLgpO-pFtyTz_JksYYaotc_Z3Zy-Szw6a39IDbuYGy1qL-15oQuc\", \"p\": \"2lrYPppRbcQWu4LtWN6tOVUrtCOPv1eLTKTc7q8vCMcem1Ox5QFB7KnUtNZ5Ni7wnZUeVDfimNebtjNsGvDSrpgIlo9dEnFBQsQIkzZ2SkoYfgmF8hNdi6P-BfRjdgYouy4c6xAnGDgSMTip1YnPRyvbMaoYT9E_tEcBW5wOeoc\", \"kid\": \"a0\", \"kty\": \"RSA\"}, {\"use\": \"sig\", \"e\": \"AQAB\", \"d\": \"DodXDEtkovWWGsMEXYy_nEEMCWyROMOebCnCv0ey3i4M4bh2dmwqgz0e-IKQAFlGiMkidGL1lNbq0uFS04FbuRAR06dYw1cbrNbDdhrWFxKTd1L5D9p-x-gW-YDWhpI8rUGRa76JXkOSxZUbg09_QyUd99CXAHh-FXi_ZkIKD8hK6FrAs68qhLf8MNkUv63DTduw7QgeFfQivdopePxyGuMk5n8veqwsUZsklQkhNlTYQqeM1xb2698ZQcNYkl0OssEsSJKRjXt-LRPowKrdvTuTo2p--HMI0pIEeFs7H_u5OW3jihjvoFClGPynHQhgWmQzlQRvWRXh6FhDVqFeGQ\", \"n\": \"zfZzttF7HmnTYwSMPdxKs5AoczbNS2mOPz-tN1g4ljqI_F1DG8cgQDcN_VDufxoFGRERo2FK6WEN41LhbGEyP6uL6wW6Cy29qE9QZcvY5mXrncndRSOkNcMizvuEJes_fMYrmP_lPiC6kWiqItTk9QBWqJfiYKhCx9cSDXsBmJXn3KWQCVHvj1ANFWW0CWLMKlWN-_NMNLIWJN_pEAocTZMzxSFBK1b5_5J8ZS7hfWRF6MQmjsJcz2jzA21SQZNpre3kwnTGRSwo05sAS-TyeadDqQPWgbqX69UzcGq5irhzN8cpZ_JaTk3Y_uV6owanTZLVvCgdjaAnMYeZhb0KFw\", \"q\": \"5E5XKK5njT-zzRqqTeY2tgP9PJBACeaH_xQRHZ_1ydE7tVd7HdgdaEHfQ1jvKIHFkknWWOBAY1mlBc4YDirLShB_voShD8C-Hx3nF5sne5fleVfU-sZy6Za4B2U75PcE62oZgCPauOTAEm9Xuvrt5aMMovyzR8ecJZhm9bw7naU\", \"p\": \"5vJHCSM3H3q4RltYzENC9RyZZV8EUmpkv9moyguT5t-BUGA-T4W_FGIxzOPXRWOckIplKkoDKhavUeNmTZMCUcue0nkICSJpvNE4Nb2p5PZk_QqSdQNvCasQtdojEG0AmfVD85SU551CYxJdLdDFOqyK2entpMr8lhokem189As\", \"kid\": \"a1\", \"kty\": \"RSA\"}, {\"d\": \"S4_OufhLBgXFMgIDMI1zlVe2uCExpcEAQ80J_lXfS8I\", \"use\": \"sig\", \"crv\": \"P-256\", \"kty\": \"EC\", \"y\": \"DBdNyq30mXmUs_BIvKMqaTTNO7HDhCi0YiC8GciwNYk\", \"x\": \"cYwzBoyjRjxj334bRTqanONf7DUYK-6TgiuN0DixJAk\", \"kid\": \"a2\"}, {\"d\": \"33TnYgdJtWAiVosKqUnz0zSmvWTbsx5-6pceynW6Xck\", \"use\": \"enc\", \"crv\": \"P-256\", \"kty\": \"EC\", \"y\": \"Cula95Eix1Ia77St3OULe6-UKWs5I06nmdfUzhXUQTs\", \"x\": \"wk8HBVxNNzj1gJBxPmmx9XYW1L61ObBGzxpRa6_OqWU\", \"kid\": \"a3\"}]}, \"application_type\": \"web\", \"contacts\": [\"roland.hedberg@umu.se\"], \"post_logout_redirect_uris\": [\"https://op.certification.openid.net:60784/logout\"], \"redirect_uris\": [\"https://op.certification.openid.net:60784/authz_cb\"], \"response_types\": [\"code\"], \"require_auth_time\": true, \"grant_types\": [\"authorization_code\"], \"default_max_age\": 3600}";
+        OIDCClientRepresentation clientRep = JsonSerialization.readValue(stringRep, OIDCClientRepresentation.class);
+        Assert.assertNotNull(clientRep.getJwks());
+    }
+
 }
diff --git a/dependencies/pom.xml b/dependencies/pom.xml
index 622b1e0..336562c 100755
--- a/dependencies/pom.xml
+++ b/dependencies/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/dependencies/server-all/pom.xml b/dependencies/server-all/pom.xml
index 75bda3e..809890a 100755
--- a/dependencies/server-all/pom.xml
+++ b/dependencies/server-all/pom.xml
@@ -21,7 +21,7 @@
 	<parent>
 		<artifactId>keycloak-parent</artifactId>
 		<groupId>org.keycloak</groupId>
-		<version>2.0.0.CR1-SNAPSHOT</version>
+		<version>2.2.0-SNAPSHOT</version>
 		<relativePath>../../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
@@ -31,6 +31,30 @@
     <name>Keycloak Dependencies Server All</name>
 	<description />
 
+    <properties>
+        <!-- Drools dependencies versions -->
+        <version.org.eclipse.sisu>0.3.0.M1</version.org.eclipse.sisu>
+        <version.org.eclipse.aether>1.0.0.v20140518</version.org.eclipse.aether>
+        <version.org.apache.ant>1.8.3</version.org.apache.ant>
+        <version.org.antlr>3.5</version.org.antlr>
+        <version.aopalliance>1.0</version.aopalliance>
+        <version.org.apache.maven>3.2.5</version.org.apache.maven>
+        <version.org.mvel>2.2.8.Final</version.org.mvel>
+        <version.org.sonatype.plexus.plexus-cipher>1.7</version.org.sonatype.plexus.plexus-cipher>
+        <version.org.codehaus.plexus.plexus-classworlds>2.5.2</version.org.codehaus.plexus.plexus-classworlds>
+        <version.org.codehaus.plexus.plexus-component-annotations>1.5.5</version.org.codehaus.plexus.plexus-component-annotations>
+        <version.org.codehaus.plexus.plexus-interpolation>1.21</version.org.codehaus.plexus.plexus-interpolation>
+        <version.org.codehaus.plexus.plexus-sec-dispatcher>1.3</version.org.codehaus.plexus.plexus-sec-dispatcher>
+        <version.org.codehaus.plexus.plexus-utils>3.0.20</version.org.codehaus.plexus.plexus-utils>
+        <version.org.apache.maven.wagon>2.6</version.org.apache.maven.wagon>
+        <version.com.thoughtworks.xstream>1.4.7</version.com.thoughtworks.xstream>
+        <version.com.google.guava>13.0.1</version.com.google.guava>
+        <version.org.eclipse.jdt.core.compiler>4.4.2</version.org.eclipse.jdt.core.compiler>
+        <version.com.lowagie>2.1.2</version.com.lowagie>
+        <version.org.sonatype.sisu>3.2.3</version.org.sonatype.sisu>
+        <version.com.google.inject.extensions.guice-servlet>3.0</version.com.google.inject.extensions.guice-servlet>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>org.keycloak</groupId>
@@ -85,6 +109,282 @@
                 </exclusion>
             </exclusions>
         </dependency>
+
+        <!-- Built-in Authorization Policy Providers  -->
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-authz-policy-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <!-- Built-in Authorization Drools Policy Provider-->
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-authz-policy-drools</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <!-- Drools -->
+        <dependency>
+            <groupId>org.kie</groupId>
+            <artifactId>kie-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.kie</groupId>
+            <artifactId>kie-ci</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.sonatype.sisu</groupId>
+                    <artifactId>sisu-guice</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.kie</groupId>
+            <artifactId>kie-internal</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.drools</groupId>
+            <artifactId>drools-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.drools</groupId>
+            <artifactId>drools-compiler</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.aether</groupId>
+            <artifactId>aether-api</artifactId>
+            <version>${version.org.eclipse.aether}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.aether</groupId>
+            <artifactId>aether-connector-basic</artifactId>
+            <version>${version.org.eclipse.aether}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.aether</groupId>
+            <artifactId>aether-spi</artifactId>
+            <version>${version.org.eclipse.aether}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.aether</groupId>
+            <artifactId>aether-impl</artifactId>
+            <version>${version.org.eclipse.aether}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.aether</groupId>
+            <artifactId>aether-transport-file</artifactId>
+            <version>${version.org.eclipse.aether}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.aether</groupId>
+            <artifactId>aether-transport-http</artifactId>
+            <version>${version.org.eclipse.aether}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.aether</groupId>
+            <artifactId>aether-transport-wagon</artifactId>
+            <version>${version.org.eclipse.aether}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.aether</groupId>
+            <artifactId>aether-util</artifactId>
+            <version>${version.org.eclipse.aether}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ant</groupId>
+            <artifactId>ant</artifactId>
+            <version>${version.org.apache.ant}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ant</groupId>
+            <artifactId>ant-launcher</artifactId>
+            <version>${version.org.apache.ant}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.antlr</groupId>
+            <artifactId>antlr-runtime</artifactId>
+            <version>${version.org.antlr}</version>
+        </dependency>
+        <dependency>
+            <groupId>aopalliance</groupId>
+            <artifactId>aopalliance</artifactId>
+            <version>${version.aopalliance}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-aether-provider</artifactId>
+            <version>${version.org.apache.maven}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-artifact</artifactId>
+            <version>${version.org.apache.maven}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-compat</artifactId>
+            <version>${version.org.apache.maven}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-core</artifactId>
+            <version>${version.org.apache.maven}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-model</artifactId>
+            <version>${version.org.apache.maven}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-model-builder</artifactId>
+            <version>${version.org.apache.maven}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-plugin-api</artifactId>
+            <version>${version.org.apache.maven}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-repository-metadata</artifactId>
+            <version>${version.org.apache.maven}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-settings</artifactId>
+            <version>${version.org.apache.maven}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-settings-builder</artifactId>
+            <version>${version.org.apache.maven}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.mvel</groupId>
+            <artifactId>mvel2</artifactId>
+            <version>${version.org.mvel}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.sisu</groupId>
+            <artifactId>org.eclipse.sisu.inject</artifactId>
+            <version>${version.org.eclipse.sisu}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.google.inject</groupId>
+                    <artifactId>guice</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>com.google.inject.extensions</groupId>
+            <artifactId>guice-servlet</artifactId>
+            <version>${version.com.google.inject.extensions.guice-servlet}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.sisu</groupId>
+            <artifactId>org.eclipse.sisu.plexus</artifactId>
+            <version>${version.org.eclipse.sisu}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.sonatype.sisu</groupId>
+                    <artifactId>sisu-guice</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.sonatype.plexus</groupId>
+            <artifactId>plexus-cipher</artifactId>
+            <version>${version.org.sonatype.plexus.plexus-cipher}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.plexus</groupId>
+            <artifactId>plexus-classworlds</artifactId>
+            <version>${version.org.codehaus.plexus.plexus-classworlds}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.plexus</groupId>
+            <artifactId>plexus-component-annotations</artifactId>
+            <version>${version.org.codehaus.plexus.plexus-component-annotations}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.plexus</groupId>
+            <artifactId>plexus-interpolation</artifactId>
+            <version>${version.org.codehaus.plexus.plexus-interpolation}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.sonatype.plexus</groupId>
+            <artifactId>plexus-sec-dispatcher</artifactId>
+            <version>${version.org.codehaus.plexus.plexus-sec-dispatcher}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.plexus</groupId>
+            <artifactId>plexus-utils</artifactId>
+            <version>${version.org.codehaus.plexus.plexus-utils}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.wagon</groupId>
+            <artifactId>wagon-http</artifactId>
+            <version>${version.org.apache.maven.wagon}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.wagon</groupId>
+            <artifactId>wagon-http-shared</artifactId>
+            <version>${version.org.apache.maven.wagon}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven.wagon</groupId>
+            <artifactId>wagon-provider-api</artifactId>
+            <version>${version.org.apache.maven.wagon}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.thoughtworks.xstream</groupId>
+            <artifactId>xstream</artifactId>
+            <version>${version.com.thoughtworks.xstream}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>${version.com.google.guava}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jdt.core.compiler</groupId>
+            <artifactId>ecj</artifactId>
+            <version>${version.org.eclipse.jdt.core.compiler}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpcore</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.lowagie</groupId>
+            <artifactId>itext</artifactId>
+            <version>${version.com.lowagie}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>bouncycastle</groupId>
+                    <artifactId>bcmail-jdk14</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>bouncycastle</groupId>
+                    <artifactId>bcprov-jdk14</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.sonatype.sisu</groupId>
+                    <artifactId>sisu-guice</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.sonatype.sisu</groupId>
+            <artifactId>sisu-guice</artifactId>
+            <version>${version.org.sonatype.sisu}</version>
+            <classifier>no_aop</classifier>
+        </dependency>
     </dependencies>
 
 </project>
diff --git a/dependencies/server-min/pom.xml b/dependencies/server-min/pom.xml
index 126ff9e..ba0d7c9 100755
--- a/dependencies/server-min/pom.xml
+++ b/dependencies/server-min/pom.xml
@@ -21,7 +21,7 @@
 	<parent>
 		<artifactId>keycloak-parent</artifactId>
 		<groupId>org.keycloak</groupId>
-		<version>2.0.0.CR1-SNAPSHOT</version>
+		<version>2.2.0-SNAPSHOT</version>
 		<relativePath>../../pom.xml</relativePath>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
diff --git a/distribution/adapters/as7-eap6-adapter/as7-adapter-zip/pom.xml b/distribution/adapters/as7-eap6-adapter/as7-adapter-zip/pom.xml
index 33a30cd..4edfeb5 100755
--- a/distribution/adapters/as7-eap6-adapter/as7-adapter-zip/pom.xml
+++ b/distribution/adapters/as7-eap6-adapter/as7-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/adapters/as7-eap6-adapter/as7-modules/pom.xml b/distribution/adapters/as7-eap6-adapter/as7-modules/pom.xml
index 189495c..0f0b609 100755
--- a/distribution/adapters/as7-eap6-adapter/as7-modules/pom.xml
+++ b/distribution/adapters/as7-eap6-adapter/as7-modules/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <artifactId>keycloak-as7-eap6-adapter-dist-pom</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/adapters/as7-eap6-adapter/eap6-adapter-zip/pom.xml b/distribution/adapters/as7-eap6-adapter/eap6-adapter-zip/pom.xml
index a73e608..e97a589 100755
--- a/distribution/adapters/as7-eap6-adapter/eap6-adapter-zip/pom.xml
+++ b/distribution/adapters/as7-eap6-adapter/eap6-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-as7-eap6-adapter-dist-pom</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/adapters/as7-eap6-adapter/pom.xml b/distribution/adapters/as7-eap6-adapter/pom.xml
index a209f73..aae4c16 100644
--- a/distribution/adapters/as7-eap6-adapter/pom.xml
+++ b/distribution/adapters/as7-eap6-adapter/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <name>Keycloak AS7 / JBoss EAP 6 Adapter Distros</name>
diff --git a/distribution/adapters/jetty81-adapter-zip/pom.xml b/distribution/adapters/jetty81-adapter-zip/pom.xml
index 53cda9b..6d5570f 100755
--- a/distribution/adapters/jetty81-adapter-zip/pom.xml
+++ b/distribution/adapters/jetty81-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/adapters/jetty91-adapter-zip/pom.xml b/distribution/adapters/jetty91-adapter-zip/pom.xml
index 2377171..c5efca9 100755
--- a/distribution/adapters/jetty91-adapter-zip/pom.xml
+++ b/distribution/adapters/jetty91-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/adapters/jetty92-adapter-zip/pom.xml b/distribution/adapters/jetty92-adapter-zip/pom.xml
index b1f4b41..b9515d8 100755
--- a/distribution/adapters/jetty92-adapter-zip/pom.xml
+++ b/distribution/adapters/jetty92-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/adapters/jetty93-adapter-zip/assembly.xml b/distribution/adapters/jetty93-adapter-zip/assembly.xml
new file mode 100644
index 0000000..172882a
--- /dev/null
+++ b/distribution/adapters/jetty93-adapter-zip/assembly.xml
@@ -0,0 +1,56 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<assembly>
+    <id>war-dist</id>
+
+    <formats>
+        <format>zip</format>
+        <format>tar.gz</format>
+    </formats>
+    <includeBaseDirectory>false</includeBaseDirectory>
+
+    <fileSets>
+        <fileSet>
+            <directory></directory>
+            <includes>
+                <include>keycloak.mod</include>
+            </includes>
+            <outputDirectory>modules</outputDirectory>
+        </fileSet>
+        <fileSet>
+            <directory>${project.build.directory}/modules</directory>
+            <outputDirectory></outputDirectory>
+        </fileSet>
+    </fileSets>
+    <dependencySets>
+        <dependencySet>
+            <unpack>false</unpack>
+            <useTransitiveDependencies>true</useTransitiveDependencies>
+            <useTransitiveFiltering>true</useTransitiveFiltering>
+            <includes>
+                <include>org.keycloak:keycloak-jetty93-adapter</include>
+            </includes>
+            <excludes>
+                <exclude>org.eclipse.jetty:jetty-server</exclude>
+                <exclude>org.eclipse.jetty:jetty-util</exclude>
+                <exclude>org.eclipse.jetty:jetty-security</exclude>
+            </excludes>
+            <outputDirectory>lib/keycloak</outputDirectory>
+        </dependencySet>
+    </dependencySets>
+</assembly>
diff --git a/distribution/adapters/jetty93-adapter-zip/pom.xml b/distribution/adapters/jetty93-adapter-zip/pom.xml
new file mode 100644
index 0000000..3bfd778
--- /dev/null
+++ b/distribution/adapters/jetty93-adapter-zip/pom.xml
@@ -0,0 +1,68 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>keycloak-parent</artifactId>
+        <groupId>org.keycloak</groupId>
+        <version>2.2.0-SNAPSHOT</version>
+        <relativePath>../../../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>keycloak-jetty93-adapter-dist</artifactId>
+    <packaging>pom</packaging>
+    <name>Keycloak Jetty 9.3.x Adapter Distro</name>
+    <description/>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-jetty93-adapter</artifactId>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>assemble</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <configuration>
+                            <descriptors>
+                                <descriptor>assembly.xml</descriptor>
+                            </descriptors>
+                            <outputDirectory>
+                                target
+                            </outputDirectory>
+                            <workDirectory>
+                                target/assembly/work
+                            </workDirectory>
+                            <appendAssemblyId>false</appendAssemblyId>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/distribution/adapters/js-adapter-zip/pom.xml b/distribution/adapters/js-adapter-zip/pom.xml
index 3a2836f..f00e188 100755
--- a/distribution/adapters/js-adapter-zip/pom.xml
+++ b/distribution/adapters/js-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/adapters/osgi/features/pom.xml b/distribution/adapters/osgi/features/pom.xml
index 7bd2236..77a9317 100755
--- a/distribution/adapters/osgi/features/pom.xml
+++ b/distribution/adapters/osgi/features/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../../pom.xml</relativePath>
     </parent>
     <name>Keycloak OSGI Features</name>
diff --git a/distribution/adapters/osgi/features/src/main/resources/features.xml b/distribution/adapters/osgi/features/src/main/resources/features.xml
index f2e825a..f3dc3e9 100755
--- a/distribution/adapters/osgi/features/src/main/resources/features.xml
+++ b/distribution/adapters/osgi/features/src/main/resources/features.xml
@@ -32,6 +32,7 @@
         <bundle dependency="true">mvn:org.jboss.logging/jboss-logging/${jboss.logging.version}</bundle>
         <bundle>mvn:org.keycloak/keycloak-common/${project.version}</bundle>
         <bundle>mvn:org.keycloak/keycloak-core/${project.version}</bundle>
+        <bundle>mvn:org.keycloak/keycloak-authz-client/${project.version}</bundle>
         <bundle>mvn:org.keycloak/keycloak-adapter-spi/${project.version}</bundle>
         <bundle>mvn:org.keycloak/keycloak-adapter-core/${project.version}</bundle>
     </feature>
diff --git a/distribution/adapters/osgi/jaas/pom.xml b/distribution/adapters/osgi/jaas/pom.xml
index bbb0a3a..6338c48 100755
--- a/distribution/adapters/osgi/jaas/pom.xml
+++ b/distribution/adapters/osgi/jaas/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../../pom.xml</relativePath>
     </parent>
     <name>Keycloak OSGI JAAS Realm Configuration</name>
diff --git a/distribution/adapters/osgi/pom.xml b/distribution/adapters/osgi/pom.xml
index 2829909..e178a97 100755
--- a/distribution/adapters/osgi/pom.xml
+++ b/distribution/adapters/osgi/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <name>Keycloak OSGI Integration</name>
diff --git a/distribution/adapters/osgi/thirdparty/pom.xml b/distribution/adapters/osgi/thirdparty/pom.xml
index 23e2ab2..e77063c 100755
--- a/distribution/adapters/osgi/thirdparty/pom.xml
+++ b/distribution/adapters/osgi/thirdparty/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/adapters/pom.xml b/distribution/adapters/pom.xml
index 91e512f..cd72e9a 100755
--- a/distribution/adapters/pom.xml
+++ b/distribution/adapters/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-distribution-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Adapters Distribution Parent</name>
@@ -35,6 +35,7 @@
         <module>jetty81-adapter-zip</module>
         <module>jetty91-adapter-zip</module>
         <module>jetty92-adapter-zip</module>
+        <module>jetty93-adapter-zip</module>
         <module>js-adapter-zip</module>
         <module>osgi</module>
         <module>tomcat6-adapter-zip</module>
diff --git a/distribution/adapters/tomcat6-adapter-zip/pom.xml b/distribution/adapters/tomcat6-adapter-zip/pom.xml
index 9f91013..5fa0d82 100755
--- a/distribution/adapters/tomcat6-adapter-zip/pom.xml
+++ b/distribution/adapters/tomcat6-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/adapters/tomcat7-adapter-zip/pom.xml b/distribution/adapters/tomcat7-adapter-zip/pom.xml
index b74a7d7..8707987 100755
--- a/distribution/adapters/tomcat7-adapter-zip/pom.xml
+++ b/distribution/adapters/tomcat7-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/adapters/tomcat8-adapter-zip/pom.xml b/distribution/adapters/tomcat8-adapter-zip/pom.xml
index 2aba29c..4efaec2 100755
--- a/distribution/adapters/tomcat8-adapter-zip/pom.xml
+++ b/distribution/adapters/tomcat8-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/adapters/wf8-adapter/pom.xml b/distribution/adapters/wf8-adapter/pom.xml
index aa6a3d7..7a4c66c 100644
--- a/distribution/adapters/wf8-adapter/pom.xml
+++ b/distribution/adapters/wf8-adapter/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <name>Keycloak Wildfly 8 Adapter</name>
diff --git a/distribution/adapters/wf8-adapter/wf8-adapter-zip/assembly.xml b/distribution/adapters/wf8-adapter/wf8-adapter-zip/assembly.xml
index a418265..fb3bf41 100755
--- a/distribution/adapters/wf8-adapter/wf8-adapter-zip/assembly.xml
+++ b/distribution/adapters/wf8-adapter/wf8-adapter-zip/assembly.xml
@@ -39,6 +39,7 @@
                 <include>org/keycloak/keycloak-wf8-subsystem/**</include>
                 <include>org/keycloak/keycloak-adapter-subsystem/**</include>
                 <include>org/keycloak/keycloak-servlet-oauth-client/**</include>
+                <include>org/keycloak/keycloak-authz-client/**</include>
             </includes>
             <excludes>
                 <exclude>**/*.war</exclude>
diff --git a/distribution/adapters/wf8-adapter/wf8-adapter-zip/pom.xml b/distribution/adapters/wf8-adapter/wf8-adapter-zip/pom.xml
index 98d4d2d..e65e21c 100755
--- a/distribution/adapters/wf8-adapter/wf8-adapter-zip/pom.xml
+++ b/distribution/adapters/wf8-adapter/wf8-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/adapters/wf8-adapter/wf8-modules/build.xml b/distribution/adapters/wf8-adapter/wf8-modules/build.xml
index ef8f986..457e673 100755
--- a/distribution/adapters/wf8-adapter/wf8-modules/build.xml
+++ b/distribution/adapters/wf8-adapter/wf8-modules/build.xml
@@ -79,6 +79,11 @@
             <maven-resource group="org.apache.httpcomponents" artifact="httpmime"/>
         </module-def>
 
+        <!-- Authorization -->
+        <module-def name="org.keycloak.keycloak-authz-client">
+            <maven-resource group="org.keycloak" artifact="keycloak-authz-client"/>
+        </module-def>
+
     </target>
 
     <target name="clean-target">
diff --git a/distribution/adapters/wf8-adapter/wf8-modules/pom.xml b/distribution/adapters/wf8-adapter/wf8-modules/pom.xml
index 72a2727..6ed6caa 100755
--- a/distribution/adapters/wf8-adapter/wf8-modules/pom.xml
+++ b/distribution/adapters/wf8-adapter/wf8-modules/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../../pom.xml</relativePath>
     </parent>
 
@@ -82,6 +82,12 @@
             <groupId>org.apache.httpcomponents</groupId>
             <artifactId>httpcore</artifactId>
         </dependency>
+
+        <!-- Authorization -->
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-authz-client</artifactId>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/distribution/adapters/wf8-adapter/wf8-modules/src/main/resources/modules/org/keycloak/keycloak-adapter-core/main/module.xml b/distribution/adapters/wf8-adapter/wf8-modules/src/main/resources/modules/org/keycloak/keycloak-adapter-core/main/module.xml
index 1642eb3..da78bf3 100755
--- a/distribution/adapters/wf8-adapter/wf8-modules/src/main/resources/modules/org/keycloak/keycloak-adapter-core/main/module.xml
+++ b/distribution/adapters/wf8-adapter/wf8-modules/src/main/resources/modules/org/keycloak/keycloak-adapter-core/main/module.xml
@@ -34,6 +34,7 @@
         <module name="org.keycloak.keycloak-adapter-spi"/>
         <module name="org.keycloak.keycloak-core"/>
         <module name="org.keycloak.keycloak-common"/>
+        <module name="org.keycloak.keycloak-authz-client"/>
     </dependencies>
 
 </module>
diff --git a/distribution/adapters/wf8-adapter/wf8-modules/src/main/resources/modules/org/keycloak/keycloak-authz-client/main/module.xml b/distribution/adapters/wf8-adapter/wf8-modules/src/main/resources/modules/org/keycloak/keycloak-authz-client/main/module.xml
new file mode 100755
index 0000000..af2bf88
--- /dev/null
+++ b/distribution/adapters/wf8-adapter/wf8-modules/src/main/resources/modules/org/keycloak/keycloak-authz-client/main/module.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<!--
+  ~ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ * and other contributors as indicated by the @author tags.
+  ~ *
+  ~ * Licensed under the Apache License, Version 2.0 (the "License");
+  ~ * you may not use this file except in compliance with the License.
+  ~ * You may obtain a copy of the License at
+  ~ *
+  ~ * http://www.apache.org/licenses/LICENSE-2.0
+  ~ *
+  ~ * Unless required by applicable law or agreed to in writing, software
+  ~ * distributed under the License is distributed on an "AS IS" BASIS,
+  ~ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ * See the License for the specific language governing permissions and
+  ~ * limitations under the License.
+  -->
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-authz-client">
+    <resources>
+        <!-- Insert resources here -->
+    </resources>
+    <dependencies>
+        <module name="org.bouncycastle" />
+        <module name="javax.api"/>
+        <module name="javax.activation.api"/>
+        <module name="sun.jdk" optional="true" />
+        <module name="javax.ws.rs.api"/>
+        <module name="org.keycloak.keycloak-core"/>
+        <module name="org.keycloak.keycloak-common"/>
+        <module name="org.apache.httpcomponents" slot="4.3"/>
+        <module name="com.fasterxml.jackson.core.jackson-core"/>
+        <module name="com.fasterxml.jackson.core.jackson-annotations"/>
+        <module name="com.fasterxml.jackson.core.jackson-databind"/>
+        <module name="com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider"/>
+    </dependencies>
+
+</module>
diff --git a/distribution/adapters/wildfly-adapter/pom.xml b/distribution/adapters/wildfly-adapter/pom.xml
index 4084253..eaa51bc 100644
--- a/distribution/adapters/wildfly-adapter/pom.xml
+++ b/distribution/adapters/wildfly-adapter/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <name>Keycloak Wildfly Adapter</name>
diff --git a/distribution/adapters/wildfly-adapter/wildfly-adapter-zip/assembly.xml b/distribution/adapters/wildfly-adapter/wildfly-adapter-zip/assembly.xml
index 8da890a..ece320b 100755
--- a/distribution/adapters/wildfly-adapter/wildfly-adapter-zip/assembly.xml
+++ b/distribution/adapters/wildfly-adapter/wildfly-adapter-zip/assembly.xml
@@ -38,6 +38,9 @@
                 <include>org/keycloak/keycloak-wildfly-subsystem/**</include>
                 <include>org/keycloak/keycloak-adapter-subsystem/**</include>
                 <include>org/keycloak/keycloak-servlet-oauth-client/**</include>
+
+                <!-- Authorization -->
+                <include>org/keycloak/keycloak-authz-client/**</include>
             </includes>
             <excludes>
                 <exclude>**/*.war</exclude>
diff --git a/distribution/adapters/wildfly-adapter/wildfly-adapter-zip/pom.xml b/distribution/adapters/wildfly-adapter/wildfly-adapter-zip/pom.xml
index 34c0a42..653eec8 100755
--- a/distribution/adapters/wildfly-adapter/wildfly-adapter-zip/pom.xml
+++ b/distribution/adapters/wildfly-adapter/wildfly-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/adapters/wildfly-adapter/wildfly-modules/build.xml b/distribution/adapters/wildfly-adapter/wildfly-modules/build.xml
index 4597205..a534b4f 100755
--- a/distribution/adapters/wildfly-adapter/wildfly-modules/build.xml
+++ b/distribution/adapters/wildfly-adapter/wildfly-modules/build.xml
@@ -73,6 +73,10 @@
             <maven-resource group="org.keycloak" artifact="keycloak-servlet-oauth-client"/>
         </module-def>
 
+        <!-- Authorization -->
+        <module-def name="org.keycloak.keycloak-authz-client">
+            <maven-resource group="org.keycloak" artifact="keycloak-authz-client"/>
+        </module-def>
     </target>
 
     <target name="clean-target">
diff --git a/distribution/adapters/wildfly-adapter/wildfly-modules/pom.xml b/distribution/adapters/wildfly-adapter/wildfly-modules/pom.xml
index 4fb605e..ec6e963 100755
--- a/distribution/adapters/wildfly-adapter/wildfly-modules/pom.xml
+++ b/distribution/adapters/wildfly-adapter/wildfly-modules/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../../pom.xml</relativePath>
     </parent>
 
@@ -82,6 +82,12 @@
             <groupId>org.apache.httpcomponents</groupId>
             <artifactId>httpcore</artifactId>
         </dependency>
+
+        <!-- Authorization -->
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-authz-client</artifactId>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/distribution/adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-adapter-core/main/module.xml b/distribution/adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-adapter-core/main/module.xml
index 8672bf4..84a08f0 100755
--- a/distribution/adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-adapter-core/main/module.xml
+++ b/distribution/adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-adapter-core/main/module.xml
@@ -34,6 +34,7 @@
         <module name="org.keycloak.keycloak-adapter-spi"/>
         <module name="org.keycloak.keycloak-common"/>
         <module name="org.keycloak.keycloak-core"/>
+        <module name="org.keycloak.keycloak-authz-client"/>
     </dependencies>
 
 </module>
diff --git a/distribution/adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-authz-client/main/module.xml b/distribution/adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-authz-client/main/module.xml
new file mode 100755
index 0000000..3cd1abd
--- /dev/null
+++ b/distribution/adapters/wildfly-adapter/wildfly-modules/src/main/resources/modules/org/keycloak/keycloak-authz-client/main/module.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<!--
+  ~ JBoss, Home of Professional Open Source.
+  ~ Copyright 2016 Red Hat, Inc., and individual contributors
+  ~ as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-authz-client">
+    <resources>
+        <!-- Insert resources here -->
+    </resources>
+    <dependencies>
+        <module name="org.bouncycastle" />
+        <module name="javax.api"/>
+        <module name="javax.activation.api"/>
+        <module name="sun.jdk" optional="true" />
+        <module name="javax.ws.rs.api"/>
+        <module name="org.keycloak.keycloak-core"/>
+        <module name="org.keycloak.keycloak-common"/>
+        <module name="org.apache.httpcomponents"/>
+        <module name="com.fasterxml.jackson.core.jackson-core"/>
+        <module name="com.fasterxml.jackson.core.jackson-annotations"/>
+        <module name="com.fasterxml.jackson.core.jackson-databind"/>
+        <module name="com.fasterxml.jackson.jaxrs.jackson-jaxrs-json-provider"/>
+    </dependencies>
+
+</module>
diff --git a/distribution/demo-dist/assembly.xml b/distribution/demo-dist/assembly.xml
index 56e5818..4c58b7d 100755
--- a/distribution/demo-dist/assembly.xml
+++ b/distribution/demo-dist/assembly.xml
@@ -61,10 +61,6 @@
             </excludes>
         </fileSet>
         <fileSet>
-            <directory>${project.build.directory}/unpacked/keycloak-docs-${project.version}</directory>
-            <outputDirectory>docs</outputDirectory>
-        </fileSet>
-        <fileSet>
             <directory>${project.build.directory}/unpacked/keycloak-examples-${project.version}</directory>
             <outputDirectory>examples</outputDirectory>
         </fileSet>
diff --git a/distribution/demo-dist/pom.xml b/distribution/demo-dist/pom.xml
index 76ec682..187d62d 100755
--- a/distribution/demo-dist/pom.xml
+++ b/distribution/demo-dist/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-distribution-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>keycloak-demo-dist</artifactId>
@@ -50,11 +50,6 @@
             <artifactId>keycloak-examples-dist</artifactId>
             <type>zip</type>
         </dependency>
-        <dependency>
-            <groupId>org.keycloak</groupId>
-            <artifactId>keycloak-docs-dist</artifactId>
-            <type>zip</type>
-        </dependency>
     </dependencies>
 
     <build>
@@ -140,23 +135,6 @@
                         </configuration>
                     </execution>
                     <execution>
-                        <id>unpack-docs</id>
-                        <phase>prepare-package</phase>
-                        <goals>
-                            <goal>unpack</goal>
-                        </goals>
-                        <configuration>
-                            <artifactItems>
-                                <artifactItem>
-                                    <groupId>org.keycloak</groupId>
-                                    <artifactId>keycloak-docs-dist</artifactId>
-                                    <type>zip</type>
-                                    <outputDirectory>${project.build.directory}/unpacked</outputDirectory>
-                                </artifactItem>
-                            </artifactItems>
-                        </configuration>
-                    </execution>
-                    <execution>
                         <id>unpack-examples</id>
                         <phase>prepare-package</phase>
                         <goals>
diff --git a/distribution/demo-dist/src/main/xslt/standalone.xsl b/distribution/demo-dist/src/main/xslt/standalone.xsl
index 94dd49c..4ef3f0e 100755
--- a/distribution/demo-dist/src/main/xslt/standalone.xsl
+++ b/distribution/demo-dist/src/main/xslt/standalone.xsl
@@ -89,10 +89,8 @@
                 <local-cache name="sessions"/>
                 <local-cache name="offlineSessions"/>
                 <local-cache name="loginFailures"/>
+                <local-cache name="authorization"/>
                 <local-cache name="work"/>
-                <local-cache name="realmVersions">
-                    <transaction mode="BATCH" locking="PESSIMISTIC"/>
-                </local-cache>
             </cache-container>
             <xsl:apply-templates select="node()|@*"/>
         </xsl:copy>
diff --git a/distribution/downloads/pom.xml b/distribution/downloads/pom.xml
index 3e1e7f1..e1356d6 100755
--- a/distribution/downloads/pom.xml
+++ b/distribution/downloads/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-distribution-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>keycloak-dist-downloads</artifactId>
@@ -102,9 +102,9 @@
 
                                 <artifactItem>
                                     <groupId>org.keycloak</groupId>
-                                    <artifactId>keycloak-docs-dist</artifactId>
+                                    <artifactId>keycloak-api-docs-dist</artifactId>
                                     <type>zip</type>
-                                    <destFileName>keycloak-docs-${project.version}.zip</destFileName>
+                                    <destFileName>keycloak-api-docs-${project.version}.zip</destFileName>
                                 </artifactItem>
                                 <artifactItem>
                                     <groupId>org.keycloak</groupId>
@@ -188,6 +188,17 @@
 
                                 <artifactItem>
                                     <groupId>org.keycloak</groupId>
+                                    <artifactId>keycloak-jetty93-adapter-dist</artifactId>
+                                    <type>zip</type>
+                                </artifactItem>
+                                <artifactItem>
+                                    <groupId>org.keycloak</groupId>
+                                    <artifactId>keycloak-jetty93-adapter-dist</artifactId>
+                                    <type>tar.gz</type>
+                                </artifactItem>
+
+                                <artifactItem>
+                                    <groupId>org.keycloak</groupId>
                                     <artifactId>keycloak-js-adapter-dist</artifactId>
                                     <type>zip</type>
                                 </artifactItem>
@@ -309,6 +320,17 @@
 
                                 <artifactItem>
                                     <groupId>org.keycloak</groupId>
+                                    <artifactId>keycloak-saml-jetty93-adapter-dist</artifactId>
+                                    <type>zip</type>
+                                </artifactItem>
+                                <artifactItem>
+                                    <groupId>org.keycloak</groupId>
+                                    <artifactId>keycloak-saml-jetty93-adapter-dist</artifactId>
+                                    <type>tar.gz</type>
+                                </artifactItem>
+
+                                <artifactItem>
+                                    <groupId>org.keycloak</groupId>
                                     <artifactId>keycloak-saml-tomcat6-adapter-dist</artifactId>
                                     <type>zip</type>
                                 </artifactItem>
diff --git a/distribution/examples-dist/build.xml b/distribution/examples-dist/build.xml
index 7714802..6e8b9bc 100755
--- a/distribution/examples-dist/build.xml
+++ b/distribution/examples-dist/build.xml
@@ -136,6 +136,14 @@
                 <exclude name="**/*.iml"/>
             </fileset>
         </copy>
+        <copy todir="target/examples/authz" overwrite="true">
+            <fileset dir="../../examples/authz">
+                <exclude name="**/target/**"/>
+                <exclude name="**/*.iml"/>
+                <exclude name="**/*.unconfigured"/>
+                <exclude name="**/subsystem-config.xml"/>
+            </fileset>
+        </copy>
         <copy file="../../examples/pom.xml" tofile="target/examples/pom.xml"/>
         <copy file="../../examples/README.md" tofile="target/examples/README.md"/>
         <move file="target/examples/unconfigured-demo/README.md.unconfigured" tofile="target/examples/unconfigured-demo/README.md"/>
diff --git a/distribution/examples-dist/pom.xml b/distribution/examples-dist/pom.xml
index eb1b1ef..7ca7173 100755
--- a/distribution/examples-dist/pom.xml
+++ b/distribution/examples-dist/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-distribution-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>keycloak-examples-dist</artifactId>
diff --git a/distribution/feature-packs/adapter-feature-pack/pom.xml b/distribution/feature-packs/adapter-feature-pack/pom.xml
index 3bced41..dc31a6b 100755
--- a/distribution/feature-packs/adapter-feature-pack/pom.xml
+++ b/distribution/feature-packs/adapter-feature-pack/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <groupId>org.keycloak</groupId>
         <artifactId>feature-packs-parent</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/distribution/feature-packs/pom.xml b/distribution/feature-packs/pom.xml
index 0e1c075..819a949 100644
--- a/distribution/feature-packs/pom.xml
+++ b/distribution/feature-packs/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-distribution-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Feature Pack Builds</name>
diff --git a/distribution/feature-packs/server-feature-pack/pom.xml b/distribution/feature-packs/server-feature-pack/pom.xml
index 82f2f74..2a8bacb 100644
--- a/distribution/feature-packs/server-feature-pack/pom.xml
+++ b/distribution/feature-packs/server-feature-pack/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <groupId>org.keycloak</groupId>
         <artifactId>feature-packs-parent</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
@@ -51,6 +51,13 @@
             <groupId>org.wildfly</groupId>
             <artifactId>wildfly-feature-pack</artifactId>
             <type>zip</type>
+            <!-- Need to exlcude that in order to use the right guava version for drools -->
+            <exclusions>
+                <exclusion>
+                    <groupId>com.google.guava</groupId>
+                    <artifactId>guava</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
     </dependencies>
 
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems.xml
index d52c9a4..e5dc8ec 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems.xml
@@ -20,6 +20,7 @@
 <config>
    <subsystems>
       <subsystem>logging.xml</subsystem>
+      <subsystem>deployment-scanner.xml</subsystem>
       <subsystem>bean-validation.xml</subsystem>
       <subsystem supplement="default">keycloak-datasources.xml</subsystem>
       <subsystem>ee.xml</subsystem>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems-ha.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems-ha.xml
index b96cb8a..d9345a1 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems-ha.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems-ha.xml
@@ -20,6 +20,7 @@
 <config>
     <subsystems>
         <subsystem>logging.xml</subsystem>
+        <subsystem>deployment-scanner.xml</subsystem>
         <subsystem>bean-validation.xml</subsystem>
         <subsystem supplement="default">keycloak-datasources.xml</subsystem>
         <subsystem>ee.xml</subsystem>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/content/standalone/configuration/keycloak-server.json b/distribution/feature-packs/server-feature-pack/src/main/resources/content/standalone/configuration/keycloak-server.json
index 87a2da8..b2f1067 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/content/standalone/configuration/keycloak-server.json
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/content/standalone/configuration/keycloak-server.json
@@ -32,6 +32,10 @@
         "provider": "jpa"
     },
 
+    "authorizationPersister": {
+        "provider": "jpa"
+    },
+
     "timer": {
         "provider": "basic"
     },
@@ -61,7 +65,6 @@
     },
 
     "realmCache": {
-        "provider": "default",
         "default" : {
             "enabled": true
         }
@@ -72,5 +75,13 @@
         "default": {
             "cacheContainer" : "java:comp/env/infinispan/Keycloak"
         }
+    },
+
+    "jta-lookup": {
+        "provider": "${keycloak.jta.lookup.provider:jboss}",
+        "jboss" : {
+            "enabled": true
+        }
+
     }
 }
\ No newline at end of file
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/drools/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/drools/main/module.xml
new file mode 100644
index 0000000..ac74233
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/drools/main/module.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+<!--
+  ~ JBoss, Home of Professional Open Source.
+  ~ Copyright 2016 Red Hat, Inc., and individual contributors
+  ~ as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<module xmlns="urn:jboss:module:1.3" name="org.drools">
+    <resources>
+        <artifact name="${org.kie:kie-api}"/>
+        <artifact name="${org.kie:kie-ci}"/>
+        <artifact name="${org.kie:kie-internal}"/>
+        <artifact name="${org.drools:drools-core}"/>
+        <artifact name="${org.drools:drools-compiler}"/>
+        <artifact name="${org.eclipse.aether:aether-api}"/>
+        <artifact name="${org.eclipse.aether:aether-connector-basic}"/>
+        <artifact name="${org.eclipse.aether:aether-spi}"/>
+        <artifact name="${org.eclipse.aether:aether-impl}"/>
+        <artifact name="${org.eclipse.aether:aether-transport-file}"/>
+        <artifact name="${org.eclipse.aether:aether-transport-http}"/>
+        <artifact name="${org.eclipse.aether:aether-transport-wagon}"/>
+        <artifact name="${org.eclipse.aether:aether-util}"/>
+        <artifact name="${org.apache.ant:ant}"/>
+        <artifact name="${org.apache.ant:ant-launcher}"/>
+        <artifact name="${org.antlr:antlr-runtime}"/>
+        <artifact name="${aopalliance:aopalliance}"/>
+        <artifact name="${org.apache.maven:maven-aether-provider}"/>
+        <artifact name="${org.apache.maven:maven-artifact}"/>
+        <artifact name="${org.apache.maven:maven-compat}"/>
+        <artifact name="${org.apache.maven:maven-core}"/>
+        <artifact name="${org.apache.maven:maven-model}"/>
+        <artifact name="${org.apache.maven:maven-model-builder}"/>
+        <artifact name="${org.apache.maven:maven-plugin-api}"/>
+        <artifact name="${org.apache.maven:maven-repository-metadata}"/>
+        <artifact name="${org.apache.maven:maven-settings}"/>
+        <artifact name="${org.apache.maven:maven-settings-builder}"/>
+        <artifact name="${org.mvel:mvel2}"/>
+        <artifact name="${org.eclipse.sisu:org.eclipse.sisu.inject}"/>
+        <artifact name="${org.eclipse.sisu:org.eclipse.sisu.plexus}"/>
+        <artifact name="${org.sonatype.plexus:plexus-cipher}"/>
+        <artifact name="${org.codehaus.plexus:plexus-classworlds}"/>
+        <artifact name="${org.codehaus.plexus:plexus-component-annotations}"/>
+        <artifact name="${org.codehaus.plexus:plexus-interpolation}"/>
+        <artifact name="${org.sonatype.plexus:plexus-sec-dispatcher}"/>
+        <artifact name="${org.codehaus.plexus:plexus-utils}"/>
+        <artifact name="${org.apache.maven.wagon:wagon-http}"/>
+        <artifact name="${org.apache.maven.wagon:wagon-http-shared}"/>
+        <artifact name="${org.apache.maven.wagon:wagon-provider-api}"/>
+        <artifact name="${com.thoughtworks.xstream:xstream}"/>
+        <artifact name="${com.google.guava:guava}"/>
+        <artifact name="${org.eclipse.jdt.core.compiler:ecj}"/>
+        <artifact name="${org.apache.httpcomponents:httpclient}"/>
+        <artifact name="${org.apache.httpcomponents:httpcore}"/>
+        <artifact name="${com.lowagie:itext}"/>
+        <artifact name="${org.sonatype.sisu:sisu-guice::no_aop}"/>
+        <artifact name="${com.google.inject.extensions:guice-servlet}"/>
+    </resources>
+    <dependencies>
+        <module name="javax.api"/>
+        <module name="javax.inject.api"/>
+        <module name="javax.enterprise.api"/>
+        <module name="org.slf4j"/>
+        <module name="org.apache.commons.logging"/>
+        <module name="org.keycloak.keycloak-core"/>
+        <module name="org.keycloak.keycloak-common"/>
+        <module name="org.keycloak.keycloak-server-spi"/>
+    </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-authz-policy-common/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-authz-policy-common/main/module.xml
new file mode 100644
index 0000000..ced09b5
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-authz-policy-common/main/module.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~  Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~  and other contributors as indicated by the @author tags.
+  ~
+  ~  Licensed under the Apache License, Version 2.0 (the "License");
+  ~  you may not use this file except in compliance with the License.
+  ~  You may obtain a copy of the License at
+  ~
+  ~  http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing, software
+  ~  distributed under the License is distributed on an "AS IS" BASIS,
+  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  See the License for the specific language governing permissions and
+  ~  limitations under the License.
+  ~
+  -->
+<module xmlns="urn:jboss:module:1.3" name="org.keycloak.keycloak-authz-policy-common">
+    <resources>
+        <artifact name="${org.keycloak:keycloak-authz-policy-common}"/>
+    </resources>
+    <dependencies>
+        <module name="javax.api"/>
+        <module name="javax.ws.rs.api"/>
+        <module name="org.keycloak.keycloak-core"/>
+        <module name="org.keycloak.keycloak-common"/>
+        <module name="org.keycloak.keycloak-server-spi"/>
+        <module name="org.keycloak.keycloak-services"/>
+    </dependencies>
+
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-authz-policy-drools/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-authz-policy-drools/main/module.xml
new file mode 100644
index 0000000..d821674
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-authz-policy-drools/main/module.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+<!--
+  ~ JBoss, Home of Professional Open Source.
+  ~ Copyright 2016 Red Hat, Inc., and individual contributors
+  ~ as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<module xmlns="urn:jboss:module:1.3" name="org.keycloak.keycloak-authz-policy-drools">
+    <resources>
+        <artifact name="${org.keycloak:keycloak-authz-policy-drools}"/>
+    </resources>
+    <dependencies>
+        <module name="javax.api"/>
+        <module name="javax.ws.rs.api"/>
+        <module name="org.keycloak.keycloak-core"/>
+        <module name="org.keycloak.keycloak-common"/>
+        <module name="org.keycloak.keycloak-server-spi"/>
+        <module name="org.keycloak.keycloak-services"/>
+        <module name="org.drools"/>
+    </dependencies>
+</module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-spi/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-spi/main/module.xml
index ae36edb..95f34b6 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-spi/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-spi/main/module.xml
@@ -32,5 +32,6 @@
         <module name="javax.api"/>
         <module name="javax.ws.rs.api"/>
         <module name="org.apache.httpcomponents"/>
+        <module name="org.jboss.resteasy.resteasy-jaxrs"/>
     </dependencies>
 </module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-subsystem/main/server-war/WEB-INF/web.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-subsystem/main/server-war/WEB-INF/web.xml
index 6f19080..6ad93e9 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-subsystem/main/server-war/WEB-INF/web.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-server-subsystem/main/server-war/WEB-INF/web.xml
@@ -45,6 +45,7 @@
     <filter>
         <filter-name>Keycloak Session Management</filter-name>
         <filter-class>org.keycloak.services.filters.KeycloakSessionServletFilter</filter-class>
+        <async-supported>true</async-supported>
     </filter>
 
     <filter-mapping>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
index a44279d..e769a7b 100755
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-services/main/module.xml
@@ -44,9 +44,14 @@
         <module name="org.keycloak.keycloak-services" export="true" services="import"/>
         <module name="org.keycloak.keycloak-wildfly-extensions" services="import"/>
 
+        <!-- Authorization -->
+        <module name="org.keycloak.keycloak-authz-policy-common" services="import"/>
+        <module name="org.keycloak.keycloak-authz-policy-drools" services="import"/>
+
         <module name="org.freemarker"/>
         <module name="javax.ws.rs.api"/>
         <module name="javax.mail.api"/>
+        <module name="javax.xml.soap.api"/>
         <module name="org.jboss.resteasy.resteasy-jaxrs"/>
         <module name="org.jboss.resteasy.resteasy-crypto"/>
         <module name="org.jboss.resteasy.resteasy-multipart-provider"/>
@@ -63,5 +68,6 @@
         <module name="javax.activation.api"/>
         <module name="org.apache.httpcomponents"/>
         <module name="org.twitter4j"/>
+        <module name="javax.transaction.api"/>
     </dependencies>
 </module>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-server-subsystem/main/module.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-server-subsystem/main/module.xml
index 62b2616..9f44e59 100644
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-server-subsystem/main/module.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/modules/system/layers/keycloak/org/keycloak/keycloak-wildfly-server-subsystem/main/module.xml
@@ -40,6 +40,7 @@
         <module name="org.jboss.as.web-common" optional="true"/>
         <module name="org.jboss.as.web" optional="true"/>
         <module name="org.jboss.as.version" optional="true"/>
+        <module name="org.keycloak.keycloak-services"/>
         <module name="org.keycloak.keycloak-wildfly-adapter" optional="true"/>
         <module name="org.jboss.metadata"/>
     </dependencies>
diff --git a/distribution/pom.xml b/distribution/pom.xml
index 707733c..74e0e40 100755
--- a/distribution/pom.xml
+++ b/distribution/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
@@ -35,7 +35,7 @@
         <module>adapters</module>
         <module>saml-adapters</module>
         <module>demo-dist</module>
-        <module>docs-dist</module>
+        <module>api-docs-dist</module>
         <module>examples-dist</module>
         <module>proxy-dist</module>
         <module>server-dist</module>
diff --git a/distribution/proxy-dist/pom.xml b/distribution/proxy-dist/pom.xml
index 379fee3..709ddc2 100755
--- a/distribution/proxy-dist/pom.xml
+++ b/distribution/proxy-dist/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-distribution-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>keycloak-proxy-dist</artifactId>
diff --git a/distribution/saml-adapters/as7-eap6-adapter/as7-adapter-zip/pom.xml b/distribution/saml-adapters/as7-eap6-adapter/as7-adapter-zip/pom.xml
index 0600717..8e00a54 100755
--- a/distribution/saml-adapters/as7-eap6-adapter/as7-adapter-zip/pom.xml
+++ b/distribution/saml-adapters/as7-eap6-adapter/as7-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/saml-adapters/as7-eap6-adapter/as7-modules/pom.xml b/distribution/saml-adapters/as7-eap6-adapter/as7-modules/pom.xml
index 5888e97..56e20d2 100755
--- a/distribution/saml-adapters/as7-eap6-adapter/as7-modules/pom.xml
+++ b/distribution/saml-adapters/as7-eap6-adapter/as7-modules/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <artifactId>keycloak-saml-as7-eap6-adapter-dist-pom</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/saml-adapters/as7-eap6-adapter/eap6-adapter-zip/pom.xml b/distribution/saml-adapters/as7-eap6-adapter/eap6-adapter-zip/pom.xml
index 848ad41..b7ebc26 100755
--- a/distribution/saml-adapters/as7-eap6-adapter/eap6-adapter-zip/pom.xml
+++ b/distribution/saml-adapters/as7-eap6-adapter/eap6-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-saml-as7-eap6-adapter-dist-pom</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/saml-adapters/as7-eap6-adapter/pom.xml b/distribution/saml-adapters/as7-eap6-adapter/pom.xml
index fa1337d..e6ac208 100755
--- a/distribution/saml-adapters/as7-eap6-adapter/pom.xml
+++ b/distribution/saml-adapters/as7-eap6-adapter/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <name>Keycloak SAML AS7 / JBoss EAP 6 Adapter Distros</name>
diff --git a/distribution/saml-adapters/jetty81-adapter-zip/pom.xml b/distribution/saml-adapters/jetty81-adapter-zip/pom.xml
index 33a6ab7..6b9eed4 100755
--- a/distribution/saml-adapters/jetty81-adapter-zip/pom.xml
+++ b/distribution/saml-adapters/jetty81-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/saml-adapters/jetty92-adapter-zip/pom.xml b/distribution/saml-adapters/jetty92-adapter-zip/pom.xml
index 0c790e3..ef403dc 100755
--- a/distribution/saml-adapters/jetty92-adapter-zip/pom.xml
+++ b/distribution/saml-adapters/jetty92-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/saml-adapters/jetty93-adapter-zip/assembly.xml b/distribution/saml-adapters/jetty93-adapter-zip/assembly.xml
new file mode 100644
index 0000000..cafc561
--- /dev/null
+++ b/distribution/saml-adapters/jetty93-adapter-zip/assembly.xml
@@ -0,0 +1,56 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<assembly>
+    <id>war-dist</id>
+
+    <formats>
+        <format>zip</format>
+        <format>tar.gz</format>
+    </formats>
+    <includeBaseDirectory>false</includeBaseDirectory>
+
+    <fileSets>
+        <fileSet>
+            <directory></directory>
+            <includes>
+                <include>keycloak.mod</include>
+            </includes>
+            <outputDirectory>modules</outputDirectory>
+        </fileSet>
+        <fileSet>
+            <directory>${project.build.directory}/modules</directory>
+            <outputDirectory></outputDirectory>
+        </fileSet>
+    </fileSets>
+    <dependencySets>
+        <dependencySet>
+            <unpack>false</unpack>
+            <useTransitiveDependencies>true</useTransitiveDependencies>
+            <useTransitiveFiltering>true</useTransitiveFiltering>
+            <includes>
+                <include>org.keycloak:keycloak-saml-jetty93-adapter</include>
+            </includes>
+            <excludes>
+                <exclude>org.eclipse.jetty:jetty-server</exclude>
+                <exclude>org.eclipse.jetty:jetty-util</exclude>
+                <exclude>org.eclipse.jetty:jetty-security</exclude>
+            </excludes>
+            <outputDirectory>lib/keycloak</outputDirectory>
+        </dependencySet>
+    </dependencySets>
+</assembly>
diff --git a/distribution/saml-adapters/pom.xml b/distribution/saml-adapters/pom.xml
index b66acfe..92fef7a 100755
--- a/distribution/saml-adapters/pom.xml
+++ b/distribution/saml-adapters/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-distribution-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>SAML Adapters Distribution Parent</name>
@@ -39,6 +39,7 @@
         <!-- jetty 9.1 doesn't work right now
         <module>jetty91-adapter-zip</module> -->
         <module>jetty92-adapter-zip</module>
+        <module>jetty93-adapter-zip</module>
         <module>as7-eap6-adapter</module>
     </modules>
 </project>
diff --git a/distribution/saml-adapters/tomcat6-adapter-zip/pom.xml b/distribution/saml-adapters/tomcat6-adapter-zip/pom.xml
index 025a901..0c5109b 100755
--- a/distribution/saml-adapters/tomcat6-adapter-zip/pom.xml
+++ b/distribution/saml-adapters/tomcat6-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/saml-adapters/tomcat7-adapter-zip/pom.xml b/distribution/saml-adapters/tomcat7-adapter-zip/pom.xml
index de00474..73f24e9 100755
--- a/distribution/saml-adapters/tomcat7-adapter-zip/pom.xml
+++ b/distribution/saml-adapters/tomcat7-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/saml-adapters/tomcat8-adapter-zip/pom.xml b/distribution/saml-adapters/tomcat8-adapter-zip/pom.xml
index 25f58b7..5b62170 100755
--- a/distribution/saml-adapters/tomcat8-adapter-zip/pom.xml
+++ b/distribution/saml-adapters/tomcat8-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/saml-adapters/wildfly-adapter/pom.xml b/distribution/saml-adapters/wildfly-adapter/pom.xml
index 8f13b8a..9a33a75 100755
--- a/distribution/saml-adapters/wildfly-adapter/pom.xml
+++ b/distribution/saml-adapters/wildfly-adapter/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../pom.xml</relativePath>
     </parent>
     <name>Keycloak Wildfly SAML Adapter</name>
diff --git a/distribution/saml-adapters/wildfly-adapter/wildfly-adapter-zip/pom.xml b/distribution/saml-adapters/wildfly-adapter/wildfly-adapter-zip/pom.xml
index cf95ea2..afd8c69 100755
--- a/distribution/saml-adapters/wildfly-adapter/wildfly-adapter-zip/pom.xml
+++ b/distribution/saml-adapters/wildfly-adapter/wildfly-adapter-zip/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/saml-adapters/wildfly-adapter/wildfly-modules/pom.xml b/distribution/saml-adapters/wildfly-adapter/wildfly-modules/pom.xml
index abe8608..60d8aec 100755
--- a/distribution/saml-adapters/wildfly-adapter/wildfly-modules/pom.xml
+++ b/distribution/saml-adapters/wildfly-adapter/wildfly-modules/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../../../pom.xml</relativePath>
     </parent>
 
diff --git a/distribution/server-dist/assembly.xml b/distribution/server-dist/assembly.xml
index c8dd06c..9e24567 100755
--- a/distribution/server-dist/assembly.xml
+++ b/distribution/server-dist/assembly.xml
@@ -44,8 +44,6 @@
                 <exclude>welcome-content/**</exclude>
                 <exclude>appclient</exclude>
                 <exclude>appclient/**</exclude>
-                <exclude>standalone/deployments</exclude>
-                <exclude>standalone/deployments/*</exclude>
                 <exclude>copyright.txt</exclude>
                 <exclude>README.txt</exclude>
             </excludes>
diff --git a/distribution/server-dist/pom.xml b/distribution/server-dist/pom.xml
index ac12d0e..da92693 100755
--- a/distribution/server-dist/pom.xml
+++ b/distribution/server-dist/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-distribution-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>keycloak-server-dist</artifactId>
diff --git a/distribution/server-overlay/assembly.xml b/distribution/server-overlay/assembly.xml
index 532308c..325cadf 100755
--- a/distribution/server-overlay/assembly.xml
+++ b/distribution/server-overlay/assembly.xml
@@ -37,9 +37,18 @@
                 <include>org/liquibase/**</include>
                 <include>org/mongodb/**</include>
                 <include>org/twitter4j/**</include>
+                <include>org/drools/**</include>
                 <include>sun/jdk/jgss/**</include>
             </includes>
         </fileSet>
+        <!-- Authorization -->
+        <fileSet>
+            <directory>${project.build.directory}/unpacked/keycloak-${project.version}/modules/system/layers/keycloak-authz</directory>
+            <outputDirectory>modules/system/add-ons/keycloak-authz</outputDirectory>
+            <includes>
+                <include>**/**</include>
+            </includes>
+        </fileSet>
         <fileSet>
             <directory>${project.build.directory}/unpacked/keycloak-${project.version}/content</directory>
             <outputDirectory></outputDirectory>
diff --git a/distribution/server-overlay/cli/keycloak-install.cli b/distribution/server-overlay/cli/keycloak-install.cli
index ce08e0a..c29cd5f 100644
--- a/distribution/server-overlay/cli/keycloak-install.cli
+++ b/distribution/server-overlay/cli/keycloak-install.cli
@@ -3,11 +3,12 @@ embed-server --server-config=standalone.xml
 /subsystem=infinispan/cache-container=keycloak:add(jndi-name="infinispan/Keycloak")
 /subsystem=infinispan/cache-container=keycloak/local-cache=realms:add()
 /subsystem=infinispan/cache-container=keycloak/local-cache=users:add()
+/subsystem=infinispan/cache-container=keycloak/local-cache=users/eviction=EVICTION:add(max-entries=10000,strategy=LRU)
 /subsystem=infinispan/cache-container=keycloak/local-cache=sessions:add()
 /subsystem=infinispan/cache-container=keycloak/local-cache=offlineSessions:add()
 /subsystem=infinispan/cache-container=keycloak/local-cache=loginFailures:add()
 /subsystem=infinispan/cache-container=keycloak/local-cache=work:add()
-/subsystem=infinispan/cache-container=keycloak/local-cache=realmVersions:add()
-/subsystem=infinispan/cache-container=keycloak/local-cache=realmVersions/transaction=TRANSACTION:add(mode=BATCH,locking=PESSIMISTIC)
+/subsystem=infinispan/cache-container=keycloak/local-cache=authorization:add()
+/subsystem=infinispan/cache-container=keycloak/local-cache=authorization/eviction=EVICTION:add(max-entries=100,strategy=LRU)
 /extension=org.keycloak.keycloak-server-subsystem/:add(module=org.keycloak.keycloak-server-subsystem)
 /subsystem=keycloak-server:add(web-context=auth)
\ No newline at end of file
diff --git a/distribution/server-overlay/cli/keycloak-install-ha.cli b/distribution/server-overlay/cli/keycloak-install-ha.cli
index e0ad848..a84a34a 100644
--- a/distribution/server-overlay/cli/keycloak-install-ha.cli
+++ b/distribution/server-overlay/cli/keycloak-install-ha.cli
@@ -4,11 +4,11 @@ embed-server --server-config=standalone-ha.xml
 /subsystem=infinispan/cache-container=keycloak/transport=TRANSPORT:add(lock-timeout=60000)
 /subsystem=infinispan/cache-container=keycloak/invalidation-cache=realms:add(mode="SYNC")
 /subsystem=infinispan/cache-container=keycloak/invalidation-cache=users:add(mode="SYNC")
+/subsystem=infinispan/cache-container=keycloak/invalidation-cache=users/eviction=EVICTION:add(max-entries=10000,strategy=LRU)
 /subsystem=infinispan/cache-container=keycloak/distributed-cache=sessions:add(mode="SYNC",owners="1")
 /subsystem=infinispan/cache-container=keycloak/distributed-cache=offlineSessions:add(mode="SYNC",owners="1")
 /subsystem=infinispan/cache-container=keycloak/distributed-cache=loginFailures:add(mode="SYNC",owners="1")
+/subsystem=infinispan/cache-container=keycloak/distributed-cache=authorization:add(mode="SYNC",owners="1")
 /subsystem=infinispan/cache-container=keycloak/replicated-cache=work:add(mode="SYNC")
-/subsystem=infinispan/cache-container=keycloak/local-cache=realmVersions:add()
-/subsystem=infinispan/cache-container=keycloak/local-cache=realmVersions/transaction=TRANSACTION:add(mode=BATCH,locking=PESSIMISTIC)
 /extension=org.keycloak.keycloak-server-subsystem/:add(module=org.keycloak.keycloak-server-subsystem)
 /subsystem=keycloak-server:add(web-context=auth)
\ No newline at end of file
diff --git a/distribution/server-overlay/pom.xml b/distribution/server-overlay/pom.xml
index d4a3bb5..96400d1 100755
--- a/distribution/server-overlay/pom.xml
+++ b/distribution/server-overlay/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-distribution-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>keycloak-server-overlay</artifactId>
diff --git a/distribution/src-dist/pom.xml b/distribution/src-dist/pom.xml
index 4057c7e..c184227 100755
--- a/distribution/src-dist/pom.xml
+++ b/distribution/src-dist/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-distribution-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>keycloak-src-dist</artifactId>
diff --git a/examples/admin-client/pom.xml b/examples/admin-client/pom.xml
index f210c62..26b0eb2 100755
--- a/examples/admin-client/pom.xml
+++ b/examples/admin-client/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <artifactId>keycloak-examples-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Keycloak Examples - Admin Client</name>
diff --git a/examples/authz/hello-world/hello-world-authz-realm.json b/examples/authz/hello-world/hello-world-authz-realm.json
new file mode 100644
index 0000000..3ab917c
--- /dev/null
+++ b/examples/authz/hello-world/hello-world-authz-realm.json
@@ -0,0 +1,49 @@
+{
+  "realm" : "hello-world-authz",
+  "enabled" : true,
+  "privateKey" : "MIIEpQIBAAKCAQEAzMhNM9HXNQWhVf1m64zS67SIyQjj+tV5GR+MqlRTWDXdo8GAWHd+alY1urRhfRoqMy4F499+8wh2REKFykNt0ng6s6wWnEaKDboS3SAUV6lybcOAkwIOCtCZj1ItddKG3m64fzxDDQrcpkbiAvw3S8KJ4UJK+pyh9iX01duSDtM/HhPawsPdY8JSMfuo1IxQ2Vxw+8RKwbbdUeew6cyYGYAeFYwA66mlM3otB0RBHh4bjwg8297+2g53TdwM2rbCHRbrorMQD3031OTyFSp7lXCtoMLWRfAFnOP/2yZWZMXbiJheC0R3sLbU7Ef0/cUbYyk4Ckfq6pcYDR+VZBF7AwIDAQABAoIBAAwa4wVnKBOIS6srmYPfBTDNsTBBCEjxiYEErmn7JhoWxQ1DCPUxyxU6F177/q9Idqoj1FFOCtEO9P6/9+ym470HQmEQkR2Xxd1d3HOZy9oKuCro3ZbTDkVxY0JnlyxZz4MihGFxDH2e4MArfHy0sAgYbdIU+x2pWKGWSMzDd/TMSOExhc/sIQAg6ljbPCLLXCPQFAncoHRyGPrkRZs6UTZi5SJuCglVa2/3G+0drDdPuA83/mwsZfIBqQgbGbFgtq5T5C6CKMkPOQ42Rcclm7kEr6riTkJRo23EO1iOJVpxzI0tbxZsJAsW7zeqv0wWRyUgVfQAje6OdsNexp5aCtECgYEA6nMHCQ9xXvufCyzpIbYGxdAGqH6m1AR5gXerHqRiGNx+8UUt/E9cy/HTOhmZDK/eC4BT9tImeF01l1oSU/+wGKfux0SeAQchBhhq8GD6jmrtgczKAfZHp0Zrht7o9qu9KE7ZNWRmY1foJN9yNYmzY6qqHEy+zNo9amcqT7UZKO8CgYEA35sp9fMpMqkJE+NEJ9Ph/t2081BEkC0DYIuETZRSi+Ek5AliWTyEkg+oisTbWzi6fMQHS7W+M1SQP6djksLQNPP+353DKgup5gtKS+K/y2xNd7fSsNmkjW1bdJJpID7WzwwmwdahHxpcnFFuEXi5FkG3Vqmtd3cD0TYL33JlRy0CgYEA0+a3eybsDy9Zpp4m8IM3R98nxW8DlimdMLlafs2QpGvWiHdAgwWwF90wTxkHzgG+raKFQVbb0npcj7mnSyiUnxRZqt2H+eHZpUq4jR76F3LpzCGui2tvg+8QDMy4vwqmYyIxDCL8r9mqRnl3HpChBPoh2oY7BahTTjKEeZpzbR0CgYEAoNnVjX+mGzNNvGi4Fo5s/BIwoPcU20IGM+Uo/0W7O7Rx/Thi7x6BnzB0ZZ7GzRA51paNSQEsGXCzc5bOIjzR2cXLisDKK+zIAxwMDhrHLWZzM7OgdGeb38DTEUBhLzkE/VwYZUgoD1+/TxOkwhy9yCzt3gGhL1cF//GJCOwZvuECgYEAgsO4rdYScgCpsyePnHsFk+YtqtdORnmttF3JFcL3w2QneXuRwg2uW2Kfz8CVphrR9eOU0tiw38w6QTHIVeyRY8qqlHtiXj6dEYz7frh/k4hI29HwFx43rRpnAnN8kBEJYBYdbjaQ35Wsqkfu1tvHJ+6fxSwvQu/TVdGp0OfilAY=",
+  "publicKey" : "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzMhNM9HXNQWhVf1m64zS67SIyQjj+tV5GR+MqlRTWDXdo8GAWHd+alY1urRhfRoqMy4F499+8wh2REKFykNt0ng6s6wWnEaKDboS3SAUV6lybcOAkwIOCtCZj1ItddKG3m64fzxDDQrcpkbiAvw3S8KJ4UJK+pyh9iX01duSDtM/HhPawsPdY8JSMfuo1IxQ2Vxw+8RKwbbdUeew6cyYGYAeFYwA66mlM3otB0RBHh4bjwg8297+2g53TdwM2rbCHRbrorMQD3031OTyFSp7lXCtoMLWRfAFnOP/2yZWZMXbiJheC0R3sLbU7Ef0/cUbYyk4Ckfq6pcYDR+VZBF7AwIDAQAB",
+  "certificate" : "MIICsTCCAZkCBgFVETX4AzANBgkqhkiG9w0BAQsFADAcMRowGAYDVQQDDBFIZWxsbyBXb3JsZCBBdXRoWjAeFw0xNjA2MDIxMzAxMzdaFw0yNjA2MDIxMzAzMTdaMBwxGjAYBgNVBAMMEUhlbGxvIFdvcmxkIEF1dGhaMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzMhNM9HXNQWhVf1m64zS67SIyQjj+tV5GR+MqlRTWDXdo8GAWHd+alY1urRhfRoqMy4F499+8wh2REKFykNt0ng6s6wWnEaKDboS3SAUV6lybcOAkwIOCtCZj1ItddKG3m64fzxDDQrcpkbiAvw3S8KJ4UJK+pyh9iX01duSDtM/HhPawsPdY8JSMfuo1IxQ2Vxw+8RKwbbdUeew6cyYGYAeFYwA66mlM3otB0RBHh4bjwg8297+2g53TdwM2rbCHRbrorMQD3031OTyFSp7lXCtoMLWRfAFnOP/2yZWZMXbiJheC0R3sLbU7Ef0/cUbYyk4Ckfq6pcYDR+VZBF7AwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQANm5gIT/c50lwjawM686gNXpppLA928WsCOn9NIIWjSKekP8Bf9S73kf7vWcsEppm5B8rRyRxolXmzwghv74L7uVDg8Injjgj+XbPVQP+cJqWpSaMZHF7UfWe0/4M945Xcbmsl5q+m9PmrPG0AaaZhqXHcp4ehB1H+awyRqiERpJUuwZNycw2+2kjDADpsFf8hZVUd1F6ReYyOkqUyUjbL+jYTC7ZBNa7Ok+w6HCXWgkgVATAgQXJRM3w14IOc5MH/vfMCrCl/eNQLbjGl9y7u8PKwh3MXHDO2OLqtg6hOTSrOGUPJZGmGtUAl+2/R7FzoWkML/BNe2hjsL6UJwg91",
+  "requiredCredentials" : [ "password" ],
+  "users" :
+  [
+    {
+      "username" : "alice",
+      "enabled" : true,
+      "credentials" : [ {
+        "type" : "password",
+        "value" : "alice"
+      } ],
+      "realmRoles" : ["uma_authorization"]
+    },
+    {
+      "username" : "jdoe",
+      "enabled" : true,
+      "credentials" : [ {
+        "type" : "password",
+        "value" : "jdoe"
+      } ],
+      "realmRoles" : ["uma_authorization"]
+    },
+    {
+      "username" : "service-account-hello-world-authz-service",
+      "enabled" : true,
+      "serviceAccountClientId" : "hello-world-authz-service",
+      "clientRoles": {
+        "hello-world-authz-service" : ["uma_protection"]
+      }
+    }
+  ],
+  "clients" : [
+    {
+      "clientId" : "hello-world-authz-service",
+      "secret" : "secret",
+      "authorizationServicesEnabled" : true,
+      "enabled" : true,
+      "redirectUris" : [ "http://localhost:8080/hello-world-authz-service/*" ],
+      "baseUrl": "http://localhost:8080/hello-world-authz-service",
+      "adminUrl": "http://localhost:8080/hello-world-authz-service",
+      "directAccessGrantsEnabled" : true
+    }
+  ]
+}
\ No newline at end of file
diff --git a/examples/authz/hello-world/hello-world-authz-service.json b/examples/authz/hello-world/hello-world-authz-service.json
new file mode 100644
index 0000000..ea56e62
--- /dev/null
+++ b/examples/authz/hello-world/hello-world-authz-service.json
@@ -0,0 +1,30 @@
+{
+  "resources": [
+    {
+      "name": "Default Resource",
+      "uri": "/*",
+      "type": "urn:hello-world-authz-service:resources:default"
+    }
+  ],
+  "policies": [
+    {
+      "name": "Only From Realm Policy",
+      "description": "A policy that grants access only for users within this realm",
+      "type": "js",
+      "config": {
+        "applyPolicies": "[]",
+        "code": "var context = $evaluation.getContext();\n\n// using attributes from the evaluation context to obtain the realm\nvar contextAttributes = context.getAttributes();\nvar realmName = contextAttributes.getValue('kc.realm.name').asString(0);\n\n// using attributes from the identity to obtain the issuer\nvar identity = context.getIdentity();\nvar identityAttributes = identity.getAttributes();\nvar issuer = identityAttributes.getValue('iss').asString(0);\n\n// only users from the realm have access granted \nif (issuer.endsWith(realmName)) {\n    $evaluation.grant();\n}"
+      }
+    },
+    {
+      "name": "Default Permission",
+      "description": "A permission that applies to the default resource type",
+      "type": "resource",
+      "config": {
+        "defaultResourceType": "urn:hello-world-authz-service:resources:default",
+        "default": "true",
+        "applyPolicies": "[\"Only From Realm Policy\"]"
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/examples/authz/hello-world/pom.xml b/examples/authz/hello-world/pom.xml
new file mode 100755
index 0000000..e43cdc9
--- /dev/null
+++ b/examples/authz/hello-world/pom.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~  Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~  and other contributors as indicated by the @author tags.
+  ~
+  ~  Licensed under the Apache License, Version 2.0 (the "License");
+  ~  you may not use this file except in compliance with the License.
+  ~  You may obtain a copy of the License at
+  ~
+  ~  http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing, software
+  ~  distributed under the License is distributed on an "AS IS" BASIS,
+  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  See the License for the specific language governing permissions and
+  ~  limitations under the License.
+  ~
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.keycloak</groupId>
+        <artifactId>keycloak-authz-example-parent</artifactId>
+        <version>2.2.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>keycloak-authz-hello-world</artifactId>
+    <packaging>pom</packaging>
+
+    <name>Keycloak Authz: Hello World Example</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-authz-client</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/examples/authz/hello-world/src/main/java/org/keycloak/authz/helloworld/AuthorizationClientExample.java b/examples/authz/hello-world/src/main/java/org/keycloak/authz/helloworld/AuthorizationClientExample.java
new file mode 100644
index 0000000..887a461
--- /dev/null
+++ b/examples/authz/hello-world/src/main/java/org/keycloak/authz/helloworld/AuthorizationClientExample.java
@@ -0,0 +1,162 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.authz.helloworld;
+
+import org.keycloak.authorization.client.AuthzClient;
+import org.keycloak.authorization.client.representation.EntitlementRequest;
+import org.keycloak.authorization.client.representation.EntitlementResponse;
+import org.keycloak.authorization.client.representation.PermissionRequest;
+import org.keycloak.authorization.client.representation.RegistrationResponse;
+import org.keycloak.authorization.client.representation.ResourceRepresentation;
+import org.keycloak.authorization.client.representation.ScopeRepresentation;
+import org.keycloak.authorization.client.representation.TokenIntrospectionResponse;
+import org.keycloak.authorization.client.resource.ProtectedResource;
+import org.keycloak.representations.idm.authorization.Permission;
+
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AuthorizationClientExample {
+
+    public static void main(String[] args) {
+        obtainEntitlementsForResource();
+        obtainAllEntitlements();
+        createResource();
+        introspectRequestingPartyToken();
+    }
+
+    private static void introspectRequestingPartyToken() {
+        // create a new instance based on the configuration define at keycloak-authz.json
+        AuthzClient authzClient = AuthzClient.create();
+
+        // query the server for a resource with a given name
+        Set<String> resourceId = authzClient.protection()
+                .resource()
+                .findByFilter("name=Default Resource");
+
+        // obtian a Entitlement API Token in order to get access to the Entitlement API.
+        // this token is just an access token issued to a client on behalf of an user with a scope kc_entitlement
+        String eat = getEntitlementAPIToken(authzClient);
+
+        // create an entitlement request
+        EntitlementRequest request = new EntitlementRequest();
+        PermissionRequest permission = new PermissionRequest();
+
+        permission.setResourceSetId(resourceId.iterator().next());
+
+        request.addPermission(permission);
+
+        // send the entitlement request to the server in order to obtain a RPT with all permissions granted to the user
+        EntitlementResponse response = authzClient.entitlement(eat).get("hello-world-authz-service", request);
+        String rpt = response.getRpt();
+
+        TokenIntrospectionResponse requestingPartyToken = authzClient.protection().introspectRequestingPartyToken(rpt);
+
+        System.out.println("Token status is: " + requestingPartyToken.getActive());
+        System.out.println("Permissions granted by the server: ");
+
+        for (Permission granted : requestingPartyToken.getPermissions()) {
+            System.out.println(granted);
+        }
+
+    }
+
+    private static void createResource() {
+        // create a new instance based on the configuration define at keycloak-authz.json
+        AuthzClient authzClient = AuthzClient.create();
+
+        // create a new resource representation with the information we want
+        ResourceRepresentation newResource = new ResourceRepresentation();
+
+        newResource.setName("New Resource");
+        newResource.setType("urn:hello-world-authz:resources:example");
+
+        newResource.addScope(new ScopeRepresentation("urn:hello-world-authz:scopes:view"));
+
+        ProtectedResource resourceClient = authzClient.protection().resource();
+        Set<String> existingResource = resourceClient.findByFilter("name=" + newResource.getName());
+
+        if (!existingResource.isEmpty()) {
+            resourceClient.delete(existingResource.iterator().next());
+        }
+
+        // create the resource on the server
+        RegistrationResponse response = resourceClient.create(newResource);
+        String resourceId = response.getId();
+
+        // query the resource using its newly generated id
+        ResourceRepresentation resource = resourceClient.findById(resourceId).getResourceDescription();
+
+        System.out.println(resource);
+    }
+
+    private static void obtainEntitlementsForResource() {
+        // create a new instance based on the configuration define at keycloak-authz.json
+        AuthzClient authzClient = AuthzClient.create();
+
+        // obtian a Entitlement API Token in order to get access to the Entitlement API.
+        // this token is just an access token issued to a client on behalf of an user with a scope kc_entitlement
+        String eat = getEntitlementAPIToken(authzClient);
+
+        // create an entitlement request
+        EntitlementRequest request = new EntitlementRequest();
+        PermissionRequest permission = new PermissionRequest();
+
+        permission.setResourceSetName("Default Resource");
+
+        request.addPermission(permission);
+
+        // send the entitlement request to the server in order to obtain a RPT with all permissions granted to the user
+        EntitlementResponse response = authzClient.entitlement(eat).get("hello-world-authz-service", request);
+        String rpt = response.getRpt();
+
+        System.out.println("You got a RPT: " + rpt);
+
+        // now you can use the RPT to access protected resources on the resource server
+    }
+
+    private static void obtainAllEntitlements() {
+        // create a new instance based on the configuration define at keycloak-authz.json
+        AuthzClient authzClient = AuthzClient.create();
+
+        // obtian a Entitlement API Token in order to get access to the Entitlement API.
+        // this token is just an access token issued to a client on behalf of an user with a scope kc_entitlement
+        String eat = getEntitlementAPIToken(authzClient);
+
+        // send the entitlement request to the server in order to obtain a RPT with all permissions granted to the user
+        EntitlementResponse response = authzClient.entitlement(eat).getAll("hello-world-authz-service");
+        String rpt = response.getRpt();
+
+        System.out.println("You got a RPT: " + rpt);
+
+        // now you can use the RPT to access protected resources on the resource server
+    }
+
+    /**
+     * Obtain an Entitlement API Token or EAT from the server. Usually, EATs are going to be obtained by clients using a
+     * authorization_code grant type. Here we are using resource owner credentials for demonstration purposes.
+     *
+     * @param authzClient the authorization client instance
+     * @return a string representing a EAT
+     */
+    private static String getEntitlementAPIToken(AuthzClient authzClient) {
+        return authzClient.obtainAccessToken("alice", "alice").getToken();
+    }
+}
diff --git a/examples/authz/hello-world/src/main/resources/keycloak.json b/examples/authz/hello-world/src/main/resources/keycloak.json
new file mode 100644
index 0000000..b337389
--- /dev/null
+++ b/examples/authz/hello-world/src/main/resources/keycloak.json
@@ -0,0 +1,8 @@
+{
+  "realm": "hello-world-authz",
+  "auth-server-url" : "http://localhost:8080/auth",
+  "resource" : "hello-world-authz-service",
+  "credentials": {
+    "secret": "secret"
+  }
+}
\ No newline at end of file
diff --git a/examples/authz/hello-world-authz-service/hello-world-authz-realm.json b/examples/authz/hello-world-authz-service/hello-world-authz-realm.json
new file mode 100644
index 0000000..022ee6f
--- /dev/null
+++ b/examples/authz/hello-world-authz-service/hello-world-authz-realm.json
@@ -0,0 +1,48 @@
+{
+  "realm" : "hello-world-authz",
+  "enabled" : true,
+  "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+  "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "requiredCredentials" : [ "password" ],
+  "users" :
+  [
+    {
+      "username" : "alice",
+      "enabled" : true,
+      "credentials" : [ {
+        "type" : "password",
+        "value" : "alice"
+      } ],
+      "realmRoles" : ["uma_authorization"]
+    },
+    {
+      "username" : "jdoe",
+      "enabled" : true,
+      "credentials" : [ {
+        "type" : "password",
+        "value" : "jdoe"
+      } ],
+      "realmRoles" : ["uma_authorization"]
+    },
+    {
+      "username" : "service-account-hello-world-authz-service",
+      "enabled" : true,
+      "serviceAccountClientId" : "hello-world-authz-service",
+      "clientRoles": {
+        "hello-world-authz-service" : ["uma_protection"]
+      }
+    }
+  ],
+  "clients" : [
+    {
+      "clientId" : "hello-world-authz-service",
+      "secret" : "secret",
+      "authorizationServicesEnabled" : true,
+      "enabled" : true,
+      "redirectUris" : [ "http://localhost:8080/hello-world-authz-service/*" ],
+      "baseUrl": "http://localhost:8080/hello-world-authz-service",
+      "adminUrl": "http://localhost:8080/hello-world-authz-service",
+      "directAccessGrantsEnabled" : true
+    }
+  ]
+}
\ No newline at end of file
diff --git a/examples/authz/hello-world-authz-service/hello-world-authz-service.json b/examples/authz/hello-world-authz-service/hello-world-authz-service.json
new file mode 100644
index 0000000..6e509c7
--- /dev/null
+++ b/examples/authz/hello-world-authz-service/hello-world-authz-service.json
@@ -0,0 +1,36 @@
+{
+  "allowRemoteResourceManagement": false,
+  "policyEnforcementMode": "ENFORCING",
+  "resources": [
+    {
+      "name": "Default Resource",
+      "uri": "/*",
+      "type": "urn:hello-world-authz-service:resources:default"
+    }
+  ],
+  "policies": [
+    {
+      "name": "Default Policy",
+      "description": "A policy that grants access only for users within this realm",
+      "type": "js",
+      "logic": "POSITIVE",
+      "decisionStrategy": "AFFIRMATIVE",
+      "config": {
+        "applyPolicies": "[]",
+        "code": "// by default, grants any permission associated with this policy\n$evaluation.grant();\n"
+      }
+    },
+    {
+      "name": "Default Permission",
+      "description": "A permission that applies to the default resource type",
+      "type": "resource",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "defaultResourceType": "urn:hello-world-authz-service:resources:default",
+        "default": "true",
+        "applyPolicies": "[\"Default Policy\"]"
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/examples/authz/hello-world-authz-service/pom.xml b/examples/authz/hello-world-authz-service/pom.xml
new file mode 100755
index 0000000..7dfb88d
--- /dev/null
+++ b/examples/authz/hello-world-authz-service/pom.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~  Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~  and other contributors as indicated by the @author tags.
+  ~
+  ~  Licensed under the Apache License, Version 2.0 (the "License");
+  ~  you may not use this file except in compliance with the License.
+  ~  You may obtain a copy of the License at
+  ~
+  ~  http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing, software
+  ~  distributed under the License is distributed on an "AS IS" BASIS,
+  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  See the License for the specific language governing permissions and
+  ~  limitations under the License.
+  ~
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.keycloak</groupId>
+        <artifactId>keycloak-authz-example-parent</artifactId>
+        <version>2.2.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>hello-world-authz-service</artifactId>
+    <packaging>war</packaging>
+
+    <name>Keycloak Authz: Hello World Example</name>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.jboss.as.plugins</groupId>
+                <artifactId>jboss-as-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.wildfly.plugins</groupId>
+                <artifactId>wildfly-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/examples/authz/hello-world-authz-service/README.md b/examples/authz/hello-world-authz-service/README.md
new file mode 100644
index 0000000..a0cc40f
--- /dev/null
+++ b/examples/authz/hello-world-authz-service/README.md
@@ -0,0 +1,47 @@
+# About the Example Application
+
+This is a simple application to get you started with Keycloak Authorization Services.
+
+It provides a single page application which is protected by a policy enforcer that decides whether an user can access
+that page or not based on the permissions obtained from a Keycloak Server.
+
+## Create the Example Realm and a Resource Server
+
+Considering that your Keycloak Server is up and running, log in to the Keycloak Administration Console.
+
+Now, create a new realm based on the following configuration file:
+
+    examples/authz/hello-world-authz-service/hello-world-authz-realm.json
+    
+That will import a pre-configured realm with everything you need to run this example. For more details about how to import a realm 
+into Keycloak, check the Keycloak's reference documentation.
+
+After importing that file, you'll have a new realm called ``hello-world-authz``. 
+
+Now, let's import another configuration using the Administration Console in order to configure the client application ``hello-world-authz-service`` as a resource server with all resources, scopes, permissions and policies.
+
+Click on ``Clients`` on the left side menu. Click on the ``hello-world-authz-service`` on the client listing page. This will
+open the ``Client Details`` page. Once there, click on the `Authorization` tab. 
+
+Click on the ``Select file`` button, which means you want to import a resource server configuration. Now select the file that is located at:
+
+    examples/authz/hello-world-authz-service/hello-world-authz-service.json
+    
+Now click ``Upload`` and the resource server will be updated accordingly.
+
+## Deploy and Run the Example Application
+
+To deploy the example application, follow these steps:
+
+    cd examples/authz/hello-world-authz-service
+    mvn clean package wildfly:deploy
+    
+Now, try to access the client application using the following URL:
+
+    http://localhost:8080/hello-world-authz-service
+
+If everything is correct, you will be redirect to Keycloak login page. You can login to the application with the following credentials:
+
+* username: jdoe / password: jdoe
+* username: alice / password: alice
+
diff --git a/examples/authz/hello-world-authz-service/src/main/webapp/error.jsp b/examples/authz/hello-world-authz-service/src/main/webapp/error.jsp
new file mode 100644
index 0000000..00d25b3
--- /dev/null
+++ b/examples/authz/hello-world-authz-service/src/main/webapp/error.jsp
@@ -0,0 +1,30 @@
+<%--
+  ~  Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~  and other contributors as indicated by the @author tags.
+  ~
+  ~  Licensed under the Apache License, Version 2.0 (the "License");
+  ~  you may not use this file except in compliance with the License.
+  ~  You may obtain a copy of the License at
+  ~
+  ~  http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing, software
+  ~  distributed under the License is distributed on an "AS IS" BASIS,
+  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  See the License for the specific language governing permissions and
+  ~  limitations under the License.
+  ~
+  --%>
+
+<%@ page import="org.keycloak.common.util.KeycloakUriBuilder" %>
+<%@ page import="org.keycloak.constants.ServiceUrlConstants" %>
+
+<html>
+<body>
+<h2><a href="<%= KeycloakUriBuilder.fromUri("/auth").path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH)
+            .queryParam("redirect_uri", "http://localhost:8080/hello-world-authz-service").build("hello-world-authz").toString()%>">Logout</a></h2>
+
+<h3>Access Denied !</h3>
+</body>
+</html>
+
diff --git a/examples/authz/hello-world-authz-service/src/main/webapp/index.jsp b/examples/authz/hello-world-authz-service/src/main/webapp/index.jsp
new file mode 100644
index 0000000..75f3d6f
--- /dev/null
+++ b/examples/authz/hello-world-authz-service/src/main/webapp/index.jsp
@@ -0,0 +1,49 @@
+<%--
+  ~  Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~  and other contributors as indicated by the @author tags.
+  ~
+  ~  Licensed under the Apache License, Version 2.0 (the "License");
+  ~  you may not use this file except in compliance with the License.
+  ~  You may obtain a copy of the License at
+  ~
+  ~  http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing, software
+  ~  distributed under the License is distributed on an "AS IS" BASIS,
+  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  See the License for the specific language governing permissions and
+  ~  limitations under the License.
+  ~
+  --%>
+<%@page import="org.keycloak.AuthorizationContext" %>
+<%@ page import="org.keycloak.common.util.KeycloakUriBuilder" %>
+<%@ page import="org.keycloak.constants.ServiceUrlConstants" %>
+<%@ page import="org.keycloak.KeycloakSecurityContext" %>
+<%@ page import="org.keycloak.representations.idm.authorization.Permission" %>
+
+<%
+    KeycloakSecurityContext keycloakSecurityContext = (KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
+    AuthorizationContext authzContext = keycloakSecurityContext.getAuthorizationContext();
+%>
+<html>
+<body>
+<h2>Welcome !</h2>
+<h2><a href="<%= KeycloakUriBuilder.fromUri("/auth").path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH)
+            .queryParam("redirect_uri", "http://localhost:8080/hello-world-authz-service").build("hello-world-authz").toString()%>">Logout</a></h2>
+
+<h3>Your permissions are:</h3>
+
+<ul>
+    <%
+        for (Permission permission : authzContext.getPermissions()) {
+    %>
+    <li>
+        <p>Resource: <%= permission.getResourceSetName() %></p>
+        <p>ID: <%= permission.getResourceSetId() %></p>
+    </li>
+    <%
+        }
+    %>
+</ul>
+</body>
+</html>
\ No newline at end of file
diff --git a/examples/authz/hello-world-authz-service/src/main/webapp/WEB-INF/keycloak.json b/examples/authz/hello-world-authz-service/src/main/webapp/WEB-INF/keycloak.json
new file mode 100644
index 0000000..a492837
--- /dev/null
+++ b/examples/authz/hello-world-authz-service/src/main/webapp/WEB-INF/keycloak.json
@@ -0,0 +1,13 @@
+{
+  "realm": "hello-world-authz",
+  "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url": "http://localhost:8080/auth",
+  "ssl-required": "external",
+  "resource": "hello-world-authz-service",
+  "credentials": {
+    "secret": "secret"
+  },
+  "policy-enforcer": {
+    "on-deny-redirect-to" : "/hello-world-authz-service/error.jsp"
+  }
+}
\ No newline at end of file
diff --git a/examples/authz/hello-world-authz-service/src/main/webapp/WEB-INF/web.xml b/examples/authz/hello-world-authz-service/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..1ca06be
--- /dev/null
+++ b/examples/authz/hello-world-authz-service/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~  Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~  and other contributors as indicated by the @author tags.
+  ~
+  ~  Licensed under the Apache License, Version 2.0 (the "License");
+  ~  you may not use this file except in compliance with the License.
+  ~  You may obtain a copy of the License at
+  ~
+  ~  http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing, software
+  ~  distributed under the License is distributed on an "AS IS" BASIS,
+  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  See the License for the specific language governing permissions and
+  ~  limitations under the License.
+  ~
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+		 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+		 version="3.0">
+
+	<module-name>hello-world-authz-service</module-name>
+
+	<security-constraint>
+		<web-resource-collection>
+			<web-resource-name>All Resources</web-resource-name>
+			<url-pattern>/*</url-pattern>
+		</web-resource-collection>
+		<auth-constraint>
+			<role-name>uma_authorization</role-name>
+		</auth-constraint>
+	</security-constraint>
+
+	<login-config>
+		<auth-method>KEYCLOAK</auth-method>
+		<realm-name>hello-world-authz</realm-name>
+	</login-config>
+
+	<security-role>
+		<role-name>uma_authorization</role-name>
+	</security-role>
+</web-app>
diff --git a/examples/authz/photoz/photoz-authz-policy/pom.xml b/examples/authz/photoz/photoz-authz-policy/pom.xml
new file mode 100755
index 0000000..a2d166c
--- /dev/null
+++ b/examples/authz/photoz/photoz-authz-policy/pom.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.keycloak</groupId>
+        <artifactId>keycloak-authz-photoz-parent</artifactId>
+        <version>2.2.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>photoz-authz-policy</artifactId>
+    <packaging>jar</packaging>
+
+    <name>Keycloak Authz: Examples - Photoz Authz Rule-based Policy</name>
+
+    <description>
+        Photoz Authz Rule-based Policies using JBoss Drools
+    </description>
+
+</project>
diff --git a/examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.admin/Main.drl b/examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.admin/Main.drl
new file mode 100644
index 0000000..deb1c84
--- /dev/null
+++ b/examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.admin/Main.drl
@@ -0,0 +1,14 @@
+package com.photoz.authz.policy.admin
+
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+
+rule "Authorize Admin Resources"
+    dialect "mvel"
+        when
+           $evaluation : Evaluation(
+               $identity : context.identity,
+               $identity.hasRole("admin")
+           )
+        then
+           $evaluation.grant();
+end
\ No newline at end of file
diff --git a/examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.resource.owner/Main.drl b/examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.resource.owner/Main.drl
new file mode 100644
index 0000000..9378b94
--- /dev/null
+++ b/examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.resource.owner/Main.drl
@@ -0,0 +1,15 @@
+package com.photoz.authz.policy.admin
+
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+
+rule "Authorize Resource Owner"
+    dialect "mvel"
+    when
+       $evaluation : Evaluation(
+           $identity: context.identity,
+           $permission: permission,
+           $permission.resource != null && $permission.resource.owner.equals($identity.id)
+       )
+    then
+        $evaluation.grant();
+end
\ No newline at end of file
diff --git a/examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.user/Main.drl b/examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.user/Main.drl
new file mode 100644
index 0000000..9b1677e
--- /dev/null
+++ b/examples/authz/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.user/Main.drl
@@ -0,0 +1,14 @@
+package com.photoz.authz.policy.admin
+
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+
+rule "Authorize View User Album"
+    dialect "mvel"
+    when
+        $evaluation : Evaluation(
+            $identity : context.identity,
+            $identity.hasRole("user")
+       )
+    then
+       $evaluation.grant();
+end
\ No newline at end of file
diff --git a/examples/authz/photoz/photoz-authz-policy/src/main/resources/com/photoz/authz/policy/contextual/Main.drl b/examples/authz/photoz/photoz-authz-policy/src/main/resources/com/photoz/authz/policy/contextual/Main.drl
new file mode 100644
index 0000000..8a6a772
--- /dev/null
+++ b/examples/authz/photoz/photoz-authz-policy/src/main/resources/com/photoz/authz/policy/contextual/Main.drl
@@ -0,0 +1,15 @@
+package com.photoz.authz.policy.admin
+
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+
+rule "Authorize Using Context Information"
+    dialect "mvel"
+    when
+       $evaluation : Evaluation(
+           $attributes: context.attributes,
+           $attributes.containsValue("kc.identity.authc.method", "otp"),
+           $attributes.containsValue("someAttribute", "you_can_access")
+       )
+    then
+        $evaluation.grant();
+end
\ No newline at end of file
diff --git a/examples/authz/photoz/photoz-authz-policy/src/main/resources/META-INF/kmodule.xml b/examples/authz/photoz/photoz-authz-policy/src/main/resources/META-INF/kmodule.xml
new file mode 100644
index 0000000..84bacd5
--- /dev/null
+++ b/examples/authz/photoz/photoz-authz-policy/src/main/resources/META-INF/kmodule.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kmodule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://jboss.org/kie/6.0.0/kmodule">
+
+    <kbase name="PhotozAuthzAdminPolicy" packages="com.photoz.authz.policy.admin">
+        <ksession name="MainAdminSession" default="true"/>
+    </kbase>
+
+    <kbase name="PhotozAuthzUserPolicy" packages="com.photoz.authz.policy.user">
+        <ksession name="MainUserSession"  default="true"/>
+    </kbase>
+
+    <kbase name="PhotozAuthzOwnerPolicy" packages="com.photoz.authz.policy.resource.owner">
+        <ksession name="MainOwnerSession" default="true"/>
+    </kbase>
+
+    <kbase name="PhotozAuthzContextualPolicy" packages="com.photoz.authz.policy.contextual">
+        <ksession name="MainContextualSession" default="true"/>
+    </kbase>
+
+</kmodule>
diff --git a/examples/authz/photoz/photoz-html5-client/pom.xml b/examples/authz/photoz/photoz-html5-client/pom.xml
new file mode 100755
index 0000000..4c0aa95
--- /dev/null
+++ b/examples/authz/photoz/photoz-html5-client/pom.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.keycloak</groupId>
+        <artifactId>keycloak-authz-photoz-parent</artifactId>
+        <version>2.2.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>photoz-html5-client</artifactId>
+    <packaging>war</packaging>
+
+    <name>Keycloak Authz: Photoz HTML5 Client</name>
+    <description>Photoz HTML5 Client</description>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.jboss.as.plugins</groupId>
+                <artifactId>jboss-as-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.wildfly.plugins</groupId>
+                <artifactId>wildfly-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/examples/authz/photoz/photoz-html5-client/src/main/webapp/index.html b/examples/authz/photoz/photoz-html5-client/src/main/webapp/index.html
new file mode 100755
index 0000000..203b6e2
--- /dev/null
+++ b/examples/authz/photoz/photoz-html5-client/src/main/webapp/index.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<html lang="en">
+
+<head>
+    <meta charset="utf-8">
+    <title>Photoz HTML5 Client</title>
+
+    <!-- Load AngularJS -->
+    <script src="lib/angular/angular.min.js"></script>
+    <script src="lib/angular/angular-resource.min.js"></script>
+    <script src="lib/angular/angular-route.min.js"></script>
+    <script src="lib/jwt-decode.min.js"></script>
+
+    <script src="http://localhost:8080/auth/js/keycloak.js"></script>
+    <script src="http://localhost:8080/auth/js/keycloak-authz.js"></script>
+    <script src="js/identity.js" type="text/javascript"></script>
+    <script src="js/app.js" type="text/javascript"></script>
+</head>
+
+<body data-ng-controller="TokenCtrl">
+
+<a href data-ng-click="showRpt()">Show Requesting Party Token </a> | <a href data-ng-click="showAccessToken()">Show Access Token </a> | <a href data-ng-click="requestEntitlements()">Request Entitlements</a> | <a href="" ng-click="Identity.logout()">Sign Out</a>
+
+<div id="content-area" class="col-md-9" role="main">
+    <div id="content" ng-view/>
+</div>
+
+<pre style="background-color: #ddd; border: 1px solid #ccc; padding: 10px;" id="output"></pre>
+
+</body>
+</html>
diff --git a/examples/authz/photoz/photoz-html5-client/src/main/webapp/js/app.js b/examples/authz/photoz/photoz-html5-client/src/main/webapp/js/app.js
new file mode 100755
index 0000000..e58c5f5
--- /dev/null
+++ b/examples/authz/photoz/photoz-html5-client/src/main/webapp/js/app.js
@@ -0,0 +1,169 @@
+var module = angular.module('photoz', ['ngRoute', 'ngResource']);
+
+var resourceServerId = 'photoz-restful-api';
+var apiUrl = window.location.origin + '/' + resourceServerId;
+
+angular.element(document).ready(function ($http) {
+    var keycloak = new Keycloak('keycloak.json');
+    keycloak.init({onLoad: 'login-required'}).success(function () {
+        console.log('User is now authenticated.');
+
+        module.factory('Identity', function () {
+            return new Identity(keycloak);
+        });
+
+        angular.bootstrap(document, ["photoz"]);
+    }).error(function () {
+        window.location.reload();
+    });
+});
+
+module.config(function ($httpProvider, $routeProvider) {
+    $httpProvider.interceptors.push('authInterceptor');
+    $routeProvider.when('/', {
+        templateUrl: 'partials/home.html',
+        controller: 'GlobalCtrl'
+    }).when('/album/create', {
+        templateUrl: 'partials/album/create.html',
+        controller: 'AlbumCtrl',
+    }).when('/album/:id', {
+        templateUrl: 'partials/album/detail.html',
+        controller: 'AlbumCtrl',
+    }).when('/admin/album', {
+        templateUrl: 'partials/admin/albums.html',
+        controller: 'AdminAlbumCtrl',
+    }).when('/profile', {
+        templateUrl: 'partials/profile.html',
+        controller: 'ProfileCtrl',
+    });
+});
+
+module.controller('GlobalCtrl', function ($scope, $http, $route, $location, Album, Identity) {
+    Album.query(function (albums) {
+        $scope.albums = albums;
+    });
+
+    $scope.Identity = Identity;
+
+    $scope.deleteAlbum = function (album) {
+        new Album(album).$delete({id: album.id}, function () {
+            $route.reload();
+        });
+    }
+});
+
+module.controller('TokenCtrl', function ($scope, Identity) {
+    $scope.showRpt = function () {
+        document.getElementById("output").innerHTML = JSON.stringify(jwt_decode(Identity.authorization.rpt), null, '  ');
+    }
+
+    $scope.showAccessToken = function () {
+        document.getElementById("output").innerHTML = JSON.stringify(jwt_decode(Identity.authc.token), null, '  ');
+    }
+
+    $scope.requestEntitlements = function () {
+        Identity.authorization.entitlement('photoz-restful-api').then(function (rpt) {});
+    }
+
+    $scope.Identity = Identity;
+});
+
+module.controller('AlbumCtrl', function ($scope, $http, $routeParams, $location, Album) {
+    $scope.album = {};
+    if ($routeParams.id) {
+        $scope.album = Album.get({id: $routeParams.id});
+    }
+    $scope.create = function () {
+        var newAlbum = new Album($scope.album);
+        newAlbum.$save({}, function (data) {
+            $location.path('/');
+        });
+    };
+});
+
+module.controller('ProfileCtrl', function ($scope, $http, $routeParams, $location, Profile) {
+    $scope.profile = Profile.get();
+});
+
+module.controller('AdminAlbumCtrl', function ($scope, $http, $route, $location, AdminAlbum, Album) {
+    $scope.albums = {};
+    $http.get(apiUrl + '/admin/album').success(function (data) {
+        $scope.albums = data;
+    });
+    $scope.deleteAlbum = function (album) {
+        new Album(album).$delete({id: album.id}, function () {
+            $route.reload();
+        });
+    }
+});
+
+module.factory('Album', ['$resource', function ($resource) {
+    return $resource(apiUrl + '/album/:id');
+}]);
+
+module.factory('Profile', ['$resource', function ($resource) {
+    return $resource(apiUrl + '/profile');
+}]);
+
+module.factory('AdminAlbum', ['$resource', function ($resource) {
+    return $resource(apiUrl + '/admin/album/:id');
+}]);
+
+module.factory('authInterceptor', function ($q, $injector, $timeout, Identity) {
+    return {
+        request: function (request) {
+            document.getElementById("output").innerHTML = '';
+            if (Identity.authorization && Identity.authorization.rpt && request.url.indexOf('/authorize') == -1) {
+                retries = 0;
+                request.headers.Authorization = 'Bearer ' + Identity.authorization.rpt;
+            } else {
+                request.headers.Authorization = 'Bearer ' + Identity.authc.token;
+            }
+            return request;
+        },
+        responseError: function (rejection) {
+            var status = rejection.status;
+
+            if (status == 403 || status == 401) {
+                var retry = (!rejection.config.retry ||  rejection.config.retry < 1);
+
+                if (!retry) {
+                    document.getElementById("output").innerHTML = 'You can not access or perform the requested operation on this resource.';
+                    return $q.reject(rejection);
+                }
+
+                if (rejection.config.url.indexOf('/authorize') == -1 && retry) {
+                    var deferred = $q.defer();
+
+                    // here is the authorization logic, which tries to obtain an authorization token from the server in case the resource server
+                    // returns a 403 or 401.
+                    Identity.authorization.authorize(rejection.headers('WWW-Authenticate')).then(function (rpt) {
+                        deferred.resolve(rejection);
+                    }, function () {
+                        document.getElementById("output").innerHTML = 'You can not access or perform the requested operation on this resource.';
+                    }, function () {
+                        document.getElementById("output").innerHTML = 'Unexpected error from server.';
+                    });
+
+                    var promise = deferred.promise;
+
+                    return promise.then(function (res) {
+                        if (!res.config.retry) {
+                            res.config.retry = 1;
+                        } else {
+                            res.config.retry++;
+                        }
+
+                        var $http = $injector.get("$http");
+
+                        return $http(res.config).then(function (response) {
+                            return response;
+                        });
+                    });
+                }
+            }
+
+            return $q.reject(rejection);
+        }
+    };
+});
\ No newline at end of file
diff --git a/examples/authz/photoz/photoz-html5-client/src/main/webapp/js/identity.js b/examples/authz/photoz/photoz-html5-client/src/main/webapp/js/identity.js
new file mode 100644
index 0000000..9a018e4
--- /dev/null
+++ b/examples/authz/photoz/photoz-html5-client/src/main/webapp/js/identity.js
@@ -0,0 +1,60 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/**
+ * Creates an Identity object holding the information obtained from the access token issued by Keycloak, after a successful authentication,
+ * and a few utility methods to manage it.
+ */
+(function (window, undefined) {
+    var Identity = function (keycloak) {
+        this.loggedIn = true;
+
+        this.claims = {};
+        this.claims.name = keycloak.idTokenParsed.name;
+
+        this.authc = {};
+        this.authc.token = keycloak.token;
+
+        this.logout = function () {
+            keycloak.logout();
+        };
+
+        this.hasRole = function (name) {
+            if (keycloak && keycloak.hasRealmRole(name)) {
+                return true;
+            }
+            return false;
+        };
+
+        this.isAdmin = function () {
+            return this.hasRole("admin");
+        };
+
+        this.authorization = new KeycloakAuthorization(keycloak);
+    }
+
+    if ( typeof module === "object" && module && typeof module.exports === "object" ) {
+        module.exports = Identity;
+    } else {
+        window.Identity = Identity;
+
+        if ( typeof define === "function" && define.amd ) {
+            define( "identity", [], function () { return Identity; } );
+        }
+    }
+})( window );
\ No newline at end of file
diff --git a/examples/authz/photoz/photoz-html5-client/src/main/webapp/keycloak.json b/examples/authz/photoz/photoz-html5-client/src/main/webapp/keycloak.json
new file mode 100644
index 0000000..c1dee24
--- /dev/null
+++ b/examples/authz/photoz/photoz-html5-client/src/main/webapp/keycloak.json
@@ -0,0 +1,8 @@
+{
+  "realm": "photoz",
+  "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url" : "http://localhost:8080/auth",
+  "ssl-required" : "external",
+  "resource" : "photoz-html5-client",
+  "public-client" : true
+}
\ No newline at end of file
diff --git a/examples/authz/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular.min.js b/examples/authz/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular.min.js
new file mode 100644
index 0000000..569a9a2
--- /dev/null
+++ b/examples/authz/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular.min.js
@@ -0,0 +1,214 @@
+/*
+ AngularJS v1.3.0-beta.5
+ (c) 2010-2014 Google, Inc. http://angularjs.org
+ License: MIT
+*/
+(function(O,U,s){'use strict';function v(b){return function(){var a=arguments[0],c,a="["+(b?b+":":"")+a+"] http://errors.angularjs.org/1.3.0-beta.5/"+(b?b+"/":"")+a;for(c=1;c<arguments.length;c++)a=a+(1==c?"?":"&")+"p"+(c-1)+"="+encodeURIComponent("function"==typeof arguments[c]?arguments[c].toString().replace(/ \{[\s\S]*$/,""):"undefined"==typeof arguments[c]?"undefined":"string"!=typeof arguments[c]?JSON.stringify(arguments[c]):arguments[c]);return Error(a)}}function db(b){if(null==b||Da(b))return!1;
+var a=b.length;return 1===b.nodeType&&a?!0:t(b)||M(b)||0===a||"number"===typeof a&&0<a&&a-1 in b}function q(b,a,c){var d;if(b)if(P(b))for(d in b)"prototype"==d||("length"==d||"name"==d||b.hasOwnProperty&&!b.hasOwnProperty(d))||a.call(c,b[d],d);else if(b.forEach&&b.forEach!==q)b.forEach(a,c);else if(db(b))for(d=0;d<b.length;d++)a.call(c,b[d],d);else for(d in b)b.hasOwnProperty(d)&&a.call(c,b[d],d);return b}function Tb(b){var a=[],c;for(c in b)b.hasOwnProperty(c)&&a.push(c);return a.sort()}function ad(b,
+a,c){for(var d=Tb(b),e=0;e<d.length;e++)a.call(c,b[d[e]],d[e]);return d}function Ub(b){return function(a,c){b(c,a)}}function eb(){for(var b=ka.length,a;b;){b--;a=ka[b].charCodeAt(0);if(57==a)return ka[b]="A",ka.join("");if(90==a)ka[b]="0";else return ka[b]=String.fromCharCode(a+1),ka.join("")}ka.unshift("0");return ka.join("")}function Vb(b,a){a?b.$$hashKey=a:delete b.$$hashKey}function A(b){var a=b.$$hashKey;q(arguments,function(a){a!==b&&q(a,function(a,c){b[c]=a})});Vb(b,a);return b}function Y(b){return parseInt(b,
+10)}function Wb(b,a){return A(new (A(function(){},{prototype:b})),a)}function C(){}function Ea(b){return b}function aa(b){return function(){return b}}function D(b){return"undefined"===typeof b}function B(b){return"undefined"!==typeof b}function X(b){return null!=b&&"object"===typeof b}function t(b){return"string"===typeof b}function Ab(b){return"number"===typeof b}function ra(b){return"[object Date]"===ya.call(b)}function M(b){return"[object Array]"===ya.call(b)}function P(b){return"function"===typeof b}
+function fb(b){return"[object RegExp]"===ya.call(b)}function Da(b){return b&&b.document&&b.location&&b.alert&&b.setInterval}function bd(b){return!(!b||!(b.nodeName||b.prop&&b.attr&&b.find))}function cd(b,a,c){var d=[];q(b,function(b,g,f){d.push(a.call(c,b,g,f))});return d}function gb(b,a){if(b.indexOf)return b.indexOf(a);for(var c=0;c<b.length;c++)if(a===b[c])return c;return-1}function Fa(b,a){var c=gb(b,a);0<=c&&b.splice(c,1);return a}function ba(b,a){if(Da(b)||b&&b.$evalAsync&&b.$watch)throw Oa("cpws");
+if(a){if(b===a)throw Oa("cpi");if(M(b))for(var c=a.length=0;c<b.length;c++)a.push(ba(b[c]));else{c=a.$$hashKey;q(a,function(b,c){delete a[c]});for(var d in b)a[d]=ba(b[d]);Vb(a,c)}}else(a=b)&&(M(b)?a=ba(b,[]):ra(b)?a=new Date(b.getTime()):fb(b)?a=RegExp(b.source):X(b)&&(a=ba(b,{})));return a}function Xb(b,a){a=a||{};for(var c in b)!b.hasOwnProperty(c)||"$"===c.charAt(0)&&"$"===c.charAt(1)||(a[c]=b[c]);return a}function za(b,a){if(b===a)return!0;if(null===b||null===a)return!1;if(b!==b&&a!==a)return!0;
+var c=typeof b,d;if(c==typeof a&&"object"==c)if(M(b)){if(!M(a))return!1;if((c=b.length)==a.length){for(d=0;d<c;d++)if(!za(b[d],a[d]))return!1;return!0}}else{if(ra(b))return ra(a)&&b.getTime()==a.getTime();if(fb(b)&&fb(a))return b.toString()==a.toString();if(b&&b.$evalAsync&&b.$watch||a&&a.$evalAsync&&a.$watch||Da(b)||Da(a)||M(a))return!1;c={};for(d in b)if("$"!==d.charAt(0)&&!P(b[d])){if(!za(b[d],a[d]))return!1;c[d]=!0}for(d in a)if(!c.hasOwnProperty(d)&&"$"!==d.charAt(0)&&a[d]!==s&&!P(a[d]))return!1;
+return!0}return!1}function Yb(){return U.securityPolicy&&U.securityPolicy.isActive||U.querySelector&&!(!U.querySelector("[ng-csp]")&&!U.querySelector("[data-ng-csp]"))}function hb(b,a){var c=2<arguments.length?sa.call(arguments,2):[];return!P(a)||a instanceof RegExp?a:c.length?function(){return arguments.length?a.apply(b,c.concat(sa.call(arguments,0))):a.apply(b,c)}:function(){return arguments.length?a.apply(b,arguments):a.call(b)}}function dd(b,a){var c=a;"string"===typeof b&&"$"===b.charAt(0)?c=
+s:Da(a)?c="$WINDOW":a&&U===a?c="$DOCUMENT":a&&(a.$evalAsync&&a.$watch)&&(c="$SCOPE");return c}function ta(b,a){return"undefined"===typeof b?s:JSON.stringify(b,dd,a?"  ":null)}function Zb(b){return t(b)?JSON.parse(b):b}function Pa(b){"function"===typeof b?b=!0:b&&0!==b.length?(b=I(""+b),b=!("f"==b||"0"==b||"false"==b||"no"==b||"n"==b||"[]"==b)):b=!1;return b}function ha(b){b=y(b).clone();try{b.empty()}catch(a){}var c=y("<div>").append(b).html();try{return 3===b[0].nodeType?I(c):c.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,
+function(a,b){return"<"+I(b)})}catch(d){return I(c)}}function $b(b){try{return decodeURIComponent(b)}catch(a){}}function ac(b){var a={},c,d;q((b||"").split("&"),function(b){b&&(c=b.split("="),d=$b(c[0]),B(d)&&(b=B(c[1])?$b(c[1]):!0,a[d]?M(a[d])?a[d].push(b):a[d]=[a[d],b]:a[d]=b))});return a}function bc(b){var a=[];q(b,function(b,d){M(b)?q(b,function(b){a.push(Aa(d,!0)+(!0===b?"":"="+Aa(b,!0)))}):a.push(Aa(d,!0)+(!0===b?"":"="+Aa(b,!0)))});return a.length?a.join("&"):""}function Bb(b){return Aa(b,
+!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function Aa(b,a){return encodeURIComponent(b).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,a?"%20":"+")}function ed(b,a){function c(a){a&&d.push(a)}var d=[b],e,g,f=["ng:app","ng-app","x-ng-app","data-ng-app"],h=/\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;q(f,function(a){f[a]=!0;c(U.getElementById(a));a=a.replace(":","\\:");b.querySelectorAll&&(q(b.querySelectorAll("."+a),c),q(b.querySelectorAll("."+
+a+"\\:"),c),q(b.querySelectorAll("["+a+"]"),c))});q(d,function(a){if(!e){var b=h.exec(" "+a.className+" ");b?(e=a,g=(b[2]||"").replace(/\s+/g,",")):q(a.attributes,function(b){!e&&f[b.name]&&(e=a,g=b.value)})}});e&&a(e,g?[g]:[])}function cc(b,a){var c=function(){b=y(b);if(b.injector()){var c=b[0]===U?"document":ha(b);throw Oa("btstrpd",c);}a=a||[];a.unshift(["$provide",function(a){a.value("$rootElement",b)}]);a.unshift("ng");c=dc(a);c.invoke(["$rootScope","$rootElement","$compile","$injector","$animate",
+function(a,b,c,d,e){a.$apply(function(){b.data("$injector",d);c(b)(a)})}]);return c},d=/^NG_DEFER_BOOTSTRAP!/;if(O&&!d.test(O.name))return c();O.name=O.name.replace(d,"");Qa.resumeBootstrap=function(b){q(b,function(b){a.push(b)});c()}}function ib(b,a){a=a||"_";return b.replace(fd,function(b,d){return(d?a:"")+b.toLowerCase()})}function Cb(b,a,c){if(!b)throw Oa("areq",a||"?",c||"required");return b}function Ra(b,a,c){c&&M(b)&&(b=b[b.length-1]);Cb(P(b),a,"not a function, got "+(b&&"object"==typeof b?
+b.constructor.name||"Object":typeof b));return b}function Ba(b,a){if("hasOwnProperty"===b)throw Oa("badname",a);}function ec(b,a,c){if(!a)return b;a=a.split(".");for(var d,e=b,g=a.length,f=0;f<g;f++)d=a[f],b&&(b=(e=b)[d]);return!c&&P(b)?hb(e,b):b}function Db(b){var a=b[0];b=b[b.length-1];if(a===b)return y(a);var c=[a];do{a=a.nextSibling;if(!a)break;c.push(a)}while(a!==b);return y(c)}function gd(b){var a=v("$injector"),c=v("ng");b=b.angular||(b.angular={});b.$$minErr=b.$$minErr||v;return b.module||
+(b.module=function(){var b={};return function(e,g,f){if("hasOwnProperty"===e)throw c("badname","module");g&&b.hasOwnProperty(e)&&(b[e]=null);return b[e]||(b[e]=function(){function b(a,d,e){return function(){c[e||"push"]([a,d,arguments]);return n}}if(!g)throw a("nomod",e);var c=[],d=[],l=b("$injector","invoke"),n={_invokeQueue:c,_runBlocks:d,requires:g,name:e,provider:b("$provide","provider"),factory:b("$provide","factory"),service:b("$provide","service"),value:b("$provide","value"),constant:b("$provide",
+"constant","unshift"),animation:b("$animateProvider","register"),filter:b("$filterProvider","register"),controller:b("$controllerProvider","register"),directive:b("$compileProvider","directive"),config:l,run:function(a){d.push(a);return this}};f&&l(f);return n}())}}())}function hd(b){A(b,{bootstrap:cc,copy:ba,extend:A,equals:za,element:y,forEach:q,injector:dc,noop:C,bind:hb,toJson:ta,fromJson:Zb,identity:Ea,isUndefined:D,isDefined:B,isString:t,isFunction:P,isObject:X,isNumber:Ab,isElement:bd,isArray:M,
+version:id,isDate:ra,lowercase:I,uppercase:Ga,callbacks:{counter:0},$$minErr:v,$$csp:Yb});Sa=gd(O);try{Sa("ngLocale")}catch(a){Sa("ngLocale",[]).provider("$locale",jd)}Sa("ng",["ngLocale"],["$provide",function(a){a.provider({$$sanitizeUri:kd});a.provider("$compile",fc).directive({a:ld,input:gc,textarea:gc,form:md,script:nd,select:od,style:pd,option:qd,ngBind:rd,ngBindHtml:sd,ngBindTemplate:td,ngClass:ud,ngClassEven:vd,ngClassOdd:wd,ngCloak:xd,ngController:yd,ngForm:zd,ngHide:Ad,ngIf:Bd,ngInclude:Cd,
+ngInit:Dd,ngNonBindable:Ed,ngPluralize:Fd,ngRepeat:Gd,ngShow:Hd,ngStyle:Id,ngSwitch:Jd,ngSwitchWhen:Kd,ngSwitchDefault:Ld,ngOptions:Md,ngTransclude:Nd,ngModel:Od,ngList:Pd,ngChange:Qd,required:hc,ngRequired:hc,ngValue:Rd}).directive({ngInclude:Sd}).directive(Eb).directive(ic);a.provider({$anchorScroll:Td,$animate:Ud,$browser:Vd,$cacheFactory:Wd,$controller:Xd,$document:Yd,$exceptionHandler:Zd,$filter:jc,$interpolate:$d,$interval:ae,$http:be,$httpBackend:ce,$location:de,$log:ee,$parse:fe,$rootScope:ge,
+$q:he,$sce:ie,$sceDelegate:je,$sniffer:ke,$templateCache:le,$timeout:me,$window:ne,$$rAF:oe,$$asyncCallback:pe})}])}function Ta(b){return b.replace(qe,function(a,b,d,e){return e?d.toUpperCase():d}).replace(re,"Moz$1")}function Fb(b,a,c,d){function e(b){var e=c&&b?[this.filter(b)]:[this],m=a,k,l,n,p,r,u;if(!d||null!=b)for(;e.length;)for(k=e.shift(),l=0,n=k.length;l<n;l++)for(p=y(k[l]),m?p.triggerHandler("$destroy"):m=!m,r=0,p=(u=p.children()).length;r<p;r++)e.push(Ha(u[r]));return g.apply(this,arguments)}
+var g=Ha.fn[b],g=g.$original||g;e.$original=g;Ha.fn[b]=e}function se(b,a){var c,d,e=a.createDocumentFragment(),g=[];if(Gb.test(b)){c=c||e.appendChild(a.createElement("div"));d=(te.exec(b)||["",""])[1].toLowerCase();d=ea[d]||ea._default;c.innerHTML=d[1]+b.replace(ue,"<$1></$2>")+d[2];for(d=d[0];d--;)c=c.lastChild;g=g.concat(sa.call(c.childNodes,void 0));c=e.firstChild;c.textContent=""}else g.push(a.createTextNode(b));e.textContent="";e.innerHTML="";q(g,function(a){e.appendChild(a)});return e}function N(b){if(b instanceof
+N)return b;t(b)&&(b=ca(b));if(!(this instanceof N)){if(t(b)&&"<"!=b.charAt(0))throw Hb("nosel");return new N(b)}if(t(b)){var a;a=U;var c;b=(c=ve.exec(b))?[a.createElement(c[1])]:(c=se(b,a))?c.childNodes:[]}kc(this,b)}function Ib(b){return b.cloneNode(!0)}function Ia(b){lc(b);var a=0;for(b=b.childNodes||[];a<b.length;a++)Ia(b[a])}function mc(b,a,c,d){if(B(d))throw Hb("offargs");var e=la(b,"events");la(b,"handle")&&(D(a)?q(e,function(a,c){Ua(b,c,a);delete e[c]}):q(a.split(" "),function(a){D(c)?(Ua(b,
+a,e[a]),delete e[a]):Fa(e[a]||[],c)}))}function lc(b,a){var c=b[jb],d=Va[c];d&&(a?delete Va[c].data[a]:(d.handle&&(d.events.$destroy&&d.handle({},"$destroy"),mc(b)),delete Va[c],b[jb]=s))}function la(b,a,c){var d=b[jb],d=Va[d||-1];if(B(c))d||(b[jb]=d=++we,d=Va[d]={}),d[a]=c;else return d&&d[a]}function nc(b,a,c){var d=la(b,"data"),e=B(c),g=!e&&B(a),f=g&&!X(a);d||f||la(b,"data",d={});if(e)d[a]=c;else if(g){if(f)return d&&d[a];A(d,a)}else return d}function Jb(b,a){return b.getAttribute?-1<(" "+(b.getAttribute("class")||
+"")+" ").replace(/[\n\t]/g," ").indexOf(" "+a+" "):!1}function kb(b,a){a&&b.setAttribute&&q(a.split(" "),function(a){b.setAttribute("class",ca((" "+(b.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ").replace(" "+ca(a)+" "," ")))})}function lb(b,a){if(a&&b.setAttribute){var c=(" "+(b.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ");q(a.split(" "),function(a){a=ca(a);-1===c.indexOf(" "+a+" ")&&(c+=a+" ")});b.setAttribute("class",ca(c))}}function kc(b,a){if(a){a=a.nodeName||!B(a.length)||
+Da(a)?[a]:a;for(var c=0;c<a.length;c++)b.push(a[c])}}function oc(b,a){return mb(b,"$"+(a||"ngController")+"Controller")}function mb(b,a,c){b=y(b);9==b[0].nodeType&&(b=b.find("html"));for(a=M(a)?a:[a];b.length;){for(var d=b[0],e=0,g=a.length;e<g;e++)if((c=b.data(a[e]))!==s)return c;b=y(d.parentNode||11===d.nodeType&&d.host)}}function pc(b){for(var a=0,c=b.childNodes;a<c.length;a++)Ia(c[a]);for(;b.firstChild;)b.removeChild(b.firstChild)}function qc(b,a){var c=nb[a.toLowerCase()];return c&&rc[b.nodeName]&&
+c}function xe(b,a){var c=function(c,e){c.preventDefault||(c.preventDefault=function(){c.returnValue=!1});c.stopPropagation||(c.stopPropagation=function(){c.cancelBubble=!0});c.target||(c.target=c.srcElement||U);if(D(c.defaultPrevented)){var g=c.preventDefault;c.preventDefault=function(){c.defaultPrevented=!0;g.call(c)};c.defaultPrevented=!1}c.isDefaultPrevented=function(){return c.defaultPrevented||!1===c.returnValue};var f=Xb(a[e||c.type]||[]);q(f,function(a){a.call(b,c)});8>=T?(c.preventDefault=
+null,c.stopPropagation=null,c.isDefaultPrevented=null):(delete c.preventDefault,delete c.stopPropagation,delete c.isDefaultPrevented)};c.elem=b;return c}function Ja(b){var a=typeof b,c;"object"==a&&null!==b?"function"==typeof(c=b.$$hashKey)?c=b.$$hashKey():c===s&&(c=b.$$hashKey=eb()):c=b;return a+":"+c}function Wa(b){q(b,this.put,this)}function sc(b){var a,c;"function"==typeof b?(a=b.$inject)||(a=[],b.length&&(c=b.toString().replace(ye,""),c=c.match(ze),q(c[1].split(Ae),function(b){b.replace(Be,function(b,
+c,d){a.push(d)})})),b.$inject=a):M(b)?(c=b.length-1,Ra(b[c],"fn"),a=b.slice(0,c)):Ra(b,"fn",!0);return a}function dc(b){function a(a){return function(b,c){if(X(b))q(b,Ub(a));else return a(b,c)}}function c(a,b){Ba(a,"service");if(P(b)||M(b))b=n.instantiate(b);if(!b.$get)throw Xa("pget",a);return l[a+h]=b}function d(a,b){return c(a,{$get:b})}function e(a){var b=[],c,d,g,h;q(a,function(a){if(!k.get(a)){k.put(a,!0);try{if(t(a))for(c=Sa(a),b=b.concat(e(c.requires)).concat(c._runBlocks),d=c._invokeQueue,
+g=0,h=d.length;g<h;g++){var f=d[g],m=n.get(f[0]);m[f[1]].apply(m,f[2])}else P(a)?b.push(n.invoke(a)):M(a)?b.push(n.invoke(a)):Ra(a,"module")}catch(l){throw M(a)&&(a=a[a.length-1]),l.message&&(l.stack&&-1==l.stack.indexOf(l.message))&&(l=l.message+"\n"+l.stack),Xa("modulerr",a,l.stack||l.message||l);}}});return b}function g(a,b){function c(d){if(a.hasOwnProperty(d)){if(a[d]===f)throw Xa("cdep",m.join(" <- "));return a[d]}try{return m.unshift(d),a[d]=f,a[d]=b(d)}catch(e){throw a[d]===f&&delete a[d],
+e;}finally{m.shift()}}function d(a,b,e){var g=[],h=sc(a),f,m,k;m=0;for(f=h.length;m<f;m++){k=h[m];if("string"!==typeof k)throw Xa("itkn",k);g.push(e&&e.hasOwnProperty(k)?e[k]:c(k))}a.$inject||(a=a[f]);return a.apply(b,g)}return{invoke:d,instantiate:function(a,b){var c=function(){},e;c.prototype=(M(a)?a[a.length-1]:a).prototype;c=new c;e=d(a,c,b);return X(e)||P(e)?e:c},get:c,annotate:sc,has:function(b){return l.hasOwnProperty(b+h)||a.hasOwnProperty(b)}}}var f={},h="Provider",m=[],k=new Wa,l={$provide:{provider:a(c),
+factory:a(d),service:a(function(a,b){return d(a,["$injector",function(a){return a.instantiate(b)}])}),value:a(function(a,b){return d(a,aa(b))}),constant:a(function(a,b){Ba(a,"constant");l[a]=b;p[a]=b}),decorator:function(a,b){var c=n.get(a+h),d=c.$get;c.$get=function(){var a=r.invoke(d,c);return r.invoke(b,null,{$delegate:a})}}}},n=l.$injector=g(l,function(){throw Xa("unpr",m.join(" <- "));}),p={},r=p.$injector=g(p,function(a){a=n.get(a+h);return r.invoke(a.$get,a)});q(e(b),function(a){r.invoke(a||
+C)});return r}function Td(){var b=!0;this.disableAutoScrolling=function(){b=!1};this.$get=["$window","$location","$rootScope",function(a,c,d){function e(a){var b=null;q(a,function(a){b||"a"!==I(a.nodeName)||(b=a)});return b}function g(){var b=c.hash(),d;b?(d=f.getElementById(b))?d.scrollIntoView():(d=e(f.getElementsByName(b)))?d.scrollIntoView():"top"===b&&a.scrollTo(0,0):a.scrollTo(0,0)}var f=a.document;b&&d.$watch(function(){return c.hash()},function(){d.$evalAsync(g)});return g}]}function pe(){this.$get=
+["$$rAF","$timeout",function(b,a){return b.supported?function(a){return b(a)}:function(b){return a(b,0,!1)}}]}function Ce(b,a,c,d){function e(a){try{a.apply(null,sa.call(arguments,1))}finally{if(u--,0===u)for(;z.length;)try{z.pop()()}catch(b){c.error(b)}}}function g(a,b){(function S(){q(K,function(a){a()});w=b(S,a)})()}function f(){x=null;H!=h.url()&&(H=h.url(),q(ma,function(a){a(h.url())}))}var h=this,m=a[0],k=b.location,l=b.history,n=b.setTimeout,p=b.clearTimeout,r={};h.isMock=!1;var u=0,z=[];h.$$completeOutstandingRequest=
+e;h.$$incOutstandingRequestCount=function(){u++};h.notifyWhenNoOutstandingRequests=function(a){q(K,function(a){a()});0===u?a():z.push(a)};var K=[],w;h.addPollFn=function(a){D(w)&&g(100,n);K.push(a);return a};var H=k.href,G=a.find("base"),x=null;h.url=function(a,c){k!==b.location&&(k=b.location);l!==b.history&&(l=b.history);if(a){if(H!=a)return H=a,d.history?c?l.replaceState(null,"",a):(l.pushState(null,"",a),G.attr("href",G.attr("href"))):(x=a,c?k.replace(a):k.href=a),h}else return x||k.href.replace(/%27/g,
+"'")};var ma=[],L=!1;h.onUrlChange=function(a){if(!L){if(d.history)y(b).on("popstate",f);if(d.hashchange)y(b).on("hashchange",f);else h.addPollFn(f);L=!0}ma.push(a);return a};h.baseHref=function(){var a=G.attr("href");return a?a.replace(/^(https?\:)?\/\/[^\/]*/,""):""};var Q={},da="",E=h.baseHref();h.cookies=function(a,b){var d,e,g,h;if(a)b===s?m.cookie=escape(a)+"=;path="+E+";expires=Thu, 01 Jan 1970 00:00:00 GMT":t(b)&&(d=(m.cookie=escape(a)+"="+escape(b)+";path="+E).length+1,4096<d&&c.warn("Cookie '"+
+a+"' possibly not set or overflowed because it was too large ("+d+" > 4096 bytes)!"));else{if(m.cookie!==da)for(da=m.cookie,d=da.split("; "),Q={},g=0;g<d.length;g++)e=d[g],h=e.indexOf("="),0<h&&(a=unescape(e.substring(0,h)),Q[a]===s&&(Q[a]=unescape(e.substring(h+1))));return Q}};h.defer=function(a,b){var c;u++;c=n(function(){delete r[c];e(a)},b||0);r[c]=!0;return c};h.defer.cancel=function(a){return r[a]?(delete r[a],p(a),e(C),!0):!1}}function Vd(){this.$get=["$window","$log","$sniffer","$document",
+function(b,a,c,d){return new Ce(b,d,a,c)}]}function Wd(){this.$get=function(){function b(b,d){function e(a){a!=n&&(p?p==a&&(p=a.n):p=a,g(a.n,a.p),g(a,n),n=a,n.n=null)}function g(a,b){a!=b&&(a&&(a.p=b),b&&(b.n=a))}if(b in a)throw v("$cacheFactory")("iid",b);var f=0,h=A({},d,{id:b}),m={},k=d&&d.capacity||Number.MAX_VALUE,l={},n=null,p=null;return a[b]={put:function(a,b){if(k<Number.MAX_VALUE){var c=l[a]||(l[a]={key:a});e(c)}if(!D(b))return a in m||f++,m[a]=b,f>k&&this.remove(p.key),b},get:function(a){if(k<
+Number.MAX_VALUE){var b=l[a];if(!b)return;e(b)}return m[a]},remove:function(a){if(k<Number.MAX_VALUE){var b=l[a];if(!b)return;b==n&&(n=b.p);b==p&&(p=b.n);g(b.n,b.p);delete l[a]}delete m[a];f--},removeAll:function(){m={};f=0;l={};n=p=null},destroy:function(){l=h=m=null;delete a[b]},info:function(){return A({},h,{size:f})}}}var a={};b.info=function(){var b={};q(a,function(a,e){b[e]=a.info()});return b};b.get=function(b){return a[b]};return b}}function le(){this.$get=["$cacheFactory",function(b){return b("templates")}]}
+function fc(b,a){var c={},d="Directive",e=/^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,g=/(([\d\w\-_]+)(?:\:([^;]+))?;?)/,f=/^(on[a-z]+|formaction)$/;this.directive=function m(a,e){Ba(a,"directive");t(a)?(Cb(e,"directiveFactory"),c.hasOwnProperty(a)||(c[a]=[],b.factory(a+d,["$injector","$exceptionHandler",function(b,d){var e=[];q(c[a],function(c,g){try{var f=b.invoke(c);P(f)?f={compile:aa(f)}:!f.compile&&f.link&&(f.compile=aa(f.link));f.priority=f.priority||0;f.index=g;f.name=f.name||a;f.require=f.require||
+f.controller&&f.name;f.restrict=f.restrict||"A";e.push(f)}catch(m){d(m)}});return e}])),c[a].push(e)):q(a,Ub(m));return this};this.aHrefSanitizationWhitelist=function(b){return B(b)?(a.aHrefSanitizationWhitelist(b),this):a.aHrefSanitizationWhitelist()};this.imgSrcSanitizationWhitelist=function(b){return B(b)?(a.imgSrcSanitizationWhitelist(b),this):a.imgSrcSanitizationWhitelist()};this.$get=["$injector","$interpolate","$exceptionHandler","$http","$templateCache","$parse","$controller","$rootScope",
+"$document","$sce","$animate","$$sanitizeUri",function(a,b,l,n,p,r,u,z,K,w,H,G){function x(a,b,c,d,e){a instanceof y||(a=y(a));q(a,function(b,c){3==b.nodeType&&b.nodeValue.match(/\S+/)&&(a[c]=y(b).wrap("<span></span>").parent()[0])});var g=L(a,b,a,c,d,e);ma(a,"ng-scope");return function(b,c,d){Cb(b,"scope");var e=c?Ka.clone.call(a):a;q(d,function(a,b){e.data("$"+b+"Controller",a)});d=0;for(var f=e.length;d<f;d++){var m=e[d].nodeType;1!==m&&9!==m||e.eq(d).data("$scope",b)}c&&c(e,b);g&&g(b,e,e);return e}}
+function ma(a,b){try{a.addClass(b)}catch(c){}}function L(a,b,c,d,e,g){function f(a,c,d,e){var g,k,l,n,r,p,u;g=c.length;var J=Array(g);for(r=0;r<g;r++)J[r]=c[r];u=r=0;for(p=m.length;r<p;u++)k=J[u],c=m[r++],g=m[r++],l=y(k),c?(c.scope?(n=a.$new(),l.data("$scope",n)):n=a,(l=c.transclude)||!e&&b?c(g,n,k,d,Q(a,l||b)):c(g,n,k,d,e)):g&&g(a,k.childNodes,s,e)}for(var m=[],k,l,n,r,p=0;p<a.length;p++)k=new Kb,l=da(a[p],[],k,0===p?d:s,e),(g=l.length?ia(l,a[p],k,b,c,null,[],[],g):null)&&g.scope&&ma(y(a[p]),"ng-scope"),
+k=g&&g.terminal||!(n=a[p].childNodes)||!n.length?null:L(n,g?g.transclude:b),m.push(g,k),r=r||g||k,g=null;return r?f:null}function Q(a,b){return function(c,d,e){var g=!1;c||(c=a.$new(),g=c.$$transcluded=!0);d=b(c,d,e);if(g)d.on("$destroy",hb(c,c.$destroy));return d}}function da(a,b,c,d,f){var m=c.$attr,k;switch(a.nodeType){case 1:S(b,na(La(a).toLowerCase()),"E",d,f);var l,n,r;k=a.attributes;for(var p=0,u=k&&k.length;p<u;p++){var z=!1,K=!1;l=k[p];if(!T||8<=T||l.specified){n=l.name;r=na(n);W.test(r)&&
+(n=ib(r.substr(6),"-"));var H=r.replace(/(Start|End)$/,"");r===H+"Start"&&(z=n,K=n.substr(0,n.length-5)+"end",n=n.substr(0,n.length-6));r=na(n.toLowerCase());m[r]=n;c[r]=l=ca(l.value);qc(a,r)&&(c[r]=!0);N(a,b,l,r);S(b,r,"A",d,f,z,K)}}a=a.className;if(t(a)&&""!==a)for(;k=g.exec(a);)r=na(k[2]),S(b,r,"C",d,f)&&(c[r]=ca(k[3])),a=a.substr(k.index+k[0].length);break;case 3:v(b,a.nodeValue);break;case 8:try{if(k=e.exec(a.nodeValue))r=na(k[1]),S(b,r,"M",d,f)&&(c[r]=ca(k[2]))}catch(x){}}b.sort(D);return b}
+function E(a,b,c){var d=[],e=0;if(b&&a.hasAttribute&&a.hasAttribute(b)){do{if(!a)throw ja("uterdir",b,c);1==a.nodeType&&(a.hasAttribute(b)&&e++,a.hasAttribute(c)&&e--);d.push(a);a=a.nextSibling}while(0<e)}else d.push(a);return y(d)}function R(a,b,c){return function(d,e,g,f,k){e=E(e[0],b,c);return a(d,e,g,f,k)}}function ia(a,c,d,e,g,f,m,n,p){function z(a,b,c,d){if(a){c&&(a=R(a,c,d));a.require=F.require;if(Q===F||F.$$isolateScope)a=uc(a,{isolateScope:!0});m.push(a)}if(b){c&&(b=R(b,c,d));b.require=F.require;
+if(Q===F||F.$$isolateScope)b=uc(b,{isolateScope:!0});n.push(b)}}function K(a,b,c){var d,e="data",g=!1;if(t(a)){for(;"^"==(d=a.charAt(0))||"?"==d;)a=a.substr(1),"^"==d&&(e="inheritedData"),g=g||"?"==d;d=null;c&&"data"===e&&(d=c[a]);d=d||b[e]("$"+a+"Controller");if(!d&&!g)throw ja("ctreq",a,v);}else M(a)&&(d=[],q(a,function(a){d.push(K(a,b,c))}));return d}function H(a,e,g,f,p){function z(a,b){var c;2>arguments.length&&(b=a,a=s);A&&(c=da);return p(a,b,c)}var J,x,w,G,R,E,da={},ob;J=c===g?d:Xb(d,new Kb(y(g),
+d.$attr));x=J.$$element;if(Q){var S=/^\s*([@=&])(\??)\s*(\w*)\s*$/;f=y(g);E=e.$new(!0);ia&&ia===Q.$$originalDirective?f.data("$isolateScope",E):f.data("$isolateScopeNoTemplate",E);ma(f,"ng-isolate-scope");q(Q.scope,function(a,c){var d=a.match(S)||[],g=d[3]||c,f="?"==d[2],d=d[1],m,l,n,p;E.$$isolateBindings[c]=d+g;switch(d){case "@":J.$observe(g,function(a){E[c]=a});J.$$observers[g].$$scope=e;J[g]&&(E[c]=b(J[g])(e));break;case "=":if(f&&!J[g])break;l=r(J[g]);p=l.literal?za:function(a,b){return a===
+b};n=l.assign||function(){m=E[c]=l(e);throw ja("nonassign",J[g],Q.name);};m=E[c]=l(e);E.$watch(function(){var a=l(e);p(a,E[c])||(p(a,m)?n(e,a=E[c]):E[c]=a);return m=a},null,l.literal);break;case "&":l=r(J[g]);E[c]=function(a){return l(e,a)};break;default:throw ja("iscp",Q.name,c,a);}})}ob=p&&z;L&&q(L,function(a){var b={$scope:a===Q||a.$$isolateScope?E:e,$element:x,$attrs:J,$transclude:ob},c;R=a.controller;"@"==R&&(R=J[a.name]);c=u(R,b);da[a.name]=c;A||x.data("$"+a.name+"Controller",c);a.controllerAs&&
+(b.$scope[a.controllerAs]=c)});f=0;for(w=m.length;f<w;f++)try{G=m[f],G(G.isolateScope?E:e,x,J,G.require&&K(G.require,x,da),ob)}catch(F){l(F,ha(x))}f=e;Q&&(Q.template||null===Q.templateUrl)&&(f=E);a&&a(f,g.childNodes,s,p);for(f=n.length-1;0<=f;f--)try{G=n[f],G(G.isolateScope?E:e,x,J,G.require&&K(G.require,x,da),ob)}catch(B){l(B,ha(x))}}p=p||{};for(var w=-Number.MAX_VALUE,G,L=p.controllerDirectives,Q=p.newIsolateScopeDirective,ia=p.templateDirective,S=p.nonTlbTranscludeDirective,D=!1,A=p.hasElementTranscludeDirective,
+Z=d.$$element=y(c),F,v,V,Ya=e,O,N=0,oa=a.length;N<oa;N++){F=a[N];var T=F.$$start,W=F.$$end;T&&(Z=E(c,T,W));V=s;if(w>F.priority)break;if(V=F.scope)G=G||F,F.templateUrl||(I("new/isolated scope",Q,F,Z),X(V)&&(Q=F));v=F.name;!F.templateUrl&&F.controller&&(V=F.controller,L=L||{},I("'"+v+"' controller",L[v],F,Z),L[v]=F);if(V=F.transclude)D=!0,F.$$tlb||(I("transclusion",S,F,Z),S=F),"element"==V?(A=!0,w=F.priority,V=E(c,T,W),Z=d.$$element=y(U.createComment(" "+v+": "+d[v]+" ")),c=Z[0],pb(g,y(sa.call(V,0)),
+c),Ya=x(V,e,w,f&&f.name,{nonTlbTranscludeDirective:S})):(V=y(Ib(c)).contents(),Z.empty(),Ya=x(V,e));if(F.template)if(I("template",ia,F,Z),ia=F,V=P(F.template)?F.template(Z,d):F.template,V=Y(V),F.replace){f=F;V=Gb.test(V)?y(V):[];c=V[0];if(1!=V.length||1!==c.nodeType)throw ja("tplrt",v,"");pb(g,Z,c);oa={$attr:{}};V=da(c,[],oa);var $=a.splice(N+1,a.length-(N+1));Q&&tc(V);a=a.concat(V).concat($);B(d,oa);oa=a.length}else Z.html(V);if(F.templateUrl)I("template",ia,F,Z),ia=F,F.replace&&(f=F),H=C(a.splice(N,
+a.length-N),Z,d,g,Ya,m,n,{controllerDirectives:L,newIsolateScopeDirective:Q,templateDirective:ia,nonTlbTranscludeDirective:S}),oa=a.length;else if(F.compile)try{O=F.compile(Z,d,Ya),P(O)?z(null,O,T,W):O&&z(O.pre,O.post,T,W)}catch(aa){l(aa,ha(Z))}F.terminal&&(H.terminal=!0,w=Math.max(w,F.priority))}H.scope=G&&!0===G.scope;H.transclude=D&&Ya;p.hasElementTranscludeDirective=A;return H}function tc(a){for(var b=0,c=a.length;b<c;b++)a[b]=Wb(a[b],{$$isolateScope:!0})}function S(b,e,g,f,k,n,r){if(e===k)return null;
+k=null;if(c.hasOwnProperty(e)){var p;e=a.get(e+d);for(var u=0,z=e.length;u<z;u++)try{p=e[u],(f===s||f>p.priority)&&-1!=p.restrict.indexOf(g)&&(n&&(p=Wb(p,{$$start:n,$$end:r})),b.push(p),k=p)}catch(K){l(K)}}return k}function B(a,b){var c=b.$attr,d=a.$attr,e=a.$$element;q(a,function(d,e){"$"!=e.charAt(0)&&(b[e]&&(d+=("style"===e?";":" ")+b[e]),a.$set(e,d,!0,c[e]))});q(b,function(b,g){"class"==g?(ma(e,b),a["class"]=(a["class"]?a["class"]+" ":"")+b):"style"==g?(e.attr("style",e.attr("style")+";"+b),a.style=
+(a.style?a.style+";":"")+b):"$"==g.charAt(0)||a.hasOwnProperty(g)||(a[g]=b,d[g]=c[g])})}function C(a,b,c,d,e,g,f,k){var m=[],l,r,u=b[0],z=a.shift(),K=A({},z,{templateUrl:null,transclude:null,replace:null,$$originalDirective:z}),x=P(z.templateUrl)?z.templateUrl(b,c):z.templateUrl;b.empty();n.get(w.getTrustedResourceUrl(x),{cache:p}).success(function(n){var p,H;n=Y(n);if(z.replace){n=Gb.test(n)?y(n):[];p=n[0];if(1!=n.length||1!==p.nodeType)throw ja("tplrt",z.name,x);n={$attr:{}};pb(d,b,p);var w=da(p,
+[],n);X(z.scope)&&tc(w);a=w.concat(a);B(c,n)}else p=u,b.html(n);a.unshift(K);l=ia(a,p,c,e,b,z,g,f,k);q(d,function(a,c){a==p&&(d[c]=b[0])});for(r=L(b[0].childNodes,e);m.length;){n=m.shift();H=m.shift();var G=m.shift(),R=m.shift(),w=b[0];if(H!==u){var E=H.className;k.hasElementTranscludeDirective&&z.replace||(w=Ib(p));pb(G,y(H),w);ma(y(w),E)}H=l.transclude?Q(n,l.transclude):R;l(r,n,w,d,H)}m=null}).error(function(a,b,c,d){throw ja("tpload",d.url);});return function(a,b,c,d,e){m?(m.push(b),m.push(c),
+m.push(d),m.push(e)):l(r,b,c,d,e)}}function D(a,b){var c=b.priority-a.priority;return 0!==c?c:a.name!==b.name?a.name<b.name?-1:1:a.index-b.index}function I(a,b,c,d){if(b)throw ja("multidir",b.name,c.name,a,ha(d));}function v(a,c){var d=b(c,!0);d&&a.push({priority:0,compile:aa(function(a,b){var c=b.parent(),e=c.data("$binding")||[];e.push(d);ma(c.data("$binding",e),"ng-binding");a.$watch(d,function(a){b[0].nodeValue=a})})})}function O(a,b){if("srcdoc"==b)return w.HTML;var c=La(a);if("xlinkHref"==b||
+"FORM"==c&&"action"==b||"IMG"!=c&&("src"==b||"ngSrc"==b))return w.RESOURCE_URL}function N(a,c,d,e){var g=b(d,!0);if(g){if("multiple"===e&&"SELECT"===La(a))throw ja("selmulti",ha(a));c.push({priority:100,compile:function(){return{pre:function(c,d,m){d=m.$$observers||(m.$$observers={});if(f.test(e))throw ja("nodomevents");if(g=b(m[e],!0,O(a,e)))m[e]=g(c),(d[e]||(d[e]=[])).$$inter=!0,(m.$$observers&&m.$$observers[e].$$scope||c).$watch(g,function(a,b){"class"===e&&a!=b?m.$updateClass(a,b):m.$set(e,a)})}}}})}}
+function pb(a,b,c){var d=b[0],e=b.length,g=d.parentNode,f,m;if(a)for(f=0,m=a.length;f<m;f++)if(a[f]==d){a[f++]=c;m=f+e-1;for(var k=a.length;f<k;f++,m++)m<k?a[f]=a[m]:delete a[f];a.length-=e-1;break}g&&g.replaceChild(c,d);a=U.createDocumentFragment();a.appendChild(d);c[y.expando]=d[y.expando];d=1;for(e=b.length;d<e;d++)g=b[d],y(g).remove(),a.appendChild(g),delete b[d];b[0]=c;b.length=1}function uc(a,b){return A(function(){return a.apply(null,arguments)},a,b)}var Kb=function(a,b){this.$$element=a;this.$attr=
+b||{}};Kb.prototype={$normalize:na,$addClass:function(a){a&&0<a.length&&H.addClass(this.$$element,a)},$removeClass:function(a){a&&0<a.length&&H.removeClass(this.$$element,a)},$updateClass:function(a,b){var c=vc(a,b),d=vc(b,a);0===c.length?H.removeClass(this.$$element,d):0===d.length?H.addClass(this.$$element,c):H.setClass(this.$$element,c,d)},$set:function(a,b,c,d){var e=qc(this.$$element[0],a);e&&(this.$$element.prop(a,b),d=e);this[a]=b;d?this.$attr[a]=d:(d=this.$attr[a])||(this.$attr[a]=d=ib(a,
+"-"));e=La(this.$$element);if("A"===e&&"href"===a||"IMG"===e&&"src"===a)this[a]=b=G(b,"src"===a);!1!==c&&(null===b||b===s?this.$$element.removeAttr(d):this.$$element.attr(d,b));(c=this.$$observers)&&q(c[a],function(a){try{a(b)}catch(c){l(c)}})},$observe:function(a,b){var c=this,d=c.$$observers||(c.$$observers={}),e=d[a]||(d[a]=[]);e.push(b);z.$evalAsync(function(){e.$$inter||b(c[a])});return function(){Fa(e,b)}}};var Z=b.startSymbol(),oa=b.endSymbol(),Y="{{"==Z||"}}"==oa?Ea:function(a){return a.replace(/\{\{/g,
+Z).replace(/}}/g,oa)},W=/^ngAttr[A-Z]/;return x}]}function na(b){return Ta(b.replace(De,""))}function vc(b,a){var c="",d=b.split(/\s+/),e=a.split(/\s+/),g=0;a:for(;g<d.length;g++){for(var f=d[g],h=0;h<e.length;h++)if(f==e[h])continue a;c+=(0<c.length?" ":"")+f}return c}function Xd(){var b={},a=/^(\S+)(\s+as\s+(\w+))?$/;this.register=function(a,d){Ba(a,"controller");X(a)?A(b,a):b[a]=d};this.$get=["$injector","$window",function(c,d){return function(e,g){var f,h,m;t(e)&&(f=e.match(a),h=f[1],m=f[3],e=
+b.hasOwnProperty(h)?b[h]:ec(g.$scope,h,!0)||ec(d,h,!0),Ra(e,h,!0));f=c.instantiate(e,g);if(m){if(!g||"object"!=typeof g.$scope)throw v("$controller")("noscp",h||e.name,m);g.$scope[m]=f}return f}}]}function Yd(){this.$get=["$window",function(b){return y(b.document)}]}function Zd(){this.$get=["$log",function(b){return function(a,c){b.error.apply(b,arguments)}}]}function wc(b){var a={},c,d,e;if(!b)return a;q(b.split("\n"),function(b){e=b.indexOf(":");c=I(ca(b.substr(0,e)));d=ca(b.substr(e+1));c&&(a[c]=
+a[c]?a[c]+(", "+d):d)});return a}function xc(b){var a=X(b)?b:s;return function(c){a||(a=wc(b));return c?a[I(c)]||null:a}}function yc(b,a,c){if(P(c))return c(b,a);q(c,function(c){b=c(b,a)});return b}function be(){var b=/^\s*(\[|\{[^\{])/,a=/[\}\]]\s*$/,c=/^\)\]\}',?\n/,d={"Content-Type":"application/json;charset=utf-8"},e=this.defaults={transformResponse:[function(d){t(d)&&(d=d.replace(c,""),b.test(d)&&a.test(d)&&(d=Zb(d)));return d}],transformRequest:[function(a){return X(a)&&"[object File]"!==ya.call(a)&&
+"[object Blob]"!==ya.call(a)?ta(a):a}],headers:{common:{Accept:"application/json, text/plain, */*"},post:ba(d),put:ba(d),patch:ba(d)},xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN"},g=this.interceptors=[],f=this.responseInterceptors=[];this.$get=["$httpBackend","$browser","$cacheFactory","$rootScope","$q","$injector",function(a,b,c,d,n,p){function r(a){function c(a){var b=A({},a,{data:yc(a.data,a.headers,d.transformResponse)});return 200<=a.status&&300>a.status?b:n.reject(b)}var d={method:"get",
+transformRequest:e.transformRequest,transformResponse:e.transformResponse},g=function(a){function b(a){var c;q(a,function(b,d){P(b)&&(c=b(),null!=c?a[d]=c:delete a[d])})}var c=e.headers,d=A({},a.headers),g,f,c=A({},c.common,c[I(a.method)]);b(c);b(d);a:for(g in c){a=I(g);for(f in d)if(I(f)===a)continue a;d[g]=c[g]}return d}(a);A(d,a);d.headers=g;d.method=Ga(d.method);(a=Lb(d.url)?b.cookies()[d.xsrfCookieName||e.xsrfCookieName]:s)&&(g[d.xsrfHeaderName||e.xsrfHeaderName]=a);var f=[function(a){g=a.headers;
+var b=yc(a.data,xc(g),a.transformRequest);D(a.data)&&q(g,function(a,b){"content-type"===I(b)&&delete g[b]});D(a.withCredentials)&&!D(e.withCredentials)&&(a.withCredentials=e.withCredentials);return u(a,b,g).then(c,c)},s],h=n.when(d);for(q(w,function(a){(a.request||a.requestError)&&f.unshift(a.request,a.requestError);(a.response||a.responseError)&&f.push(a.response,a.responseError)});f.length;){a=f.shift();var k=f.shift(),h=h.then(a,k)}h.success=function(a){h.then(function(b){a(b.data,b.status,b.headers,
+d)});return h};h.error=function(a){h.then(null,function(b){a(b.data,b.status,b.headers,d)});return h};return h}function u(b,c,g){function f(a,b,c,e){w&&(200<=a&&300>a?w.put(s,[a,b,wc(c),e]):w.remove(s));m(b,a,c,e);d.$$phase||d.$apply()}function m(a,c,d,e){c=Math.max(c,0);(200<=c&&300>c?p.resolve:p.reject)({data:a,status:c,headers:xc(d),config:b,statusText:e})}function k(){var a=gb(r.pendingRequests,b);-1!==a&&r.pendingRequests.splice(a,1)}var p=n.defer(),u=p.promise,w,q,s=z(b.url,b.params);r.pendingRequests.push(b);
+u.then(k,k);(b.cache||e.cache)&&(!1!==b.cache&&"GET"==b.method)&&(w=X(b.cache)?b.cache:X(e.cache)?e.cache:K);if(w)if(q=w.get(s),B(q)){if(q.then)return q.then(k,k),q;M(q)?m(q[1],q[0],ba(q[2]),q[3]):m(q,200,{},"OK")}else w.put(s,u);D(q)&&a(b.method,s,c,f,g,b.timeout,b.withCredentials,b.responseType);return u}function z(a,b){if(!b)return a;var c=[];ad(b,function(a,b){null===a||D(a)||(M(a)||(a=[a]),q(a,function(a){X(a)&&(a=ta(a));c.push(Aa(b)+"="+Aa(a))}))});0<c.length&&(a+=(-1==a.indexOf("?")?"?":"&")+
+c.join("&"));return a}var K=c("$http"),w=[];q(g,function(a){w.unshift(t(a)?p.get(a):p.invoke(a))});q(f,function(a,b){var c=t(a)?p.get(a):p.invoke(a);w.splice(b,0,{response:function(a){return c(n.when(a))},responseError:function(a){return c(n.reject(a))}})});r.pendingRequests=[];(function(a){q(arguments,function(a){r[a]=function(b,c){return r(A(c||{},{method:a,url:b}))}})})("get","delete","head","jsonp");(function(a){q(arguments,function(a){r[a]=function(b,c,d){return r(A(d||{},{method:a,url:b,data:c}))}})})("post",
+"put");r.defaults=e;return r}]}function Ee(b){if(8>=T&&(!b.match(/^(get|post|head|put|delete|options)$/i)||!O.XMLHttpRequest))return new O.ActiveXObject("Microsoft.XMLHTTP");if(O.XMLHttpRequest)return new O.XMLHttpRequest;throw v("$httpBackend")("noxhr");}function ce(){this.$get=["$browser","$window","$document",function(b,a,c){return Fe(b,Ee,b.defer,a.angular.callbacks,c[0])}]}function Fe(b,a,c,d,e){function g(a,b,c){var g=e.createElement("script"),f=null;g.type="text/javascript";g.src=a;g.async=
+!0;f=function(a){Ua(g,"load",f);Ua(g,"error",f);e.body.removeChild(g);g=null;var h=-1,u="unknown";a&&("load"!==a.type||d[b].called||(a={type:"error"}),u=a.type,h="error"===a.type?404:200);c&&c(h,u)};qb(g,"load",f);qb(g,"error",f);e.body.appendChild(g);return f}var f=-1;return function(e,m,k,l,n,p,r,u){function z(){w=f;G&&G();x&&x.abort()}function K(a,d,e,g,f){L&&c.cancel(L);G=x=null;0===d&&(d=e?200:"file"==ua(m).protocol?404:0);a(1223===d?204:d,e,g,f||"");b.$$completeOutstandingRequest(C)}var w;b.$$incOutstandingRequestCount();
+m=m||b.url();if("jsonp"==I(e)){var H="_"+(d.counter++).toString(36);d[H]=function(a){d[H].data=a;d[H].called=!0};var G=g(m.replace("JSON_CALLBACK","angular.callbacks."+H),H,function(a,b){K(l,a,d[H].data,"",b);d[H]=C})}else{var x=a(e);x.open(e,m,!0);q(n,function(a,b){B(a)&&x.setRequestHeader(b,a)});x.onreadystatechange=function(){if(x&&4==x.readyState){var a=null,b=null;w!==f&&(a=x.getAllResponseHeaders(),b="response"in x?x.response:x.responseText);K(l,w||x.status,b,a,x.statusText||"")}};r&&(x.withCredentials=
+!0);if(u)try{x.responseType=u}catch(s){if("json"!==u)throw s;}x.send(k||null)}if(0<p)var L=c(z,p);else p&&p.then&&p.then(z)}}function $d(){var b="{{",a="}}";this.startSymbol=function(a){return a?(b=a,this):b};this.endSymbol=function(b){return b?(a=b,this):a};this.$get=["$parse","$exceptionHandler","$sce",function(c,d,e){function g(g,k,l){for(var n,p,r=0,u=[],z=g.length,K=!1,w=[];r<z;)-1!=(n=g.indexOf(b,r))&&-1!=(p=g.indexOf(a,n+f))?(r!=n&&u.push(g.substring(r,n)),u.push(r=c(K=g.substring(n+f,p))),
+r.exp=K,r=p+h,K=!0):(r!=z&&u.push(g.substring(r)),r=z);(z=u.length)||(u.push(""),z=1);if(l&&1<u.length)throw zc("noconcat",g);if(!k||K)return w.length=z,r=function(a){try{for(var b=0,c=z,f;b<c;b++)"function"==typeof(f=u[b])&&(f=f(a),f=l?e.getTrusted(l,f):e.valueOf(f),null===f||D(f)?f="":"string"!=typeof f&&(f=ta(f))),w[b]=f;return w.join("")}catch(h){a=zc("interr",g,h.toString()),d(a)}},r.exp=g,r.parts=u,r}var f=b.length,h=a.length;g.startSymbol=function(){return b};g.endSymbol=function(){return a};
+return g}]}function ae(){this.$get=["$rootScope","$window","$q",function(b,a,c){function d(d,f,h,m){var k=a.setInterval,l=a.clearInterval,n=c.defer(),p=n.promise,r=0,u=B(m)&&!m;h=B(h)?h:0;p.then(null,null,d);p.$$intervalId=k(function(){n.notify(r++);0<h&&r>=h&&(n.resolve(r),l(p.$$intervalId),delete e[p.$$intervalId]);u||b.$apply()},f);e[p.$$intervalId]=n;return p}var e={};d.cancel=function(a){return a&&a.$$intervalId in e?(e[a.$$intervalId].reject("canceled"),clearInterval(a.$$intervalId),delete e[a.$$intervalId],
+!0):!1};return d}]}function jd(){this.$get=function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3,lgSize:3},{minInt:1,minFrac:2,maxFrac:2,posPre:"\u00a4",posSuf:"",negPre:"(\u00a4",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"},DATETIME_FORMATS:{MONTH:"January February March April May June July August September October November December".split(" "),SHORTMONTH:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),
+DAY:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),SHORTDAY:"Sun Mon Tue Wed Thu Fri Sat".split(" "),AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a","short":"M/d/yy h:mm a",fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a",shortTime:"h:mm a"},pluralCat:function(b){return 1===b?"one":"other"}}}}function Ac(b){b=b.split("/");for(var a=b.length;a--;)b[a]=Bb(b[a]);return b.join("/")}function Bc(b,a,c){b=ua(b,c);a.$$protocol=
+b.protocol;a.$$host=b.hostname;a.$$port=Y(b.port)||Ge[b.protocol]||null}function Cc(b,a,c){var d="/"!==b.charAt(0);d&&(b="/"+b);b=ua(b,c);a.$$path=decodeURIComponent(d&&"/"===b.pathname.charAt(0)?b.pathname.substring(1):b.pathname);a.$$search=ac(b.search);a.$$hash=decodeURIComponent(b.hash);a.$$path&&"/"!=a.$$path.charAt(0)&&(a.$$path="/"+a.$$path)}function pa(b,a){if(0===a.indexOf(b))return a.substr(b.length)}function Za(b){var a=b.indexOf("#");return-1==a?b:b.substr(0,a)}function Mb(b){return b.substr(0,
+Za(b).lastIndexOf("/")+1)}function Dc(b,a){this.$$html5=!0;a=a||"";var c=Mb(b);Bc(b,this,b);this.$$parse=function(a){var e=pa(c,a);if(!t(e))throw Nb("ipthprfx",a,c);Cc(e,this,b);this.$$path||(this.$$path="/");this.$$compose()};this.$$compose=function(){var a=bc(this.$$search),b=this.$$hash?"#"+Bb(this.$$hash):"";this.$$url=Ac(this.$$path)+(a?"?"+a:"")+b;this.$$absUrl=c+this.$$url.substr(1)};this.$$rewrite=function(d){var e;if((e=pa(b,d))!==s)return d=e,(e=pa(a,e))!==s?c+(pa("/",e)||e):b+d;if((e=pa(c,
+d))!==s)return c+e;if(c==d+"/")return c}}function Ob(b,a){var c=Mb(b);Bc(b,this,b);this.$$parse=function(d){var e=pa(b,d)||pa(c,d),e="#"==e.charAt(0)?pa(a,e):this.$$html5?e:"";if(!t(e))throw Nb("ihshprfx",d,a);Cc(e,this,b);d=this.$$path;var g=/^\/?.*?:(\/.*)/;0===e.indexOf(b)&&(e=e.replace(b,""));g.exec(e)||(d=(e=g.exec(d))?e[1]:d);this.$$path=d;this.$$compose()};this.$$compose=function(){var c=bc(this.$$search),e=this.$$hash?"#"+Bb(this.$$hash):"";this.$$url=Ac(this.$$path)+(c?"?"+c:"")+e;this.$$absUrl=
+b+(this.$$url?a+this.$$url:"")};this.$$rewrite=function(a){if(Za(b)==Za(a))return a}}function Ec(b,a){this.$$html5=!0;Ob.apply(this,arguments);var c=Mb(b);this.$$rewrite=function(d){var e;if(b==Za(d))return d;if(e=pa(c,d))return b+a+e;if(c===d+"/")return c}}function rb(b){return function(){return this[b]}}function Fc(b,a){return function(c){if(D(c))return this[b];this[b]=a(c);this.$$compose();return this}}function de(){var b="",a=!1;this.hashPrefix=function(a){return B(a)?(b=a,this):b};this.html5Mode=
+function(b){return B(b)?(a=b,this):a};this.$get=["$rootScope","$browser","$sniffer","$rootElement",function(c,d,e,g){function f(a){c.$broadcast("$locationChangeSuccess",h.absUrl(),a)}var h,m=d.baseHref(),k=d.url();a?(m=k.substring(0,k.indexOf("/",k.indexOf("//")+2))+(m||"/"),e=e.history?Dc:Ec):(m=Za(k),e=Ob);h=new e(m,"#"+b);h.$$parse(h.$$rewrite(k));g.on("click",function(a){if(!a.ctrlKey&&!a.metaKey&&2!=a.which){for(var b=y(a.target);"a"!==I(b[0].nodeName);)if(b[0]===g[0]||!(b=b.parent())[0])return;
+var e=b.prop("href");X(e)&&"[object SVGAnimatedString]"===e.toString()&&(e=ua(e.animVal).href);var f=h.$$rewrite(e);e&&(!b.attr("target")&&f&&!a.isDefaultPrevented())&&(a.preventDefault(),f!=d.url()&&(h.$$parse(f),c.$apply(),O.angular["ff-684208-preventDefault"]=!0))}});h.absUrl()!=k&&d.url(h.absUrl(),!0);d.onUrlChange(function(a){h.absUrl()!=a&&(c.$evalAsync(function(){var b=h.absUrl();h.$$parse(a);c.$broadcast("$locationChangeStart",a,b).defaultPrevented?(h.$$parse(b),d.url(b)):f(b)}),c.$$phase||
+c.$digest())});var l=0;c.$watch(function(){var a=d.url(),b=h.$$replace;l&&a==h.absUrl()||(l++,c.$evalAsync(function(){c.$broadcast("$locationChangeStart",h.absUrl(),a).defaultPrevented?h.$$parse(a):(d.url(h.absUrl(),b),f(a))}));h.$$replace=!1;return l});return h}]}function ee(){var b=!0,a=this;this.debugEnabled=function(a){return B(a)?(b=a,this):b};this.$get=["$window",function(c){function d(a){a instanceof Error&&(a.stack?a=a.message&&-1===a.stack.indexOf(a.message)?"Error: "+a.message+"\n"+a.stack:
+a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function e(a){var b=c.console||{},e=b[a]||b.log||C;a=!1;try{a=!!e.apply}catch(m){}return a?function(){var a=[];q(arguments,function(b){a.push(d(b))});return e.apply(b,a)}:function(a,b){e(a,null==b?"":b)}}return{log:e("log"),info:e("info"),warn:e("warn"),error:e("error"),debug:function(){var c=e("debug");return function(){b&&c.apply(a,arguments)}}()}}]}function fa(b,a){if("constructor"===b)throw Ca("isecfld",a);return b}function $a(b,
+a){if(b){if(b.constructor===b)throw Ca("isecfn",a);if(b.document&&b.location&&b.alert&&b.setInterval)throw Ca("isecwindow",a);if(b.children&&(b.nodeName||b.prop&&b.attr&&b.find))throw Ca("isecdom",a);}return b}function sb(b,a,c,d,e){e=e||{};a=a.split(".");for(var g,f=0;1<a.length;f++){g=fa(a.shift(),d);var h=b[g];h||(h={},b[g]=h);b=h;b.then&&e.unwrapPromises&&(va(d),"$$v"in b||function(a){a.then(function(b){a.$$v=b})}(b),b.$$v===s&&(b.$$v={}),b=b.$$v)}g=fa(a.shift(),d);return b[g]=c}function Gc(b,
+a,c,d,e,g,f){fa(b,g);fa(a,g);fa(c,g);fa(d,g);fa(e,g);return f.unwrapPromises?function(f,m){var k=m&&m.hasOwnProperty(b)?m:f,l;if(null==k)return k;(k=k[b])&&k.then&&(va(g),"$$v"in k||(l=k,l.$$v=s,l.then(function(a){l.$$v=a})),k=k.$$v);if(!a)return k;if(null==k)return s;(k=k[a])&&k.then&&(va(g),"$$v"in k||(l=k,l.$$v=s,l.then(function(a){l.$$v=a})),k=k.$$v);if(!c)return k;if(null==k)return s;(k=k[c])&&k.then&&(va(g),"$$v"in k||(l=k,l.$$v=s,l.then(function(a){l.$$v=a})),k=k.$$v);if(!d)return k;if(null==
+k)return s;(k=k[d])&&k.then&&(va(g),"$$v"in k||(l=k,l.$$v=s,l.then(function(a){l.$$v=a})),k=k.$$v);if(!e)return k;if(null==k)return s;(k=k[e])&&k.then&&(va(g),"$$v"in k||(l=k,l.$$v=s,l.then(function(a){l.$$v=a})),k=k.$$v);return k}:function(g,f){var k=f&&f.hasOwnProperty(b)?f:g;if(null==k)return k;k=k[b];if(!a)return k;if(null==k)return s;k=k[a];if(!c)return k;if(null==k)return s;k=k[c];if(!d)return k;if(null==k)return s;k=k[d];return e?null==k?s:k=k[e]:k}}function He(b,a){fa(b,a);return function(a,
+d){return null==a?s:(d&&d.hasOwnProperty(b)?d:a)[b]}}function Ie(b,a,c){fa(b,c);fa(a,c);return function(c,e){if(null==c)return s;c=(e&&e.hasOwnProperty(b)?e:c)[b];return null==c?s:c[a]}}function Hc(b,a,c){if(Pb.hasOwnProperty(b))return Pb[b];var d=b.split("."),e=d.length,g;if(a.unwrapPromises||1!==e)if(a.unwrapPromises||2!==e)if(a.csp)g=6>e?Gc(d[0],d[1],d[2],d[3],d[4],c,a):function(b,g){var f=0,h;do h=Gc(d[f++],d[f++],d[f++],d[f++],d[f++],c,a)(b,g),g=s,b=h;while(f<e);return h};else{var f="var p;\n";
+q(d,function(b,d){fa(b,c);f+="if(s == null) return undefined;\ns="+(d?"s":'((k&&k.hasOwnProperty("'+b+'"))?k:s)')+'["'+b+'"];\n'+(a.unwrapPromises?'if (s && s.then) {\n pw("'+c.replace(/(["\r\n])/g,"\\$1")+'");\n if (!("$$v" in s)) {\n p=s;\n p.$$v = undefined;\n p.then(function(v) {p.$$v=v;});\n}\n s=s.$$v\n}\n':"")});var f=f+"return s;",h=new Function("s","k","pw",f);h.toString=aa(f);g=a.unwrapPromises?function(a,b){return h(a,b,va)}:h}else g=Ie(d[0],d[1],c);else g=He(d[0],c);"hasOwnProperty"!==
+b&&(Pb[b]=g);return g}function fe(){var b={},a={csp:!1,unwrapPromises:!1,logPromiseWarnings:!0};this.unwrapPromises=function(b){return B(b)?(a.unwrapPromises=!!b,this):a.unwrapPromises};this.logPromiseWarnings=function(b){return B(b)?(a.logPromiseWarnings=b,this):a.logPromiseWarnings};this.$get=["$filter","$sniffer","$log",function(c,d,e){a.csp=d.csp;va=function(b){a.logPromiseWarnings&&!Ic.hasOwnProperty(b)&&(Ic[b]=!0,e.warn("[$parse] Promise found in the expression `"+b+"`. Automatic unwrapping of promises in Angular expressions is deprecated."))};
+return function(d){var e;switch(typeof d){case "string":if(b.hasOwnProperty(d))return b[d];e=new Qb(a);e=(new ab(e,c,a)).parse(d,!1);"hasOwnProperty"!==d&&(b[d]=e);return e;case "function":return d;default:return C}}}]}function he(){this.$get=["$rootScope","$exceptionHandler",function(b,a){return Je(function(a){b.$evalAsync(a)},a)}]}function Je(b,a){function c(a){return a}function d(a){return f(a)}var e=function(){var f=[],k,l;return l={resolve:function(a){if(f){var c=f;f=s;k=g(a);c.length&&b(function(){for(var a,
+b=0,d=c.length;b<d;b++)a=c[b],k.then(a[0],a[1],a[2])})}},reject:function(a){l.resolve(h(a))},notify:function(a){if(f){var c=f;f.length&&b(function(){for(var b,d=0,e=c.length;d<e;d++)b=c[d],b[2](a)})}},promise:{then:function(b,g,h){var l=e(),z=function(d){try{l.resolve((P(b)?b:c)(d))}catch(e){l.reject(e),a(e)}},K=function(b){try{l.resolve((P(g)?g:d)(b))}catch(c){l.reject(c),a(c)}},w=function(b){try{l.notify((P(h)?h:c)(b))}catch(d){a(d)}};f?f.push([z,K,w]):k.then(z,K,w);return l.promise},"catch":function(a){return this.then(null,
+a)},"finally":function(a){function b(a,c){var d=e();c?d.resolve(a):d.reject(a);return d.promise}function d(e,g){var f=null;try{f=(a||c)()}catch(h){return b(h,!1)}return f&&P(f.then)?f.then(function(){return b(e,g)},function(a){return b(a,!1)}):b(e,g)}return this.then(function(a){return d(a,!0)},function(a){return d(a,!1)})}}}},g=function(a){return a&&P(a.then)?a:{then:function(c){var d=e();b(function(){d.resolve(c(a))});return d.promise}}},f=function(a){var b=e();b.reject(a);return b.promise},h=function(c){return{then:function(g,
+f){var h=e();b(function(){try{h.resolve((P(f)?f:d)(c))}catch(b){h.reject(b),a(b)}});return h.promise}}};return{defer:e,reject:f,when:function(h,k,l,n){var p=e(),r,u=function(b){try{return(P(k)?k:c)(b)}catch(d){return a(d),f(d)}},z=function(b){try{return(P(l)?l:d)(b)}catch(c){return a(c),f(c)}},K=function(b){try{return(P(n)?n:c)(b)}catch(d){a(d)}};b(function(){g(h).then(function(a){r||(r=!0,p.resolve(g(a).then(u,z,K)))},function(a){r||(r=!0,p.resolve(z(a)))},function(a){r||p.notify(K(a))})});return p.promise},
+all:function(a){var b=e(),c=0,d=M(a)?[]:{};q(a,function(a,e){c++;g(a).then(function(a){d.hasOwnProperty(e)||(d[e]=a,--c||b.resolve(d))},function(a){d.hasOwnProperty(e)||b.reject(a)})});0===c&&b.resolve(d);return b.promise}}}function oe(){this.$get=["$window","$timeout",function(b,a){var c=b.requestAnimationFrame||b.webkitRequestAnimationFrame||b.mozRequestAnimationFrame,d=b.cancelAnimationFrame||b.webkitCancelAnimationFrame||b.mozCancelAnimationFrame||b.webkitCancelRequestAnimationFrame,e=!!c,g=e?
+function(a){var b=c(a);return function(){d(b)}}:function(b){var c=a(b,16.66,!1);return function(){a.cancel(c)}};g.supported=e;return g}]}function ge(){var b=10,a=v("$rootScope"),c=null;this.digestTtl=function(a){arguments.length&&(b=a);return b};this.$get=["$injector","$exceptionHandler","$parse","$browser",function(d,e,g,f){function h(){this.$id=eb();this.$$phase=this.$parent=this.$$watchers=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null;this["this"]=this.$root=this;
+this.$$destroyed=!1;this.$$asyncQueue=[];this.$$postDigestQueue=[];this.$$listeners={};this.$$listenerCount={};this.$$isolateBindings={}}function m(b){if(p.$$phase)throw a("inprog",p.$$phase);p.$$phase=b}function k(a,b){var c=g(a);Ra(c,b);return c}function l(a,b,c){do a.$$listenerCount[c]-=b,0===a.$$listenerCount[c]&&delete a.$$listenerCount[c];while(a=a.$parent)}function n(){}h.prototype={constructor:h,$new:function(a){a?(a=new h,a.$root=this.$root,a.$$asyncQueue=this.$$asyncQueue,a.$$postDigestQueue=
+this.$$postDigestQueue):(a=function(){},a.prototype=this,a=new a,a.$id=eb());a["this"]=a;a.$$listeners={};a.$$listenerCount={};a.$parent=this;a.$$watchers=a.$$nextSibling=a.$$childHead=a.$$childTail=null;a.$$prevSibling=this.$$childTail;this.$$childHead?this.$$childTail=this.$$childTail.$$nextSibling=a:this.$$childHead=this.$$childTail=a;return a},$watch:function(a,b,d){var e=k(a,"watch"),g=this.$$watchers,f={fn:b,last:n,get:e,exp:a,eq:!!d};c=null;if(!P(b)){var h=k(b||C,"listener");f.fn=function(a,
+b,c){h(c)}}if("string"==typeof a&&e.constant){var m=f.fn;f.fn=function(a,b,c){m.call(this,a,b,c);Fa(g,f)}}g||(g=this.$$watchers=[]);g.unshift(f);return function(){Fa(g,f);c=null}},$watchCollection:function(a,b){var c=this,d,e,f,h=1<b.length,k=0,m=g(a),l=[],n={},p=!0,q=0;return this.$watch(function(){d=m(c);var a,b;if(X(d))if(db(d))for(e!==l&&(e=l,q=e.length=0,k++),a=d.length,q!==a&&(k++,e.length=q=a),b=0;b<a;b++)e[b]!==e[b]&&d[b]!==d[b]||e[b]===d[b]||(k++,e[b]=d[b]);else{e!==n&&(e=n={},q=0,k++);a=
+0;for(b in d)d.hasOwnProperty(b)&&(a++,e.hasOwnProperty(b)?e[b]!==d[b]&&(k++,e[b]=d[b]):(q++,e[b]=d[b],k++));if(q>a)for(b in k++,e)e.hasOwnProperty(b)&&!d.hasOwnProperty(b)&&(q--,delete e[b])}else e!==d&&(e=d,k++);return k},function(){p?(p=!1,b(d,d,c)):b(d,f,c);if(h)if(X(d))if(db(d)){f=Array(d.length);for(var a=0;a<d.length;a++)f[a]=d[a]}else for(a in f={},d)Jc.call(d,a)&&(f[a]=d[a]);else f=d})},$digest:function(){var d,g,f,h,k=this.$$asyncQueue,l=this.$$postDigestQueue,q,x,s=b,L,Q=[],y,E,R;m("$digest");
+c=null;do{x=!1;for(L=this;k.length;){try{R=k.shift(),R.scope.$eval(R.expression)}catch(B){p.$$phase=null,e(B)}c=null}a:do{if(h=L.$$watchers)for(q=h.length;q--;)try{if(d=h[q])if((g=d.get(L))!==(f=d.last)&&!(d.eq?za(g,f):"number"==typeof g&&"number"==typeof f&&isNaN(g)&&isNaN(f)))x=!0,c=d,d.last=d.eq?ba(g):g,d.fn(g,f===n?g:f,L),5>s&&(y=4-s,Q[y]||(Q[y]=[]),E=P(d.exp)?"fn: "+(d.exp.name||d.exp.toString()):d.exp,E+="; newVal: "+ta(g)+"; oldVal: "+ta(f),Q[y].push(E));else if(d===c){x=!1;break a}}catch(t){p.$$phase=
+null,e(t)}if(!(h=L.$$childHead||L!==this&&L.$$nextSibling))for(;L!==this&&!(h=L.$$nextSibling);)L=L.$parent}while(L=h);if((x||k.length)&&!s--)throw p.$$phase=null,a("infdig",b,ta(Q));}while(x||k.length);for(p.$$phase=null;l.length;)try{l.shift()()}catch(S){e(S)}},$destroy:function(){if(!this.$$destroyed){var a=this.$parent;this.$broadcast("$destroy");this.$$destroyed=!0;this!==p&&(q(this.$$listenerCount,hb(null,l,this)),a.$$childHead==this&&(a.$$childHead=this.$$nextSibling),a.$$childTail==this&&
+(a.$$childTail=this.$$prevSibling),this.$$prevSibling&&(this.$$prevSibling.$$nextSibling=this.$$nextSibling),this.$$nextSibling&&(this.$$nextSibling.$$prevSibling=this.$$prevSibling),this.$parent=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=this.$root=null,this.$$listeners={},this.$$watchers=this.$$asyncQueue=this.$$postDigestQueue=[],this.$destroy=this.$digest=this.$apply=C,this.$on=this.$watch=function(){return C})}},$eval:function(a,b){return g(a)(this,b)},$evalAsync:function(a){p.$$phase||
+p.$$asyncQueue.length||f.defer(function(){p.$$asyncQueue.length&&p.$digest()});this.$$asyncQueue.push({scope:this,expression:a})},$$postDigest:function(a){this.$$postDigestQueue.push(a)},$apply:function(a){try{return m("$apply"),this.$eval(a)}catch(b){e(b)}finally{p.$$phase=null;try{p.$digest()}catch(c){throw e(c),c;}}},$on:function(a,b){var c=this.$$listeners[a];c||(this.$$listeners[a]=c=[]);c.push(b);var d=this;do d.$$listenerCount[a]||(d.$$listenerCount[a]=0),d.$$listenerCount[a]++;while(d=d.$parent);
+var e=this;return function(){c[gb(c,b)]=null;l(e,1,a)}},$emit:function(a,b){var c=[],d,g=this,f=!1,h={name:a,targetScope:g,stopPropagation:function(){f=!0},preventDefault:function(){h.defaultPrevented=!0},defaultPrevented:!1},k=[h].concat(sa.call(arguments,1)),m,l;do{d=g.$$listeners[a]||c;h.currentScope=g;m=0;for(l=d.length;m<l;m++)if(d[m])try{d[m].apply(null,k)}catch(n){e(n)}else d.splice(m,1),m--,l--;if(f)break;g=g.$parent}while(g);return h},$broadcast:function(a,b){for(var c=this,d=this,g={name:a,
+targetScope:this,preventDefault:function(){g.defaultPrevented=!0},defaultPrevented:!1},f=[g].concat(sa.call(arguments,1)),h,k;c=d;){g.currentScope=c;d=c.$$listeners[a]||[];h=0;for(k=d.length;h<k;h++)if(d[h])try{d[h].apply(null,f)}catch(m){e(m)}else d.splice(h,1),h--,k--;if(!(d=c.$$listenerCount[a]&&c.$$childHead||c!==this&&c.$$nextSibling))for(;c!==this&&!(d=c.$$nextSibling);)c=c.$parent}return g}};var p=new h;return p}]}function kd(){var b=/^\s*(https?|ftp|mailto|tel|file):/,a=/^\s*(https?|ftp|file|blob):|data:image\//;
+this.aHrefSanitizationWhitelist=function(a){return B(a)?(b=a,this):b};this.imgSrcSanitizationWhitelist=function(b){return B(b)?(a=b,this):a};this.$get=function(){return function(c,d){var e=d?a:b,g;if(!T||8<=T)if(g=ua(c).href,""!==g&&!g.match(e))return"unsafe:"+g;return c}}}function Ke(b){if("self"===b)return b;if(t(b)){if(-1<b.indexOf("***"))throw wa("iwcard",b);b=b.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g,"\\$1").replace(/\x08/g,"\\x08").replace("\\*\\*",".*").replace("\\*","[^:/.?&;]*");return RegExp("^"+
+b+"$")}if(fb(b))return RegExp("^"+b.source+"$");throw wa("imatcher");}function Kc(b){var a=[];B(b)&&q(b,function(b){a.push(Ke(b))});return a}function je(){this.SCE_CONTEXTS=ga;var b=["self"],a=[];this.resourceUrlWhitelist=function(a){arguments.length&&(b=Kc(a));return b};this.resourceUrlBlacklist=function(b){arguments.length&&(a=Kc(b));return a};this.$get=["$injector",function(c){function d(a){var b=function(a){this.$$unwrapTrustedValue=function(){return a}};a&&(b.prototype=new a);b.prototype.valueOf=
+function(){return this.$$unwrapTrustedValue()};b.prototype.toString=function(){return this.$$unwrapTrustedValue().toString()};return b}var e=function(a){throw wa("unsafe");};c.has("$sanitize")&&(e=c.get("$sanitize"));var g=d(),f={};f[ga.HTML]=d(g);f[ga.CSS]=d(g);f[ga.URL]=d(g);f[ga.JS]=d(g);f[ga.RESOURCE_URL]=d(f[ga.URL]);return{trustAs:function(a,b){var c=f.hasOwnProperty(a)?f[a]:null;if(!c)throw wa("icontext",a,b);if(null===b||b===s||""===b)return b;if("string"!==typeof b)throw wa("itype",a);return new c(b)},
+getTrusted:function(c,d){if(null===d||d===s||""===d)return d;var g=f.hasOwnProperty(c)?f[c]:null;if(g&&d instanceof g)return d.$$unwrapTrustedValue();if(c===ga.RESOURCE_URL){var g=ua(d.toString()),l,n,p=!1;l=0;for(n=b.length;l<n;l++)if("self"===b[l]?Lb(g):b[l].exec(g.href)){p=!0;break}if(p)for(l=0,n=a.length;l<n;l++)if("self"===a[l]?Lb(g):a[l].exec(g.href)){p=!1;break}if(p)return d;throw wa("insecurl",d.toString());}if(c===ga.HTML)return e(d);throw wa("unsafe");},valueOf:function(a){return a instanceof
+g?a.$$unwrapTrustedValue():a}}}]}function ie(){var b=!0;this.enabled=function(a){arguments.length&&(b=!!a);return b};this.$get=["$parse","$sniffer","$sceDelegate",function(a,c,d){if(b&&c.msie&&8>c.msieDocumentMode)throw wa("iequirks");var e=ba(ga);e.isEnabled=function(){return b};e.trustAs=d.trustAs;e.getTrusted=d.getTrusted;e.valueOf=d.valueOf;b||(e.trustAs=e.getTrusted=function(a,b){return b},e.valueOf=Ea);e.parseAs=function(b,c){var d=a(c);return d.literal&&d.constant?d:function(a,c){return e.getTrusted(b,
+d(a,c))}};var g=e.parseAs,f=e.getTrusted,h=e.trustAs;q(ga,function(a,b){var c=I(b);e[Ta("parse_as_"+c)]=function(b){return g(a,b)};e[Ta("get_trusted_"+c)]=function(b){return f(a,b)};e[Ta("trust_as_"+c)]=function(b){return h(a,b)}});return e}]}function ke(){this.$get=["$window","$document",function(b,a){var c={},d=Y((/android (\d+)/.exec(I((b.navigator||{}).userAgent))||[])[1]),e=/Boxee/i.test((b.navigator||{}).userAgent),g=a[0]||{},f=g.documentMode,h,m=/^(Moz|webkit|O|ms)(?=[A-Z])/,k=g.body&&g.body.style,
+l=!1,n=!1;if(k){for(var p in k)if(l=m.exec(p)){h=l[0];h=h.substr(0,1).toUpperCase()+h.substr(1);break}h||(h="WebkitOpacity"in k&&"webkit");l=!!("transition"in k||h+"Transition"in k);n=!!("animation"in k||h+"Animation"in k);!d||l&&n||(l=t(g.body.style.webkitTransition),n=t(g.body.style.webkitAnimation))}return{history:!(!b.history||!b.history.pushState||4>d||e),hashchange:"onhashchange"in b&&(!f||7<f),hasEvent:function(a){if("input"==a&&9==T)return!1;if(D(c[a])){var b=g.createElement("div");c[a]="on"+
+a in b}return c[a]},csp:Yb(),vendorPrefix:h,transitions:l,animations:n,android:d,msie:T,msieDocumentMode:f}}]}function me(){this.$get=["$rootScope","$browser","$q","$exceptionHandler",function(b,a,c,d){function e(e,h,m){var k=c.defer(),l=k.promise,n=B(m)&&!m;h=a.defer(function(){try{k.resolve(e())}catch(a){k.reject(a),d(a)}finally{delete g[l.$$timeoutId]}n||b.$apply()},h);l.$$timeoutId=h;g[h]=k;return l}var g={};e.cancel=function(b){return b&&b.$$timeoutId in g?(g[b.$$timeoutId].reject("canceled"),
+delete g[b.$$timeoutId],a.defer.cancel(b.$$timeoutId)):!1};return e}]}function ua(b,a){var c=b;T&&(W.setAttribute("href",c),c=W.href);W.setAttribute("href",c);return{href:W.href,protocol:W.protocol?W.protocol.replace(/:$/,""):"",host:W.host,search:W.search?W.search.replace(/^\?/,""):"",hash:W.hash?W.hash.replace(/^#/,""):"",hostname:W.hostname,port:W.port,pathname:"/"===W.pathname.charAt(0)?W.pathname:"/"+W.pathname}}function Lb(b){b=t(b)?ua(b):b;return b.protocol===Lc.protocol&&b.host===Lc.host}
+function ne(){this.$get=aa(O)}function jc(b){function a(d,e){if(X(d)){var g={};q(d,function(b,c){g[c]=a(c,b)});return g}return b.factory(d+c,e)}var c="Filter";this.register=a;this.$get=["$injector",function(a){return function(b){return a.get(b+c)}}];a("currency",Mc);a("date",Nc);a("filter",Le);a("json",Me);a("limitTo",Ne);a("lowercase",Oe);a("number",Oc);a("orderBy",Pc);a("uppercase",Pe)}function Le(){return function(b,a,c){if(!M(b))return b;var d=typeof c,e=[];e.check=function(a){for(var b=0;b<e.length;b++)if(!e[b](a))return!1;
+return!0};"function"!==d&&(c="boolean"===d&&c?function(a,b){return Qa.equals(a,b)}:function(a,b){if(a&&b&&"object"===typeof a&&"object"===typeof b){for(var d in a)if("$"!==d.charAt(0)&&Jc.call(a,d)&&c(a[d],b[d]))return!0;return!1}b=(""+b).toLowerCase();return-1<(""+a).toLowerCase().indexOf(b)});var g=function(a,b){if("string"==typeof b&&"!"===b.charAt(0))return!g(a,b.substr(1));switch(typeof a){case "boolean":case "number":case "string":return c(a,b);case "object":switch(typeof b){case "object":return c(a,
+b);default:for(var d in a)if("$"!==d.charAt(0)&&g(a[d],b))return!0}return!1;case "array":for(d=0;d<a.length;d++)if(g(a[d],b))return!0;return!1;default:return!1}};switch(typeof a){case "boolean":case "number":case "string":a={$:a};case "object":for(var f in a)(function(b){"undefined"!=typeof a[b]&&e.push(function(c){return g("$"==b?c:c&&c[b],a[b])})})(f);break;case "function":e.push(a);break;default:return b}d=[];for(f=0;f<b.length;f++){var h=b[f];e.check(h)&&d.push(h)}return d}}function Mc(b){var a=
+b.NUMBER_FORMATS;return function(b,d){D(d)&&(d=a.CURRENCY_SYM);return Qc(b,a.PATTERNS[1],a.GROUP_SEP,a.DECIMAL_SEP,2).replace(/\u00A4/g,d)}}function Oc(b){var a=b.NUMBER_FORMATS;return function(b,d){return Qc(b,a.PATTERNS[0],a.GROUP_SEP,a.DECIMAL_SEP,d)}}function Qc(b,a,c,d,e){if(null==b||!isFinite(b)||X(b))return"";var g=0>b;b=Math.abs(b);var f=b+"",h="",m=[],k=!1;if(-1!==f.indexOf("e")){var l=f.match(/([\d\.]+)e(-?)(\d+)/);l&&"-"==l[2]&&l[3]>e+1?f="0":(h=f,k=!0)}if(k)0<e&&(-1<b&&1>b)&&(h=b.toFixed(e));
+else{f=(f.split(Rc)[1]||"").length;D(e)&&(e=Math.min(Math.max(a.minFrac,f),a.maxFrac));f=Math.pow(10,e);b=Math.round(b*f)/f;b=(""+b).split(Rc);f=b[0];b=b[1]||"";var l=0,n=a.lgSize,p=a.gSize;if(f.length>=n+p)for(l=f.length-n,k=0;k<l;k++)0===(l-k)%p&&0!==k&&(h+=c),h+=f.charAt(k);for(k=l;k<f.length;k++)0===(f.length-k)%n&&0!==k&&(h+=c),h+=f.charAt(k);for(;b.length<e;)b+="0";e&&"0"!==e&&(h+=d+b.substr(0,e))}m.push(g?a.negPre:a.posPre);m.push(h);m.push(g?a.negSuf:a.posSuf);return m.join("")}function tb(b,
+a,c){var d="";0>b&&(d="-",b=-b);for(b=""+b;b.length<a;)b="0"+b;c&&(b=b.substr(b.length-a));return d+b}function $(b,a,c,d){c=c||0;return function(e){e=e["get"+b]();if(0<c||e>-c)e+=c;0===e&&-12==c&&(e=12);return tb(e,a,d)}}function ub(b,a){return function(c,d){var e=c["get"+b](),g=Ga(a?"SHORT"+b:b);return d[g][e]}}function Sc(b){var a=(new Date(b,0,1)).getDay();return new Date(b,0,(4>=a?5:12)-a)}function Tc(b){return function(a){var c=Sc(a.getFullYear());a=+new Date(a.getFullYear(),a.getMonth(),a.getDate()+
+(4-a.getDay()))-+c;a=1+Math.round(a/6048E5);return tb(a,b)}}function Nc(b){function a(a){var b;if(b=a.match(c)){a=new Date(0);var g=0,f=0,h=b[8]?a.setUTCFullYear:a.setFullYear,m=b[8]?a.setUTCHours:a.setHours;b[9]&&(g=Y(b[9]+b[10]),f=Y(b[9]+b[11]));h.call(a,Y(b[1]),Y(b[2])-1,Y(b[3]));g=Y(b[4]||0)-g;f=Y(b[5]||0)-f;h=Y(b[6]||0);b=Math.round(1E3*parseFloat("0."+(b[7]||0)));m.call(a,g,f,h,b)}return a}var c=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
+return function(c,e){var g="",f=[],h,m;e=e||"mediumDate";e=b.DATETIME_FORMATS[e]||e;t(c)&&(c=Qe.test(c)?Y(c):a(c));Ab(c)&&(c=new Date(c));if(!ra(c))return c;for(;e;)(m=Re.exec(e))?(f=f.concat(sa.call(m,1)),e=f.pop()):(f.push(e),e=null);q(f,function(a){h=Se[a];g+=h?h(c,b.DATETIME_FORMATS):a.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return g}}function Me(){return function(b){return ta(b,!0)}}function Ne(){return function(b,a){if(!M(b)&&!t(b))return b;a=Y(a);if(t(b))return a?0<=a?b.slice(0,a):b.slice(a,
+b.length):"";var c=[],d,e;a>b.length?a=b.length:a<-b.length&&(a=-b.length);0<a?(d=0,e=a):(d=b.length+a,e=b.length);for(;d<e;d++)c.push(b[d]);return c}}function Pc(b){return function(a,c,d){function e(a,b){return Pa(b)?function(b,c){return a(c,b)}:a}function g(a,b){var c=typeof a,d=typeof b;return c==d?("string"==c&&(a=a.toLowerCase(),b=b.toLowerCase()),a===b?0:a<b?-1:1):c<d?-1:1}if(!M(a)||!c)return a;c=M(c)?c:[c];c=cd(c,function(a){var c=!1,d=a||Ea;if(t(a)){if("+"==a.charAt(0)||"-"==a.charAt(0))c=
+"-"==a.charAt(0),a=a.substring(1);d=b(a);if(d.constant){var f=d();return e(function(a,b){return g(a[f],b[f])},c)}}return e(function(a,b){return g(d(a),d(b))},c)});for(var f=[],h=0;h<a.length;h++)f.push(a[h]);return f.sort(e(function(a,b){for(var d=0;d<c.length;d++){var e=c[d](a,b);if(0!==e)return e}return 0},d))}}function xa(b){P(b)&&(b={link:b});b.restrict=b.restrict||"AC";return aa(b)}function Uc(b,a,c,d){function e(a,c){c=c?"-"+ib(c,"-"):"";d.removeClass(b,(a?vb:wb)+c);d.addClass(b,(a?wb:vb)+c)}
+var g=this,f=b.parent().controller("form")||xb,h=0,m=g.$error={},k=[];g.$name=a.name||a.ngForm;g.$dirty=!1;g.$pristine=!0;g.$valid=!0;g.$invalid=!1;f.$addControl(g);b.addClass(Ma);e(!0);g.$addControl=function(a){Ba(a.$name,"input");k.push(a);a.$name&&(g[a.$name]=a)};g.$removeControl=function(a){a.$name&&g[a.$name]===a&&delete g[a.$name];q(m,function(b,c){g.$setValidity(c,!0,a)});Fa(k,a)};g.$setValidity=function(a,b,c){var d=m[a];if(b)d&&(Fa(d,c),d.length||(h--,h||(e(b),g.$valid=!0,g.$invalid=!1),
+m[a]=!1,e(!0,a),f.$setValidity(a,!0,g)));else{h||e(b);if(d){if(-1!=gb(d,c))return}else m[a]=d=[],h++,e(!1,a),f.$setValidity(a,!1,g);d.push(c);g.$valid=!1;g.$invalid=!0}};g.$setDirty=function(){d.removeClass(b,Ma);d.addClass(b,yb);g.$dirty=!0;g.$pristine=!1;f.$setDirty()};g.$setPristine=function(){d.removeClass(b,yb);d.addClass(b,Ma);g.$dirty=!1;g.$pristine=!0;q(k,function(a){a.$setPristine()})}}function qa(b,a,c,d){b.$setValidity(a,c);return c?d:s}function Te(b,a,c){var d=c.prop("validity");X(d)&&
+b.$parsers.push(function(c){if(b.$error[a]||!(d.badInput||d.customError||d.typeMismatch)||d.valueMissing)return c;b.$setValidity(a,!1)})}function bb(b,a,c,d,e,g){var f=a.prop("validity");if(!e.android){var h=!1;a.on("compositionstart",function(a){h=!0});a.on("compositionend",function(){h=!1;m()})}var m=function(){if(!h){var e=a.val();Pa(c.ngTrim||"T")&&(e=ca(e));if(d.$viewValue!==e||f&&""===e&&!f.valueMissing)b.$$phase?d.$setViewValue(e):b.$apply(function(){d.$setViewValue(e)})}};if(e.hasEvent("input"))a.on("input",
+m);else{var k,l=function(){k||(k=g.defer(function(){m();k=null}))};a.on("keydown",function(a){a=a.keyCode;91===a||(15<a&&19>a||37<=a&&40>=a)||l()});if(e.hasEvent("paste"))a.on("paste cut",l)}a.on("change",m);d.$render=function(){a.val(d.$isEmpty(d.$viewValue)?"":d.$viewValue)};var n=c.ngPattern;n&&((e=n.match(/^\/(.*)\/([gim]*)$/))?(n=RegExp(e[1],e[2]),e=function(a){return qa(d,"pattern",d.$isEmpty(a)||n.test(a),a)}):e=function(c){var e=b.$eval(n);if(!e||!e.test)throw v("ngPattern")("noregexp",n,
+e,ha(a));return qa(d,"pattern",d.$isEmpty(c)||e.test(c),c)},d.$formatters.push(e),d.$parsers.push(e));if(c.ngMinlength){var p=Y(c.ngMinlength);e=function(a){return qa(d,"minlength",d.$isEmpty(a)||a.length>=p,a)};d.$parsers.push(e);d.$formatters.push(e)}if(c.ngMaxlength){var r=Y(c.ngMaxlength);e=function(a){return qa(d,"maxlength",d.$isEmpty(a)||a.length<=r,a)};d.$parsers.push(e);d.$formatters.push(e)}}function zb(b,a){return function(c){var d;return ra(c)?c:t(c)&&(b.lastIndex=0,c=b.exec(c))?(c.shift(),
+d={yyyy:0,MM:1,dd:1,HH:0,mm:0},q(c,function(b,c){c<a.length&&(d[a[c]]=+b)}),new Date(d.yyyy,d.MM-1,d.dd,d.HH,d.mm)):NaN}}function cb(b,a,c,d){return function(e,g,f,h,m,k,l){bb(e,g,f,h,m,k);h.$parsers.push(function(d){if(h.$isEmpty(d))return h.$setValidity(b,!0),null;if(a.test(d))return h.$setValidity(b,!0),c(d);h.$setValidity(b,!1);return s});h.$formatters.push(function(a){return ra(a)?l("date")(a,d):""});f.min&&(e=function(a){var b=h.$isEmpty(a)||c(a)>=c(f.min);h.$setValidity("min",b);return b?a:
+s},h.$parsers.push(e),h.$formatters.push(e));f.max&&(e=function(a){var b=h.$isEmpty(a)||c(a)<=c(f.max);h.$setValidity("max",b);return b?a:s},h.$parsers.push(e),h.$formatters.push(e))}}function Rb(b,a){b="ngClass"+b;return["$animate",function(c){function d(a,b){var c=[],d=0;a:for(;d<a.length;d++){for(var e=a[d],l=0;l<b.length;l++)if(e==b[l])continue a;c.push(e)}return c}function e(a){if(!M(a)){if(t(a))return a.split(" ");if(X(a)){var b=[];q(a,function(a,c){a&&b.push(c)});return b}}return a}return{restrict:"AC",
+link:function(g,f,h){function m(a,b){var c=f.data("$classCounts")||{},d=[];q(a,function(a){if(0<b||c[a])c[a]=(c[a]||0)+b,c[a]===+(0<b)&&d.push(a)});f.data("$classCounts",c);return d.join(" ")}function k(b){if(!0===a||g.$index%2===a){var k=e(b||[]);if(!l){var r=m(k,1);h.$addClass(r)}else if(!za(b,l)){var q=e(l),r=d(k,q),k=d(q,k),k=m(k,-1),r=m(r,1);0===r.length?c.removeClass(f,k):0===k.length?c.addClass(f,r):c.setClass(f,r,k)}}l=ba(b)}var l;g.$watch(h[b],k,!0);h.$observe("class",function(a){k(g.$eval(h[b]))});
+"ngClass"!==b&&g.$watch("$index",function(c,d){var f=c&1;if(f!==d&1){var k=e(g.$eval(h[b]));f===a?(f=m(k,1),h.$addClass(f)):(f=m(k,-1),h.$removeClass(f))}})}}}]}var I=function(b){return t(b)?b.toLowerCase():b},Jc=Object.prototype.hasOwnProperty,Ga=function(b){return t(b)?b.toUpperCase():b},T,y,Ha,sa=[].slice,Ue=[].push,ya=Object.prototype.toString,Oa=v("ng"),Qa=O.angular||(O.angular={}),Sa,La,ka=["0","0","0"];T=Y((/msie (\d+)/.exec(I(navigator.userAgent))||[])[1]);isNaN(T)&&(T=Y((/trident\/.*; rv:(\d+)/.exec(I(navigator.userAgent))||
+[])[1]));C.$inject=[];Ea.$inject=[];var ca=function(){return String.prototype.trim?function(b){return t(b)?b.trim():b}:function(b){return t(b)?b.replace(/^\s\s*/,"").replace(/\s\s*$/,""):b}}();La=9>T?function(b){b=b.nodeName?b:b[0];return b.scopeName&&"HTML"!=b.scopeName?Ga(b.scopeName+":"+b.nodeName):b.nodeName}:function(b){return b.nodeName?b.nodeName:b[0].nodeName};var fd=/[A-Z]/g,id={full:"1.3.0-beta.5",major:1,minor:3,dot:0,codeName:"chimeric-glitterfication"},Va=N.cache={},jb=N.expando="ng-"+
+(new Date).getTime(),we=1,qb=O.document.addEventListener?function(b,a,c){b.addEventListener(a,c,!1)}:function(b,a,c){b.attachEvent("on"+a,c)},Ua=O.document.removeEventListener?function(b,a,c){b.removeEventListener(a,c,!1)}:function(b,a,c){b.detachEvent("on"+a,c)};N._data=function(b){return this.cache[b[this.expando]]||{}};var qe=/([\:\-\_]+(.))/g,re=/^moz([A-Z])/,Hb=v("jqLite"),ve=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,Gb=/<|&#?\w+;/,te=/<([\w:]+)/,ue=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
+ea={option:[1,'<select multiple="multiple">',"</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ea.optgroup=ea.option;ea.tbody=ea.tfoot=ea.colgroup=ea.caption=ea.thead;ea.th=ea.td;var Ka=N.prototype={ready:function(b){function a(){c||(c=!0,b())}var c=!1;"complete"===U.readyState?setTimeout(a):(this.on("DOMContentLoaded",a),N(O).on("load",a))},
+toString:function(){var b=[];q(this,function(a){b.push(""+a)});return"["+b.join(", ")+"]"},eq:function(b){return 0<=b?y(this[b]):y(this[this.length+b])},length:0,push:Ue,sort:[].sort,splice:[].splice},nb={};q("multiple selected checked disabled readOnly required open".split(" "),function(b){nb[I(b)]=b});var rc={};q("input select option textarea button form details".split(" "),function(b){rc[Ga(b)]=!0});q({data:nc,inheritedData:mb,scope:function(b){return y(b).data("$scope")||mb(b.parentNode||b,["$isolateScope",
+"$scope"])},isolateScope:function(b){return y(b).data("$isolateScope")||y(b).data("$isolateScopeNoTemplate")},controller:oc,injector:function(b){return mb(b,"$injector")},removeAttr:function(b,a){b.removeAttribute(a)},hasClass:Jb,css:function(b,a,c){a=Ta(a);if(B(c))b.style[a]=c;else{var d;8>=T&&(d=b.currentStyle&&b.currentStyle[a],""===d&&(d="auto"));d=d||b.style[a];8>=T&&(d=""===d?s:d);return d}},attr:function(b,a,c){var d=I(a);if(nb[d])if(B(c))c?(b[a]=!0,b.setAttribute(a,d)):(b[a]=!1,b.removeAttribute(d));
+else return b[a]||(b.attributes.getNamedItem(a)||C).specified?d:s;else if(B(c))b.setAttribute(a,c);else if(b.getAttribute)return b=b.getAttribute(a,2),null===b?s:b},prop:function(b,a,c){if(B(c))b[a]=c;else return b[a]},text:function(){function b(b,d){var e=a[b.nodeType];if(D(d))return e?b[e]:"";b[e]=d}var a=[];9>T?(a[1]="innerText",a[3]="nodeValue"):a[1]=a[3]="textContent";b.$dv="";return b}(),val:function(b,a){if(D(a)){if("SELECT"===La(b)&&b.multiple){var c=[];q(b.options,function(a){a.selected&&
+c.push(a.value||a.text)});return 0===c.length?null:c}return b.value}b.value=a},html:function(b,a){if(D(a))return b.innerHTML;for(var c=0,d=b.childNodes;c<d.length;c++)Ia(d[c]);b.innerHTML=a},empty:pc},function(b,a){N.prototype[a]=function(a,d){var e,g;if(b!==pc&&(2==b.length&&b!==Jb&&b!==oc?a:d)===s){if(X(a)){for(e=0;e<this.length;e++)if(b===nc)b(this[e],a);else for(g in a)b(this[e],g,a[g]);return this}e=b.$dv;g=e===s?Math.min(this.length,1):this.length;for(var f=0;f<g;f++){var h=b(this[f],a,d);e=
+e?e+h:h}return e}for(e=0;e<this.length;e++)b(this[e],a,d);return this}});q({removeData:lc,dealoc:Ia,on:function a(c,d,e,g){if(B(g))throw Hb("onargs");var f=la(c,"events"),h=la(c,"handle");f||la(c,"events",f={});h||la(c,"handle",h=xe(c,f));q(d.split(" "),function(d){var g=f[d];if(!g){if("mouseenter"==d||"mouseleave"==d){var l=U.body.contains||U.body.compareDocumentPosition?function(a,c){var d=9===a.nodeType?a.documentElement:a,e=c&&c.parentNode;return a===e||!!(e&&1===e.nodeType&&(d.contains?d.contains(e):
+a.compareDocumentPosition&&a.compareDocumentPosition(e)&16))}:function(a,c){if(c)for(;c=c.parentNode;)if(c===a)return!0;return!1};f[d]=[];a(c,{mouseleave:"mouseout",mouseenter:"mouseover"}[d],function(a){var c=a.relatedTarget;c&&(c===this||l(this,c))||h(a,d)})}else qb(c,d,h),f[d]=[];g=f[d]}g.push(e)})},off:mc,one:function(a,c,d){a=y(a);a.on(c,function g(){a.off(c,d);a.off(c,g)});a.on(c,d)},replaceWith:function(a,c){var d,e=a.parentNode;Ia(a);q(new N(c),function(c){d?e.insertBefore(c,d.nextSibling):
+e.replaceChild(c,a);d=c})},children:function(a){var c=[];q(a.childNodes,function(a){1===a.nodeType&&c.push(a)});return c},contents:function(a){return a.contentDocument||a.childNodes||[]},append:function(a,c){q(new N(c),function(c){1!==a.nodeType&&11!==a.nodeType||a.appendChild(c)})},prepend:function(a,c){if(1===a.nodeType){var d=a.firstChild;q(new N(c),function(c){a.insertBefore(c,d)})}},wrap:function(a,c){c=y(c)[0];var d=a.parentNode;d&&d.replaceChild(c,a);c.appendChild(a)},remove:function(a){Ia(a);
+var c=a.parentNode;c&&c.removeChild(a)},after:function(a,c){var d=a,e=a.parentNode;q(new N(c),function(a){e.insertBefore(a,d.nextSibling);d=a})},addClass:lb,removeClass:kb,toggleClass:function(a,c,d){c&&q(c.split(" "),function(c){var g=d;D(g)&&(g=!Jb(a,c));(g?lb:kb)(a,c)})},parent:function(a){return(a=a.parentNode)&&11!==a.nodeType?a:null},next:function(a){if(a.nextElementSibling)return a.nextElementSibling;for(a=a.nextSibling;null!=a&&1!==a.nodeType;)a=a.nextSibling;return a},find:function(a,c){return a.getElementsByTagName?
+a.getElementsByTagName(c):[]},clone:Ib,triggerHandler:function(a,c,d){c=(la(a,"events")||{})[c];d=d||[];var e=[{preventDefault:C,stopPropagation:C}];q(c,function(c){c.apply(a,e.concat(d))})}},function(a,c){N.prototype[c]=function(c,e,g){for(var f,h=0;h<this.length;h++)D(f)?(f=a(this[h],c,e,g),B(f)&&(f=y(f))):kc(f,a(this[h],c,e,g));return B(f)?f:this};N.prototype.bind=N.prototype.on;N.prototype.unbind=N.prototype.off});Wa.prototype={put:function(a,c){this[Ja(a)]=c},get:function(a){return this[Ja(a)]},
+remove:function(a){var c=this[a=Ja(a)];delete this[a];return c}};var ze=/^function\s*[^\(]*\(\s*([^\)]*)\)/m,Ae=/,/,Be=/^\s*(_?)(\S+?)\1\s*$/,ye=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,Xa=v("$injector"),Ve=v("$animate"),Ud=["$provide",function(a){this.$$selectors={};this.register=function(c,d){var e=c+"-animation";if(c&&"."!=c.charAt(0))throw Ve("notcsel",c);this.$$selectors[c.substr(1)]=e;a.factory(e,d)};this.classNameFilter=function(a){1===arguments.length&&(this.$$classNameFilter=a instanceof RegExp?
+a:null);return this.$$classNameFilter};this.$get=["$timeout","$$asyncCallback",function(a,d){return{enter:function(a,c,f,h){f?f.after(a):c.prepend(a);h&&d(h)},leave:function(a,c){a.remove();c&&d(c)},move:function(a,c,d,h){this.enter(a,c,d,h)},addClass:function(a,c,f){c=t(c)?c:M(c)?c.join(" "):"";q(a,function(a){lb(a,c)});f&&d(f)},removeClass:function(a,c,f){c=t(c)?c:M(c)?c.join(" "):"";q(a,function(a){kb(a,c)});f&&d(f)},setClass:function(a,c,f,h){q(a,function(a){lb(a,c);kb(a,f)});h&&d(h)},enabled:C}}]}],
+ja=v("$compile");fc.$inject=["$provide","$$sanitizeUriProvider"];var De=/^(x[\:\-_]|data[\:\-_])/i,zc=v("$interpolate"),We=/^([^\?#]*)(\?([^#]*))?(#(.*))?$/,Ge={http:80,https:443,ftp:21},Nb=v("$location");Ec.prototype=Ob.prototype=Dc.prototype={$$html5:!1,$$replace:!1,absUrl:rb("$$absUrl"),url:function(a,c){if(D(a))return this.$$url;var d=We.exec(a);d[1]&&this.path(decodeURIComponent(d[1]));(d[2]||d[1])&&this.search(d[3]||"");this.hash(d[5]||"",c);return this},protocol:rb("$$protocol"),host:rb("$$host"),
+port:rb("$$port"),path:Fc("$$path",function(a){return"/"==a.charAt(0)?a:"/"+a}),search:function(a,c){switch(arguments.length){case 0:return this.$$search;case 1:if(t(a))this.$$search=ac(a);else if(X(a))this.$$search=a;else throw Nb("isrcharg");break;default:D(c)||null===c?delete this.$$search[a]:this.$$search[a]=c}this.$$compose();return this},hash:Fc("$$hash",Ea),replace:function(){this.$$replace=!0;return this}};var Ca=v("$parse"),Ic={},va,Na={"null":function(){return null},"true":function(){return!0},
+"false":function(){return!1},undefined:C,"+":function(a,c,d,e){d=d(a,c);e=e(a,c);return B(d)?B(e)?d+e:d:B(e)?e:s},"-":function(a,c,d,e){d=d(a,c);e=e(a,c);return(B(d)?d:0)-(B(e)?e:0)},"*":function(a,c,d,e){return d(a,c)*e(a,c)},"/":function(a,c,d,e){return d(a,c)/e(a,c)},"%":function(a,c,d,e){return d(a,c)%e(a,c)},"^":function(a,c,d,e){return d(a,c)^e(a,c)},"=":C,"===":function(a,c,d,e){return d(a,c)===e(a,c)},"!==":function(a,c,d,e){return d(a,c)!==e(a,c)},"==":function(a,c,d,e){return d(a,c)==e(a,
+c)},"!=":function(a,c,d,e){return d(a,c)!=e(a,c)},"<":function(a,c,d,e){return d(a,c)<e(a,c)},">":function(a,c,d,e){return d(a,c)>e(a,c)},"<=":function(a,c,d,e){return d(a,c)<=e(a,c)},">=":function(a,c,d,e){return d(a,c)>=e(a,c)},"&&":function(a,c,d,e){return d(a,c)&&e(a,c)},"||":function(a,c,d,e){return d(a,c)||e(a,c)},"&":function(a,c,d,e){return d(a,c)&e(a,c)},"|":function(a,c,d,e){return e(a,c)(a,c,d(a,c))},"!":function(a,c,d){return!d(a,c)}},Xe={n:"\n",f:"\f",r:"\r",t:"\t",v:"\v","'":"'",'"':'"'},
+Qb=function(a){this.options=a};Qb.prototype={constructor:Qb,lex:function(a){this.text=a;this.index=0;this.ch=s;this.lastCh=":";this.tokens=[];var c;for(a=[];this.index<this.text.length;){this.ch=this.text.charAt(this.index);if(this.is("\"'"))this.readString(this.ch);else if(this.isNumber(this.ch)||this.is(".")&&this.isNumber(this.peek()))this.readNumber();else if(this.isIdent(this.ch))this.readIdent(),this.was("{,")&&("{"===a[0]&&(c=this.tokens[this.tokens.length-1]))&&(c.json=-1===c.text.indexOf("."));
+else if(this.is("(){}[].,;:?"))this.tokens.push({index:this.index,text:this.ch,json:this.was(":[,")&&this.is("{[")||this.is("}]:,")}),this.is("{[")&&a.unshift(this.ch),this.is("}]")&&a.shift(),this.index++;else if(this.isWhitespace(this.ch)){this.index++;continue}else{var d=this.ch+this.peek(),e=d+this.peek(2),g=Na[this.ch],f=Na[d],h=Na[e];h?(this.tokens.push({index:this.index,text:e,fn:h}),this.index+=3):f?(this.tokens.push({index:this.index,text:d,fn:f}),this.index+=2):g?(this.tokens.push({index:this.index,
+text:this.ch,fn:g,json:this.was("[,:")&&this.is("+-")}),this.index+=1):this.throwError("Unexpected next character ",this.index,this.index+1)}this.lastCh=this.ch}return this.tokens},is:function(a){return-1!==a.indexOf(this.ch)},was:function(a){return-1!==a.indexOf(this.lastCh)},peek:function(a){a=a||1;return this.index+a<this.text.length?this.text.charAt(this.index+a):!1},isNumber:function(a){return"0"<=a&&"9">=a},isWhitespace:function(a){return" "===a||"\r"===a||"\t"===a||"\n"===a||"\v"===a||"\u00a0"===
+a},isIdent:function(a){return"a"<=a&&"z">=a||"A"<=a&&"Z">=a||"_"===a||"$"===a},isExpOperator:function(a){return"-"===a||"+"===a||this.isNumber(a)},throwError:function(a,c,d){d=d||this.index;c=B(c)?"s "+c+"-"+this.index+" ["+this.text.substring(c,d)+"]":" "+d;throw Ca("lexerr",a,c,this.text);},readNumber:function(){for(var a="",c=this.index;this.index<this.text.length;){var d=I(this.text.charAt(this.index));if("."==d||this.isNumber(d))a+=d;else{var e=this.peek();if("e"==d&&this.isExpOperator(e))a+=
+d;else if(this.isExpOperator(d)&&e&&this.isNumber(e)&&"e"==a.charAt(a.length-1))a+=d;else if(!this.isExpOperator(d)||e&&this.isNumber(e)||"e"!=a.charAt(a.length-1))break;else this.throwError("Invalid exponent")}this.index++}a*=1;this.tokens.push({index:c,text:a,json:!0,fn:function(){return a}})},readIdent:function(){for(var a=this,c="",d=this.index,e,g,f,h;this.index<this.text.length;){h=this.text.charAt(this.index);if("."===h||this.isIdent(h)||this.isNumber(h))"."===h&&(e=this.index),c+=h;else break;
+this.index++}if(e)for(g=this.index;g<this.text.length;){h=this.text.charAt(g);if("("===h){f=c.substr(e-d+1);c=c.substr(0,e-d);this.index=g;break}if(this.isWhitespace(h))g++;else break}d={index:d,text:c};if(Na.hasOwnProperty(c))d.fn=Na[c],d.json=Na[c];else{var m=Hc(c,this.options,this.text);d.fn=A(function(a,c){return m(a,c)},{assign:function(d,e){return sb(d,c,e,a.text,a.options)}})}this.tokens.push(d);f&&(this.tokens.push({index:e,text:".",json:!1}),this.tokens.push({index:e+1,text:f,json:!1}))},
+readString:function(a){var c=this.index;this.index++;for(var d="",e=a,g=!1;this.index<this.text.length;){var f=this.text.charAt(this.index),e=e+f;if(g)"u"===f?(f=this.text.substring(this.index+1,this.index+5),f.match(/[\da-f]{4}/i)||this.throwError("Invalid unicode escape [\\u"+f+"]"),this.index+=4,d+=String.fromCharCode(parseInt(f,16))):d=(g=Xe[f])?d+g:d+f,g=!1;else if("\\"===f)g=!0;else{if(f===a){this.index++;this.tokens.push({index:c,text:e,string:d,json:!0,fn:function(){return d}});return}d+=
+f}this.index++}this.throwError("Unterminated quote",c)}};var ab=function(a,c,d){this.lexer=a;this.$filter=c;this.options=d};ab.ZERO=A(function(){return 0},{constant:!0});ab.prototype={constructor:ab,parse:function(a,c){this.text=a;this.json=c;this.tokens=this.lexer.lex(a);c&&(this.assignment=this.logicalOR,this.functionCall=this.fieldAccess=this.objectIndex=this.filterChain=function(){this.throwError("is not valid json",{text:a,index:0})});var d=c?this.primary():this.statements();0!==this.tokens.length&&
+this.throwError("is an unexpected token",this.tokens[0]);d.literal=!!d.literal;d.constant=!!d.constant;return d},primary:function(){var a;if(this.expect("("))a=this.filterChain(),this.consume(")");else if(this.expect("["))a=this.arrayDeclaration();else if(this.expect("{"))a=this.object();else{var c=this.expect();(a=c.fn)||this.throwError("not a primary expression",c);c.json&&(a.constant=!0,a.literal=!0)}for(var d;c=this.expect("(","[",".");)"("===c.text?(a=this.functionCall(a,d),d=null):"["===c.text?
+(d=a,a=this.objectIndex(a)):"."===c.text?(d=a,a=this.fieldAccess(a)):this.throwError("IMPOSSIBLE");return a},throwError:function(a,c){throw Ca("syntax",c.text,a,c.index+1,this.text,this.text.substring(c.index));},peekToken:function(){if(0===this.tokens.length)throw Ca("ueoe",this.text);return this.tokens[0]},peek:function(a,c,d,e){if(0<this.tokens.length){var g=this.tokens[0],f=g.text;if(f===a||f===c||f===d||f===e||!(a||c||d||e))return g}return!1},expect:function(a,c,d,e){return(a=this.peek(a,c,d,
+e))?(this.json&&!a.json&&this.throwError("is not valid json",a),this.tokens.shift(),a):!1},consume:function(a){this.expect(a)||this.throwError("is unexpected, expecting ["+a+"]",this.peek())},unaryFn:function(a,c){return A(function(d,e){return a(d,e,c)},{constant:c.constant})},ternaryFn:function(a,c,d){return A(function(e,g){return a(e,g)?c(e,g):d(e,g)},{constant:a.constant&&c.constant&&d.constant})},binaryFn:function(a,c,d){return A(function(e,g){return c(e,g,a,d)},{constant:a.constant&&d.constant})},
+statements:function(){for(var a=[];;)if(0<this.tokens.length&&!this.peek("}",")",";","]")&&a.push(this.filterChain()),!this.expect(";"))return 1===a.length?a[0]:function(c,d){for(var e,g=0;g<a.length;g++){var f=a[g];f&&(e=f(c,d))}return e}},filterChain:function(){for(var a=this.expression(),c;;)if(c=this.expect("|"))a=this.binaryFn(a,c.fn,this.filter());else return a},filter:function(){for(var a=this.expect(),c=this.$filter(a.text),d=[];;)if(a=this.expect(":"))d.push(this.expression());else{var e=
+function(a,e,h){h=[h];for(var m=0;m<d.length;m++)h.push(d[m](a,e));return c.apply(a,h)};return function(){return e}}},expression:function(){return this.assignment()},assignment:function(){var a=this.ternary(),c,d;return(d=this.expect("="))?(a.assign||this.throwError("implies assignment but ["+this.text.substring(0,d.index)+"] can not be assigned to",d),c=this.ternary(),function(d,g){return a.assign(d,c(d,g),g)}):a},ternary:function(){var a=this.logicalOR(),c,d;if(this.expect("?")){c=this.ternary();
+if(d=this.expect(":"))return this.ternaryFn(a,c,this.ternary());this.throwError("expected :",d)}else return a},logicalOR:function(){for(var a=this.logicalAND(),c;;)if(c=this.expect("||"))a=this.binaryFn(a,c.fn,this.logicalAND());else return a},logicalAND:function(){var a=this.equality(),c;if(c=this.expect("&&"))a=this.binaryFn(a,c.fn,this.logicalAND());return a},equality:function(){var a=this.relational(),c;if(c=this.expect("==","!=","===","!=="))a=this.binaryFn(a,c.fn,this.equality());return a},
+relational:function(){var a=this.additive(),c;if(c=this.expect("<",">","<=",">="))a=this.binaryFn(a,c.fn,this.relational());return a},additive:function(){for(var a=this.multiplicative(),c;c=this.expect("+","-");)a=this.binaryFn(a,c.fn,this.multiplicative());return a},multiplicative:function(){for(var a=this.unary(),c;c=this.expect("*","/","%");)a=this.binaryFn(a,c.fn,this.unary());return a},unary:function(){var a;return this.expect("+")?this.primary():(a=this.expect("-"))?this.binaryFn(ab.ZERO,a.fn,
+this.unary()):(a=this.expect("!"))?this.unaryFn(a.fn,this.unary()):this.primary()},fieldAccess:function(a){var c=this,d=this.expect().text,e=Hc(d,this.options,this.text);return A(function(c,d,h){return e(h||a(c,d))},{assign:function(e,f,h){return sb(a(e,h),d,f,c.text,c.options)}})},objectIndex:function(a){var c=this,d=this.expression();this.consume("]");return A(function(e,g){var f=a(e,g),h=d(e,g),m;if(!f)return s;(f=$a(f[h],c.text))&&(f.then&&c.options.unwrapPromises)&&(m=f,"$$v"in f||(m.$$v=s,m.then(function(a){m.$$v=
+a})),f=f.$$v);return f},{assign:function(e,g,f){var h=d(e,f);return $a(a(e,f),c.text)[h]=g}})},functionCall:function(a,c){var d=[];if(")"!==this.peekToken().text){do d.push(this.expression());while(this.expect(","))}this.consume(")");var e=this;return function(g,f){for(var h=[],m=c?c(g,f):g,k=0;k<d.length;k++)h.push(d[k](g,f));k=a(g,f,m)||C;$a(m,e.text);$a(k,e.text);h=k.apply?k.apply(m,h):k(h[0],h[1],h[2],h[3],h[4]);return $a(h,e.text)}},arrayDeclaration:function(){var a=[],c=!0;if("]"!==this.peekToken().text){do{if(this.peek("]"))break;
+var d=this.expression();a.push(d);d.constant||(c=!1)}while(this.expect(","))}this.consume("]");return A(function(c,d){for(var f=[],h=0;h<a.length;h++)f.push(a[h](c,d));return f},{literal:!0,constant:c})},object:function(){var a=[],c=!0;if("}"!==this.peekToken().text){do{if(this.peek("}"))break;var d=this.expect(),d=d.string||d.text;this.consume(":");var e=this.expression();a.push({key:d,value:e});e.constant||(c=!1)}while(this.expect(","))}this.consume("}");return A(function(c,d){for(var e={},m=0;m<
+a.length;m++){var k=a[m];e[k.key]=k.value(c,d)}return e},{literal:!0,constant:c})}};var Pb={},wa=v("$sce"),ga={HTML:"html",CSS:"css",URL:"url",RESOURCE_URL:"resourceUrl",JS:"js"},W=U.createElement("a"),Lc=ua(O.location.href,!0);jc.$inject=["$provide"];Mc.$inject=["$locale"];Oc.$inject=["$locale"];var Rc=".",Se={yyyy:$("FullYear",4),yy:$("FullYear",2,0,!0),y:$("FullYear",1),MMMM:ub("Month"),MMM:ub("Month",!0),MM:$("Month",2,1),M:$("Month",1,1),dd:$("Date",2),d:$("Date",1),HH:$("Hours",2),H:$("Hours",
+1),hh:$("Hours",2,-12),h:$("Hours",1,-12),mm:$("Minutes",2),m:$("Minutes",1),ss:$("Seconds",2),s:$("Seconds",1),sss:$("Milliseconds",3),EEEE:ub("Day"),EEE:ub("Day",!0),a:function(a,c){return 12>a.getHours()?c.AMPMS[0]:c.AMPMS[1]},Z:function(a){a=-1*a.getTimezoneOffset();return a=(0<=a?"+":"")+(tb(Math[0<a?"floor":"ceil"](a/60),2)+tb(Math.abs(a%60),2))},ww:Tc(2),w:Tc(1)},Re=/((?:[^yMdHhmsaZEw']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|w+))(.*)/,Qe=/^\-?\d+$/;Nc.$inject=["$locale"];var Oe=
+aa(I),Pe=aa(Ga);Pc.$inject=["$parse"];var ld=aa({restrict:"E",compile:function(a,c){8>=T&&(c.href||c.name||c.$set("href",""),a.append(U.createComment("IE fix")));if(!c.href&&!c.xlinkHref&&!c.name)return function(a,c){var g="[object SVGAnimatedString]"===ya.call(c.prop("href"))?"xlink:href":"href";c.on("click",function(a){c.attr(g)||a.preventDefault()})}}}),Eb={};q(nb,function(a,c){if("multiple"!=a){var d=na("ng-"+c);Eb[d]=function(){return{priority:100,link:function(a,g,f){a.$watch(f[d],function(a){f.$set(c,
+!!a)})}}}}});q(["src","srcset","href"],function(a){var c=na("ng-"+a);Eb[c]=function(){return{priority:99,link:function(d,e,g){var f=a,h=a;"href"===a&&"[object SVGAnimatedString]"===ya.call(e.prop("href"))&&(h="xlinkHref",g.$attr[h]="xlink:href",f=null);g.$observe(c,function(a){a&&(g.$set(h,a),T&&f&&e.prop(f,g[h]))})}}}});var xb={$addControl:C,$removeControl:C,$setValidity:C,$setDirty:C,$setPristine:C};Uc.$inject=["$element","$attrs","$scope","$animate"];var Vc=function(a){return["$timeout",function(c){return{name:"form",
+restrict:a?"EAC":"E",controller:Uc,compile:function(){return{pre:function(a,e,g,f){if(!g.action){var h=function(a){a.preventDefault?a.preventDefault():a.returnValue=!1};qb(e[0],"submit",h);e.on("$destroy",function(){c(function(){Ua(e[0],"submit",h)},0,!1)})}var m=e.parent().controller("form"),k=g.name||g.ngForm;k&&sb(a,k,f,k);if(m)e.on("$destroy",function(){m.$removeControl(f);k&&sb(a,k,s,k);A(f,xb)})}}}}}]},md=Vc(),zd=Vc(!0),Ye=/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/,
+Ze=/^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*$/i,$e=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/,Wc=/^(\d{4})-(\d{2})-(\d{2})$/,Xc=/^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)$/,Sb=/^(\d{4})-W(\d\d)$/,Yc=/^(\d{4})-(\d\d)$/,Zc=/^(\d\d):(\d\d)$/,$c={text:bb,date:cb("date",Wc,zb(Wc,["yyyy","MM","dd"]),"yyyy-MM-dd"),"datetime-local":cb("datetimelocal",Xc,zb(Xc,["yyyy","MM","dd","HH","mm"]),"yyyy-MM-ddTHH:mm"),time:cb("time",Zc,zb(Zc,["HH","mm"]),"HH:mm"),week:cb("week",Sb,function(a){if(ra(a))return a;
+if(t(a)){Sb.lastIndex=0;var c=Sb.exec(a);if(c){a=+c[1];var d=+c[2],c=Sc(a),d=7*(d-1);return new Date(a,0,c.getDate()+d)}}return NaN},"yyyy-Www"),month:cb("month",Yc,zb(Yc,["yyyy","MM"]),"yyyy-MM"),number:function(a,c,d,e,g,f){bb(a,c,d,e,g,f);e.$parsers.push(function(a){var c=e.$isEmpty(a);if(c||$e.test(a))return e.$setValidity("number",!0),""===a?null:c?a:parseFloat(a);e.$setValidity("number",!1);return s});Te(e,"number",c);e.$formatters.push(function(a){return e.$isEmpty(a)?"":""+a});d.min&&(a=function(a){var c=
+parseFloat(d.min);return qa(e,"min",e.$isEmpty(a)||a>=c,a)},e.$parsers.push(a),e.$formatters.push(a));d.max&&(a=function(a){var c=parseFloat(d.max);return qa(e,"max",e.$isEmpty(a)||a<=c,a)},e.$parsers.push(a),e.$formatters.push(a));e.$formatters.push(function(a){return qa(e,"number",e.$isEmpty(a)||Ab(a),a)})},url:function(a,c,d,e,g,f){bb(a,c,d,e,g,f);a=function(a){return qa(e,"url",e.$isEmpty(a)||Ye.test(a),a)};e.$formatters.push(a);e.$parsers.push(a)},email:function(a,c,d,e,g,f){bb(a,c,d,e,g,f);
+a=function(a){return qa(e,"email",e.$isEmpty(a)||Ze.test(a),a)};e.$formatters.push(a);e.$parsers.push(a)},radio:function(a,c,d,e){D(d.name)&&c.attr("name",eb());c.on("click",function(){c[0].checked&&a.$apply(function(){e.$setViewValue(d.value)})});e.$render=function(){c[0].checked=d.value==e.$viewValue};d.$observe("value",e.$render)},checkbox:function(a,c,d,e){var g=d.ngTrueValue,f=d.ngFalseValue;t(g)||(g=!0);t(f)||(f=!1);c.on("click",function(){a.$apply(function(){e.$setViewValue(c[0].checked)})});
+e.$render=function(){c[0].checked=e.$viewValue};e.$isEmpty=function(a){return a!==g};e.$formatters.push(function(a){return a===g});e.$parsers.push(function(a){return a?g:f})},hidden:C,button:C,submit:C,reset:C,file:C},gc=["$browser","$sniffer","$filter",function(a,c,d){return{restrict:"E",require:"?ngModel",link:function(e,g,f,h){h&&($c[I(f.type)]||$c.text)(e,g,f,h,c,a,d)}}}],wb="ng-valid",vb="ng-invalid",Ma="ng-pristine",yb="ng-dirty",af=["$scope","$exceptionHandler","$attrs","$element","$parse",
+"$animate",function(a,c,d,e,g,f){function h(a,c){c=c?"-"+ib(c,"-"):"";f.removeClass(e,(a?vb:wb)+c);f.addClass(e,(a?wb:vb)+c)}this.$modelValue=this.$viewValue=Number.NaN;this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$pristine=!0;this.$dirty=!1;this.$valid=!0;this.$invalid=!1;this.$name=d.name;var m=g(d.ngModel),k=m.assign;if(!k)throw v("ngModel")("nonassign",d.ngModel,ha(e));this.$render=C;this.$isEmpty=function(a){return D(a)||""===a||null===a||a!==a};var l=e.inheritedData("$formController")||
+xb,n=0,p=this.$error={};e.addClass(Ma);h(!0);this.$setValidity=function(a,c){p[a]!==!c&&(c?(p[a]&&n--,n||(h(!0),this.$valid=!0,this.$invalid=!1)):(h(!1),this.$invalid=!0,this.$valid=!1,n++),p[a]=!c,h(c,a),l.$setValidity(a,c,this))};this.$setPristine=function(){this.$dirty=!1;this.$pristine=!0;f.removeClass(e,yb);f.addClass(e,Ma)};this.$setViewValue=function(d){this.$viewValue=d;this.$pristine&&(this.$dirty=!0,this.$pristine=!1,f.removeClass(e,Ma),f.addClass(e,yb),l.$setDirty());q(this.$parsers,function(a){d=
+a(d)});this.$modelValue!==d&&(this.$modelValue=d,k(a,d),q(this.$viewChangeListeners,function(a){try{a()}catch(d){c(d)}}))};var r=this;a.$watch(function(){var c=m(a);if(r.$modelValue!==c){var d=r.$formatters,e=d.length;for(r.$modelValue=c;e--;)c=d[e](c);r.$viewValue!==c&&(r.$viewValue=c,r.$render())}return c})}],Od=function(){return{require:["ngModel","^?form"],controller:af,link:function(a,c,d,e){var g=e[0],f=e[1]||xb;f.$addControl(g);a.$on("$destroy",function(){f.$removeControl(g)})}}},Qd=aa({require:"ngModel",
+link:function(a,c,d,e){e.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}),hc=function(){return{require:"?ngModel",link:function(a,c,d,e){if(e){d.required=!0;var g=function(a){if(d.required&&e.$isEmpty(a))e.$setValidity("required",!1);else return e.$setValidity("required",!0),a};e.$formatters.push(g);e.$parsers.unshift(g);d.$observe("required",function(){g(e.$viewValue)})}}}},Pd=function(){return{require:"ngModel",link:function(a,c,d,e){var g=(a=/\/(.*)\//.exec(d.ngList))&&RegExp(a[1])||
+d.ngList||",";e.$parsers.push(function(a){if(!D(a)){var c=[];a&&q(a.split(g),function(a){a&&c.push(ca(a))});return c}});e.$formatters.push(function(a){return M(a)?a.join(", "):s});e.$isEmpty=function(a){return!a||!a.length}}}},bf=/^(true|false|\d+)$/,Rd=function(){return{priority:100,compile:function(a,c){return bf.test(c.ngValue)?function(a,c,g){g.$set("value",a.$eval(g.ngValue))}:function(a,c,g){a.$watch(g.ngValue,function(a){g.$set("value",a)})}}}},rd=xa(function(a,c,d){c.addClass("ng-binding").data("$binding",
+d.ngBind);a.$watch(d.ngBind,function(a){c.text(a==s?"":a)})}),td=["$interpolate",function(a){return function(c,d,e){c=a(d.attr(e.$attr.ngBindTemplate));d.addClass("ng-binding").data("$binding",c);e.$observe("ngBindTemplate",function(a){d.text(a)})}}],sd=["$sce","$parse",function(a,c){return function(d,e,g){e.addClass("ng-binding").data("$binding",g.ngBindHtml);var f=c(g.ngBindHtml);d.$watch(function(){return(f(d)||"").toString()},function(c){e.html(a.getTrustedHtml(f(d))||"")})}}],ud=Rb("",!0),wd=
+Rb("Odd",0),vd=Rb("Even",1),xd=xa({compile:function(a,c){c.$set("ngCloak",s);a.removeClass("ng-cloak")}}),yd=[function(){return{scope:!0,controller:"@",priority:500}}],ic={};q("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste".split(" "),function(a){var c=na("ng-"+a);ic[c]=["$parse",function(d){return{compile:function(e,g){var f=d(g[c]);return function(c,d,e){d.on(I(a),function(a){c.$apply(function(){f(c,{$event:a})})})}}}}]});
+var Bd=["$animate",function(a){return{transclude:"element",priority:600,terminal:!0,restrict:"A",$$tlb:!0,link:function(c,d,e,g,f){var h,m,k;c.$watch(e.ngIf,function(g){Pa(g)?m||(m=c.$new(),f(m,function(c){c[c.length++]=U.createComment(" end ngIf: "+e.ngIf+" ");h={clone:c};a.enter(c,d.parent(),d)})):(k&&(k.remove(),k=null),m&&(m.$destroy(),m=null),h&&(k=Db(h.clone),a.leave(k,function(){k=null}),h=null))})}}}],Cd=["$http","$templateCache","$anchorScroll","$animate","$sce",function(a,c,d,e,g){return{restrict:"ECA",
+priority:400,terminal:!0,transclude:"element",controller:Qa.noop,compile:function(f,h){var m=h.ngInclude||h.src,k=h.onload||"",l=h.autoscroll;return function(f,h,r,q,z){var s=0,w,y,G,x=function(){y&&(y.remove(),y=null);w&&(w.$destroy(),w=null);G&&(e.leave(G,function(){y=null}),y=G,G=null)};f.$watch(g.parseAsResourceUrl(m),function(g){var m=function(){!B(l)||l&&!f.$eval(l)||d()},r=++s;g?(a.get(g,{cache:c}).success(function(a){if(r===s){var c=f.$new();q.template=a;a=z(c,function(a){x();e.enter(a,null,
+h,m)});w=c;G=a;w.$emit("$includeContentLoaded");f.$eval(k)}}).error(function(){r===s&&x()}),f.$emit("$includeContentRequested")):(x(),q.template=null)})}}}}],Sd=["$compile",function(a){return{restrict:"ECA",priority:-400,require:"ngInclude",link:function(c,d,e,g){d.html(g.template);a(d.contents())(c)}}}],Dd=xa({priority:450,compile:function(){return{pre:function(a,c,d){a.$eval(d.ngInit)}}}}),Ed=xa({terminal:!0,priority:1E3}),Fd=["$locale","$interpolate",function(a,c){var d=/{}/g;return{restrict:"EA",
+link:function(e,g,f){var h=f.count,m=f.$attr.when&&g.attr(f.$attr.when),k=f.offset||0,l=e.$eval(m)||{},n={},p=c.startSymbol(),r=c.endSymbol(),s=/^when(Minus)?(.+)$/;q(f,function(a,c){s.test(c)&&(l[I(c.replace("when","").replace("Minus","-"))]=g.attr(f.$attr[c]))});q(l,function(a,e){n[e]=c(a.replace(d,p+h+"-"+k+r))});e.$watch(function(){var c=parseFloat(e.$eval(h));if(isNaN(c))return"";c in l||(c=a.pluralCat(c-k));return n[c](e,g,!0)},function(a){g.text(a)})}}}],Gd=["$parse","$animate",function(a,
+c){var d=v("ngRepeat");return{transclude:"element",priority:1E3,terminal:!0,$$tlb:!0,link:function(e,g,f,h,m){var k=f.ngRepeat,l=k.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),n,p,r,s,z,B,w={$id:Ja};if(!l)throw d("iexp",k);f=l[1];h=l[2];(l=l[3])?(n=a(l),p=function(a,c,d){B&&(w[B]=a);w[z]=c;w.$index=d;return n(e,w)}):(r=function(a,c){return Ja(c)},s=function(a){return a});l=f.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);if(!l)throw d("iidexp",f);z=l[3]||l[1];
+B=l[2];var H={};e.$watchCollection(h,function(a){var f,h,l=g[0],n,w={},E,R,t,C,S,v,D=[];if(db(a))S=a,n=p||r;else{n=p||s;S=[];for(t in a)a.hasOwnProperty(t)&&"$"!=t.charAt(0)&&S.push(t);S.sort()}E=S.length;h=D.length=S.length;for(f=0;f<h;f++)if(t=a===S?f:S[f],C=a[t],C=n(t,C,f),Ba(C,"`track by` id"),H.hasOwnProperty(C))v=H[C],delete H[C],w[C]=v,D[f]=v;else{if(w.hasOwnProperty(C))throw q(D,function(a){a&&a.scope&&(H[a.id]=a)}),d("dupes",k,C);D[f]={id:C};w[C]=!1}for(t in H)H.hasOwnProperty(t)&&(v=H[t],
+f=Db(v.clone),c.leave(f),q(f,function(a){a.$$NG_REMOVED=!0}),v.scope.$destroy());f=0;for(h=S.length;f<h;f++){t=a===S?f:S[f];C=a[t];v=D[f];D[f-1]&&(l=D[f-1].clone[D[f-1].clone.length-1]);if(v.scope){R=v.scope;n=l;do n=n.nextSibling;while(n&&n.$$NG_REMOVED);v.clone[0]!=n&&c.move(Db(v.clone),null,y(l));l=v.clone[v.clone.length-1]}else R=e.$new();R[z]=C;B&&(R[B]=t);R.$index=f;R.$first=0===f;R.$last=f===E-1;R.$middle=!(R.$first||R.$last);R.$odd=!(R.$even=0===(f&1));v.scope||m(R,function(a){a[a.length++]=
+U.createComment(" end ngRepeat: "+k+" ");c.enter(a,null,y(l));l=a;v.scope=R;v.clone=a;w[v.id]=v})}H=w})}}}],Hd=["$animate",function(a){return function(c,d,e){c.$watch(e.ngShow,function(c){a[Pa(c)?"removeClass":"addClass"](d,"ng-hide")})}}],Ad=["$animate",function(a){return function(c,d,e){c.$watch(e.ngHide,function(c){a[Pa(c)?"addClass":"removeClass"](d,"ng-hide")})}}],Id=xa(function(a,c,d){a.$watch(d.ngStyle,function(a,d){d&&a!==d&&q(d,function(a,d){c.css(d,"")});a&&c.css(a)},!0)}),Jd=["$animate",
+function(a){return{restrict:"EA",require:"ngSwitch",controller:["$scope",function(){this.cases={}}],link:function(c,d,e,g){var f,h,m,k=[];c.$watch(e.ngSwitch||e.on,function(d){var n,p=k.length;if(0<p){if(m){for(n=0;n<p;n++)m[n].remove();m=null}m=[];for(n=0;n<p;n++){var r=h[n];k[n].$destroy();m[n]=r;a.leave(r,function(){m.splice(n,1);0===m.length&&(m=null)})}}h=[];k=[];if(f=g.cases["!"+d]||g.cases["?"])c.$eval(e.change),q(f,function(d){var e=c.$new();k.push(e);d.transclude(e,function(c){var e=d.element;
+h.push(c);a.enter(c,e.parent(),e)})})})}}}],Kd=xa({transclude:"element",priority:800,require:"^ngSwitch",link:function(a,c,d,e,g){e.cases["!"+d.ngSwitchWhen]=e.cases["!"+d.ngSwitchWhen]||[];e.cases["!"+d.ngSwitchWhen].push({transclude:g,element:c})}}),Ld=xa({transclude:"element",priority:800,require:"^ngSwitch",link:function(a,c,d,e,g){e.cases["?"]=e.cases["?"]||[];e.cases["?"].push({transclude:g,element:c})}}),Nd=xa({link:function(a,c,d,e,g){if(!g)throw v("ngTransclude")("orphan",ha(c));g(function(a){c.empty();
+c.append(a)})}}),nd=["$templateCache",function(a){return{restrict:"E",terminal:!0,compile:function(c,d){"text/ng-template"==d.type&&a.put(d.id,c[0].text)}}}],cf=v("ngOptions"),Md=aa({terminal:!0}),od=["$compile","$parse",function(a,c){var d=/^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/,e={$setViewValue:C};return{restrict:"E",require:["select","?ngModel"],
+controller:["$element","$scope","$attrs",function(a,c,d){var m=this,k={},l=e,n;m.databound=d.ngModel;m.init=function(a,c,d){l=a;n=d};m.addOption=function(c){Ba(c,'"option value"');k[c]=!0;l.$viewValue==c&&(a.val(c),n.parent()&&n.remove())};m.removeOption=function(a){this.hasOption(a)&&(delete k[a],l.$viewValue==a&&this.renderUnknownOption(a))};m.renderUnknownOption=function(c){c="? "+Ja(c)+" ?";n.val(c);a.prepend(n);a.val(c);n.prop("selected",!0)};m.hasOption=function(a){return k.hasOwnProperty(a)};
+c.$on("$destroy",function(){m.renderUnknownOption=C})}],link:function(e,f,h,m){function k(a,c,d,e){d.$render=function(){var a=d.$viewValue;e.hasOption(a)?(G.parent()&&G.remove(),c.val(a),""===a&&v.prop("selected",!0)):D(a)&&v?c.val(""):e.renderUnknownOption(a)};c.on("change",function(){a.$apply(function(){G.parent()&&G.remove();d.$setViewValue(c.val())})})}function l(a,c,d){var e;d.$render=function(){var a=new Wa(d.$viewValue);q(c.find("option"),function(c){c.selected=B(a.get(c.value))})};a.$watch(function(){za(e,
+d.$viewValue)||(e=ba(d.$viewValue),d.$render())});c.on("change",function(){a.$apply(function(){var a=[];q(c.find("option"),function(c){c.selected&&a.push(c.value)});d.$setViewValue(a)})})}function n(e,f,g){function h(){var a={"":[]},c=[""],d,k,s,t,u;t=g.$modelValue;u=y(e)||[];var D=n?Tb(u):u,G,J,A;J={};s=!1;var E,I;if(r)if(v&&M(t))for(s=new Wa([]),A=0;A<t.length;A++)J[l]=t[A],s.put(v(e,J),t[A]);else s=new Wa(t);for(A=0;G=D.length,A<G;A++){k=A;if(n){k=D[A];if("$"===k.charAt(0))continue;J[n]=k}J[l]=
+u[k];d=p(e,J)||"";(k=a[d])||(k=a[d]=[],c.push(d));r?d=B(s.remove(v?v(e,J):q(e,J))):(v?(d={},d[l]=t,d=v(e,d)===v(e,J)):d=t===q(e,J),s=s||d);E=m(e,J);E=B(E)?E:"";k.push({id:v?v(e,J):n?D[A]:A,label:E,selected:d})}r||(z||null===t?a[""].unshift({id:"",label:"",selected:!s}):s||a[""].unshift({id:"?",label:"",selected:!0}));J=0;for(D=c.length;J<D;J++){d=c[J];k=a[d];x.length<=J?(t={element:C.clone().attr("label",d),label:k.label},u=[t],x.push(u),f.append(t.element)):(u=x[J],t=u[0],t.label!=d&&t.element.attr("label",
+t.label=d));E=null;A=0;for(G=k.length;A<G;A++)s=k[A],(d=u[A+1])?(E=d.element,d.label!==s.label&&E.text(d.label=s.label),d.id!==s.id&&E.val(d.id=s.id),d.selected!==s.selected&&E.prop("selected",d.selected=s.selected)):(""===s.id&&z?I=z:(I=w.clone()).val(s.id).attr("selected",s.selected).text(s.label),u.push({element:I,label:s.label,id:s.id,selected:s.selected}),E?E.after(I):t.element.append(I),E=I);for(A++;u.length>A;)u.pop().element.remove()}for(;x.length>J;)x.pop()[0].element.remove()}var k;if(!(k=
+t.match(d)))throw cf("iexp",t,ha(f));var m=c(k[2]||k[1]),l=k[4]||k[6],n=k[5],p=c(k[3]||""),q=c(k[2]?k[1]:l),y=c(k[7]),v=k[8]?c(k[8]):null,x=[[{element:f,label:""}]];z&&(a(z)(e),z.removeClass("ng-scope"),z.remove());f.empty();f.on("change",function(){e.$apply(function(){var a,c=y(e)||[],d={},h,k,m,p,t,w,u;if(r)for(k=[],p=0,w=x.length;p<w;p++)for(a=x[p],m=1,t=a.length;m<t;m++){if((h=a[m].element)[0].selected){h=h.val();n&&(d[n]=h);if(v)for(u=0;u<c.length&&(d[l]=c[u],v(e,d)!=h);u++);else d[l]=c[h];k.push(q(e,
+d))}}else{h=f.val();if("?"==h)k=s;else if(""===h)k=null;else if(v)for(u=0;u<c.length;u++){if(d[l]=c[u],v(e,d)==h){k=q(e,d);break}}else d[l]=c[h],n&&(d[n]=h),k=q(e,d);1<x[0].length&&x[0][1].id!==h&&(x[0][1].selected=!1)}g.$setViewValue(k)})});g.$render=h;e.$watch(h)}if(m[1]){var p=m[0];m=m[1];var r=h.multiple,t=h.ngOptions,z=!1,v,w=y(U.createElement("option")),C=y(U.createElement("optgroup")),G=w.clone();h=0;for(var x=f.children(),A=x.length;h<A;h++)if(""===x[h].value){v=z=x.eq(h);break}p.init(m,z,
+G);r&&(m.$isEmpty=function(a){return!a||0===a.length});t?n(e,f,m):r?l(e,f,m):k(e,f,m,p)}}}}],qd=["$interpolate",function(a){var c={addOption:C,removeOption:C};return{restrict:"E",priority:100,compile:function(d,e){if(D(e.value)){var g=a(d.text(),!0);g||e.$set("value",d.text())}return function(a,d,e){var k=d.parent(),l=k.data("$selectController")||k.parent().data("$selectController");l&&l.databound?d.prop("selected",!1):l=c;g?a.$watch(g,function(a,c){e.$set("value",a);a!==c&&l.removeOption(c);l.addOption(a)}):
+l.addOption(e.value);d.on("$destroy",function(){l.removeOption(e.value)})}}}}],pd=aa({restrict:"E",terminal:!1});O.angular.bootstrap?console.log("WARNING: Tried to load angular more than once."):((Ha=O.jQuery)?(y=Ha,A(Ha.fn,{scope:Ka.scope,isolateScope:Ka.isolateScope,controller:Ka.controller,injector:Ka.injector,inheritedData:Ka.inheritedData}),Fb("remove",!0,!0,!1),Fb("empty",!1,!1,!1),Fb("html",!1,!1,!0)):y=N,Qa.element=y,hd(Qa),y(U).ready(function(){ed(U,cc)}))})(window,document);
+!angular.$$csp()&&angular.element(document).find("head").prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}</style>');
+//# sourceMappingURL=angular.min.js.map
diff --git a/examples/authz/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular-resource.min.js b/examples/authz/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular-resource.min.js
new file mode 100644
index 0000000..3f196c3
--- /dev/null
+++ b/examples/authz/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular-resource.min.js
@@ -0,0 +1,13 @@
+/*
+ AngularJS v1.3.0-beta.5
+ (c) 2010-2014 Google, Inc. http://angularjs.org
+ License: MIT
+*/
+(function(H,a,A){'use strict';function D(p,g){g=g||{};a.forEach(g,function(a,c){delete g[c]});for(var c in p)!p.hasOwnProperty(c)||"$"===c.charAt(0)&&"$"===c.charAt(1)||(g[c]=p[c]);return g}var v=a.$$minErr("$resource"),C=/^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/;a.module("ngResource",["ng"]).factory("$resource",["$http","$q",function(p,g){function c(a,c){this.template=a;this.defaults=c||{};this.urlParams={}}function t(n,w,l){function r(h,d){var e={};d=x({},w,d);s(d,function(b,d){u(b)&&(b=b());var k;if(b&&
+b.charAt&&"@"==b.charAt(0)){k=h;var a=b.substr(1);if(null==a||""===a||"hasOwnProperty"===a||!C.test("."+a))throw v("badmember",a);for(var a=a.split("."),f=0,c=a.length;f<c&&k!==A;f++){var g=a[f];k=null!==k?k[g]:A}}else k=b;e[d]=k});return e}function e(a){return a.resource}function f(a){D(a||{},this)}var F=new c(n);l=x({},B,l);s(l,function(h,d){var c=/^(POST|PUT|PATCH)$/i.test(h.method);f[d]=function(b,d,k,w){var q={},n,l,y;switch(arguments.length){case 4:y=w,l=k;case 3:case 2:if(u(d)){if(u(b)){l=
+b;y=d;break}l=d;y=k}else{q=b;n=d;l=k;break}case 1:u(b)?l=b:c?n=b:q=b;break;case 0:break;default:throw v("badargs",arguments.length);}var t=this instanceof f,m=t?n:h.isArray?[]:new f(n),z={},B=h.interceptor&&h.interceptor.response||e,C=h.interceptor&&h.interceptor.responseError||A;s(h,function(a,b){"params"!=b&&("isArray"!=b&&"interceptor"!=b)&&(z[b]=G(a))});c&&(z.data=n);F.setUrlParams(z,x({},r(n,h.params||{}),q),h.url);q=p(z).then(function(b){var d=b.data,k=m.$promise;if(d){if(a.isArray(d)!==!!h.isArray)throw v("badcfg",
+h.isArray?"array":"object",a.isArray(d)?"array":"object");h.isArray?(m.length=0,s(d,function(b){m.push(new f(b))})):(D(d,m),m.$promise=k)}m.$resolved=!0;b.resource=m;return b},function(b){m.$resolved=!0;(y||E)(b);return g.reject(b)});q=q.then(function(b){var a=B(b);(l||E)(a,b.headers);return a},C);return t?q:(m.$promise=q,m.$resolved=!1,m)};f.prototype["$"+d]=function(b,a,k){u(b)&&(k=a,a=b,b={});b=f[d].call(this,b,this,a,k);return b.$promise||b}});f.bind=function(a){return t(n,x({},w,a),l)};return f}
+var B={get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}},E=a.noop,s=a.forEach,x=a.extend,G=a.copy,u=a.isFunction;c.prototype={setUrlParams:function(c,g,l){var r=this,e=l||r.template,f,p,h=r.urlParams={};s(e.split(/\W/),function(a){if("hasOwnProperty"===a)throw v("badname");!/^\d+$/.test(a)&&(a&&RegExp("(^|[^\\\\]):"+a+"(\\W|$)").test(e))&&(h[a]=!0)});e=e.replace(/\\:/g,":");g=g||{};s(r.urlParams,function(d,c){f=g.hasOwnProperty(c)?
+g[c]:r.defaults[c];a.isDefined(f)&&null!==f?(p=encodeURIComponent(f).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"%20").replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+"),e=e.replace(RegExp(":"+c+"(\\W|$)","g"),function(a,c){return p+c})):e=e.replace(RegExp("(/?):"+c+"(\\W|$)","g"),function(a,c,d){return"/"==d.charAt(0)?d:c+d})});e=e.replace(/\/+$/,"")||"/";e=e.replace(/\/\.(?=\w+($|\?))/,".");c.url=e.replace(/\/\\\./,"/.");s(g,function(a,
+e){r.urlParams[e]||(c.params=c.params||{},c.params[e]=a)})}};return t}])})(window,window.angular);
+//# sourceMappingURL=angular-resource.min.js.map
diff --git a/examples/authz/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular-route.min.js b/examples/authz/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular-route.min.js
new file mode 100644
index 0000000..9e161e2
--- /dev/null
+++ b/examples/authz/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular-route.min.js
@@ -0,0 +1,14 @@
+/*
+ AngularJS v1.3.0-beta.5
+ (c) 2010-2014 Google, Inc. http://angularjs.org
+ License: MIT
+*/
+(function(n,e,A){'use strict';function x(s,g,k){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(a,c,b,f,w){function y(){p&&(p.remove(),p=null);h&&(h.$destroy(),h=null);l&&(k.leave(l,function(){p=null}),p=l,l=null)}function v(){var b=s.current&&s.current.locals;if(e.isDefined(b&&b.$template)){var b=a.$new(),d=s.current;l=w(b,function(d){k.enter(d,null,l||c,function(){!e.isDefined(t)||t&&!a.$eval(t)||g()});y()});h=d.scope=b;h.$emit("$viewContentLoaded");h.$eval(u)}else y()}
+var h,l,p,t=b.autoscroll,u=b.onload||"";a.$on("$routeChangeSuccess",v);v()}}}function z(e,g,k){return{restrict:"ECA",priority:-400,link:function(a,c){var b=k.current,f=b.locals;c.html(f.$template);var w=e(c.contents());b.controller&&(f.$scope=a,f=g(b.controller,f),b.controllerAs&&(a[b.controllerAs]=f),c.data("$ngControllerController",f),c.children().data("$ngControllerController",f));w(a)}}}n=e.module("ngRoute",["ng"]).provider("$route",function(){function s(a,c){return e.extend(new (e.extend(function(){},
+{prototype:a})),c)}function g(a,e){var b=e.caseInsensitiveMatch,f={originalPath:a,regexp:a},k=f.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)([\?\*])?/g,function(a,e,b,c){a="?"===c?c:null;c="*"===c?c:null;k.push({name:b,optional:!!a});e=e||"";return""+(a?"":e)+"(?:"+(a?e:"")+(c&&"(.+?)"||"([^/]+)")+(a||"")+")"+(a||"")}).replace(/([\/$\*])/g,"\\$1");f.regexp=RegExp("^"+a+"$",b?"i":"");return f}var k={};this.when=function(a,c){k[a]=e.extend({reloadOnSearch:!0},c,a&&g(a,c));if(a){var b=
+"/"==a[a.length-1]?a.substr(0,a.length-1):a+"/";k[b]=e.extend({redirectTo:a},g(b,c))}return this};this.otherwise=function(a){this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache","$sce",function(a,c,b,f,g,n,v,h){function l(){var d=p(),m=r.current;if(d&&m&&d.$$route===m.$$route&&e.equals(d.pathParams,m.pathParams)&&!d.reloadOnSearch&&!u)m.params=d.params,e.copy(m.params,b),a.$broadcast("$routeUpdate",m);else if(d||m)u=!1,a.$broadcast("$routeChangeStart",
+d,m),(r.current=d)&&d.redirectTo&&(e.isString(d.redirectTo)?c.path(t(d.redirectTo,d.params)).search(d.params).replace():c.url(d.redirectTo(d.pathParams,c.path(),c.search())).replace()),f.when(d).then(function(){if(d){var a=e.extend({},d.resolve),c,b;e.forEach(a,function(d,c){a[c]=e.isString(d)?g.get(d):g.invoke(d)});e.isDefined(c=d.template)?e.isFunction(c)&&(c=c(d.params)):e.isDefined(b=d.templateUrl)&&(e.isFunction(b)&&(b=b(d.params)),b=h.getTrustedResourceUrl(b),e.isDefined(b)&&(d.loadedTemplateUrl=
+b,c=n.get(b,{cache:v}).then(function(a){return a.data})));e.isDefined(c)&&(a.$template=c);return f.all(a)}}).then(function(c){d==r.current&&(d&&(d.locals=c,e.copy(d.params,b)),a.$broadcast("$routeChangeSuccess",d,m))},function(c){d==r.current&&a.$broadcast("$routeChangeError",d,m,c)})}function p(){var a,b;e.forEach(k,function(f,k){var q;if(q=!b){var g=c.path();q=f.keys;var l={};if(f.regexp)if(g=f.regexp.exec(g)){for(var h=1,p=g.length;h<p;++h){var n=q[h-1],r="string"==typeof g[h]?decodeURIComponent(g[h]):
+g[h];n&&r&&(l[n.name]=r)}q=l}else q=null;else q=null;q=a=q}q&&(b=s(f,{params:e.extend({},c.search(),a),pathParams:a}),b.$$route=f)});return b||k[null]&&s(k[null],{params:{},pathParams:{}})}function t(a,c){var b=[];e.forEach((a||"").split(":"),function(a,d){if(0===d)b.push(a);else{var e=a.match(/(\w+)(.*)/),f=e[1];b.push(c[f]);b.push(e[2]||"");delete c[f]}});return b.join("")}var u=!1,r={routes:k,reload:function(){u=!0;a.$evalAsync(l)}};a.$on("$locationChangeSuccess",l);return r}]});n.provider("$routeParams",
+function(){this.$get=function(){return{}}});n.directive("ngView",x);n.directive("ngView",z);x.$inject=["$route","$anchorScroll","$animate"];z.$inject=["$compile","$controller","$route"]})(window,window.angular);
+//# sourceMappingURL=angular-route.min.js.map
diff --git a/examples/authz/photoz/photoz-html5-client/src/main/webapp/lib/jwt-decode.min.js b/examples/authz/photoz/photoz-html5-client/src/main/webapp/lib/jwt-decode.min.js
new file mode 100644
index 0000000..f56f967
--- /dev/null
+++ b/examples/authz/photoz/photoz-html5-client/src/main/webapp/lib/jwt-decode.min.js
@@ -0,0 +1 @@
+!function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g<d.length;g++)e(d[g]);return e}({1:[function(a,b){function c(a){return decodeURIComponent(atob(a).replace(/(.)/g,function(a,b){var c=b.charCodeAt(0).toString(16).toUpperCase();return c.length<2&&(c="0"+c),"%"+c}))}var d=a("Base64");b.exports=function(a){var b=a.replace(/-/g,"+").replace(/_/g,"/");switch(b.length%4){case 0:break;case 2:b+="==";break;case 3:b+="=";break;default:throw"Illegal base64url string!"}try{return c(b)}catch(e){return d.atob(b)}}},{Base64:4}],2:[function(a,b){"use strict";var c=a("./base64_url_decode"),d=a("./json_parse");b.exports=function(a){if(!a)throw new Error("Invalid token specified");return d(c(a.split(".")[1]))}},{"./base64_url_decode":1,"./json_parse":3}],3:[function(require,module,exports){module.exports=function(str){var parsed;return parsed="object"==typeof JSON?JSON.parse(str):eval("("+str+")")}},{}],4:[function(a,b,c){!function(){var a="undefined"!=typeof c?c:this,b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",d=function(){try{document.createElement("$")}catch(a){return a}}();a.btoa||(a.btoa=function(a){for(var c,e,f=0,g=b,h="";a.charAt(0|f)||(g="=",f%1);h+=g.charAt(63&c>>8-f%1*8)){if(e=a.charCodeAt(f+=.75),e>255)throw d;c=c<<8|e}return h}),a.atob||(a.atob=function(a){if(a=a.replace(/=+$/,""),a.length%4==1)throw d;for(var c,e,f=0,g=0,h="";e=a.charAt(g++);~e&&(c=f%4?64*c+e:e,f++%4)?h+=String.fromCharCode(255&c>>(-2*f&6)):0)e=b.indexOf(e);return h})}()},{}],5:[function(a){var b="undefined"!=typeof self?self:"undefined"!=typeof window?window:{},c=a("./lib/index");"function"==typeof b.window.define&&b.window.define.amd?b.window.define("jwt_decode",function(){return c}):b.window&&(b.window.jwt_decode=c)},{"./lib/index":2}]},{},[5]);
\ No newline at end of file
diff --git a/examples/authz/photoz/photoz-html5-client/src/main/webapp/partials/admin/albums.html b/examples/authz/photoz/photoz-html5-client/src/main/webapp/partials/admin/albums.html
new file mode 100644
index 0000000..c0cc6e1
--- /dev/null
+++ b/examples/authz/photoz/photoz-html5-client/src/main/webapp/partials/admin/albums.html
@@ -0,0 +1,19 @@
+<h1>All Albums</h1>
+<table class="table" data-ng-repeat="(key, value) in albums">
+    <thead>
+        <tr>
+            <th>{{key}}</th>
+        </tr>
+    </thead>
+    <tbody>
+        <tr>
+            <td>
+                <ul>
+                    <li data-ng-repeat="p in value">
+                        <a id="view-{{p.name}}" href="#/album/{{p.id}}">{{p.name}}</a> - [<a href="#/admin/album" id="delete-{{p.name}}" ng-click="deleteAlbum(p)">X</a>]
+                    </li>
+                </ul>
+            </td>
+        </tr>
+    </tbody>
+</table>
\ No newline at end of file
diff --git a/examples/authz/photoz/photoz-html5-client/src/main/webapp/partials/album/create.html b/examples/authz/photoz/photoz-html5-client/src/main/webapp/partials/album/create.html
new file mode 100644
index 0000000..d9ddd25
--- /dev/null
+++ b/examples/authz/photoz/photoz-html5-client/src/main/webapp/partials/album/create.html
@@ -0,0 +1,7 @@
+<h1>Create an Album</h1>
+
+<form>
+    Name: <input type="text" id="album.name" ng-model="album.name"/>
+
+    <button ng-click="create()" id="save-album">Save</button>
+</form>
diff --git a/examples/authz/photoz/photoz-html5-client/src/main/webapp/partials/album/detail.html b/examples/authz/photoz/photoz-html5-client/src/main/webapp/partials/album/detail.html
new file mode 100644
index 0000000..cf32df1
--- /dev/null
+++ b/examples/authz/photoz/photoz-html5-client/src/main/webapp/partials/album/detail.html
@@ -0,0 +1 @@
+<h1>{{album.name}}</h1>
\ No newline at end of file
diff --git a/examples/authz/photoz/photoz-html5-client/src/main/webapp/partials/home.html b/examples/authz/photoz/photoz-html5-client/src/main/webapp/partials/home.html
new file mode 100644
index 0000000..78c252a
--- /dev/null
+++ b/examples/authz/photoz/photoz-html5-client/src/main/webapp/partials/home.html
@@ -0,0 +1,22 @@
+<h2><span>Welcome To Photoz, {{Identity.claims.name}}</span></h2>
+<div data-ng-show="Identity.isAdmin()"><b>Administration: </b> [<a href="#/admin/album" id="admin-albums">All Albums</a>]</div>
+<hr/>
+<br/>
+<div data-ng-show="!Identity.isAdmin()">
+<a href="#/album/create" id="create-album">Create Album</a> | <a href="#/profile">My Profile</a>
+<br/>
+<br/>
+<span data-ng-show="albums.length == 0" id="resource-list-empty">You don't have any albums, yet.</span>
+<table class="table" data-ng-show="albums.length > 0">
+    <thead>
+        <tr>
+            <th>Your Albums</th>
+        </tr>
+    </thead>
+    <tbody>
+        <tr data-ng-repeat="p in albums">
+            <td><a id="view-{{p.name}}" href="#/album/{{p.id}}">{{p.name}}</a> - [<a href="#" id="delete-{{p.name}}" ng-click="deleteAlbum(p)">X</a>]</td>
+        </tr>
+    </tbody>
+</table>
+</div>
\ No newline at end of file
diff --git a/examples/authz/photoz/photoz-html5-client/src/main/webapp/partials/profile.html b/examples/authz/photoz/photoz-html5-client/src/main/webapp/partials/profile.html
new file mode 100644
index 0000000..c6f6750
--- /dev/null
+++ b/examples/authz/photoz/photoz-html5-client/src/main/webapp/partials/profile.html
@@ -0,0 +1,6 @@
+<h1>My Profile</h1>
+
+<form>
+    <p>Name: {{profile.userName}}</p>
+    <p>Total of albums: {{profile.totalAlbums}}</p>
+</form>
diff --git a/examples/authz/photoz/photoz-html5-client/src/main/webapp/WEB-INF/web.xml b/examples/authz/photoz/photoz-html5-client/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..a370557
--- /dev/null
+++ b/examples/authz/photoz/photoz-html5-client/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>photoz-html5-client</module-name>
+
+</web-app>
diff --git a/examples/authz/photoz/photoz-realm.json b/examples/authz/photoz/photoz-realm.json
new file mode 100644
index 0000000..b0aeb5d
--- /dev/null
+++ b/examples/authz/photoz/photoz-realm.json
@@ -0,0 +1,125 @@
+{
+  "realm": "photoz",
+  "enabled": true,
+  "sslRequired": "external",
+  "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+  "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "requiredCredentials": [
+    "password"
+  ],
+  "users": [
+    {
+      "username": "alice",
+      "enabled": true,
+      "email": "alice@keycloak.org",
+      "firstName": "Alice",
+      "lastName": "In Chains",
+      "credentials": [
+        {
+          "type": "password",
+          "value": "alice"
+        }
+      ],
+      "realmRoles": [
+        "user", "uma_authorization"
+      ],
+      "clientRoles": {
+        "photoz-restful-api": [
+          "manage-albums"
+        ]
+      }
+    },
+    {
+      "username": "jdoe",
+      "enabled": true,
+      "email": "jdoe@keycloak.org",
+      "firstName": "John",
+      "lastName": "Doe",
+      "credentials": [
+        {
+          "type": "password",
+          "value": "jdoe"
+        }
+      ],
+      "realmRoles": [
+        "user", "uma_authorization"
+      ],
+      "clientRoles": {
+        "photoz-restful-api": [
+          "manage-albums"
+        ]
+      }
+    },
+    {
+      "username": "admin",
+      "enabled": true,
+      "email": "admin@admin.com",
+      "firstName": "Admin",
+      "lastName": "Istrator",
+      "credentials": [
+        {
+          "type": "password",
+          "value": "admin"
+        }
+      ],
+      "realmRoles": [
+        "admin", "uma_authorization"
+      ],
+      "clientRoles": {
+        "realm-management": [
+          "realm-admin"
+        ],
+        "photoz-restful-api": [
+          "manage-albums"
+        ]
+      }
+    },
+    {
+      "username": "service-account-photoz-restful-api",
+      "enabled": true,
+      "email": "service-account-photoz-restful-api@placeholder.org",
+      "serviceAccountClientId": "photoz-restful-api",
+      "clientRoles": {
+        "photoz-restful-api" : ["uma_protection"]
+      }
+    }
+  ],
+  "roles": {
+    "realm": [
+      {
+        "name": "user",
+        "description": "User privileges"
+      },
+      {
+        "name": "admin",
+        "description": "Administrator privileges"
+      }
+    ]
+  },
+  "clients": [
+    {
+      "clientId": "photoz-html5-client",
+      "enabled": true,
+      "adminUrl": "/photoz-html5-client",
+      "baseUrl": "/photoz-html5-client",
+      "publicClient": true,
+      "consentRequired" : true,
+      "fullScopeAllowed" : true,
+      "redirectUris": [
+        "/photoz-html5-client/*"
+      ],
+      "webOrigins": ["*"]
+    },
+    {
+      "clientId": "photoz-restful-api",
+      "secret": "secret",
+      "enabled": true,
+      "baseUrl": "/photoz-restful-api",
+      "authorizationServicesEnabled" : true,
+      "redirectUris": [
+        "/photoz-restful-api/*"
+      ],
+      "webOrigins" : ["*"]
+    }
+  ]
+}
diff --git a/examples/authz/photoz/photoz-restful-api/pom.xml b/examples/authz/photoz/photoz-restful-api/pom.xml
new file mode 100755
index 0000000..ba7a880
--- /dev/null
+++ b/examples/authz/photoz/photoz-restful-api/pom.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.keycloak</groupId>
+        <artifactId>keycloak-authz-photoz-parent</artifactId>
+        <version>2.2.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>photoz-restful-api</artifactId>
+    <packaging>war</packaging>
+
+    <name>Keycloak Authz: Photoz RESTful API</name>
+    <description>Photoz RESTful API</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.jboss.spec.javax.ws.rs</groupId>
+            <artifactId>jboss-jaxrs-api_2.0_spec</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.spec.javax.servlet</groupId>
+            <artifactId>jboss-servlet-api_3.0_spec</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.persistence</groupId>
+            <artifactId>persistence-api</artifactId>
+            <version>1.0.2</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.spec.javax.ejb</groupId>
+            <artifactId>jboss-ejb-api_3.2_spec</artifactId>
+            <version>1.0.0.Final</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-authz-client</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.jboss.as.plugins</groupId>
+                <artifactId>jboss-as-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.wildfly.plugins</groupId>
+                <artifactId>wildfly-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/admin/AdminAlbumService.java b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/admin/AdminAlbumService.java
new file mode 100644
index 0000000..b349e02
--- /dev/null
+++ b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/admin/AdminAlbumService.java
@@ -0,0 +1,62 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.example.photoz.admin;
+
+import org.keycloak.example.photoz.entity.Album;
+
+import javax.ejb.Stateless;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@Path("/admin/album")
+@Stateless
+public class AdminAlbumService {
+
+    public static final String SCOPE_ADMIN_ALBUM_MANAGE = "urn:photoz.com:scopes:album:admin:manage";
+
+    @PersistenceContext
+    private EntityManager entityManager;
+
+    @Context
+    private HttpHeaders headers;
+
+    @GET
+    @Produces("application/json")
+    public Response findAll() {
+        HashMap<String, List<Album>> albums = new HashMap<>();
+        List<Album> result = this.entityManager.createQuery("from Album").getResultList();
+
+        for (Album album : result) {
+            albums.computeIfAbsent(album.getUserId(), key -> new ArrayList<>()).add(album);
+        }
+
+        return Response.ok(albums).build();
+    }
+}
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/AlbumService.java b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/AlbumService.java
new file mode 100644
index 0000000..a5d7f16
--- /dev/null
+++ b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/AlbumService.java
@@ -0,0 +1,158 @@
+package org.keycloak.example.photoz.album;
+
+import org.keycloak.authorization.client.AuthzClient;
+import org.keycloak.authorization.client.Configuration;
+import org.keycloak.authorization.client.representation.ResourceRepresentation;
+import org.keycloak.authorization.client.representation.ScopeRepresentation;
+import org.keycloak.authorization.client.resource.ProtectionResource;
+import org.keycloak.example.photoz.ErrorResponse;
+import org.keycloak.example.photoz.entity.Album;
+import org.keycloak.representations.adapters.config.AdapterConfig;
+import org.keycloak.util.JsonSerialization;
+
+import javax.ejb.Stateless;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import java.security.Principal;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Path("/album")
+@Stateless
+public class AlbumService {
+
+    public static final String SCOPE_ALBUM_VIEW = "urn:photoz.com:scopes:album:view";
+    public static final String SCOPE_ALBUM_CREATE = "urn:photoz.com:scopes:album:create";
+    public static final String SCOPE_ALBUM_DELETE = "urn:photoz.com:scopes:album:delete";
+
+    @PersistenceContext
+    private EntityManager entityManager;
+
+    @Context
+    private HttpServletRequest request;
+
+    private AuthzClient authzClient;
+
+    public AlbumService() {
+
+    }
+
+    @POST
+    @Consumes("application/json")
+    public Response create(Album newAlbum) {
+        Principal userPrincipal = request.getUserPrincipal();
+
+        newAlbum.setUserId(userPrincipal.getName());
+
+        Query queryDuplicatedAlbum = this.entityManager.createQuery("from Album where name = :name and userId = :userId");
+
+        queryDuplicatedAlbum.setParameter("name", newAlbum.getName());
+        queryDuplicatedAlbum.setParameter("userId", userPrincipal.getName());
+
+        if (!queryDuplicatedAlbum.getResultList().isEmpty()) {
+            throw new ErrorResponse("Name [" + newAlbum.getName() + "] already taken. Choose another one.", Status.CONFLICT);
+        }
+
+        this.entityManager.persist(newAlbum);
+
+        createProtectedResource(newAlbum);
+
+        return Response.ok(newAlbum).build();
+    }
+
+    @Path("{id}")
+    @DELETE
+    public Response delete(@PathParam("id") String id) {
+        Album album = this.entityManager.find(Album.class, Long.valueOf(id));
+
+        try {
+            deleteProtectedResource(album);
+            this.entityManager.remove(album);
+        } catch (Exception e) {
+            throw new RuntimeException("Could not delete album.", e);
+        }
+
+        return Response.ok().build();
+    }
+
+    @GET
+    @Produces("application/json")
+    public Response findAll() {
+        return Response.ok(this.entityManager.createQuery("from Album where userId = '" + request.getUserPrincipal().getName() + "'").getResultList()).build();
+    }
+
+    @GET
+    @Path("{id}")
+    @Produces("application/json")
+    public Response findById(@PathParam("id") String id) {
+        List result = this.entityManager.createQuery("from Album where id = " + id).getResultList();
+
+        if (result.isEmpty()) {
+            return Response.status(Status.NOT_FOUND).build();
+        }
+
+        return Response.ok(result.get(0)).build();
+    }
+
+    private void createProtectedResource(Album album) {
+        try {
+            HashSet<ScopeRepresentation> scopes = new HashSet<>();
+
+            scopes.add(new ScopeRepresentation(SCOPE_ALBUM_VIEW));
+            scopes.add(new ScopeRepresentation(SCOPE_ALBUM_DELETE));
+
+            ResourceRepresentation albumResource = new ResourceRepresentation(album.getName(), scopes, "/album/" + album.getId(), "http://photoz.com/album");
+
+            albumResource.setOwner(album.getUserId());
+
+            getAuthzClient().protection().resource().create(albumResource);
+        } catch (Exception e) {
+            throw new RuntimeException("Could not register protected resource.", e);
+        }
+    }
+
+    private void deleteProtectedResource(Album album) {
+        String uri = "/album/" + album.getId();
+
+        try {
+            ProtectionResource protection = getAuthzClient().protection();
+            Set<String> search = protection.resource().findByFilter("uri=" + uri);
+
+            if (search.isEmpty()) {
+                throw new RuntimeException("Could not find protected resource with URI [" + uri + "]");
+            }
+
+            protection.resource().delete(search.iterator().next());
+        } catch (Exception e) {
+            throw new RuntimeException("Could not search protected resource.", e);
+        }
+    }
+
+    private AuthzClient getAuthzClient() {
+        if (this.authzClient == null) {
+            try {
+                AdapterConfig adapterConfig = JsonSerialization.readValue(this.request.getServletContext().getResourceAsStream("/WEB-INF/keycloak.json"), AdapterConfig.class);
+                Configuration configuration = new Configuration(adapterConfig.getAuthServerUrl(), adapterConfig.getRealm(), adapterConfig.getResource(), adapterConfig.getCredentials(), null);
+
+                this.authzClient = AuthzClient.create(configuration);
+            } catch (Exception e) {
+                throw new RuntimeException("Could not create authorization client.", e);
+            }
+        }
+
+        return this.authzClient;
+    }
+}
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/ProfileService.java b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/ProfileService.java
new file mode 100644
index 0000000..be638b6
--- /dev/null
+++ b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/ProfileService.java
@@ -0,0 +1,70 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.example.photoz.album;
+
+import javax.ejb.Stateless;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import java.security.Principal;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@Path("/profile")
+@Stateless
+public class ProfileService {
+
+    private static final String PROFILE_VIEW = "urn:photoz.com:scopes:profile:view";
+
+    @PersistenceContext
+    private EntityManager entityManager;
+
+    @GET
+    @Produces("application/json")
+    public Response view(@Context HttpServletRequest request) {
+        Principal userPrincipal = request.getUserPrincipal();
+        List albums = this.entityManager.createQuery("from Album where userId = '" + userPrincipal.getName() + "'").getResultList();
+        return Response.ok(new Profile(userPrincipal.getName(), albums.size())).build();
+    }
+
+    public static class Profile {
+        private String userName;
+        private int totalAlbums;
+
+        public Profile(String name, int totalAlbums) {
+            this.userName = name;
+            this.totalAlbums = totalAlbums;
+        }
+
+        public String getUserName() {
+            return userName;
+        }
+
+        public int getTotalAlbums() {
+            return totalAlbums;
+        }
+    }
+}
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Album.java b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Album.java
new file mode 100644
index 0000000..978bdea
--- /dev/null
+++ b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Album.java
@@ -0,0 +1,79 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.example.photoz.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@Entity
+public class Album {
+
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    @Column(nullable = false)
+    private String name;
+
+    @OneToMany(mappedBy = "album", fetch = FetchType.EAGER)
+    private List<Photo> photos = new ArrayList<>();
+
+    @Column(nullable = false)
+    private String userId;
+
+    public Long getId() {
+        return this.id;
+    }
+
+    public void setId(final Long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    public List<Photo> getPhotos() {
+        return this.photos;
+    }
+
+    public void setPhotos(final List<Photo> photos) {
+        this.photos = photos;
+    }
+
+    public void setUserId(final String userId) {
+        this.userId = userId;
+    }
+
+    public String getUserId() {
+        return this.userId;
+    }
+}
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Photo.java b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Photo.java
new file mode 100644
index 0000000..08b7495
--- /dev/null
+++ b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Photo.java
@@ -0,0 +1,81 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.example.photoz.entity;
+
+import javax.persistence.Basic;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Lob;
+import javax.persistence.ManyToOne;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@Entity
+public class Photo {
+
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    @Column
+    private String name;
+
+    @ManyToOne
+    private Album album;
+
+    @Lob
+    @Column
+    @Basic(fetch = FetchType.LAZY)
+    private byte[] image;
+
+    public Long getId() {
+        return this.id;
+    }
+
+    public void setId(final Long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    public Album getAlbum() {
+        return this.album;
+    }
+
+    public void setAlbum(final Album album) {
+        this.album = album;
+    }
+
+    public byte[] getImage() {
+        return this.image;
+    }
+
+    public void setImage(final byte[] image) {
+        this.image = image;
+    }
+}
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/ErrorResponse.java b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/ErrorResponse.java
new file mode 100644
index 0000000..51755d8
--- /dev/null
+++ b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/ErrorResponse.java
@@ -0,0 +1,32 @@
+package org.keycloak.example.photoz;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ErrorResponse extends WebApplicationException {
+
+    private final Response.Status status;
+
+    public ErrorResponse(String message) {
+        this(message, Response.Status.INTERNAL_SERVER_ERROR);
+    }
+
+    public ErrorResponse(String message, Response.Status status) {
+        super(message, status);
+        this.status = status;
+    }
+
+    @Override
+    public Response getResponse() {
+        Map<String, String> errorResponse = new HashMap<>();
+
+        errorResponse.put("message", getMessage());
+
+        return Response.status(status).entity(errorResponse).build();
+    }
+}
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/PhotozApplication.java b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/PhotozApplication.java
new file mode 100644
index 0000000..5b8377c
--- /dev/null
+++ b/examples/authz/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/PhotozApplication.java
@@ -0,0 +1,12 @@
+package org.keycloak.example.photoz;
+
+import javax.ws.rs.ApplicationPath;
+import javax.ws.rs.core.Application;
+
+/**
+ * Basic auth app.
+ */
+@ApplicationPath("/")
+public class PhotozApplication extends Application {
+
+}
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/resources/META-INF/beans.xml b/examples/authz/photoz/photoz-restful-api/src/main/resources/META-INF/beans.xml
new file mode 100644
index 0000000..957dc8a
--- /dev/null
+++ b/examples/authz/photoz/photoz-restful-api/src/main/resources/META-INF/beans.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+   xsi:schemaLocation="
+        http://java.sun.com/xml/ns/javaee 
+        http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
+        
+</beans>
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/resources/META-INF/persistence.xml b/examples/authz/photoz/photoz-restful-api/src/main/resources/META-INF/persistence.xml
new file mode 100644
index 0000000..9323182
--- /dev/null
+++ b/examples/authz/photoz/photoz-restful-api/src/main/resources/META-INF/persistence.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<persistence version="2.0"
+	xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="
+        http://java.sun.com/xml/ns/persistence
+        http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
+	<persistence-unit name="primary">
+		<non-jta-data-source>java:jboss/datasources/PhotozDS</non-jta-data-source>
+
+		<class>org.keycloak.example.photoz.entity.Album</class>
+		<class>org.keycloak.example.photoz.entity.Photo</class>
+
+		<properties>
+			<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
+			<property name="hibernate.hbm2ddl.auto" value="update" />
+			<property name="hibernate.show_sql" value="false" />
+		</properties>
+	</persistence-unit>
+</persistence>
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/webapp/META-INF/jboss-deployment-structure.xml b/examples/authz/photoz/photoz-restful-api/src/main/webapp/META-INF/jboss-deployment-structure.xml
new file mode 100644
index 0000000..4b23be6
--- /dev/null
+++ b/examples/authz/photoz/photoz-restful-api/src/main/webapp/META-INF/jboss-deployment-structure.xml
@@ -0,0 +1,26 @@
+<!--
+  ~  Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~  and other contributors as indicated by the @author tags.
+  ~
+  ~  Licensed under the Apache License, Version 2.0 (the "License");
+  ~  you may not use this file except in compliance with the License.
+  ~  You may obtain a copy of the License at
+  ~
+  ~  http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing, software
+  ~  distributed under the License is distributed on an "AS IS" BASIS,
+  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  See the License for the specific language governing permissions and
+  ~  limitations under the License.
+  ~
+  -->
+
+<jboss-deployment-structure>
+    <deployment>
+        <dependencies>
+            <module name="org.keycloak.keycloak-authz-client" services="import"/>
+        </dependencies>
+    </deployment>
+</jboss-deployment-structure>
+
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/webapp/WEB-INF/keycloak.json b/examples/authz/photoz/photoz-restful-api/src/main/webapp/WEB-INF/keycloak.json
new file mode 100644
index 0000000..6849d07
--- /dev/null
+++ b/examples/authz/photoz/photoz-restful-api/src/main/webapp/WEB-INF/keycloak.json
@@ -0,0 +1,50 @@
+{
+  "realm": "photoz",
+  "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url": "http://localhost:8080/auth",
+  "ssl-required": "external",
+  "resource": "photoz-restful-api",
+  "bearer-only" : true,
+  "credentials": {
+    "secret": "secret"
+  },
+  "policy-enforcer": {
+    "user-managed-access" : {},
+    "paths": [
+      {
+        "path" : "/album/*",
+        "methods" : [
+          {
+            "method": "POST",
+            "scopes" : ["urn:photoz.com:scopes:album:create"]
+          },
+          {
+            "method": "GET",
+            "scopes" : ["urn:photoz.com:scopes:album:view"]
+          }
+        ]
+      },
+      {
+        "name" : "Album Resource",
+        "path" : "/album/{id}",
+        "methods" : [
+          {
+            "method": "DELETE",
+            "scopes" : ["urn:photoz.com:scopes:album:delete"]
+          },
+          {
+            "method": "GET",
+            "scopes" : ["urn:photoz.com:scopes:album:view"]
+          }
+        ]
+      },
+      {
+        "path" : "/profile"
+      },
+      {
+        "name" : "Admin Resources",
+        "path" : "/admin/*"
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/webapp/WEB-INF/photoz-ds.xml b/examples/authz/photoz/photoz-restful-api/src/main/webapp/WEB-INF/photoz-ds.xml
new file mode 100644
index 0000000..247448f
--- /dev/null
+++ b/examples/authz/photoz/photoz-restful-api/src/main/webapp/WEB-INF/photoz-ds.xml
@@ -0,0 +1,12 @@
+<datasources xmlns="http://www.jboss.org/ironjacamar/schema"
+             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+             xsi:schemaLocation="http://www.jboss.org/ironjacamar/schema http://docs.jboss.org/ironjacamar/schema/datasources_1_0.xsd">
+    <datasource jndi-name="java:jboss/datasources/PhotozDS" pool-name="PhotozDS" enabled="true" use-java-context="true">
+        <connection-url>jdbc:h2:${jboss.server.data.dir}/kc-authz-photo;AUTO_SERVER=TRUE</connection-url>
+        <driver>h2</driver>
+        <security>
+            <user-name>sa</user-name>
+            <password>sa</password>
+        </security>
+    </datasource>
+</datasources>
\ No newline at end of file
diff --git a/examples/authz/photoz/photoz-restful-api/src/main/webapp/WEB-INF/web.xml b/examples/authz/photoz/photoz-restful-api/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..34cf6bd
--- /dev/null
+++ b/examples/authz/photoz/photoz-restful-api/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>photoz-restful-api</module-name>
+
+	<security-constraint>
+		<web-resource-collection>
+			<web-resource-name>All Resources</web-resource-name>
+			<url-pattern>/*</url-pattern>
+		</web-resource-collection>
+		<auth-constraint>
+			<role-name>user</role-name>
+		</auth-constraint>
+	</security-constraint>
+
+	<security-constraint>
+		<web-resource-collection>
+			<web-resource-name>All Resources</web-resource-name>
+			<url-pattern>/*</url-pattern>
+		</web-resource-collection>
+		<auth-constraint>
+			<role-name>admin</role-name>
+		</auth-constraint>
+	</security-constraint>
+
+	<login-config>
+		<auth-method>KEYCLOAK</auth-method>
+		<realm-name>photoz</realm-name>
+	</login-config>
+
+	<security-role>
+		<role-name>admin</role-name>
+	</security-role>
+
+	<security-role>
+		<role-name>user</role-name>
+	</security-role>
+</web-app>
diff --git a/examples/authz/photoz/photoz-restful-api-authz-service.json b/examples/authz/photoz/photoz-restful-api-authz-service.json
new file mode 100644
index 0000000..455948c
--- /dev/null
+++ b/examples/authz/photoz/photoz-restful-api-authz-service.json
@@ -0,0 +1,183 @@
+{
+  "allowRemoteResourceManagement": true,
+  "policyEnforcementMode": "ENFORCING",
+  "resources": [
+    {
+      "name": "User Profile Resource",
+      "uri": "/profile",
+      "type": "http://photoz.com/profile",
+      "scopes": [
+        {
+          "name": "urn:photoz.com:scopes:profile:view"
+        }
+      ]
+    },
+    {
+      "name": "Album Resource",
+      "uri": "/album/*",
+      "type": "http://photoz.com/album",
+      "scopes": [
+        {
+          "name": "urn:photoz.com:scopes:album:view"
+        },
+        {
+          "name": "urn:photoz.com:scopes:album:delete"
+        },
+        {
+          "name": "urn:photoz.com:scopes:album:create"
+        }
+      ]
+    },
+    {
+      "name": "Admin Resources",
+      "uri": "/admin/*",
+      "type": "http://photoz.com/admin",
+      "scopes": [
+        {
+          "name": "urn:photoz.com:scopes:album:admin:manage"
+        }
+      ]
+    }
+  ],
+  "policies": [
+    {
+      "name": "Only Owner Policy",
+      "description": "Defines that only the resource owner is allowed to do something",
+      "type": "drools",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "mavenArtifactVersion": "2.1.0-SNAPSHOT",
+        "mavenArtifactId": "photoz-authz-policy",
+        "sessionName": "MainOwnerSession",
+        "mavenArtifactGroupId": "org.keycloak",
+        "moduleName": "PhotozAuthzOwnerPolicy",
+        "scannerPeriod": "1",
+        "scannerPeriodUnit": "Hours"
+      }
+    },
+    {
+      "name": "Any Admin Policy",
+      "description": "Defines that adminsitrators can do something",
+      "type": "role",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "roles": "[{\"id\":\"admin\",\"required\":true}]"
+      }
+    },
+    {
+      "name": "Any User Policy",
+      "description": "Defines that only users from well known clients are allowed to access",
+      "type": "role",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "roles": "[{\"id\":\"user\"},{\"id\":\"manage-albums\",\"required\":true}]"
+      }
+    },
+    {
+      "name": "Only From a Specific Client Address",
+      "description": "Defines that only clients from a specific address can do something",
+      "type": "js",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "code": "var contextAttributes = $evaluation.getContext().getAttributes();\n\nif (contextAttributes.containsValue('kc.client.network.ip_address', '127.0.0.1')) {\n    $evaluation.grant();\n}"
+      }
+    },
+    {
+      "name": "Administration Policy",
+      "description": "Defines that only administrators from a specific network address can do something.",
+      "type": "aggregate",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "applyPolicies": "[\"Only From a Specific Client Address\",\"Any Admin Policy\"]"
+      }
+    },
+    {
+      "name": "Only Owner and Administrators Policy",
+      "description": "Defines that only the resource owner and administrators can do something",
+      "type": "aggregate",
+      "logic": "POSITIVE",
+      "decisionStrategy": "AFFIRMATIVE",
+      "config": {
+        "applyPolicies": "[\"Administration Policy\",\"Only Owner Policy\"]"
+      }
+    },
+    {
+      "name": "Only From @keycloak.org or Admin",
+      "description": "Defines that only users from @keycloak.org",
+      "type": "js",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "code": "var context = $evaluation.getContext();\nvar identity = context.getIdentity();\nvar attributes = identity.getAttributes();\nvar email = attributes.getValue('email').asString(0);\n\nif (identity.hasRole('admin') || email.endsWith('@keycloak.org')) {\n    $evaluation.grant();\n}"
+      }
+    },
+    {
+      "name": "Album Resource Permission",
+      "description": "General policies that apply to all album resources.",
+      "type": "resource",
+      "logic": "POSITIVE",
+      "decisionStrategy": "AFFIRMATIVE",
+      "config": {
+        "defaultResourceType": "http://photoz.com/album",
+        "default": "true",
+        "applyPolicies": "[\"Any User Policy\",\"Administration Policy\"]"
+      }
+    },
+    {
+      "name": "Admin Resource Permission",
+      "description": "General policy for any administrative resource.",
+      "type": "resource",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "defaultResourceType": "http://photoz.com/admin",
+        "default": "true",
+        "applyPolicies": "[\"Administration Policy\"]"
+      }
+    },
+    {
+      "name": "View User Permission",
+      "description": "Defines who is allowed to view an user profile",
+      "type": "scope",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "applyPolicies": "[\"Only From @keycloak.org or Admin\"]",
+        "scopes": "[\"urn:photoz.com:scopes:profile:view\"]"
+      }
+    },
+    {
+      "name": "Delete Album Permission",
+      "description": "A policy that only allows the owner to delete his albums.",
+      "type": "scope",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "applyPolicies": "[\"Only Owner and Administrators Policy\"]",
+        "scopes": "[\"urn:photoz.com:scopes:album:delete\"]"
+      }
+    }
+  ],
+  "scopes": [
+    {
+      "name": "urn:photoz.com:scopes:profile:view"
+    },
+    {
+      "name": "urn:photoz.com:scopes:album:view"
+    },
+    {
+      "name": "urn:photoz.com:scopes:album:create"
+    },
+    {
+      "name": "urn:photoz.com:scopes:album:delete"
+    },
+    {
+      "name": "urn:photoz.com:scopes:album:admin:manage"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/examples/authz/photoz/pom.xml b/examples/authz/photoz/pom.xml
new file mode 100755
index 0000000..95cd801
--- /dev/null
+++ b/examples/authz/photoz/pom.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.keycloak</groupId>
+        <artifactId>keycloak-authz-example-parent</artifactId>
+        <version>2.2.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>keycloak-authz-photoz-parent</artifactId>
+    <packaging>pom</packaging>
+
+    <name>Keycloak Authz: PhotoZ  Example Application Parent</name>
+    <description>PhotoZ Example Application</description>
+
+    <modules>
+        <module>photoz-restful-api</module>
+        <module>photoz-html5-client</module>
+        <module>photoz-authz-policy</module>
+    </modules>
+</project>
diff --git a/examples/authz/photoz/README.md b/examples/authz/photoz/README.md
new file mode 100644
index 0000000..c915a1f
--- /dev/null
+++ b/examples/authz/photoz/README.md
@@ -0,0 +1,98 @@
+# About the Example Application
+
+This is a simple application based on HTML5+AngularJS+JAX-RS that will introduce you to some of the main concepts around Keycloak Authorization Services.
+
+Basically, it is a project containing three modules:
+ 
+* **photoz-restful-api**, a simple RESTFul API based on JAX-RS and acting as a resource server.
+* **photoz-html5-client**, a HTML5+AngularJS client that will consume the RESTful API published by a resource resourcer.
+* **photoz-authz-policy**, a simple project with some rule-based policies using JBoss Drools.
+
+For this application, users can be regular users or administrators. Regular users can create/view/delete their albums 
+and administrators can do anything.
+
+In Keycloak, albums are resources that must be protected based on a set of policies that defines who and how can access them.
+
+The resources are also associated with a set of scopes that defines a specific access context. In this case, albums have three main scopes:
+
+* urn:photoz.com:scopes:album:create
+* urn:photoz.com:scopes:album:view
+* urn:photoz.com:scopes:album:delete
+
+The authorization requirements for this example application are based on the following assumptions:
+
+* By default, any regular user can perform any operation on his resources.
+
+    * For instance, Alice can create, view and delete her albums. 
+
+* Only the owner and administrators can delete albums. Here we are considering policies based on the *urn:photoz.com:scopes:album:delete* scope
+
+    * For instance, only Alice can delete her album.
+
+* Only administrators can access the Administration API (which basically provides ways to query albums for all users)
+
+* Administrators are only authorized to access resources if the client's ip address is well known
+
+That said, this application will show you how to use the Keycloak to define policies using:
+
+* Role-based Access Control
+* Attribute-based Access Control
+* Rule-based policies using JBoss Drools
+* Rule-based policies using JavaScript 
+
+Beside that, this example demonstrates how to create resources dynamically and how to protected them using the *Protection API* and the *Authorization Client API*. Here you'll see
+how to create a resource whose owner is the authenticated user.
+
+It also provides some background on how you can actually protect your JAX-RS endpoints using a *policy enforcer*.
+
+## Create the Example Realm and a Resource Server
+
+Considering that your Keycloak Server is up and running, log in to the Keycloak Administration Console.
+
+Now, create a new realm based on the following configuration file:
+
+    examples/authz/photoz/photoz-realm.json
+    
+That will import a pre-configured realm with everything you need to run this example. For more details about how to import a realm 
+into Keycloak, check the Keycloak's reference documentation.
+
+After importing that file, you'll have a new realm called ``photoz``. 
+
+Back to the command-line, build the example application. This step is necessary given that we're using policies based on
+JBoss Drools, which require ``photoz-authz-policy`` artifact installed into your local maven repository.
+
+    cd examples/authz/photoz
+    mvn clean install 
+
+Now, let's import another configuration using the Administration Console in order to configure the client application ``photoz-restful-api`` as a resource server with all resources, scopes, permissions and policies.
+
+Click on ``Clients`` on the left side menu. Click on the ``photoz-restful-api`` on the client listing page. This will
+open the ``Client Details`` page. Once there, click on the `Authorization` tab. 
+
+Click on the ``Select file`` button, which means you want to import a resource server configuration. Now select the file that is located at:
+
+    examples/authz/photoz/photoz-restful-api/photoz-restful-api-authz-config.json
+    
+Now click ``Upload`` and the resource server will be updated accordingly.
+
+## Deploy and Run the Example Applications
+
+To deploy the example applications, follow these steps:
+
+    cd examples/authz/photoz/photoz-html5-client
+    mvn clean package wildfly:deploy
+    
+And then:
+
+    cd examples/authz/photoz/photoz-restful-api
+    mvn clean package wildfly:deploy
+   
+Now, try to access the client application using the following URL:
+
+    http://localhost:8080/photoz-html5-client
+
+If everything is correct, you will be redirect to Keycloak login page. You can login to the application with the following credentials:
+
+* username: jdoe / password: jdoe
+* username: alice / password: alice
+* username: admin / password: admin
\ No newline at end of file
diff --git a/examples/authz/pom.xml b/examples/authz/pom.xml
new file mode 100755
index 0000000..398a9be
--- /dev/null
+++ b/examples/authz/pom.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <artifactId>keycloak-examples-parent</artifactId>
+        <groupId>org.keycloak</groupId>
+        <version>2.2.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>keycloak-authz-example-parent</artifactId>
+    <packaging>pom</packaging>
+
+    <name>Keycloak Authz: Examples Parent</name>
+    <description/>
+
+    <properties>
+        <maven.compiler.target>1.8</maven.compiler.target>
+        <maven.compiler.source>1.8</maven.compiler.source>
+    </properties>
+
+    <modules>
+        <module>photoz</module>
+        <module>servlet-authz</module>
+        <module>hello-world</module>
+        <module>hello-world-authz-service</module>
+    </modules>
+</project>
diff --git a/examples/authz/servlet-authz/pom.xml b/examples/authz/servlet-authz/pom.xml
new file mode 100755
index 0000000..767331f
--- /dev/null
+++ b/examples/authz/servlet-authz/pom.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.keycloak</groupId>
+        <artifactId>keycloak-authz-example-parent</artifactId>
+        <version>2.2.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>servlet-authz</artifactId>
+    <packaging>war</packaging>
+
+    <name>Keycloak Authz: Examples - Servlet Authorization</name>
+    <description>Servlet Authorization</description>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-authz-client</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-core</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.jboss.as.plugins</groupId>
+                <artifactId>jboss-as-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.wildfly.plugins</groupId>
+                <artifactId>wildfly-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/examples/authz/servlet-authz/README.md b/examples/authz/servlet-authz/README.md
new file mode 100644
index 0000000..f93acb5
--- /dev/null
+++ b/examples/authz/servlet-authz/README.md
@@ -0,0 +1,54 @@
+# About the Example Application
+
+This is a simple Servlet-based application that will introduce you to some of the main concepts around Keycloak Authorization Services.
+
+For this application, users can be regular users, premium users or administrators, where:
+
+* Regular users have very limited access.
+* Premium users have access to the *premium area*
+* Administrators have access to the *administration area*
+
+In Keycloak, all the paths being protected are resources on the server.
+
+This application will also show you how to create a dynamic menu with the permissions granted to an user.
+
+## Create the Example Realm and a Resource Server
+
+Considering that your Keycloak Server is up and running, log in to the Keycloak Administration Console.
+
+Now, create a new realm based on the following configuration file:
+
+    examples/authz/servlet-authz/servlet-authz-realm.json
+    
+That will import a pre-configured realm with everything you need to run this example. For more details about how to import a realm 
+into Keycloak, check the Keycloak's reference documentation.
+
+After importing that file, you'll have a new realm called ``servlet-authz``. 
+
+Now, let's import another configuration using the Administration Console in order to configure the client application ``servlet-authz-app`` as a resource server with all resources, scopes, permissions and policies.
+
+Click on ``Clients`` on the left side menu. Click on the ``servlet-authz-app`` on the client listing page. This will
+open the ``Client Details`` page. Once there, click on the `Authorization` tab. 
+
+Click on the ``Select file`` button, which means you want to import a resource server configuration. Now select the file that is located at:
+
+    examples/authz/servlet-authz/servlet-authz-app-config.json
+    
+Now click ``Upload`` and the resource server will be updated accordingly.
+
+## Deploy and Run the Example Applications
+
+To deploy the example application, follow these steps:
+
+    cd examples/authz/servlet-authz
+    mvn clean package wildfly:deploy
+    
+Now, try to access the client application using the following URL:
+
+    http://localhost:8080/servlet-authz-app
+
+If everything is correct, you will be redirect to Keycloak login page. You can login to the application with the following credentials:
+
+* username: jdoe / password: jdoe
+* username: alice / password: alice
+* username: admin / password: admin
\ No newline at end of file
diff --git a/examples/authz/servlet-authz/servlet-authz-app-config.json b/examples/authz/servlet-authz/servlet-authz-app-config.json
new file mode 100644
index 0000000..43ebde4
--- /dev/null
+++ b/examples/authz/servlet-authz/servlet-authz-app-config.json
@@ -0,0 +1,147 @@
+{
+  "allowRemoteResourceManagement": true,
+  "policyEnforcementMode": "ENFORCING",
+  "resources": [
+    {
+      "name": "Admin Resource",
+      "uri": "/protected/admin/*",
+      "type": "http://servlet-authz/protected/admin",
+      "scopes": [
+        {
+          "name": "urn:servlet-authz:protected:admin:access"
+        }
+      ]
+    },
+    {
+      "name": "Protected Resource",
+      "uri": "/*",
+      "type": "http://servlet-authz/protected/resource",
+      "scopes": [
+        {
+          "name": "urn:servlet-authz:protected:resource:access"
+        }
+      ]
+    },
+    {
+      "name": "Premium Resource",
+      "uri": "/protected/premium/*",
+      "type": "urn:servlet-authz:protected:resource",
+      "scopes": [
+        {
+          "name": "urn:servlet-authz:protected:premium:access"
+        }
+      ]
+    },
+    {
+      "name": "Main Page",
+      "type": "urn:servlet-authz:protected:resource",
+      "scopes": [
+        {
+          "name": "urn:servlet-authz:page:main:actionForAdmin"
+        },
+        {
+          "name": "urn:servlet-authz:page:main:actionForUser"
+        },
+        {
+          "name": "urn:servlet-authz:page:main:actionForPremiumUser"
+        }
+      ]
+    }
+  ],
+  "policies": [
+    {
+      "name": "Any Admin Policy",
+      "description": "Defines that adminsitrators can do something",
+      "type": "role",
+      "config": {
+        "roles": "[{\"id\":\"admin\"}]"
+      }
+    },
+    {
+      "name": "Any User Policy",
+      "description": "Defines that any user can do something",
+      "type": "role",
+      "config": {
+        "roles": "[{\"id\":\"user\"}]"
+      }
+    },
+    {
+      "name": "Only Premium User Policy",
+      "description": "Defines that only premium users can do something",
+      "type": "role",
+      "logic": "POSITIVE",
+      "config": {
+        "roles": "[{\"id\":\"user_premium\"}]"
+      }
+    },
+    {
+      "name": "All Users Policy",
+      "description": "Defines that all users can do something",
+      "type": "aggregate",
+      "decisionStrategy": "AFFIRMATIVE",
+      "config": {
+        "applyPolicies": "[\"Any User Policy\",\"Any Admin Policy\",\"Only Premium User Policy\"]"
+      }
+    },
+    {
+      "name": "Premium Resource Permission",
+      "description": "A policy that defines access to premium resources",
+      "type": "resource",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "resources": "[\"Premium Resource\"]",
+        "applyPolicies": "[\"Only Premium User Policy\"]"
+      }
+    },
+    {
+      "name": "Administrative Resource Permission",
+      "description": "A policy that defines access to administrative resources",
+      "type": "resource",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "resources": "[\"Admin Resource\"]",
+        "applyPolicies": "[\"Any Admin Policy\"]"
+      }
+    },
+    {
+      "name": "Protected Resource Permission",
+      "description": "A policy that defines access to any protected resource",
+      "type": "resource",
+      "decisionStrategy": "AFFIRMATIVE",
+      "config": {
+        "resources": "[\"Protected Resource\"]",
+        "applyPolicies": "[\"All Users Policy\"]"
+      }
+    },
+    {
+      "name": "Action 1 on Main Page Resource Permission",
+      "description": "A policy that defines access to action 1 on the main page",
+      "type": "scope",
+      "decisionStrategy": "AFFIRMATIVE",
+      "config": {
+        "scopes": "[\"urn:servlet-authz:page:main:actionForAdmin\"]",
+        "applyPolicies": "[\"Any Admin Policy\"]"
+      }
+    },
+    {
+      "name": "Action 2 on Main Page Resource Permission",
+      "description": "A policy that defines access to action 2 on the main page",
+      "type": "scope",
+      "decisionStrategy": "AFFIRMATIVE",
+      "config": {
+        "scopes": "[\"urn:servlet-authz:page:main:actionForUser\"]",
+        "applyPolicies": "[\"Any User Policy\"]"
+      }
+    },
+    {
+      "name": "Action 3 on Main Page Resource Permission",
+      "description": "A policy that defines access to action 3 on the main page",
+      "type": "scope",
+      "decisionStrategy": "AFFIRMATIVE",
+      "config": {
+        "scopes": "[\"urn:servlet-authz:page:main:actionForPremiumUser\"]",
+        "applyPolicies": "[\"Only Premium User Policy\"]"
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/examples/authz/servlet-authz/servlet-authz-realm.json b/examples/authz/servlet-authz/servlet-authz-realm.json
new file mode 100644
index 0000000..371e451
--- /dev/null
+++ b/examples/authz/servlet-authz/servlet-authz-realm.json
@@ -0,0 +1,95 @@
+{
+  "realm": "servlet-authz",
+  "enabled": true,
+  "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+  "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "requiredCredentials": [
+    "password"
+  ],
+  "users": [
+    {
+      "username": "alice",
+      "enabled": true,
+      "credentials": [
+        {
+          "type": "password",
+          "value": "alice"
+        }
+      ],
+      "realmRoles": [
+        "user"
+      ]
+    },
+    {
+      "username": "jdoe",
+      "enabled": true,
+      "credentials": [
+        {
+          "type": "password",
+          "value": "jdoe"
+        }
+      ],
+      "realmRoles": [
+        "user",
+        "user_premium"
+      ]
+    },
+    {
+      "username": "admin",
+      "enabled": true,
+      "credentials": [
+        {
+          "type": "password",
+          "value": "admin"
+        }
+      ],
+      "realmRoles": [
+        "user",
+        "admin"
+      ],
+      "clientRoles": {
+        "realm-management": [
+          "realm-admin"
+        ]
+      }
+    },
+    {
+      "username": "service-account-servlet-authz-app",
+      "enabled": true,
+      "serviceAccountClientId": "servlet-authz-app",
+      "clientRoles": {
+        "servlet-authz-app" : ["uma_protection"]
+      }
+    }
+  ],
+  "roles": {
+    "realm": [
+      {
+        "name": "user",
+        "description": "User privileges"
+      },
+      {
+        "name": "admin",
+        "description": "Administrator privileges"
+      },
+      {
+        "name": "user_premium",
+        "description": "User Premium privileges"
+      }
+    ]
+  },
+  "clients": [
+    {
+      "clientId": "servlet-authz-app",
+      "enabled": true,
+      "baseUrl": "/servlet-authz-app",
+      "adminUrl": "/servlet-authz-app",
+      "bearerOnly": false,
+      "authorizationServicesEnabled": true,
+      "redirectUris": [
+        "/servlet-authz-app/*"
+      ],
+      "secret": "secret"
+    }
+  ]
+}
diff --git a/examples/authz/servlet-authz/src/main/webapp/accessDenied.jsp b/examples/authz/servlet-authz/src/main/webapp/accessDenied.jsp
new file mode 100644
index 0000000..6f25023
--- /dev/null
+++ b/examples/authz/servlet-authz/src/main/webapp/accessDenied.jsp
@@ -0,0 +1,6 @@
+<html>
+    <body>
+        <h2 style="color: red">You can not access this resource.</h2>
+        <%@include file="logout-include.jsp"%>
+    </body>
+</html>
\ No newline at end of file
diff --git a/examples/authz/servlet-authz/src/main/webapp/index.jsp b/examples/authz/servlet-authz/src/main/webapp/index.jsp
new file mode 100755
index 0000000..3fbfca2
--- /dev/null
+++ b/examples/authz/servlet-authz/src/main/webapp/index.jsp
@@ -0,0 +1,35 @@
+<%@page import="org.keycloak.AuthorizationContext" %>
+<%@ page import="org.keycloak.KeycloakSecurityContext" %>
+<%@ page import="org.keycloak.representations.idm.authorization.Permission" %>
+
+<%
+    KeycloakSecurityContext keycloakSecurityContext = (KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
+    AuthorizationContext authzContext = keycloakSecurityContext.getAuthorizationContext();
+%>
+
+<html>
+<body>
+    <%@include file="logout-include.jsp"%>
+    <h2>This is a public resource. Try to access one of these <i>protected</i> resources:</h2>
+
+    <p><a href="protected/dynamicMenu.jsp">Dynamic Menu</a></p>
+    <p><a href="protected/premium/onlyPremium.jsp">User Premium</a></p>
+    <p><a href="protected/admin/onlyAdmin.jsp">Administration</a></p>
+
+    <h3>Your permissions are:</h3>
+
+    <ul>
+        <%
+            for (Permission permission : authzContext.getPermissions()) {
+        %>
+        <li>
+            <p>Resource: <%= permission.getResourceSetName() %></p>
+            <p>ID: <%= permission.getResourceSetId() %></p>
+            <p>Scopes: <%= permission.getScopes() %></p>
+        </li>
+        <%
+            }
+        %>
+    </ul>
+</body>
+</html>
diff --git a/examples/authz/servlet-authz/src/main/webapp/logout-include.jsp b/examples/authz/servlet-authz/src/main/webapp/logout-include.jsp
new file mode 100644
index 0000000..364d887
--- /dev/null
+++ b/examples/authz/servlet-authz/src/main/webapp/logout-include.jsp
@@ -0,0 +1,11 @@
+<%@ page import="org.keycloak.common.util.KeycloakUriBuilder" %>
+<%@ page import="org.keycloak.constants.ServiceUrlConstants" %>
+<%
+    String scheme = request.getScheme();
+    String host = request.getServerName();
+    int port = request.getServerPort();
+    String contextPath = request.getContextPath();
+    String redirectUri = scheme + "://" + host + ":" + port + contextPath;
+%>
+<h2>Click here <a href="<%= KeycloakUriBuilder.fromUri("http://localhost:8080/auth").path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH)
+            .queryParam("redirect_uri", redirectUri).build("servlet-authz").toString()%>">Sign Out</a></h2>
\ No newline at end of file
diff --git a/examples/authz/servlet-authz/src/main/webapp/META-INF/jboss-deployment-structure.xml b/examples/authz/servlet-authz/src/main/webapp/META-INF/jboss-deployment-structure.xml
new file mode 100644
index 0000000..515ffa5
--- /dev/null
+++ b/examples/authz/servlet-authz/src/main/webapp/META-INF/jboss-deployment-structure.xml
@@ -0,0 +1,25 @@
+<!--
+  ~  Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~  and other contributors as indicated by the @author tags.
+  ~
+  ~  Licensed under the Apache License, Version 2.0 (the "License");
+  ~  you may not use this file except in compliance with the License.
+  ~  You may obtain a copy of the License at
+  ~
+  ~  http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing, software
+  ~  distributed under the License is distributed on an "AS IS" BASIS,
+  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  See the License for the specific language governing permissions and
+  ~  limitations under the License.
+  ~
+  -->
+
+<jboss-deployment-structure>
+    <deployment>
+        <dependencies>
+            <module name="org.keycloak.keycloak-authz-client" services="import"/>
+        </dependencies>
+    </deployment>
+</jboss-deployment-structure>
\ No newline at end of file
diff --git a/examples/authz/servlet-authz/src/main/webapp/protected/admin/onlyAdmin.jsp b/examples/authz/servlet-authz/src/main/webapp/protected/admin/onlyAdmin.jsp
new file mode 100644
index 0000000..5946cd6
--- /dev/null
+++ b/examples/authz/servlet-authz/src/main/webapp/protected/admin/onlyAdmin.jsp
@@ -0,0 +1,6 @@
+<html>
+<body>
+    <h2>Only Administrators can access this page.</h2>
+    <%@include file="../../logout-include.jsp"%>
+</body>
+</html>
\ No newline at end of file
diff --git a/examples/authz/servlet-authz/src/main/webapp/protected/dynamicMenu.jsp b/examples/authz/servlet-authz/src/main/webapp/protected/dynamicMenu.jsp
new file mode 100644
index 0000000..1473d22
--- /dev/null
+++ b/examples/authz/servlet-authz/src/main/webapp/protected/dynamicMenu.jsp
@@ -0,0 +1,48 @@
+<%@page import="org.keycloak.AuthorizationContext" %>
+<%@ page import="org.keycloak.KeycloakSecurityContext" %>
+
+<%
+    KeycloakSecurityContext keycloakSecurityContext = (KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
+    AuthorizationContext authzContext = keycloakSecurityContext.getAuthorizationContext();
+%>
+
+<html>
+<body>
+<h2>Any authenticated user can access this page.</h2>
+<%@include file="../logout-include.jsp"%>
+
+<p>Here is a dynamic menu built from the permissions returned by the server:</p>
+
+<ul>
+    <%
+        if (authzContext.hasResourcePermission("Protected Resource")) {
+    %>
+    <li>
+        Do user thing
+    </li>
+    <%
+        }
+    %>
+
+    <%
+        if (authzContext.hasResourcePermission("Premium Resource")) {
+    %>
+    <li>
+        Do  user premium thing
+    </li>
+    <%
+        }
+    %>
+
+    <%
+        if (authzContext.hasPermission("Admin Resource", "urn:servlet-authz:protected:admin:access")) {
+    %>
+    <li>
+        Do administration thing
+    </li>
+    <%
+        }
+    %>
+</ul>
+</body>
+</html>
\ No newline at end of file
diff --git a/examples/authz/servlet-authz/src/main/webapp/protected/premium/onlyPremium.jsp b/examples/authz/servlet-authz/src/main/webapp/protected/premium/onlyPremium.jsp
new file mode 100644
index 0000000..9244f9c
--- /dev/null
+++ b/examples/authz/servlet-authz/src/main/webapp/protected/premium/onlyPremium.jsp
@@ -0,0 +1,6 @@
+<html>
+<body>
+<h2>Only for premium users.</h2>
+<%@include file="../../logout-include.jsp"%>
+</body>
+</html>
\ No newline at end of file
diff --git a/examples/authz/servlet-authz/src/main/webapp/WEB-INF/keycloak.json b/examples/authz/servlet-authz/src/main/webapp/WEB-INF/keycloak.json
new file mode 100644
index 0000000..eaffea8
--- /dev/null
+++ b/examples/authz/servlet-authz/src/main/webapp/WEB-INF/keycloak.json
@@ -0,0 +1,14 @@
+{
+  "realm": "servlet-authz",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url" : "http://localhost:8080/auth",
+  "ssl-required" : "external",
+  "resource" : "servlet-authz-app",
+  "public-client" : false,
+  "credentials": {
+    "secret": "secret"
+  },
+  "policy-enforcer": {
+    "on-deny-redirect-to" : "/servlet-authz-app/accessDenied.jsp"
+  }
+}
\ No newline at end of file
diff --git a/examples/authz/servlet-authz/src/main/webapp/WEB-INF/web.xml b/examples/authz/servlet-authz/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..14d0615
--- /dev/null
+++ b/examples/authz/servlet-authz/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+		 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+		 version="3.0">
+
+	<module-name>servlet-authz-app</module-name>
+
+	<security-constraint>
+		<web-resource-collection>
+			<web-resource-name>All Resources</web-resource-name>
+			<url-pattern>/*</url-pattern>
+		</web-resource-collection>
+		<auth-constraint>
+			<role-name>user</role-name>
+		</auth-constraint>
+	</security-constraint>
+
+	<security-constraint>
+		<web-resource-collection>
+			<web-resource-name>All Resources</web-resource-name>
+			<url-pattern>/*</url-pattern>
+		</web-resource-collection>
+		<auth-constraint>
+			<role-name>admin</role-name>
+		</auth-constraint>
+	</security-constraint>
+
+	<login-config>
+		<auth-method>KEYCLOAK</auth-method>
+		<realm-name>servlet-authz</realm-name>
+	</login-config>
+
+	<security-role>
+		<role-name>admin</role-name>
+	</security-role>
+
+	<security-role>
+		<role-name>user</role-name>
+	</security-role>
+
+	<error-page>
+		<error-code>403</error-code>
+		<location>/accessDenied.jsp</location>
+	</error-page>
+
+</web-app>
diff --git a/examples/basic-auth/pom.xml b/examples/basic-auth/pom.xml
index df1a594..a550b75 100755
--- a/examples/basic-auth/pom.xml
+++ b/examples/basic-auth/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <artifactId>keycloak-examples-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Keycloak Examples - Basic Auth</name>
diff --git a/examples/basic-auth/README.md b/examples/basic-auth/README.md
index be96c59..8eb4fc5 100644
--- a/examples/basic-auth/README.md
+++ b/examples/basic-auth/README.md
@@ -22,7 +22,7 @@ Step 2: Deploy and run the example
 
     curl http://admin:password@localhost:8080/basicauth/service/echo?value=hello
 
-(If we navigate directly to http://localhost:8080/basicauth/service/echo?value=hello, we get "Client is not allowed to initiate browser login with given response_type. Standard flow is disabled for the client.").
+(If we navigate directly to http://localhost:8080/basicauth/service/echo?value=hello, we get an error in the browser because the request is not authenticated).
 
 This should result in the value 'hello' being returned as a response.
 
diff --git a/examples/broker/facebook-authentication/pom.xml b/examples/broker/facebook-authentication/pom.xml
index cdd609c..03eaa7c 100755
--- a/examples/broker/facebook-authentication/pom.xml
+++ b/examples/broker/facebook-authentication/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <artifactId>keycloak-examples-broker-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Keycloak Broker Examples - Facebook Authentication</name>
diff --git a/examples/broker/google-authentication/pom.xml b/examples/broker/google-authentication/pom.xml
index a7dd2fa..9a5397f 100755
--- a/examples/broker/google-authentication/pom.xml
+++ b/examples/broker/google-authentication/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <artifactId>keycloak-examples-broker-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Keycloak Broker Examples - Google Authentication</name>
diff --git a/examples/broker/pom.xml b/examples/broker/pom.xml
index b104917..ecc3c9c 100755
--- a/examples/broker/pom.xml
+++ b/examples/broker/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-examples-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Broker Examples</name>
diff --git a/examples/broker/saml-broker-authentication/pom.xml b/examples/broker/saml-broker-authentication/pom.xml
index c5640ae..33f4f25 100755
--- a/examples/broker/saml-broker-authentication/pom.xml
+++ b/examples/broker/saml-broker-authentication/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <artifactId>keycloak-examples-broker-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Keycloak Broker Examples - SAML Identity Provider Brokering</name>
diff --git a/examples/broker/twitter-authentication/pom.xml b/examples/broker/twitter-authentication/pom.xml
index a4a6ac7..dff3fd2 100755
--- a/examples/broker/twitter-authentication/pom.xml
+++ b/examples/broker/twitter-authentication/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <artifactId>keycloak-examples-broker-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Keycloak Broker Examples - Twitter Authentication</name>
diff --git a/examples/cors/angular-product-app/pom.xml b/examples/cors/angular-product-app/pom.xml
index b67e4de..b4ce0f2 100755
--- a/examples/cors/angular-product-app/pom.xml
+++ b/examples/cors/angular-product-app/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-cors-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/cors/database-service/pom.xml b/examples/cors/database-service/pom.xml
index 6e4fc7d..a9f0559 100755
--- a/examples/cors/database-service/pom.xml
+++ b/examples/cors/database-service/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-cors-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/cors/pom.xml b/examples/cors/pom.xml
index f0a52d5..61b9531 100755
--- a/examples/cors/pom.xml
+++ b/examples/cors/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Keycloak Examples - CORS</name>
diff --git a/examples/demo-template/admin-access-app/pom.xml b/examples/demo-template/admin-access-app/pom.xml
index 1a5f460..6d65cb6 100755
--- a/examples/demo-template/admin-access-app/pom.xml
+++ b/examples/demo-template/admin-access-app/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-demo-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/demo-template/angular-product-app/pom.xml b/examples/demo-template/angular-product-app/pom.xml
index fa8d798..9297fad 100755
--- a/examples/demo-template/angular-product-app/pom.xml
+++ b/examples/demo-template/angular-product-app/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-demo-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/demo-template/customer-app/pom.xml b/examples/demo-template/customer-app/pom.xml
index 479e282..13b818d 100755
--- a/examples/demo-template/customer-app/pom.xml
+++ b/examples/demo-template/customer-app/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-demo-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/demo-template/customer-app-cli/pom.xml b/examples/demo-template/customer-app-cli/pom.xml
index b6091bc..900f90d 100755
--- a/examples/demo-template/customer-app-cli/pom.xml
+++ b/examples/demo-template/customer-app-cli/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-demo-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/demo-template/customer-app-filter/pom.xml b/examples/demo-template/customer-app-filter/pom.xml
index c28fb7e..de3aa27 100755
--- a/examples/demo-template/customer-app-filter/pom.xml
+++ b/examples/demo-template/customer-app-filter/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-demo-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/demo-template/customer-app-js/pom.xml b/examples/demo-template/customer-app-js/pom.xml
index 7f5a1bb..0126d06 100755
--- a/examples/demo-template/customer-app-js/pom.xml
+++ b/examples/demo-template/customer-app-js/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-demo-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/demo-template/customer-app-js/src/main/webapp/customers/view.html b/examples/demo-template/customer-app-js/src/main/webapp/customers/view.html
index 5a2ba05..e59c67e 100755
--- a/examples/demo-template/customer-app-js/src/main/webapp/customers/view.html
+++ b/examples/demo-template/customer-app-js/src/main/webapp/customers/view.html
@@ -97,7 +97,11 @@ User <b id="subject"></b> made this request.
                 });
     }
 
-    keycloak.init({ onLoad: 'login-required' }).success(reloadData);
+    keycloak.init({ onLoad: 'login-required' })
+        .success(reloadData)
+        .error(function(errorData) {
+            document.getElementById('customers').innerHTML = '<b>Failed to load data. Error: ' + JSON.stringify(errorData) + '</b>';
+        });
 
 </script>
 
diff --git a/examples/demo-template/database-service/pom.xml b/examples/demo-template/database-service/pom.xml
index e209f26..cd4504f 100755
--- a/examples/demo-template/database-service/pom.xml
+++ b/examples/demo-template/database-service/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-demo-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/demo-template/example-ear/pom.xml b/examples/demo-template/example-ear/pom.xml
index 4926f3d..b44a500 100755
--- a/examples/demo-template/example-ear/pom.xml
+++ b/examples/demo-template/example-ear/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-demo-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/demo-template/offline-access-app/pom.xml b/examples/demo-template/offline-access-app/pom.xml
index 3965a25..88222ba 100755
--- a/examples/demo-template/offline-access-app/pom.xml
+++ b/examples/demo-template/offline-access-app/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-demo-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/demo-template/pom.xml b/examples/demo-template/pom.xml
index 2da8e1a..b7fc027 100755
--- a/examples/demo-template/pom.xml
+++ b/examples/demo-template/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-examples-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Examples</name>
diff --git a/examples/demo-template/product-app/pom.xml b/examples/demo-template/product-app/pom.xml
index 736f0f9..1ce2954 100755
--- a/examples/demo-template/product-app/pom.xml
+++ b/examples/demo-template/product-app/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-demo-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/demo-template/service-account/pom.xml b/examples/demo-template/service-account/pom.xml
index a6a006c..f245cf0 100755
--- a/examples/demo-template/service-account/pom.xml
+++ b/examples/demo-template/service-account/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-demo-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/demo-template/third-party/pom.xml b/examples/demo-template/third-party/pom.xml
index 8b82458..0e426b4 100755
--- a/examples/demo-template/third-party/pom.xml
+++ b/examples/demo-template/third-party/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-demo-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/demo-template/third-party-cdi/pom.xml b/examples/demo-template/third-party-cdi/pom.xml
index af43b9c..9e8d1e7 100755
--- a/examples/demo-template/third-party-cdi/pom.xml
+++ b/examples/demo-template/third-party-cdi/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-demo-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/fuse/camel/pom.xml b/examples/fuse/camel/pom.xml
index 47d475c..424aeca 100755
--- a/examples/fuse/camel/pom.xml
+++ b/examples/fuse/camel/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-fuse-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/fuse/customer-app-fuse/pom.xml b/examples/fuse/customer-app-fuse/pom.xml
index 64e4a71..2ae6658 100755
--- a/examples/fuse/customer-app-fuse/pom.xml
+++ b/examples/fuse/customer-app-fuse/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-fuse-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/fuse/cxf-jaxrs/pom.xml b/examples/fuse/cxf-jaxrs/pom.xml
index a07a78b..0992d0d 100755
--- a/examples/fuse/cxf-jaxrs/pom.xml
+++ b/examples/fuse/cxf-jaxrs/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-fuse-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/fuse/cxf-jaxws/pom.xml b/examples/fuse/cxf-jaxws/pom.xml
index 8923a0d..2ca6843 100755
--- a/examples/fuse/cxf-jaxws/pom.xml
+++ b/examples/fuse/cxf-jaxws/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-fuse-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/fuse/external-config/pom.xml b/examples/fuse/external-config/pom.xml
index 89768e9..0148b00 100755
--- a/examples/fuse/external-config/pom.xml
+++ b/examples/fuse/external-config/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-fuse-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Keycloak Examples - External Config</name>
diff --git a/examples/fuse/features/pom.xml b/examples/fuse/features/pom.xml
index 22664f3..97f6af4 100755
--- a/examples/fuse/features/pom.xml
+++ b/examples/fuse/features/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-fuse-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/fuse/fuse-admin/README.md b/examples/fuse/fuse-admin/README.md
index bae96d9..050d709 100644
--- a/examples/fuse/fuse-admin/README.md
+++ b/examples/fuse/fuse-admin/README.md
@@ -70,15 +70,15 @@ may be still able to access MBeans remotely via HTTP (Hawtio). So make sure to p
 really protect JMX mbeans.
 
 
-SSH and JMX on JBoss Fuse 6.2 and Apache Karaf 3.0.3
-----------------------------------------------------
+SSH and JMX on JBoss Fuse 6.2 
+-----------------------------
 For SSH steps are very similar to above for 6.1. In JBoss Fuse 6.2 you may need to install `ssh` feature as it doesn't seem to be installed here by default.
 
 ```
 features:install ssh
 ```
 
-For JMX, the steps are similar like for Fuse 6.1, however there is more fine grained authorization for JMX access in Fuse 6.2 and Karaf 3.
+For JMX, the steps are similar like for Fuse 6.1, however there is more fine grained authorization for JMX access in Fuse 6.2.
 
 Actually if you login as user `admin`, you have very limited privileges without possibility to do much JMX operations as this user has just `admin` role, which is not allowed to do much in JMX.
 
diff --git a/examples/fuse/pom.xml b/examples/fuse/pom.xml
index be94867..5417855 100755
--- a/examples/fuse/pom.xml
+++ b/examples/fuse/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-examples-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Fuse examples</name>
diff --git a/examples/fuse/product-app-fuse/pom.xml b/examples/fuse/product-app-fuse/pom.xml
index 4de29b3..811b31f 100755
--- a/examples/fuse/product-app-fuse/pom.xml
+++ b/examples/fuse/product-app-fuse/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-fuse-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/fuse/README.md b/examples/fuse/README.md
index 10232b9..edfba47 100644
--- a/examples/fuse/README.md
+++ b/examples/fuse/README.md
@@ -5,12 +5,15 @@ Currently Keycloak supports securing your web applications running inside [JBoss
 - Jetty8 adapter for both JBoss Fuse 6.2 and Apache Karaf 3, that include [Jetty8](http://eclipse.org/jetty/) server under the covers and Jetty is used for running various kinds of web applications
 - Jetty9 adapter for both JBoss Fuse 6.3 and Apache Karaf 4, that include [Jetty9](http://eclipse.org/jetty/) server under the covers and Jetty is used for running various kinds of web applications
 
+**WARNING:** Running your applications inside standalone Apache Karaf may work, however we are testing just with JBoss Fuse and not with standalone Karaf server. 
+So if you really want adapter on standalone Karaf server, it's up to you to figure exact steps to have it working.
+
 The Fuse example is slightly modified version of Keycloak base demo applications. The main difference among base demo is that for Fuse demo 
-are applications running on separate Fuse/Karaf server. Keycloak server is supposed to run separately on Wildfly.
+are applications running on separate Fuse server. Keycloak server is supposed to run separately on Wildfly.
 
-What is supported for Fuse/Karaf is:
-* Security for classic WAR applications deployed on Fuse/Karaf with [pax-war extender](https://ops4j1.jira.com/wiki/display/ops4j/Pax+Web+Extender+-+War). 
-* Security for servlets deployed on Fuse/Karaf as OSGI services with [pax-whiteboard extender](https://ops4j1.jira.com/wiki/display/ops4j/Pax+Web+Extender+-+Whiteboard).
+What is supported for Fuse is:
+* Security for classic WAR applications deployed on Fuse with [pax-war extender](https://ops4j1.jira.com/wiki/display/ops4j/Pax+Web+Extender+-+War). 
+* Security for servlets deployed on Fuse as OSGI services with [pax-whiteboard extender](https://ops4j1.jira.com/wiki/display/ops4j/Pax+Web+Extender+-+Whiteboard).
 * Security for [Apache Camel](http://camel.apache.org/) Jetty endpoints running with [camel-jetty](http://camel.apache.org/jetty.html) component.
 * Security for [Apache CXF](http://cxf.apache.org/) endpoints running on their own separate [Jetty engine](http://cxf.apache.org/docs/jetty-configuration.html). 
 Supports both securing JAX-RS and JAX-WS endpoints.
@@ -27,7 +30,7 @@ The customer-app-fuse invokes the endpoint to get data
 * **cxf-jaxws** [Apache CXF](http://cxf.apache.org/) JAX-WS endpoint running on separate Jetty engine on [http://localhost:8282/PersonServiceCF](http://localhost:8282/PersonServiceCF). 
 The product-app-fuse invokes the endpoint to get data.
 
-Running of demo consists of 2 steps. First you need to run separate Keycloak server and then Fuse/Karaf server with the applications
+Running of demo consists of 2 steps. First you need to run separate Keycloak server and then Fuse server with the applications
 
 Base steps
 ----------
@@ -74,25 +77,6 @@ features:addurl mvn:org.keycloak.example.demo/keycloak-fuse-example-features/1.9
 features:install keycloak-fuse-6.3-example
 ```
 
-Running demo on Apache Karaf 3.0.3
-----------------------------------
-
-Demo is using Apache camel and Apache CXF, which are not in standalone Karaf by default. So you will need to install feature repositories for both of them.
-Next step is to add feature repository for main set of Keycloak karaf features and for the demo. Once all feature URLs are added, you just need to install `keycloak-fuse-example` feature,
-which automatically installs all other needed stuff.
-
-Once you run Apache Karaf, you need to run these commands from Karaf console (Make sure to replace keycloak versions in the example with actual Keycloak version):
-
-```
-feature:repo-add mvn:org.apache.camel.karaf/apache-camel/2.15.1/xml/features
-feature:repo-add mvn:org.apache.cxf.karaf/apache-cxf/3.0.4/xml/features
-feature:repo-add mvn:org.keycloak/keycloak-osgi-features/1.9.4.Final/xml/features
-feature:repo-add mvn:org.keycloak.example.demo/keycloak-fuse-example-features/1.9.4.Final/xml/features
-feature:install keycloak-fuse-example
-```
-
-Now you can test example applications similarly like described for "JBoss Fuse 6.2" section.
-
 
 How to secure your own applications
 -----------------------------------
diff --git a/examples/js-console/pom.xml b/examples/js-console/pom.xml
index e9a784d..44ff29a 100755
--- a/examples/js-console/pom.xml
+++ b/examples/js-console/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/js-console/src/main/webapp/index.html b/examples/js-console/src/main/webapp/index.html
index a2282f7..3b293f2 100644
--- a/examples/js-console/src/main/webapp/index.html
+++ b/examples/js-console/src/main/webapp/index.html
@@ -110,8 +110,8 @@
         event('Auth Success');
     };
 
-    keycloak.onAuthError = function () {
-        event('Auth Error');
+    keycloak.onAuthError = function (errorData) {
+        event("Auth Error: " + JSON.stringify(errorData) );
     };
 
     keycloak.onAuthRefreshSuccess = function () {
diff --git a/examples/kerberos/pom.xml b/examples/kerberos/pom.xml
index ca1b196..063eacb 100755
--- a/examples/kerberos/pom.xml
+++ b/examples/kerberos/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <artifactId>keycloak-examples-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Keycloak Examples - Kerberos Credential Delegation</name>
diff --git a/examples/ldap/pom.xml b/examples/ldap/pom.xml
index f16e8b0..56a99c1 100644
--- a/examples/ldap/pom.xml
+++ b/examples/ldap/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <artifactId>keycloak-examples-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/examples/multi-tenant/pom.xml b/examples/multi-tenant/pom.xml
index d6271f0..4e4e04f 100755
--- a/examples/multi-tenant/pom.xml
+++ b/examples/multi-tenant/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-examples-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Keycloak Examples - Multi Tenant</name>

examples/pom.xml 3(+2 -1)

diff --git a/examples/pom.xml b/examples/pom.xml
index 3d55a42..7d1b6b9 100755
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Examples</name>
@@ -66,5 +66,6 @@
         <module>themes</module>
         <module>saml</module>
         <module>ldap</module>
+        <module>authz</module>
     </modules>
 </project>
diff --git a/examples/providers/authenticator/pom.xml b/examples/providers/authenticator/pom.xml
index 0097cae..5a1b100 100755
--- a/examples/providers/authenticator/pom.xml
+++ b/examples/providers/authenticator/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-examples-providers-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Authenticator Example</name>
diff --git a/examples/providers/authenticator/README.md b/examples/providers/authenticator/README.md
index 38f6983..1edf0ed 100755
--- a/examples/providers/authenticator/README.md
+++ b/examples/providers/authenticator/README.md
@@ -1,4 +1,4 @@
-Example User Federation Provider
+Example Custom Authenticator
 ===================================================
 
 This is an example of defining a custom Authenticator and Required action.  This example is explained in the user documentation
diff --git a/examples/providers/domain-extension/invoke-authenticated.sh b/examples/providers/domain-extension/invoke-authenticated.sh
new file mode 100755
index 0000000..19b56b1
--- /dev/null
+++ b/examples/providers/domain-extension/invoke-authenticated.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+export DIRECT_GRANT_RESPONSE=$(curl -i --request POST http://localhost:8080/auth/realms/master/protocol/openid-connect/token --header "Accept: application/json" --header "Content-Type: application/x-www-form-urlencoded" --data "grant_type=password&username=admin&password=admin&client_id=admin-cli")
+
+echo -e "\n\nSENT RESOURCE-OWNER-PASSWORD-CREDENTIALS-REQUEST. OUTPUT IS:\n\n";
+echo $DIRECT_GRANT_RESPONSE;
+
+export ACCESS_TOKEN=$(echo $DIRECT_GRANT_RESPONSE | grep "access_token" | sed 's/.*\"access_token\":\"\([^\"]*\)\".*/\1/g');
+echo -e "\n\nACCESS TOKEN IS \"$ACCESS_TOKEN\"";
+
+echo -e "\n\nSENDING UN-AUTHENTICATED REQUEST. THIS SHOULD FAIL WITH 401: ";
+curl -i --request POST http://localhost:8080/auth/realms/master/example/companies-auth --data "{ \"name\": \"auth foo company\" }" --header "Content-type: application/json"
+
+echo -e "\n\nSENDING AUTHENTICATED REQUEST. THIS SHOULD SUCCESSFULY CREATE COMPANY AND SUCCESS WITH 201: ";
+curl -i --request POST http://localhost:8080/auth/realms/master/example/companies-auth --data "{ \"name\": \"auth foo company\" }" --header "Content-type: application/json" --header "Authorization: Bearer $ACCESS_TOKEN";
+
+echo -e "\n\nSEARCH COMPANIES: ";
+curl -i --request GET http://localhost:8080/auth/realms/master/example/companies-auth --header "Accept: application/json" --header "Authorization: Bearer $ACCESS_TOKEN";
+
diff --git a/examples/providers/domain-extension/pom.xml b/examples/providers/domain-extension/pom.xml
new file mode 100755
index 0000000..cbf9408
--- /dev/null
+++ b/examples/providers/domain-extension/pom.xml
@@ -0,0 +1,64 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <parent>
+        <artifactId>keycloak-examples-providers-parent</artifactId>
+        <groupId>org.keycloak</groupId>
+        <version>2.2.0-SNAPSHOT</version>
+    </parent>
+
+    <name>Domain Extension Example</name>
+    <description/>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>keycloak-examples-providers-domain-extension</artifactId>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-services</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-model-jpa</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.spec.javax.ws.rs</groupId>
+            <artifactId>jboss-jaxrs-api_2.0_spec</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>domain-extension-example</finalName>
+    </build>
+</project>
+
diff --git a/examples/providers/domain-extension/README.md b/examples/providers/domain-extension/README.md
new file mode 100644
index 0000000..e1aa2cd
--- /dev/null
+++ b/examples/providers/domain-extension/README.md
@@ -0,0 +1,44 @@
+Example Domain Extension 
+========================
+
+To run, deploy as a module by running:
+
+    $KEYCLOAK_HOME/bin/jboss-cli.sh --command="module add --name=org.keycloak.examples.domain-extension-example --resources=target/domain-extension-example.jar --dependencies=org.keycloak.keycloak-core,org.keycloak.keycloak-services,org.keycloak.keycloak-model-jpa,org.keycloak.keycloak-server-spi,javax.ws.rs.api,javax.persistence.api,org.hibernate,org.javassist"
+
+
+Then registering the provider by editing keycloak-server.json and adding the module to the providers field:
+
+    "providers": [
+        ....
+        "module:org.keycloak.examples.domain-extension-example"
+    ],
+
+Then start (or restart) the server.
+
+Testing
+-------
+First you can create some example companies with these CURL requests.
+
+````
+curl -i --request POST http://localhost:8080/auth/realms/master/example/companies --data "{ \"name\": \"foo company\" }" --header "Content-type: application/json"
+curl -i --request POST http://localhost:8080/auth/realms/master/example/companies --data "{ \"name\": \"bar company\" }" --header "Content-type: application/json"
+````
+
+Then you can lookup all companies 
+
+````
+curl -i --request GET http://localhost:8080/auth/realms/master/example/companies --header "Accept: application/json"
+````
+
+If you create realm `foo` in Keycloak admin console and then replace the realm name in the URI (for example like `http://localhost:8080/auth/realms/foo/example/companies` ) you will see
+that companies are scoped per-realm. So you will see different companies for realm `master` and for realm `foo` .
+
+
+Testing with authenticated access
+---------------------------------
+Example contains the endpoint, which is accessible just for authenticated users. REST request must be authenticated with bearer access token
+of authenticated user and the user must be in realm role `admin` in order to access the resource. You can run bash script from the current directory:
+````
+./invoke-authenticated.sh
+````
+The script assumes user `admin` with password `admin` exists in realm `master`. Also it assumes that you have `curl` installed.
\ No newline at end of file
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/CompanyRepresentation.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/CompanyRepresentation.java
new file mode 100644
index 0000000..2b76d57
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/CompanyRepresentation.java
@@ -0,0 +1,33 @@
+package org.keycloak.examples.domainextension;
+
+import org.keycloak.examples.domainextension.jpa.Company;
+
+public class CompanyRepresentation {
+
+    private String id;
+    private String name;
+
+    public CompanyRepresentation() {
+    }
+
+    public CompanyRepresentation(Company company) {
+        id = company.getId();
+        name = company.getName();
+    }
+    
+    public String getId() {
+		return id;
+	}
+    
+    public String getName() {
+		return name;
+	}
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/jpa/Company.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/jpa/Company.java
new file mode 100644
index 0000000..bca8e1d
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/jpa/Company.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.examples.domainextension.jpa;
+
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "EXAMPLE_COMPANY")
+@NamedQueries({ @NamedQuery(name = "findByRealm", query = "from Company where realmId = :realmId") })
+public class Company {
+
+    @Id
+    @Column(name = "ID")
+    private String id;
+
+    @Column(name = "NAME", nullable = false)
+    private String name;
+
+    @Column(name = "REALM_ID", nullable = false)
+    private String realmId;
+
+    public String getId() {
+		return id;
+	}
+    
+    public String getRealmId() {
+        return realmId;
+    }
+    
+    public String getName() {
+		return name;
+	}
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setRealmId(String realmId) {
+        this.realmId = realmId;
+    }
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/jpa/ExampleJpaEntityProvider.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/jpa/ExampleJpaEntityProvider.java
new file mode 100644
index 0000000..b6529fd
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/jpa/ExampleJpaEntityProvider.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.examples.domainextension.jpa;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.keycloak.connections.jpa.entityprovider.JpaEntityProvider;
+
+/**
+ * @author <a href="mailto:erik.mulder@docdatapayments.com">Erik Mulder</a>
+ * 
+ * Example JpaEntityProvider.
+ */
+public class ExampleJpaEntityProvider implements JpaEntityProvider {
+
+    @Override
+    public List<Class<?>> getEntities() {
+        return Collections.<Class<?>>singletonList(Company.class);
+    }
+
+    @Override
+    public String getChangelogLocation() {
+    	return "META-INF/example-changelog.xml";
+    }
+    
+    @Override
+    public void close() {
+    }
+
+    @Override
+    public String getFactoryId() {
+        return ExampleJpaEntityProviderFactory.ID;
+    }
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/jpa/ExampleJpaEntityProviderFactory.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/jpa/ExampleJpaEntityProviderFactory.java
new file mode 100644
index 0000000..2c919f4
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/jpa/ExampleJpaEntityProviderFactory.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.examples.domainextension.jpa;
+
+import org.keycloak.Config.Scope;
+import org.keycloak.connections.jpa.entityprovider.JpaEntityProvider;
+import org.keycloak.connections.jpa.entityprovider.JpaEntityProviderFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:erik.mulder@docdatapayments.com">Erik Mulder</a>
+ * 
+ * Example JpaEntityProviderFactory.
+ */
+public class ExampleJpaEntityProviderFactory implements JpaEntityProviderFactory {
+
+	protected static final String ID = "example-entity-provider";
+	
+    @Override
+    public JpaEntityProvider create(KeycloakSession session) {
+        return new ExampleJpaEntityProvider();
+    }
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+    @Override
+    public void init(Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/CompanyResource.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/CompanyResource.java
new file mode 100644
index 0000000..ba98978
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/CompanyResource.java
@@ -0,0 +1,52 @@
+package org.keycloak.examples.domainextension.rest;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.examples.domainextension.CompanyRepresentation;
+import org.keycloak.examples.domainextension.spi.ExampleService;
+import org.keycloak.models.KeycloakSession;
+
+public class CompanyResource {
+
+	private final KeycloakSession session;
+	
+	public CompanyResource(KeycloakSession session) {
+		this.session = session;
+	}
+
+    @GET
+    @Path("")
+    @NoCache
+    @Produces(MediaType.APPLICATION_JSON)
+    public List<CompanyRepresentation> getCompanies() {
+        return session.getProvider(ExampleService.class).listCompanies();
+    }
+
+    @POST
+    @Path("")
+    @NoCache
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response createCompany(CompanyRepresentation rep) {
+        session.getProvider(ExampleService.class).addCompany(rep);
+        return Response.created(session.getContext().getUri().getAbsolutePathBuilder().path(rep.getId()).build()).build();
+    }
+
+    @GET
+    @NoCache
+    @Path("{id}")
+    @Produces(MediaType.APPLICATION_JSON)
+    public CompanyRepresentation getCompany(@PathParam("id") final String id) {
+        return session.getProvider(ExampleService.class).findCompany(id);
+    }
+
+}
\ No newline at end of file
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/ExampleRealmResourceProvider.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/ExampleRealmResourceProvider.java
new file mode 100644
index 0000000..0882d22
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/ExampleRealmResourceProvider.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.examples.domainextension.rest;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.services.resource.RealmResourceProvider;
+
+public class ExampleRealmResourceProvider implements RealmResourceProvider {
+
+    private KeycloakSession session;
+
+    public ExampleRealmResourceProvider(KeycloakSession session) {
+        this.session = session;
+    }
+
+    @Override
+    public Object getResource() {
+        return new ExampleRestResource(session);
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/ExampleRealmResourceProviderFactory.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/ExampleRealmResourceProviderFactory.java
new file mode 100644
index 0000000..33c2ca2
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/ExampleRealmResourceProviderFactory.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.examples.domainextension.rest;
+
+import org.keycloak.Config.Scope;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.services.resource.RealmResourceProvider;
+import org.keycloak.services.resource.RealmResourceProviderFactory;
+
+public class ExampleRealmResourceProviderFactory implements RealmResourceProviderFactory {
+
+    public static final String ID = "example";
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+    @Override
+    public RealmResourceProvider create(KeycloakSession session) {
+        return new ExampleRealmResourceProvider(session);
+    }
+
+    @Override
+    public void init(Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/ExampleRestResource.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/ExampleRestResource.java
new file mode 100644
index 0000000..db774cf
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/rest/ExampleRestResource.java
@@ -0,0 +1,43 @@
+package org.keycloak.examples.domainextension.rest;
+
+import javax.ws.rs.ForbiddenException;
+import javax.ws.rs.NotAuthorizedException;
+import javax.ws.rs.Path;
+
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.services.managers.AppAuthManager;
+import org.keycloak.services.managers.AuthenticationManager;
+
+public class ExampleRestResource {
+
+	private final KeycloakSession session;
+    private final AuthenticationManager.AuthResult auth;
+	
+	public ExampleRestResource(KeycloakSession session) {
+		this.session = session;
+        this.auth = new AppAuthManager().authenticateBearerToken(session, session.getContext().getRealm());
+	}
+	
+    @Path("companies")
+    public CompanyResource getCompanyResource() {
+        return new CompanyResource(session);
+    }
+
+    // Same like "companies" endpoint, but REST endpoint is authenticated with Bearer token and user must be in realm role "admin"
+    // Just for illustration purposes
+    @Path("companies-auth")
+    public CompanyResource getCompanyResourceAuthenticated() {
+        checkRealmAdmin();
+        return new CompanyResource(session);
+    }
+
+    private void checkRealmAdmin() {
+        if (auth == null) {
+            throw new NotAuthorizedException("Bearer");
+        } else if (auth.getToken().getRealmAccess() == null || !auth.getToken().getRealmAccess().isUserInRole("admin")) {
+            throw new ForbiddenException("Does not have realm admin role");
+        }
+    }
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/spi/ExampleService.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/spi/ExampleService.java
new file mode 100644
index 0000000..7f41327
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/spi/ExampleService.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.examples.domainextension.spi;
+
+import java.util.List;
+
+import org.keycloak.examples.domainextension.CompanyRepresentation;
+import org.keycloak.provider.Provider;
+
+public interface ExampleService extends Provider {
+
+    List<CompanyRepresentation> listCompanies();
+
+    CompanyRepresentation findCompany(String id);
+
+    CompanyRepresentation addCompany(CompanyRepresentation company);
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/spi/ExampleServiceProviderFactory.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/spi/ExampleServiceProviderFactory.java
new file mode 100644
index 0000000..2c6a122
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/spi/ExampleServiceProviderFactory.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.examples.domainextension.spi;
+
+import org.keycloak.provider.ProviderFactory;
+
+public interface ExampleServiceProviderFactory extends ProviderFactory<ExampleService> {
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/spi/ExampleSpi.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/spi/ExampleSpi.java
new file mode 100644
index 0000000..811ec92
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/spi/ExampleSpi.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.examples.domainextension.spi;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+public class ExampleSpi implements Spi {
+
+    @Override
+    public boolean isInternal() {
+        return false;
+    }
+
+    @Override
+    public String getName() {
+        return "example";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return ExampleService.class;
+    }
+
+    @Override
+    @SuppressWarnings("rawtypes")
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return ExampleServiceProviderFactory.class;
+    }
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/spi/impl/ExampleServiceImpl.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/spi/impl/ExampleServiceImpl.java
new file mode 100644
index 0000000..49cc228
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/spi/impl/ExampleServiceImpl.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.examples.domainextension.spi.impl;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.persistence.EntityManager;
+
+import org.keycloak.connections.jpa.JpaConnectionProvider;
+import org.keycloak.examples.domainextension.jpa.Company;
+import org.keycloak.examples.domainextension.CompanyRepresentation;
+import org.keycloak.examples.domainextension.spi.ExampleService;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
+
+public class ExampleServiceImpl implements ExampleService {
+
+    private final KeycloakSession session;
+
+    public ExampleServiceImpl(KeycloakSession session) {
+        this.session = session;
+        if (getRealm() == null) {
+            throw new IllegalStateException("The service cannot accept a session without a realm in it's context.");
+        }
+    }
+
+    private EntityManager getEntityManager() {
+        return session.getProvider(JpaConnectionProvider.class).getEntityManager();
+    }
+
+    protected RealmModel getRealm() {
+        return session.getContext().getRealm();
+    }
+    
+    @Override
+    public List<CompanyRepresentation> listCompanies() {
+    	List<Company> companyEntities = getEntityManager().createNamedQuery("findByRealm", Company.class)
+                .setParameter("realmId", getRealm().getId())
+                .getResultList();
+
+        List<CompanyRepresentation> result = new LinkedList<>();
+        for (Company entity : companyEntities) {
+            result.add(new CompanyRepresentation(entity));
+        }
+        return result;
+    }
+    
+    @Override
+    public CompanyRepresentation findCompany(String id) {
+    	Company entity = getEntityManager().find(Company.class, id);
+        return entity==null ? null : new CompanyRepresentation(entity);
+    }
+    
+    @Override
+    public CompanyRepresentation addCompany(CompanyRepresentation company) {
+        Company entity = new Company();
+        String id = company.getId()==null ?  KeycloakModelUtils.generateId() : company.getId();
+        entity.setId(id);
+        entity.setName(company.getName());
+        entity.setRealmId(getRealm().getId());
+        getEntityManager().persist(entity);
+
+        company.setId(id);
+        return company;
+    }
+
+    public void close() {
+        // Nothing to do.
+    }
+
+}
diff --git a/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/spi/impl/ExampleServiceProviderFactoryImpl.java b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/spi/impl/ExampleServiceProviderFactoryImpl.java
new file mode 100644
index 0000000..e4e2ddf
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/java/org/keycloak/examples/domainextension/spi/impl/ExampleServiceProviderFactoryImpl.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.examples.domainextension.spi.impl;
+
+import org.keycloak.Config.Scope;
+import org.keycloak.examples.domainextension.spi.ExampleService;
+import org.keycloak.examples.domainextension.spi.ExampleServiceProviderFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+public class ExampleServiceProviderFactoryImpl implements ExampleServiceProviderFactory {
+
+    @Override
+    public ExampleService create(KeycloakSession session) {
+        return new ExampleServiceImpl(session);
+    }
+
+    @Override
+    public void init(Scope config) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "exampleServiceImpl";
+    }
+
+}
diff --git a/examples/providers/domain-extension/src/main/resources/META-INF/example-changelog.xml b/examples/providers/domain-extension/src/main/resources/META-INF/example-changelog.xml
new file mode 100644
index 0000000..5edd719
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/resources/META-INF/example-changelog.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
+    <changeSet author="erik.mulder@docdatapayments.com" id="example-1.0">
+
+        <createTable tableName="EXAMPLE_COMPANY">
+            <column name="ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="NAME" type="VARCHAR(255)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="REALM_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+        </createTable>
+
+        <addPrimaryKey
+            constraintName="PK_COMPANY"
+            tableName="EXAMPLE_COMPANY"
+            columnNames="ID"
+        />
+
+    </changeSet>
+    
+</databaseChangeLog>
diff --git a/examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.examples.domainextension.spi.ExampleServiceProviderFactory b/examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.examples.domainextension.spi.ExampleServiceProviderFactory
new file mode 100644
index 0000000..57f9f89
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.examples.domainextension.spi.ExampleServiceProviderFactory
@@ -0,0 +1,18 @@
+#
+# Copyright 2016 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.keycloak.examples.domainextension.spi.impl.ExampleServiceProviderFactoryImpl
diff --git a/examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.provider.Spi
new file mode 100644
index 0000000..e013bbd
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -0,0 +1,18 @@
+#
+# Copyright 2016 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.keycloak.examples.domainextension.spi.ExampleSpi
diff --git a/examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory b/examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory
new file mode 100644
index 0000000..ea81617
--- /dev/null
+++ b/examples/providers/domain-extension/src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory
@@ -0,0 +1,18 @@
+#
+# Copyright 2016 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.keycloak.examples.domainextension.rest.ExampleRealmResourceProviderFactory
\ No newline at end of file
diff --git a/examples/providers/event-listener-sysout/pom.xml b/examples/providers/event-listener-sysout/pom.xml
index 81a5e50..00a47ad 100755
--- a/examples/providers/event-listener-sysout/pom.xml
+++ b/examples/providers/event-listener-sysout/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-examples-providers-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Event Listener System.out Example</name>
diff --git a/examples/providers/event-store-mem/pom.xml b/examples/providers/event-store-mem/pom.xml
index 189438e..ece01c3 100755
--- a/examples/providers/event-store-mem/pom.xml
+++ b/examples/providers/event-store-mem/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-examples-providers-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Event Store In-Mem Example</name>
diff --git a/examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemAdminEventQuery.java b/examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemAdminEventQuery.java
index bffc462..168c709 100755
--- a/examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemAdminEventQuery.java
+++ b/examples/providers/event-store-mem/src/main/java/org/keycloak/examples/providers/events/MemAdminEventQuery.java
@@ -26,6 +26,7 @@ import java.util.regex.Pattern;
 import org.keycloak.events.admin.AdminEvent;
 import org.keycloak.events.admin.AdminEventQuery;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 
 /**
  * @author <a href="mailto:giriraj.sharma27@gmail.com">Giriraj Sharma</a>
@@ -71,6 +72,27 @@ public class MemAdminEventQuery implements AdminEventQuery {
         }
         return this;
     }
+
+    @Override
+    public AdminEventQuery resourceType(ResourceType... resourceTypes) {
+
+        Iterator<AdminEvent> itr = this.adminEvents.iterator();
+        while (itr.hasNext()) {
+            AdminEvent next = itr.next();
+            boolean include = false;
+            for (ResourceType e : resourceTypes) {
+                if (next.getResourceType().equals(e)) {
+                    include = true;
+                    break;
+                }
+            }
+            if (!include) {
+                itr.remove();
+            }
+        }
+
+        return this;
+    }
     
     @Override
     public AdminEventQuery authRealm(String authRealmId) {
diff --git a/examples/providers/federation-provider/pom.xml b/examples/providers/federation-provider/pom.xml
index 78f7986..3429947 100755
--- a/examples/providers/federation-provider/pom.xml
+++ b/examples/providers/federation-provider/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-examples-providers-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Properties Authentication Provider Example</name>
diff --git a/examples/providers/pom.xml b/examples/providers/pom.xml
index 9557807..a8d3637 100755
--- a/examples/providers/pom.xml
+++ b/examples/providers/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-examples-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Provider Examples</name>
@@ -36,5 +36,7 @@
         <module>federation-provider</module>
         <module>authenticator</module>
         <module>rest</module>
+        <module>domain-extension</module>
+        <module>user-storage-jpa</module>
     </modules>
 </project>
diff --git a/examples/providers/rest/pom.xml b/examples/providers/rest/pom.xml
index 8666e37..9cc2b4c 100755
--- a/examples/providers/rest/pom.xml
+++ b/examples/providers/rest/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-examples-providers-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Authenticator Example</name>
diff --git a/examples/providers/user-storage-jpa/pom.xml b/examples/providers/user-storage-jpa/pom.xml
new file mode 100755
index 0000000..a0c7b2a
--- /dev/null
+++ b/examples/providers/user-storage-jpa/pom.xml
@@ -0,0 +1,87 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <parent>
+        <artifactId>keycloak-examples-providers-parent</artifactId>
+        <groupId>org.keycloak</groupId>
+        <version>2.2.0-SNAPSHOT</version>
+    </parent>
+
+    <name>User Storage JPA Provider Exapmle</name>
+    <description/>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>user-storage-jpa-example</artifactId>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.logging</groupId>
+            <artifactId>jboss-logging</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.hibernate.javax.persistence</groupId>
+            <artifactId>hibernate-jpa-2.1-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.hibernate</groupId>
+            <artifactId>hibernate-entitymanager</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.spec.javax.ejb</groupId>
+            <artifactId>jboss-ejb-api_3.2_spec</artifactId>
+            <version>1.0.0.Final</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>user-storage-jpa-example</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.8</source>
+                    <target>1.8</target>
+                </configuration>
+            </plugin>
+             <plugin>
+                <groupId>org.wildfly.plugins</groupId>
+                <artifactId>wildfly-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/examples/providers/user-storage-jpa/README.md b/examples/providers/user-storage-jpa/README.md
new file mode 100755
index 0000000..f965ef2
--- /dev/null
+++ b/examples/providers/user-storage-jpa/README.md
@@ -0,0 +1,13 @@
+Example User Storage Provider with EJB and JPA
+===================================================
+
+This is an example of the User Storage SPI implemented using EJB and JPA.  To deploy this provider you must have Keycloak
+running in standalone or standalone-ha mode.  Then type the follow maven command:
+
+    mvn clean install wildfly:deploy
+
+Login and go to the User Federation tab and you should now see your deployed provider in the add-provider list box.
+Add the provider, save it, then any new user you create will be stored and in the custom store you implemented.  You
+can modify the example and hot deploy it using the above maven command again.
+
+This example uses the built in in-memory datasource that comes with keycloak: ExampleDS.
diff --git a/examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/EjbExampleUserStorageProvider.java b/examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/EjbExampleUserStorageProvider.java
new file mode 100644
index 0000000..a9bbc9b
--- /dev/null
+++ b/examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/EjbExampleUserStorageProvider.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.examples.storage.user;
+
+import org.jboss.logging.Logger;
+import org.keycloak.component.ComponentModel;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.storage.StorageId;
+import org.keycloak.storage.UserStorageProvider;
+import org.keycloak.storage.user.UserCredentialValidatorProvider;
+import org.keycloak.storage.user.UserLookupProvider;
+import org.keycloak.storage.user.UserQueryProvider;
+import org.keycloak.storage.user.UserRegistrationProvider;
+
+import javax.ejb.Local;
+import javax.ejb.Remove;
+import javax.ejb.Stateful;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.TypedQuery;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@Stateful
+@Local(EjbExampleUserStorageProvider.class)
+public class EjbExampleUserStorageProvider implements UserStorageProvider,
+        UserLookupProvider,
+        UserRegistrationProvider,
+        UserCredentialValidatorProvider,
+        UserQueryProvider {
+    private static final Logger logger = Logger.getLogger(EjbExampleUserStorageProvider.class);
+
+    @PersistenceContext
+    protected EntityManager em;
+
+    protected ComponentModel model;
+    protected KeycloakSession session;
+
+    public void setModel(ComponentModel model) {
+        this.model = model;
+    }
+
+    public void setSession(KeycloakSession session) {
+        this.session = session;
+    }
+
+    @Override
+    public void preRemove(RealmModel realm) {
+
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, GroupModel group) {
+
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, RoleModel role) {
+
+    }
+
+    @Remove
+    @Override
+    public void close() {
+    }
+
+    @Override
+    public UserModel getUserById(String id, RealmModel realm) {
+        logger.info("getUserById: " + id);
+        String persistenceId = StorageId.externalId(id);
+        UserEntity entity = em.find(UserEntity.class, persistenceId);
+        if (entity == null) {
+            logger.info("could not find user by id: " + id);
+            return null;
+        }
+        return new UserAdapter(session, realm, model, entity);
+    }
+
+    @Override
+    public UserModel getUserByUsername(String username, RealmModel realm) {
+        logger.info("getUserByUsername: " + username);
+        TypedQuery<UserEntity> query = em.createNamedQuery("getUserByUsername", UserEntity.class);
+        query.setParameter("username", username);
+        List<UserEntity> result = query.getResultList();
+        if (result.isEmpty()) {
+            logger.info("could not find username: " + username);
+            return null;
+        }
+
+        return new UserAdapter(session, realm, model, result.get(0));
+    }
+
+    @Override
+    public UserModel getUserByEmail(String email, RealmModel realm) {
+        TypedQuery<UserEntity> query = em.createNamedQuery("getUserByEmail", UserEntity.class);
+        query.setParameter("email", email);
+        List<UserEntity> result = query.getResultList();
+        if (result.isEmpty()) return null;
+        return new UserAdapter(session, realm, model, result.get(0));
+    }
+
+    @Override
+    public UserModel addUser(RealmModel realm, String username) {
+        UserEntity entity = new UserEntity();
+        entity.setId(KeycloakModelUtils.generateId());
+        entity.setUsername(username);
+        em.persist(entity);
+        logger.info("added user: " + username);
+        return new UserAdapter(session, realm, model, entity);
+    }
+
+    @Override
+    public boolean removeUser(RealmModel realm, UserModel user) {
+        String persistenceId = StorageId.externalId(user.getId());
+        UserEntity entity = em.find(UserEntity.class, persistenceId);
+        if (entity == null) return false;
+        em.remove(entity);
+        return true;
+    }
+
+    @Override
+    public void grantToAllUsers(RealmModel realm, RoleModel role) {
+
+    }
+
+    @Override
+    public boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, List<UserCredentialModel> input) {
+        // having a "password" attribute is a workaround so that passwords can be cached.  All done for performance reasons...
+        // If we override getCredentialsDirectly/updateCredentialsDirectly
+        // then the realm passsword policy will/may try and overwrite the plain text password with a hash.
+        // If you don't like this workaround, you can query the database every time to validate the password
+        for (UserCredentialModel cred : input) {
+            if (!UserCredentialModel.PASSWORD.equals(cred.getType())) return false;
+            if (!cred.getValue().equals(user.getFirstAttribute("password"))) return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int getUsersCount(RealmModel realm) {
+        Object count = em.createNamedQuery("getUserCount")
+                .getSingleResult();
+        return ((Number)count).intValue();
+    }
+
+    @Override
+    public List<UserModel> getUsers(RealmModel realm) {
+        return getUsers(realm, -1, -1);
+    }
+
+    @Override
+    public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) {
+
+        TypedQuery<UserEntity> query = em.createNamedQuery("getAllUsers", UserEntity.class);
+        if (firstResult != -1) {
+            query.setFirstResult(firstResult);
+        }
+        if (maxResults != -1) {
+            query.setMaxResults(maxResults);
+        }
+        List<UserEntity> results = query.getResultList();
+        List<UserModel> users = new LinkedList<>();
+        for (UserEntity entity : results) users.add(new UserAdapter(session, realm, model, entity));
+        return users;
+    }
+
+    @Override
+    public List<UserModel> searchForUser(String search, RealmModel realm) {
+        return searchForUser(search, realm, -1, -1);
+    }
+
+    @Override
+    public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) {
+        TypedQuery<UserEntity> query = em.createNamedQuery("searchForUser", UserEntity.class);
+        query.setParameter("search", "%" + search.toLowerCase() + "%");
+        if (firstResult != -1) {
+            query.setFirstResult(firstResult);
+        }
+        if (maxResults != -1) {
+            query.setMaxResults(maxResults);
+        }
+        List<UserEntity> results = query.getResultList();
+        List<UserModel> users = new LinkedList<>();
+        for (UserEntity entity : results) users.add(new UserAdapter(session, realm, model, entity));
+        return users;
+    }
+
+    @Override
+    public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm) {
+        return Collections.EMPTY_LIST;
+    }
+
+    @Override
+    public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm, int firstResult, int maxResults) {
+        return Collections.EMPTY_LIST;
+    }
+
+    @Override
+    public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
+        return Collections.EMPTY_LIST;
+    }
+
+    @Override
+    public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) {
+        return Collections.EMPTY_LIST;
+    }
+
+    @Override
+    public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) {
+        return Collections.EMPTY_LIST;
+    }
+}
diff --git a/examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/EjbExampleUserStorageProviderFactory.java b/examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/EjbExampleUserStorageProviderFactory.java
new file mode 100644
index 0000000..a1db65d
--- /dev/null
+++ b/examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/EjbExampleUserStorageProviderFactory.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.examples.storage.user;
+
+import org.keycloak.Config;
+import org.keycloak.component.ComponentModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.provider.ProviderConfigProperty;
+import org.keycloak.storage.UserStorageProviderFactory;
+
+import javax.naming.InitialContext;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class EjbExampleUserStorageProviderFactory implements UserStorageProviderFactory<EjbExampleUserStorageProvider> {
+
+
+    @Override
+    public EjbExampleUserStorageProvider create(KeycloakSession session, ComponentModel model) {
+        try {
+            InitialContext ctx = new InitialContext();
+            EjbExampleUserStorageProvider provider = (EjbExampleUserStorageProvider)ctx.lookup("java:global/user-storage-jpa-example/" + EjbExampleUserStorageProvider.class.getSimpleName());
+            provider.setModel(model);
+            provider.setSession(session);
+            return provider;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public String getId() {
+        return "example-user-storage-jpa";
+    }
+
+    @Override
+    public String getHelpText() {
+        return "JPA Example User Storage Provider";
+    }
+}
diff --git a/examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/UserAdapter.java b/examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/UserAdapter.java
new file mode 100644
index 0000000..6276f7f
--- /dev/null
+++ b/examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/UserAdapter.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.examples.storage.user;
+
+import org.jboss.logging.Logger;
+import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.component.ComponentModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.storage.StorageId;
+import org.keycloak.storage.adapter.AbstractUserAdapterFederatedStorage;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class UserAdapter extends AbstractUserAdapterFederatedStorage {
+    private static final Logger logger = Logger.getLogger(EjbExampleUserStorageProvider.class);
+    protected UserEntity entity;
+    protected String keycloakId;
+
+    public UserAdapter(KeycloakSession session, RealmModel realm, ComponentModel model, UserEntity entity) {
+        super(session, realm, model);
+        this.entity = entity;
+        keycloakId = StorageId.keycloakId(model, entity.getId());
+    }
+
+    @Override
+    public String getUsername() {
+        return entity.getUsername();
+    }
+
+    @Override
+    public void setUsername(String username) {
+        entity.setUsername(username);
+
+    }
+
+    @Override
+    public void setEmail(String email) {
+        entity.setEmail(email);
+    }
+
+    @Override
+    public String getEmail() {
+        return entity.getEmail();
+    }
+
+    @Override
+    public String getId() {
+        return keycloakId;
+    }
+
+    @Override
+    public void updateCredential(UserCredentialModel cred) {
+        if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
+            entity.setPassword(cred.getValue());
+        } else {
+            super.updateCredential(cred);
+        }
+    }
+
+    @Override
+    public void setSingleAttribute(String name, String value) {
+        if (name.equals("phone")) {
+            entity.setPhone(value);
+        } else if (name.equals("password")) {
+            // ignore
+
+            // having a "password" attribute is a workaround so that passwords can be cached.  All done for performance reasons...
+            // If we override getCredentialsDirectly/updateCredentialsDirectly
+            // then the realm passsword policy will/may try and overwrite the plain text password with a hash.
+            // If you don't like this workaround, you can query the database every time to validate the password
+        } else {
+            super.setSingleAttribute(name, value);
+        }
+    }
+
+    @Override
+    public void removeAttribute(String name) {
+        if (name.equals("phone")) {
+            entity.setPhone(null);
+        } else if (name.equals("password")) {
+            // ignore
+
+            // having a "password" attribute is a workaround so that passwords can be cached.  All done for performance reasons...
+            // If we override getCredentialsDirectly/updateCredentialsDirectly
+            // then the realm passsword policy will/may try and overwrite the plain text password with a hash.
+            // If you don't like this workaround, you can query the database every time to validate the password
+        } else {
+            super.removeAttribute(name);
+        }
+    }
+
+    @Override
+    public void setAttribute(String name, List<String> values) {
+        if (name.equals("phone")) {
+            entity.setPhone(values.get(0));
+        } else if (name.equals("password")) {
+            // ignore
+
+            // having a "password" attribute is a workaround so that passwords can be cached.  All done for performance reasons...
+            // If we override getCredentialsDirectly/updateCredentialsDirectly
+            // then the realm passsword policy will/may try and overwrite the plain text password with a hash.
+            // If you don't like this workaround, you can query the database every time to validate the password
+        } else {
+            super.setAttribute(name, values);
+        }
+    }
+
+    @Override
+    public String getFirstAttribute(String name) {
+        if (name.equals("phone")) {
+            return entity.getPhone();
+        } else if (name.equals("password")) {
+            // having a "password" attribute is a workaround so that passwords can be cached.  All done for performance reasons...
+            // If we override getCredentialsDirectly/updateCredentialsDirectly
+            // then the realm passsword policy will/may try and overwrite the plain text password with a hash.
+            // If you don't like this workaround, you can query the database every time to validate the password
+            return entity.getPassword();
+        } else {
+            return super.getFirstAttribute(name);
+        }
+    }
+
+    @Override
+    public Map<String, List<String>> getAttributes() {
+        Map<String, List<String>> attrs = super.getAttributes();
+        MultivaluedHashMap<String, String> all = new MultivaluedHashMap<>();
+        all.putAll(attrs);
+        all.add("phone", entity.getPhone());
+
+        // having a "password" attribute is a workaround so that passwords can be cached.  All done for performance reasons...
+        // If we override getCredentialsDirectly/updateCredentialsDirectly
+        // then the realm passsword policy will/may try and overwrite the plain text password with a hash.
+        // If you don't like this workaround, you can query the database every time to validate the password
+        all.add("password", entity.getPassword());
+        return all;
+    }
+
+    @Override
+    public List<String> getAttribute(String name) {
+        if (name.equals("phone")) {
+            List<String> phone = new LinkedList<>();
+            phone.add(entity.getPhone());
+            return phone;
+        } else {
+            return super.getAttribute(name);
+        }
+    }
+}
diff --git a/examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/UserEntity.java b/examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/UserEntity.java
new file mode 100644
index 0000000..299e900
--- /dev/null
+++ b/examples/providers/user-storage-jpa/src/main/java/org/keycloak/examples/storage/user/UserEntity.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.examples.storage.user;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@NamedQueries({
+        @NamedQuery(name="getUserByUsername", query="select u from UserEntity u where u.username = :username"),
+        @NamedQuery(name="getUserByEmail", query="select u from UserEntity u where u.email = :email"),
+        @NamedQuery(name="getUserCount", query="select count(u) from UserEntity u"),
+        @NamedQuery(name="getAllUsers", query="select u from UserEntity u"),
+        @NamedQuery(name="searchForUser", query="select u from UserEntity u where " +
+                "( lower(u.username) like :search or u.email like :search ) order by u.username"),
+})
+@Entity
+public class UserEntity {
+    @Id
+    private String id;
+
+
+    private String username;
+    private String email;
+    private String password;
+    private String phone;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getPhone() {
+        return phone;
+    }
+
+    public void setPhone(String phone) {
+        this.phone = phone;
+    }
+}
diff --git a/examples/providers/user-storage-jpa/src/main/resources/META-INF/persistence.xml b/examples/providers/user-storage-jpa/src/main/resources/META-INF/persistence.xml
new file mode 100644
index 0000000..9894af4
--- /dev/null
+++ b/examples/providers/user-storage-jpa/src/main/resources/META-INF/persistence.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<persistence version="2.0"
+             xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+             xsi:schemaLocation="
+        http://java.sun.com/xml/ns/persistence
+        http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
+    <persistence-unit name="user-storage-jpa-example">
+        <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
+
+        <class>org.keycloak.examples.storage.user.UserEntity</class>
+
+        <properties>
+            <property name="hibernate.hbm2ddl.auto" value="update" />
+            <property name="hibernate.show_sql" value="false" />
+        </properties>
+    </persistence-unit>
+</persistence>
diff --git a/examples/providers/user-storage-jpa/src/main/resources/META-INF/services/org.keycloak.storage.UserStorageProviderFactory b/examples/providers/user-storage-jpa/src/main/resources/META-INF/services/org.keycloak.storage.UserStorageProviderFactory
new file mode 100644
index 0000000..8f92432
--- /dev/null
+++ b/examples/providers/user-storage-jpa/src/main/resources/META-INF/services/org.keycloak.storage.UserStorageProviderFactory
@@ -0,0 +1 @@
+org.keycloak.examples.storage.user.EjbExampleUserStorageProviderFactory
\ No newline at end of file
diff --git a/examples/saml/pom.xml b/examples/saml/pom.xml
index 88b9ada..ccec399 100755
--- a/examples/saml/pom.xml
+++ b/examples/saml/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-examples-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Provider Examples</name>
diff --git a/examples/saml/post-with-encryption/pom.xml b/examples/saml/post-with-encryption/pom.xml
index 73e5191..588a731 100755
--- a/examples/saml/post-with-encryption/pom.xml
+++ b/examples/saml/post-with-encryption/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <artifactId>keycloak-examples-saml-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>saml-post-encryption</artifactId>
diff --git a/examples/saml/post-with-signature/pom.xml b/examples/saml/post-with-signature/pom.xml
index a1bd611..bbc4b87 100755
--- a/examples/saml/post-with-signature/pom.xml
+++ b/examples/saml/post-with-signature/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <artifactId>keycloak-examples-saml-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>sales-post-sig</artifactId>
diff --git a/examples/saml/redirect-with-signature/pom.xml b/examples/saml/redirect-with-signature/pom.xml
index cf3be5a..b8a62a7 100755
--- a/examples/saml/redirect-with-signature/pom.xml
+++ b/examples/saml/redirect-with-signature/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <artifactId>keycloak-examples-saml-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>saml-redirect-signatures</artifactId>
diff --git a/examples/saml/servlet-filter/pom.xml b/examples/saml/servlet-filter/pom.xml
index bf05a91..1a2b67a 100755
--- a/examples/saml/servlet-filter/pom.xml
+++ b/examples/saml/servlet-filter/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <artifactId>keycloak-examples-saml-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>saml-servlet-filter</artifactId>
diff --git a/examples/themes/pom.xml b/examples/themes/pom.xml
index b0ebc4d..317b50f 100755
--- a/examples/themes/pom.xml
+++ b/examples/themes/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-examples-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Themes Examples</name>
diff --git a/federation/kerberos/pom.xml b/federation/kerberos/pom.xml
index cdb65d2..e56bcc7 100755
--- a/federation/kerberos/pom.xml
+++ b/federation/kerberos/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/federation/ldap/pom.xml b/federation/ldap/pom.xml
index 7fe4b65..f6a8c4b 100755
--- a/federation/ldap/pom.xml
+++ b/federation/ldap/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/TxAwareLDAPUserModelDelegate.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/TxAwareLDAPUserModelDelegate.java
index 622ebb6..9126a66 100644
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/TxAwareLDAPUserModelDelegate.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/TxAwareLDAPUserModelDelegate.java
@@ -70,7 +70,7 @@ public abstract class TxAwareLDAPUserModelDelegate extends UserModelDelegate {
                 logger.trace("Starting and enlisting transaction for object " + ldapUser.getDn().toString());
             }
 
-            this.provider.getSession().getTransaction().enlistAfterCompletion(transaction);
+            this.provider.getSession().getTransactionManager().enlistAfterCompletion(transaction);
         }
     }
 
diff --git a/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/UserAttributeLDAPFederationMapper.java b/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/UserAttributeLDAPFederationMapper.java
index af910a7..b577326 100644
--- a/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/UserAttributeLDAPFederationMapper.java
+++ b/federation/ldap/src/main/java/org/keycloak/federation/ldap/mappers/UserAttributeLDAPFederationMapper.java
@@ -163,7 +163,7 @@ public class UserAttributeLDAPFederationMapper extends AbstractLDAPFederationMap
 
             UserModel that = session.userStorage().getUserByEmail(email, realm);
             if (that != null && !that.getId().equals(user.getId())) {
-                session.getTransaction().setRollbackOnly();
+                session.getTransactionManager().setRollbackOnly();
                 String exceptionMessage = String.format("Can't import user '%s' from LDAP because email '%s' already exists in Keycloak. Existing user with this email is '%s'", user.getUsername(), email, that.getUsername());
                 throw new ModelDuplicateException(exceptionMessage, UserModel.EMAIL);
             }
diff --git a/federation/pom.xml b/federation/pom.xml
index 14d3532..663f857 100755
--- a/federation/pom.xml
+++ b/federation/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/integration/admin-client/pom.xml b/integration/admin-client/pom.xml
index 3a36063..753fcfe 100755
--- a/integration/admin-client/pom.xml
+++ b/integration/admin-client/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <artifactId>keycloak-integration-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/AttackDetectionResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/AttackDetectionResource.java
index 7888cad..ea77759 100644
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/AttackDetectionResource.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/AttackDetectionResource.java
@@ -33,16 +33,16 @@ import java.util.Map;
 public interface AttackDetectionResource {
 
     @GET
-    @Path("brute-force/usernames/{username}")
+    @Path("brute-force/users/{userId}")
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
-    Map<String, Object> bruteForceUserStatus(@PathParam("username") String username);
+    Map<String, Object> bruteForceUserStatus(@PathParam("userId") String userId);
 
-    @Path("brute-force/usernames/{username}")
+    @Path("brute-force/users/{userId}")
     @DELETE
-    void clearBruteForceForUser(@PathParam("username") String username);
+    void clearBruteForceForUser(@PathParam("userId") String userId);
 
-    @Path("brute-force/usernames")
+    @Path("brute-force/users")
     @DELETE
     void clearAllBruteForce();
 
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/AuthorizationResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/AuthorizationResource.java
new file mode 100644
index 0000000..07276ec
--- /dev/null
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/AuthorizationResource.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.admin.client.resource;
+
+import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface AuthorizationResource {
+
+    @PUT
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    void update(ResourceServerRepresentation server);
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    ResourceServerRepresentation getSettings();
+
+    @Path("/import")
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    void importSettings(ResourceServerRepresentation server);
+
+    @Path("/settings")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    ResourceServerRepresentation exportSettings();
+
+    @Path("/resource")
+    ResourcesResource resources();
+
+    @Path("/scope")
+    ResourceScopesResource scopes();
+
+    @Path("/policy")
+    PoliciesResource policies();
+}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientRegistrationTrustedHostResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientRegistrationTrustedHostResource.java
new file mode 100644
index 0000000..4f5ace9
--- /dev/null
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientRegistrationTrustedHostResource.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.admin.client.resource;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.keycloak.representations.idm.ClientRegistrationTrustedHostRepresentation;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public interface ClientRegistrationTrustedHostResource {
+
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    Response create(ClientRegistrationTrustedHostRepresentation config);
+
+    @PUT
+    @Path("{hostname}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    Response update(final @PathParam("hostname") String hostName, ClientRegistrationTrustedHostRepresentation config);
+
+    @GET
+    @Path("{hostname}")
+    @Produces(MediaType.APPLICATION_JSON)
+    ClientRegistrationTrustedHostRepresentation get(final @PathParam("hostname") String hostName);
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    List<ClientRegistrationTrustedHostRepresentation> list();
+
+    @DELETE
+    @Path("{hostname}")
+    void delete(final @PathParam("hostname") String hostName);
+
+}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientResource.java
index ca1745d..fb9640b 100755
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientResource.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ClientResource.java
@@ -142,4 +142,6 @@ public interface ClientResource {
     @Produces(MediaType.APPLICATION_JSON)
     GlobalRequestResult testNodesAvailable();
 
+    @Path("/authz/resource-server")
+    AuthorizationResource authorization();
 }
\ No newline at end of file
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ComponentResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ComponentResource.java
new file mode 100644
index 0000000..2839f86
--- /dev/null
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ComponentResource.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.admin.client.resource;
+
+import org.jboss.resteasy.spi.NotFoundException;
+import org.keycloak.representations.idm.ComponentRepresentation;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.core.MediaType;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface ComponentResource {
+    @GET
+    public ComponentRepresentation toRepresentation();
+
+    @PUT
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void update(ComponentRepresentation rep);
+
+    @DELETE
+    public void remove();
+}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ComponentsResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ComponentsResource.java
new file mode 100644
index 0000000..d59c983
--- /dev/null
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ComponentsResource.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.admin.client.resource;
+
+import org.keycloak.representations.idm.ComponentRepresentation;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface ComponentsResource {
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public List<ComponentRepresentation> query();
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public List<ComponentRepresentation> query(@QueryParam("parent") String parent);
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public List<ComponentRepresentation> query(@QueryParam("parent") String parent, @QueryParam("type") String type);
+
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    Response add(ComponentRepresentation rep);
+
+    @Path("{id}")
+    ComponentResource component(@PathParam("id") String id);
+
+
+}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/GroupsResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/GroupsResource.java
index 5bf0c4b..7807094 100755
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/GroupsResource.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/GroupsResource.java
@@ -38,7 +38,7 @@ public interface GroupsResource {
     @GET
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
-    public List<GroupRepresentation> groups();
+    List<GroupRepresentation> groups();
 
     /**
      * create or add a top level realm groupSet or create child.  This will update the group and set the parent if it exists.  Create it and set the parent
@@ -48,9 +48,9 @@ public interface GroupsResource {
      */
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
-    public Response add(GroupRepresentation rep);
+    Response add(GroupRepresentation rep);
 
     @Path("{id}")
-    public GroupResource group(@PathParam("id") String id);
+    GroupResource group(@PathParam("id") String id);
 
 }
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PoliciesResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PoliciesResource.java
new file mode 100644
index 0000000..fd5d43a
--- /dev/null
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PoliciesResource.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.admin.client.resource;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.representations.idm.authorization.PolicyProviderRepresentation;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface PoliciesResource {
+
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    Response create(PolicyRepresentation representation);
+
+    @Path("{id}")
+    PolicyResource policy(@PathParam("id") String id);
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @NoCache
+    List<PolicyRepresentation> policies();
+
+    @Path("providers")
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @NoCache
+    List<PolicyProviderRepresentation> policyProviders();
+}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PolicyResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PolicyResource.java
new file mode 100644
index 0000000..9a45045
--- /dev/null
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/PolicyResource.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.admin.client.resource;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface PolicyResource {
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @NoCache
+    PolicyRepresentation toRepresentation();
+
+    @PUT
+    @Consumes(MediaType.APPLICATION_JSON)
+    void update(PolicyRepresentation representation);
+
+    @DELETE
+    void remove();
+}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RealmResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RealmResource.java
index b6db357..ba91227 100644
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RealmResource.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/RealmResource.java
@@ -148,6 +148,9 @@ public interface RealmResource {
     @Path("clients-initial-access")
     ClientInitialAccessResource clientInitialAccess();
 
+    @Path("clients-trusted-hosts")
+    public ClientRegistrationTrustedHostResource clientRegistrationTrustedHost();
+
     @Path("partialImport")
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
@@ -193,4 +196,7 @@ public interface RealmResource {
     @DELETE
     void deleteSession(@PathParam("session") String sessionId);
 
+    @Path("components")
+    ComponentsResource components();
+
 }
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourceResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourceResource.java
new file mode 100644
index 0000000..834cb06
--- /dev/null
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourceResource.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.admin.client.resource;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface ResourceResource {
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @NoCache
+    ResourceRepresentation toRepresentation();
+
+    @PUT
+    @Consumes(MediaType.APPLICATION_JSON)
+    void update(ResourceRepresentation resource);
+
+    @DELETE
+    void remove();
+}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourceScopeResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourceScopeResource.java
new file mode 100644
index 0000000..4a0ad8e
--- /dev/null
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourceScopeResource.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.admin.client.resource;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface ResourceScopeResource {
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @NoCache
+    ScopeRepresentation toRepresentation();
+
+    @PUT
+    @Consumes(MediaType.APPLICATION_JSON)
+    void update(ScopeRepresentation scope);
+
+    @DELETE
+    void remove();
+}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourceScopesResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourceScopesResource.java
new file mode 100644
index 0000000..88f5c74
--- /dev/null
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourceScopesResource.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.admin.client.resource;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface ResourceScopesResource {
+
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    Response create(ScopeRepresentation scope);
+
+    @Path("{id}")
+    ResourceScopeResource scope(@PathParam("id") String id);
+
+    @GET
+    @NoCache
+    @Produces(MediaType.APPLICATION_JSON)
+    List<ScopeRepresentation> scopes();
+}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourcesResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourcesResource.java
new file mode 100644
index 0000000..1aaaa23
--- /dev/null
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/ResourcesResource.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.admin.client.resource;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface ResourcesResource {
+
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    Response create(ResourceRepresentation resource);
+
+    @Path("{id}")
+    ResourceResource resource(@PathParam("id") String id);
+
+    @GET
+    @NoCache
+    @Produces(MediaType.APPLICATION_JSON)
+    List<ResourceRepresentation> resources();
+}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UserResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UserResource.java
index 2df2cbf..eebefe7 100755
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UserResource.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UserResource.java
@@ -146,4 +146,8 @@ public interface UserResource {
     @Path("consents/{client}")
     public void revokeConsent(@PathParam("client") String clientId);
 
+    @POST
+    @Path("impersonation")
+    @Produces(MediaType.APPLICATION_JSON)
+    Map<String, Object> impersonate();
 }
diff --git a/integration/client-registration/pom.xml b/integration/client-registration/pom.xml
index 5baf102..c19c1de 100755
--- a/integration/client-registration/pom.xml
+++ b/integration/client-registration/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-integration-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/integration/client-registration/src/main/java/org/keycloak/client/registration/HttpErrorException.java b/integration/client-registration/src/main/java/org/keycloak/client/registration/HttpErrorException.java
index 4078b73..640bc0d 100644
--- a/integration/client-registration/src/main/java/org/keycloak/client/registration/HttpErrorException.java
+++ b/integration/client-registration/src/main/java/org/keycloak/client/registration/HttpErrorException.java
@@ -18,6 +18,8 @@
 package org.keycloak.client.registration;
 
 import org.apache.http.StatusLine;
+import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
+import org.keycloak.util.JsonSerialization;
 
 import java.io.IOException;
 
@@ -26,14 +28,31 @@ import java.io.IOException;
  */
 public class HttpErrorException extends IOException {
 
-    private StatusLine statusLine;
+    private final StatusLine statusLine;
+    private final String errorResponse;
 
-    public HttpErrorException(StatusLine statusLine) {
+    public HttpErrorException(StatusLine statusLine, String errorResponse) {
         this.statusLine = statusLine;
+        this.errorResponse = errorResponse;
     }
 
     public StatusLine getStatusLine() {
         return statusLine;
     }
 
+    public String getErrorResponse() {
+        return errorResponse;
+    }
+
+    public OAuth2ErrorRepresentation toErrorRepresentation() {
+        if (errorResponse == null) {
+            return null;
+        }
+
+        try {
+            return JsonSerialization.readValue(errorResponse, OAuth2ErrorRepresentation.class);
+        } catch (IOException ioe) {
+            throw new RuntimeException("Not OAuth2 error");
+        }
+    }
 }
diff --git a/integration/client-registration/src/main/java/org/keycloak/client/registration/HttpUtil.java b/integration/client-registration/src/main/java/org/keycloak/client/registration/HttpUtil.java
index 8d524ce..66808ed 100644
--- a/integration/client-registration/src/main/java/org/keycloak/client/registration/HttpUtil.java
+++ b/integration/client-registration/src/main/java/org/keycloak/client/registration/HttpUtil.java
@@ -23,9 +23,7 @@ import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.*;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.impl.client.CloseableHttpClient;
-import org.keycloak.client.registration.Auth;
-import org.keycloak.client.registration.ClientRegistrationException;
-import org.keycloak.client.registration.HttpErrorException;
+import org.keycloak.common.util.StreamUtil;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -69,8 +67,7 @@ class HttpUtil {
             if (response.getStatusLine().getStatusCode() == 201) {
                 return responseStream;
             } else {
-                responseStream.close();
-                throw new HttpErrorException(response.getStatusLine());
+                throw httpErrorException(response, responseStream);
             }
         } catch (IOException e) {
             throw new ClientRegistrationException("Failed to send request", e);
@@ -97,10 +94,7 @@ class HttpUtil {
                 responseStream.close();
                 return null;
             } else {
-                if (responseStream != null) {
-                    responseStream.close();
-                }
-                throw new HttpErrorException(response.getStatusLine());
+                throw httpErrorException(response, responseStream);
             }
         } catch (IOException e) {
             throw new ClientRegistrationException("Failed to send request", e);
@@ -118,9 +112,6 @@ class HttpUtil {
             addAuth(request);
 
             HttpResponse response = httpClient.execute(request);
-            if (response.getEntity() != null) {
-                response.getEntity().getContent();
-            }
 
             InputStream responseStream = null;
             if (response.getEntity() != null) {
@@ -130,10 +121,7 @@ class HttpUtil {
             if (response.getStatusLine().getStatusCode() == 200) {
                 return responseStream;
             } else {
-                if (responseStream != null) {
-                    responseStream.close();
-                }
-                throw new HttpErrorException(response.getStatusLine());
+                throw httpErrorException(response, responseStream);
             }
         } catch (IOException e) {
             throw new ClientRegistrationException("Failed to send request", e);
@@ -147,12 +135,13 @@ class HttpUtil {
             addAuth(request);
 
             HttpResponse response = httpClient.execute(request);
+            InputStream responseStream = null;
             if (response.getEntity() != null) {
-                response.getEntity().getContent().close();
+                responseStream = response.getEntity().getContent();
             }
 
             if (response.getStatusLine().getStatusCode() != 204) {
-                throw new HttpErrorException(response.getStatusLine());
+                throw httpErrorException(response, responseStream);
             }
         } catch (IOException e) {
             throw new ClientRegistrationException("Failed to send request", e);
@@ -185,4 +174,13 @@ class HttpUtil {
         }
     }
 
+    private HttpErrorException httpErrorException(HttpResponse response, InputStream responseStream) throws IOException {
+        if (responseStream != null) {
+            String errorResponse = StreamUtil.readString(responseStream);
+            return new HttpErrorException(response.getStatusLine(), errorResponse);
+        } else {
+            return new HttpErrorException(response.getStatusLine(), null);
+        }
+    }
+
 }
diff --git a/integration/pom.xml b/integration/pom.xml
index 2d1c939..270d6f1 100755
--- a/integration/pom.xml
+++ b/integration/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <name>Keycloak Integration</name>
diff --git a/misc/HackingOnKeycloak.md b/misc/HackingOnKeycloak.md
index dafadf3..590a301 100644
--- a/misc/HackingOnKeycloak.md
+++ b/misc/HackingOnKeycloak.md
@@ -61,9 +61,3 @@ Here's a quick check list for a good pull request (PR):
 * Do a rebase on upstream master
 
 Once you're happy with your changes go to GitHub and create a PR.
-
-
-Release Keycloak
-----------------
-
-* [Release Process](ReleaseProcess.md)
diff --git a/misc/OIDCConformanceTestsuite.md b/misc/OIDCConformanceTestsuite.md
new file mode 100644
index 0000000..72ec17b
--- /dev/null
+++ b/misc/OIDCConformanceTestsuite.md
@@ -0,0 +1,114 @@
+Executing OIDC Conformance Testsuite
+====================================
+
+Run Keycloak on Openshift
+-------------------------
+First step is to run Keycloak server in the environment, where it is available online, so the OIDC conformance testsuite can connect to it.
+
+1) Take a look at https://github.com/keycloak/openshift-keycloak-cartridge for how to run Keycloak on Openshift. Follow the instructions until you have 
+openshift instance with Keycloak 2.0.0.CR1 available on some URL like https://keycloak-mposolda.rhcloud.com/auth .
+ 
+2) Admin user needs to be manually created on command line on Openshift cartridge. Then cartridge needs to be restarted. See Keycloak docs for details.
+
+3) Login to Keycloak admin console. Create confidential client `openidd` with redirect_uri `https://op.certification.openid.net:60720/authz_cb` . 
+This points to the testing client deployed by OIDC conformance testsuite. You will need to change the port later based on where your OIDC conformance testing app will be running.  
+                                                                                                               
+4) Create some user with basic claims filled (email, first name, last name).
+
+Run conformance testsuite
+-------------------------
+
+Full instructions on http://openid.net/certification/testing/ . 
+
+So what I did was:
+
+1) Go to https://op.certification.openid.net:60000/
+
+
+2) Fill issuer `https://keycloak-mposolda.rhcloud.com/auth/realms/master`
+
+
+3) Configured the testing instance like this (second line are my answers):
+
+Q: Does the OP have a .well-known/openid-configuration endpoint?
+A: Yes
+
+Q: Do the provider support dynamic client registration?
+A: No (See below for how to run with dynamic client registration)
+
+Q: redirect_uris
+Non-editable value: https://op.certification.openid.net:60720/authz_cb
+Copy/paste that and use it as valid redirect_uri in Keycloak admin console for your Openshift client (See above paragraph `Run Keycloak on Openshift` )
+
+Q: client_id:
+A: openidd
+
+Q: client_secret:
+A: 98d90dd1-9d2e-43ad-a46b-1daeec3f5133 (copy/paste from your client in KC admin console)
+
+Q: Which subject type do you want to use by default?
+A: Public
+
+Q: Which response type should be used by default?
+A: Code (this is just for OIDC Basic profile)
+
+Q: Select supported features:
+A: JWT signed with algorithm other than "none"
+
+Q: Test specific request parameters:
+Nothing filled
+ 
+
+4) After setup, you will be redirected to the testing application. Something like `https://op.certification.openid.net:60720/` and can run individual tests.
+Some tests require some manual actions (eg. delete cookies). The conformance testsuite should guide you.
+
+Run conformance testsuite with Dynamic client registration
+----------------------------------------------------------
+1) The steps are similar to above, however for question:
+
+Q: Do the provider support dynamic client registration?
+The answer will be: Yes
+
+Then you don't need to configure redirect_uris, client_id and client_secret.
+
+2) With the setup from previous point, OIDC Conformance testsuite will dynamically register new client in Keycloak. But you also need to allow the anonymous
+ client registration requests from the OIDC conformance to register clients.
+ 
+ So you need to login to Keycloak admin console and in tab "Initial Access Tokens" for realm master, you need to fill new trusted host. Fill the hostname "op.certification.openid.net" and enable big 
+ count of registrations for it (1000 or so) as running each test will register new client. 
+
+
+Update the openshift cartridge with latest Keycloak
+---------------------------------------------------
+
+Once some issue is fixed on Keycloak side, you may want to doublecheck if test on OIDC conformance side is passing. Hence you may want to test with JARs from latest
+Keycloak master instead of the "official release" Keycloak JARs from cartridge.
+ 
+Openshift allows to connect with SSH and restart the cartridge. So you may use something like this on your laptop (example with the fix in module keycloak-services ). 
+
+On your laptop
+````bash
+cd $KEYCLOAK_SOURCES
+cd services
+mvn clean install
+scp target/keycloak-services-2.1.0-SNAPSHOT.jar 51122e382d5271c5ca0000bc@keycloak-mposolda.rhcloud.com:/tmp/
+ssh 51122e382d5271c5ca0000bc@keycloak-mposolda.rhcloud.com
+````
+
+Then on the machine:
+
+1) update the version in `/var/lib/openshift/51122e382d5271c5ca0000bc/wildfly/modules/system/add-ons/keycloak/org/keycloak/keycloak-server-spi/main/modules.xml`
+ 
+2) Replace JAR and restart server:
+
+````bash
+cp /tmp/keycloak-server-spi-2.1.0-SNAPSHOT.jar /var/lib/openshift/51122e382d5271c5ca0000bc/wildfly/modules/system/add-ons/keycloak/org/keycloak/keycloak-server-spi/main/
+ps aux | grep java
+kill -9 <PID>
+cd /var/lib/openshift/51122e382d5271c5ca0000bc/wildfly/bin
+./standalone.sh -b 127.3.168.129 -bmanagement=127.3.168.129 -Dh2.bindAddress=127.3.168.129
+````
+
+Wait for the server to start. Then rerun the OIDC test with the updated cartridge.
+
+Another possibility is to test with pure Wildfly Openshift cartridge and always install the latest keycloak-overlay to it.
diff --git a/model/infinispan/pom.xml b/model/infinispan/pom.xml
index 24634e6..07ea633 100755
--- a/model/infinispan/pom.xml
+++ b/model/infinispan/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
index ded6c3c..7b5f1d9 100755
--- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
+++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/DefaultInfinispanConnectionProviderFactory.java
@@ -21,6 +21,8 @@ import org.infinispan.configuration.cache.CacheMode;
 import org.infinispan.configuration.cache.Configuration;
 import org.infinispan.configuration.cache.ConfigurationBuilder;
 import org.infinispan.configuration.global.GlobalConfigurationBuilder;
+import org.infinispan.eviction.EvictionStrategy;
+import org.infinispan.eviction.EvictionType;
 import org.infinispan.manager.DefaultCacheManager;
 import org.infinispan.manager.EmbeddedCacheManager;
 import org.infinispan.transaction.LockingMode;
@@ -96,6 +98,17 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
             cacheManager = (EmbeddedCacheManager) new InitialContext().lookup(cacheContainerLookup);
             containerManaged = true;
 
+            cacheManager.defineConfiguration(InfinispanConnectionProvider.REALM_REVISIONS_CACHE_NAME, getRevisionCacheConfig(true, InfinispanConnectionProvider.REALM_REVISIONS_CACHE_DEFAULT_MAX));
+            cacheManager.getCache(InfinispanConnectionProvider.REALM_CACHE_NAME, true);
+
+            long maxEntries = cacheManager.getCache(InfinispanConnectionProvider.USER_CACHE_NAME).getCacheConfiguration().eviction().maxEntries();
+            if (maxEntries <= 0) {
+                maxEntries = InfinispanConnectionProvider.USER_REVISIONS_CACHE_DEFAULT_MAX;
+            }
+
+            cacheManager.defineConfiguration(InfinispanConnectionProvider.USER_REVISIONS_CACHE_NAME, getRevisionCacheConfig(true, maxEntries));
+            cacheManager.getCache(InfinispanConnectionProvider.USER_REVISIONS_CACHE_NAME, true);
+            cacheManager.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME, true);
             logger.debugv("Using container managed Infinispan cache container, lookup={1}", cacheContainerLookup);
         } catch (Exception e) {
             throw new RuntimeException("Failed to retrieve cache container", e);
@@ -148,6 +161,7 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
         cacheManager.defineConfiguration(InfinispanConnectionProvider.SESSION_CACHE_NAME, sessionCacheConfiguration);
         cacheManager.defineConfiguration(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME, sessionCacheConfiguration);
         cacheManager.defineConfiguration(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME, sessionCacheConfiguration);
+        cacheManager.defineConfiguration(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME, sessionCacheConfiguration);
 
         ConfigurationBuilder replicationConfigBuilder = new ConfigurationBuilder();
         if (clustered) {
@@ -161,9 +175,33 @@ public class DefaultInfinispanConnectionProviderFactory implements InfinispanCon
                 .transaction().transactionMode(TransactionMode.TRANSACTIONAL);
         counterConfigBuilder.transaction().transactionManagerLookup(new DummyTransactionManagerLookup());
         counterConfigBuilder.transaction().lockingMode(LockingMode.PESSIMISTIC);
-        Configuration counterCacheConfiguration = counterConfigBuilder.build();
 
-        cacheManager.defineConfiguration(InfinispanConnectionProvider.VERSION_CACHE_NAME, counterCacheConfiguration);
+        cacheManager.defineConfiguration(InfinispanConnectionProvider.REALM_REVISIONS_CACHE_NAME, getRevisionCacheConfig(false, InfinispanConnectionProvider.REALM_REVISIONS_CACHE_DEFAULT_MAX));
+        cacheManager.getCache(InfinispanConnectionProvider.REALM_CACHE_NAME, true);
+
+        long maxEntries = cacheManager.getCache(InfinispanConnectionProvider.USER_CACHE_NAME).getCacheConfiguration().eviction().maxEntries();
+        if (maxEntries <= 0) {
+            maxEntries = InfinispanConnectionProvider.USER_REVISIONS_CACHE_DEFAULT_MAX;
+        }
+
+        cacheManager.defineConfiguration(InfinispanConnectionProvider.USER_REVISIONS_CACHE_NAME, getRevisionCacheConfig(false, maxEntries));
+        cacheManager.getCache(InfinispanConnectionProvider.USER_REVISIONS_CACHE_NAME, true);
+    }
+
+    private Configuration getRevisionCacheConfig(boolean managed, long maxEntries) {
+        ConfigurationBuilder cb = new ConfigurationBuilder();
+        cb.invocationBatching().enable().transaction().transactionMode(TransactionMode.TRANSACTIONAL);
+
+        // Workaround: Use Dummy manager even in managed ( wildfly/eap ) environment. Without this workaround, there is an issue in EAP7 overlay.
+        // After start+end revisions batch is left the JTA transaction in committed state. This is incorrect and causes other issues afterwards.
+        // TODO: Investigate
+        // if (!managed)
+            cb.transaction().transactionManagerLookup(new DummyTransactionManagerLookup());
+
+        cb.transaction().lockingMode(LockingMode.PESSIMISTIC);
+
+        cb.eviction().strategy(EvictionStrategy.LRU).type(EvictionType.COUNT).size(maxEntries);
+        return cb.build();
     }
 
 }
diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java
index 8a21def..143056c 100755
--- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java
+++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/InfinispanConnectionProvider.java
@@ -25,13 +25,20 @@ import org.keycloak.provider.Provider;
  */
 public interface InfinispanConnectionProvider extends Provider {
 
-    public static final String VERSION_CACHE_NAME = "realmVersions";
-    static final String REALM_CACHE_NAME = "realms";
-    static final String USER_CACHE_NAME = "users";
-    static final String SESSION_CACHE_NAME = "sessions";
-    static final String OFFLINE_SESSION_CACHE_NAME = "offlineSessions";
-    static final String LOGIN_FAILURE_CACHE_NAME = "loginFailures";
-    static final String WORK_CACHE_NAME = "work";
+    String REALM_CACHE_NAME = "realms";
+    String REALM_REVISIONS_CACHE_NAME = "realmRevisions";
+    int REALM_REVISIONS_CACHE_DEFAULT_MAX = 10000;
+
+    String USER_CACHE_NAME = "users";
+    String USER_REVISIONS_CACHE_NAME = "userRevisions";
+    int USER_REVISIONS_CACHE_DEFAULT_MAX = 100000;
+
+    String SESSION_CACHE_NAME = "sessions";
+    String OFFLINE_SESSION_CACHE_NAME = "offlineSessions";
+    String LOGIN_FAILURE_CACHE_NAME = "loginFailures";
+    String WORK_CACHE_NAME = "work";
+    String AUTHORIZATION_CACHE_NAME = "authorization";
+
 
     <K, V> Cache<K, V> getCache(String name);
 
diff --git a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedPolicyStore.java b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedPolicyStore.java
new file mode 100644
index 0000000..4657633
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedPolicyStore.java
@@ -0,0 +1,411 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.authorization.infinispan;
+
+import org.infinispan.Cache;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.authorization.infinispan.InfinispanStoreFactoryProvider.CacheTransaction;
+import org.keycloak.models.authorization.infinispan.entities.CachedPolicy;
+import org.keycloak.representations.idm.authorization.DecisionStrategy;
+import org.keycloak.representations.idm.authorization.Logic;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class CachedPolicyStore implements PolicyStore {
+
+    private static final String POLICY_ID_CACHE_PREFIX = "policy-id-";
+
+    private final Cache<String, List> cache;
+    private final KeycloakSession session;
+    private final CacheTransaction transaction;
+    private StoreFactory storeFactory;
+    private PolicyStore delegate;
+
+    public CachedPolicyStore(KeycloakSession session, CacheTransaction transaction) {
+        this.session = session;
+        this.transaction = transaction;
+        InfinispanConnectionProvider provider = session.getProvider(InfinispanConnectionProvider.class);
+        this.cache = provider.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME);
+    }
+
+    @Override
+    public Policy create(String name, String type, ResourceServer resourceServer) {
+        Policy policy = getDelegate().create(name, type, getStoreFactory().getResourceServerStore().findById(resourceServer.getId()));
+
+        this.transaction.whenRollback(() -> cache.remove(getCacheKeyForPolicy(policy.getId())));
+
+        return createAdapter(new CachedPolicy(policy));
+    }
+
+    @Override
+    public void delete(String id) {
+        getDelegate().delete(id);
+        this.transaction.whenCommit(() -> cache.remove(getCacheKeyForPolicy(id)));
+    }
+
+    @Override
+    public Policy findById(String id) {
+        String cacheKeyForPolicy = getCacheKeyForPolicy(id);
+        List<CachedPolicy> cached = this.cache.get(cacheKeyForPolicy);
+
+        if (cached == null) {
+            Policy policy = getDelegate().findById(id);
+
+            if (policy != null) {
+                return createAdapter(updatePolicyCache(policy));
+            }
+
+            return null;
+        }
+
+        return createAdapter(cached.get(0));
+    }
+
+    @Override
+    public Policy findByName(String name, String resourceServerId) {
+        return getDelegate().findByName(name, resourceServerId);
+    }
+
+    @Override
+    public List<Policy> findByResourceServer(String resourceServerId) {
+        return getDelegate().findByResourceServer(resourceServerId).stream().map(policy -> findById(policy.getId())).collect(Collectors.toList());
+    }
+
+    @Override
+    public List<Policy> findByResource(String resourceId) {
+        List<Policy> cache = new ArrayList<>();
+
+        for (Entry entry : this.cache.entrySet()) {
+            String cacheKey = (String) entry.getKey();
+
+            if (cacheKey.startsWith(POLICY_ID_CACHE_PREFIX)) {
+                List<CachedPolicy> value = (List<CachedPolicy>) entry.getValue();
+                CachedPolicy policy = value.get(0);
+
+                if (policy.getResourcesIds().contains(resourceId)) {
+                    cache.add(findById(policy.getId()));
+                }
+            }
+        }
+
+        if (cache.isEmpty()) {
+            getDelegate().findByResource(resourceId).forEach(policy -> cache.add(findById(updatePolicyCache(policy).getId())));
+        }
+
+        return cache;
+    }
+
+    @Override
+    public List<Policy> findByResourceType(String resourceType, String resourceServerId) {
+        List<Policy> cache = new ArrayList<>();
+
+        for (Entry entry : this.cache.entrySet()) {
+            String cacheKey = (String) entry.getKey();
+
+            if (cacheKey.startsWith(POLICY_ID_CACHE_PREFIX)) {
+                List<CachedPolicy> value = (List<CachedPolicy>) entry.getValue();
+                CachedPolicy policy = value.get(0);
+
+                if (policy.getResourceServerId().equals(resourceServerId) && policy.getConfig().getOrDefault("defaultResourceType", "").equals(resourceType)) {
+                    cache.add(findById(policy.getId()));
+                }
+            }
+        }
+
+        if (cache.isEmpty()) {
+            getDelegate().findByResourceType(resourceType, resourceServerId).forEach(policy -> cache.add(findById(updatePolicyCache(policy).getId())));
+        }
+
+        return cache;
+    }
+
+    @Override
+    public List<Policy> findByScopeIds(List<String> scopeIds, String resourceServerId) {
+        List<Policy> cache = new ArrayList<>();
+
+        for (Entry entry : this.cache.entrySet()) {
+            String cacheKey = (String) entry.getKey();
+
+            if (cacheKey.startsWith(POLICY_ID_CACHE_PREFIX)) {
+                List<CachedPolicy> value = (List<CachedPolicy>) entry.getValue();
+                CachedPolicy policy = value.get(0);
+
+                for (String scopeId : policy.getScopesIds()) {
+                    if (scopeIds.contains(scopeId)) {
+                        cache.add(findById(policy.getId()));
+                        break;
+                    }
+                }
+            }
+        }
+
+        if (cache.isEmpty()) {
+            getDelegate().findByScopeIds(scopeIds, resourceServerId).forEach(policy -> cache.add(findById(updatePolicyCache(policy).getId())));
+        }
+
+        return cache;
+    }
+
+    @Override
+    public List<Policy> findByType(String type) {
+        return getDelegate().findByType(type).stream().map(policy -> findById(policy.getId())).collect(Collectors.toList());
+    }
+
+    @Override
+    public List<Policy> findDependentPolicies(String id) {
+        return getDelegate().findDependentPolicies(id).stream().map(policy -> findById(policy.getId())).collect(Collectors.toList());
+    }
+
+    private String getCacheKeyForPolicy(String policyId) {
+        return POLICY_ID_CACHE_PREFIX + policyId;
+    }
+
+    private StoreFactory getStoreFactory() {
+        if (this.storeFactory == null) {
+            this.storeFactory = this.session.getProvider(StoreFactory.class);
+        }
+
+        return this.storeFactory;
+    }
+
+    private PolicyStore getDelegate() {
+        if (this.delegate == null) {
+            this.delegate = getStoreFactory().getPolicyStore();
+        }
+
+        return this.delegate;
+    }
+
+    private Policy createAdapter(CachedPolicy cached) {
+        return new Policy() {
+
+            private Policy updated;
+
+            @Override
+            public String getId() {
+                return cached.getId();
+            }
+
+            @Override
+            public String getType() {
+                return cached.getType();
+            }
+
+            @Override
+            public DecisionStrategy getDecisionStrategy() {
+                return cached.getDecisionStrategy();
+            }
+
+            @Override
+            public void setDecisionStrategy(DecisionStrategy decisionStrategy) {
+                getDelegateForUpdate().setDecisionStrategy(decisionStrategy);
+                cached.setDecisionStrategy(decisionStrategy);
+            }
+
+            @Override
+            public Logic getLogic() {
+                return cached.getLogic();
+            }
+
+            @Override
+            public void setLogic(Logic logic) {
+                getDelegateForUpdate().setLogic(logic);
+                cached.setLogic(logic);
+            }
+
+            @Override
+            public Map<String, String> getConfig() {
+                return cached.getConfig();
+            }
+
+            @Override
+            public void setConfig(Map<String, String> config) {
+                getDelegateForUpdate().setConfig(config);
+                cached.setConfig(config);
+            }
+
+            @Override
+            public String getName() {
+                return cached.getName();
+            }
+
+            @Override
+            public void setName(String name) {
+                getDelegateForUpdate().setName(name);
+                cached.setName(name);
+            }
+
+            @Override
+            public String getDescription() {
+                return cached.getDescription();
+            }
+
+            @Override
+            public void setDescription(String description) {
+                getDelegateForUpdate().setDescription(description);
+                cached.setDescription(description);
+            }
+
+            @Override
+            public ResourceServer getResourceServer() {
+                return getStoreFactory().getResourceServerStore().findById(cached.getResourceServerId());
+            }
+
+            @Override
+            public void addScope(Scope scope) {
+                getDelegateForUpdate().addScope(getStoreFactory().getScopeStore().findById(scope.getId()));
+                cached.addScope(scope);
+            }
+
+            @Override
+            public void removeScope(Scope scope) {
+                getDelegateForUpdate().removeScope(getStoreFactory().getScopeStore().findById(scope.getId()));
+                cached.removeScope(scope);
+            }
+
+            @Override
+            public void addAssociatedPolicy(Policy associatedPolicy) {
+                getDelegateForUpdate().addAssociatedPolicy(getStoreFactory().getPolicyStore().findById(associatedPolicy.getId()));
+                cached.addAssociatedPolicy(associatedPolicy);
+            }
+
+            @Override
+            public void removeAssociatedPolicy(Policy associatedPolicy) {
+                getDelegateForUpdate().removeAssociatedPolicy(getStoreFactory().getPolicyStore().findById(associatedPolicy.getId()));
+                cached.removeAssociatedPolicy(associatedPolicy);
+            }
+
+            @Override
+            public void addResource(Resource resource) {
+                getDelegateForUpdate().addResource(getStoreFactory().getResourceStore().findById(resource.getId()));
+                cached.addResource(resource);
+            }
+
+            @Override
+            public void removeResource(Resource resource) {
+                getDelegateForUpdate().removeResource(getStoreFactory().getResourceStore().findById(resource.getId()));
+                cached.removeResource(resource);
+            }
+
+            @Override
+            public Set<Policy> getAssociatedPolicies() {
+                Set<Policy> associatedPolicies = new HashSet<>();
+
+                for (String id : cached.getAssociatedPoliciesIds()) {
+                    Policy cached = findById(id);
+
+                    if (cached != null) {
+                        associatedPolicies.add(cached);
+                    }
+                }
+
+                return associatedPolicies;
+            }
+
+            @Override
+            public Set<Resource> getResources() {
+                Set<Resource> resources = new HashSet<>();
+
+                for (String id : cached.getResourcesIds()) {
+                    Resource cached = getStoreFactory().getResourceStore().findById(id);
+
+                    if (cached != null) {
+                        resources.add(cached);
+                    }
+                }
+
+                return resources;
+            }
+
+            @Override
+            public Set<Scope> getScopes() {
+                Set<Scope> scopes = new HashSet<>();
+
+                for (String id : cached.getScopesIds()) {
+                    Scope cached = getStoreFactory().getScopeStore().findById(id);
+
+                    if (cached != null) {
+                        scopes.add(cached);
+                    }
+                }
+
+                return scopes;
+            }
+
+            @Override
+            public boolean equals(Object o) {
+                if (o == this) return true;
+
+                if (getId() == null) return false;
+
+                if (!Policy.class.isInstance(o)) return false;
+
+                Policy that = (Policy) o;
+
+                if (!getId().equals(that.getId())) return false;
+
+                return true;
+
+            }
+
+            @Override
+            public int hashCode() {
+                return getId()!=null ? getId().hashCode() : super.hashCode();
+            }
+
+            private Policy getDelegateForUpdate() {
+                if (this.updated == null) {
+                    this.updated = getDelegate().findById(getId());
+                    if (this.updated == null) throw new IllegalStateException("Not found in database");
+                    transaction.whenCommit(() -> cache.remove(getCacheKeyForPolicy(getId())));
+                }
+
+                return this.updated;
+            }
+        };
+    }
+
+    private CachedPolicy updatePolicyCache(Policy policy) {
+        CachedPolicy cached = new CachedPolicy(policy);
+        List<Policy> cache = new ArrayList<>();
+
+        cache.add(cached);
+
+        this.cache.put(getCacheKeyForPolicy(policy.getId()), cache);
+
+        return cached;
+    }
+
+}
\ No newline at end of file
diff --git a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceServerStore.java b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceServerStore.java
new file mode 100644
index 0000000..2685135
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceServerStore.java
@@ -0,0 +1,190 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.authorization.infinispan;
+
+import org.infinispan.Cache;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.store.ResourceServerStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.authorization.infinispan.InfinispanStoreFactoryProvider.CacheTransaction;
+import org.keycloak.models.authorization.infinispan.entities.CachedResourceServer;
+import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class CachedResourceServerStore implements ResourceServerStore {
+
+    private static final String RS_ID_CACHE_PREFIX = "rs-id-";
+
+    private final KeycloakSession session;
+    private final CacheTransaction transaction;
+    private StoreFactory storeFactory;
+    private ResourceServerStore delegate;
+    private final Cache<String, List> cache;
+
+    public CachedResourceServerStore(KeycloakSession session, CacheTransaction transaction) {
+        this.session = session;
+        this.transaction = transaction;
+        InfinispanConnectionProvider provider = session.getProvider(InfinispanConnectionProvider.class);
+        this.cache = provider.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME);
+    }
+
+    @Override
+    public ResourceServer create(String clientId) {
+        ResourceServer resourceServer = getDelegate().create(clientId);
+
+        this.transaction.whenRollback(() -> cache.remove(getCacheKeyForResourceServer(resourceServer.getId())));
+
+        return createAdapter(new CachedResourceServer(resourceServer));
+    }
+
+    @Override
+    public void delete(String id) {
+        getDelegate().delete(id);
+        this.transaction.whenCommit(() -> this.cache.remove(getCacheKeyForResourceServer(id)));
+    }
+
+    @Override
+    public ResourceServer findById(String id) {
+        String cacheKeyForResourceServer = getCacheKeyForResourceServer(id);
+        List<ResourceServer> cached = this.cache.get(cacheKeyForResourceServer);
+
+        if (cached == null) {
+            ResourceServer resourceServer = getDelegate().findById(id);
+
+            if (resourceServer != null) {
+                return createAdapter(updateResourceServerCache(resourceServer));
+            }
+
+            return null;
+        }
+
+        return createAdapter(cached.get(0));
+    }
+
+    @Override
+    public ResourceServer findByClient(String id) {
+        for (Map.Entry entry : this.cache.entrySet()) {
+            String cacheKey = (String) entry.getKey();
+
+            if (cacheKey.startsWith(RS_ID_CACHE_PREFIX)) {
+                List<ResourceServer> cache = (List<ResourceServer>) entry.getValue();
+                ResourceServer resourceServer = cache.get(0);
+
+                if (resourceServer.getClientId().equals(id)) {
+                    return findById(resourceServer.getId());
+                }
+            }
+        }
+
+        ResourceServer resourceServer = getDelegate().findByClient(id);
+
+        if (resourceServer != null) {
+            return findById(updateResourceServerCache(resourceServer).getId());
+        }
+
+        return null;
+    }
+
+    private String getCacheKeyForResourceServer(String id) {
+        return RS_ID_CACHE_PREFIX + id;
+    }
+
+    private ResourceServerStore getDelegate() {
+        if (this.delegate == null) {
+            this.delegate = getStoreFactory().getResourceServerStore();
+        }
+
+        return this.delegate;
+    }
+
+    private StoreFactory getStoreFactory() {
+        if (this.storeFactory == null) {
+            this.storeFactory = session.getProvider(StoreFactory.class);
+        }
+
+        return this.storeFactory;
+    }
+    private ResourceServer createAdapter(ResourceServer cached) {
+        return new ResourceServer() {
+
+            private ResourceServer updated;
+
+            @Override
+            public String getId() {
+                return cached.getId();
+            }
+
+            @Override
+            public String getClientId() {
+                return cached.getClientId();
+            }
+
+            @Override
+            public boolean isAllowRemoteResourceManagement() {
+                return cached.isAllowRemoteResourceManagement();
+            }
+
+            @Override
+            public void setAllowRemoteResourceManagement(boolean allowRemoteResourceManagement) {
+                getDelegateForUpdate().setAllowRemoteResourceManagement(allowRemoteResourceManagement);
+                cached.setAllowRemoteResourceManagement(allowRemoteResourceManagement);
+            }
+
+            @Override
+            public PolicyEnforcementMode getPolicyEnforcementMode() {
+                return cached.getPolicyEnforcementMode();
+            }
+
+            @Override
+            public void setPolicyEnforcementMode(PolicyEnforcementMode enforcementMode) {
+                getDelegateForUpdate().setPolicyEnforcementMode(enforcementMode);
+                cached.setPolicyEnforcementMode(enforcementMode);
+            }
+
+            private ResourceServer getDelegateForUpdate() {
+                if (this.updated == null) {
+                    this.updated = getDelegate().findById(getId());
+                    if (this.updated == null) throw new IllegalStateException("Not found in database");
+                    transaction.whenCommit(() -> cache.remove(getCacheKeyForResourceServer(getId())));
+                }
+
+                return this.updated;
+            }
+        };
+    }
+
+    private CachedResourceServer updateResourceServerCache(ResourceServer resourceServer) {
+        CachedResourceServer cached = new CachedResourceServer(resourceServer);
+        List<ResourceServer> cache = new ArrayList<>();
+
+        cache.add(cached);
+
+        this.cache.put(getCacheKeyForResourceServer(resourceServer.getId()), cache);
+
+        return cached;
+    }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceStore.java b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceStore.java
new file mode 100644
index 0000000..4d9a946
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedResourceStore.java
@@ -0,0 +1,311 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.authorization.infinispan;
+
+import org.infinispan.Cache;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.store.ResourceStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.authorization.infinispan.InfinispanStoreFactoryProvider.CacheTransaction;
+import org.keycloak.models.authorization.infinispan.entities.CachedResource;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class CachedResourceStore implements ResourceStore {
+
+    private static final String RESOURCE_ID_CACHE_PREFIX = "rsc-id-";
+    private static final String RESOURCE_OWNER_CACHE_PREFIX = "rsc-owner-";
+
+    private final KeycloakSession session;
+    private final CacheTransaction transaction;
+    private StoreFactory storeFactory;
+    private ResourceStore delegate;
+    private final Cache<String, List> cache;
+
+    public CachedResourceStore(KeycloakSession session, CacheTransaction transaction) {
+        this.session = session;
+        InfinispanConnectionProvider provider = session.getProvider(InfinispanConnectionProvider.class);
+        this.cache = provider.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME);
+        this.transaction = transaction;
+    }
+
+    @Override
+    public Resource create(String name, ResourceServer resourceServer, String owner) {
+        Resource resource = getDelegate().create(name, getStoreFactory().getResourceServerStore().findById(resourceServer.getId()), owner);
+
+        this.transaction.whenRollback(() -> cache.remove(getCacheKeyForResource(resource.getId())));
+
+        return createAdapter(new CachedResource(resource));
+    }
+
+    @Override
+    public void delete(String id) {
+        List<CachedResource> removed = this.cache.remove(getCacheKeyForResource(id));
+
+        if (removed != null) {
+            CachedResource cachedResource = removed.get(0);
+            List<String> byOwner = this.cache.get(getResourceOwnerCacheKey(cachedResource.getOwner()));
+
+            if (byOwner != null) {
+                byOwner.remove(id);
+
+                if (byOwner.isEmpty()) {
+                    this.cache.remove(getResourceOwnerCacheKey(cachedResource.getOwner()));
+                }
+            }
+        }
+
+        getDelegate().delete(id);
+    }
+
+    @Override
+    public Resource findById(String id) {
+        String cacheKeyForResource = getCacheKeyForResource(id);
+        List<CachedResource> cached = this.cache.get(cacheKeyForResource);
+
+        if (cached == null) {
+            Resource resource = getDelegate().findById(id);
+
+            if (resource != null) {
+                updateCachedIds(getResourceOwnerCacheKey(resource.getOwner()), resource, false);
+                return createAdapter(updateResourceCache(resource));
+            }
+
+            return null;
+        }
+
+        return createAdapter(cached.get(0));
+    }
+
+    @Override
+    public List<Resource> findByOwner(String ownerId) {
+        List<String> cachedIds = this.cache.get(getResourceOwnerCacheKey(ownerId));
+
+        if (cachedIds == null) {
+            for (Resource resource : getDelegate().findByOwner(ownerId)) {
+                updateCachedIds(getResourceOwnerCacheKey(ownerId), resource, true);
+            }
+            cachedIds = this.cache.getOrDefault(getResourceOwnerCacheKey(ownerId), Collections.emptyList());
+        }
+
+        return  ((List<String>) this.cache.getOrDefault(getResourceOwnerCacheKey(ownerId), Collections.emptyList())).stream().map(this::findById)
+                        .filter(resource -> resource != null)
+                        .collect(Collectors.toList());
+    }
+
+    @Override
+    public List<Resource> findByResourceServer(String resourceServerId) {
+        return getDelegate().findByResourceServer(resourceServerId).stream().map(resource -> findById(resource.getId())).collect(Collectors.toList());
+    }
+
+    @Override
+    public List<Resource> findByScope(String... id) {
+        return getDelegate().findByScope(id).stream().map(resource -> findById(resource.getId())).collect(Collectors.toList());
+    }
+
+    @Override
+    public Resource findByName(String name, String resourceServerId) {
+        for (Entry entry : this.cache.entrySet()) {
+            String cacheKey = (String) entry.getKey();
+
+            if (cacheKey.startsWith(RESOURCE_ID_CACHE_PREFIX)) {
+                List<CachedResource> value = (List<CachedResource>) entry.getValue();
+                CachedResource resource = value.get(0);
+
+                if (resource.getResourceServerId().equals(resourceServerId) && resource.getName().equals(name)) {
+                    return findById(resource.getId());
+                }
+            }
+        }
+
+        Resource resource = getDelegate().findByName(name, resourceServerId);
+
+        if (resource != null) {
+            return findById(updateResourceCache(resource).getId());
+        }
+
+        return null;
+    }
+
+    @Override
+    public List<Resource> findByType(String type) {
+        return  getDelegate().findByType(type).stream().map(resource -> findById(resource.getId())).collect(Collectors.toList());
+    }
+
+    private String getCacheKeyForResource(String id) {
+        return RESOURCE_ID_CACHE_PREFIX + id;
+    }
+
+    private ResourceStore getDelegate() {
+        if (this.delegate == null) {
+            this.delegate = getStoreFactory().getResourceStore();
+        }
+
+        return this.delegate;
+    }
+
+    private StoreFactory getStoreFactory() {
+        if (this.storeFactory == null) {
+            this.storeFactory = session.getProvider(StoreFactory.class);
+        }
+
+        return this.storeFactory;
+    }
+
+    private Resource createAdapter(CachedResource cached) {
+        return new Resource() {
+
+            private List<Scope> scopes;
+            private Resource updated;
+
+            @Override
+            public String getId() {
+                return cached.getId();
+            }
+
+            @Override
+            public String getName() {
+                return cached.getName();
+            }
+
+            @Override
+            public void setName(String name) {
+                getDelegateForUpdate().setName(name);
+                cached.setName(name);
+            }
+
+            @Override
+            public String getUri() {
+                return cached.getUri();
+            }
+
+            @Override
+            public void setUri(String uri) {
+                getDelegateForUpdate().setUri(uri);
+                cached.setUri(uri);
+            }
+
+            @Override
+            public String getType() {
+                return cached.getType();
+            }
+
+            @Override
+            public void setType(String type) {
+                getDelegateForUpdate().setType(type);
+                cached.setType(type);
+            }
+
+            @Override
+            public List<Scope> getScopes() {
+                List<Scope> scopes = new ArrayList<>();
+
+                for (String id : cached.getScopesIds()) {
+                    Scope cached = getStoreFactory().getScopeStore().findById(id);
+
+                    if (cached != null) {
+                        scopes.add(cached);
+                    }
+                }
+
+                return scopes;
+            }
+
+            @Override
+            public String getIconUri() {
+                return cached.getIconUri();
+            }
+
+            @Override
+            public void setIconUri(String iconUri) {
+                getDelegateForUpdate().setIconUri(iconUri);
+                cached.setIconUri(iconUri);
+            }
+
+            @Override
+            public ResourceServer getResourceServer() {
+                return getStoreFactory().getResourceServerStore().findById(cached.getResourceServerId());
+            }
+
+            @Override
+            public String getOwner() {
+                return cached.getOwner();
+            }
+
+            @Override
+            public void updateScopes(Set<Scope> scopes) {
+                getDelegateForUpdate().updateScopes(scopes.stream().map(scope -> getStoreFactory().getScopeStore().findById(scope.getId())).collect(Collectors.toSet()));
+                cached.updateScopes(scopes);
+            }
+
+            private Resource getDelegateForUpdate() {
+                if (this.updated == null) {
+                    this.updated = getDelegate().findById(getId());
+                    if (this.updated == null) throw new IllegalStateException("Not found in database");
+                    transaction.whenCommit(() -> cache.remove(getCacheKeyForResource(getId())));
+                }
+
+                return this.updated;
+            }
+        };
+    }
+
+    private CachedResource updateResourceCache(Resource resource) {
+        CachedResource cached = new CachedResource(resource);
+        List cache = new ArrayList<>();
+
+        cache.add(cached);
+
+        this.cache.put(getCacheKeyForResource(resource.getId()), cache);
+
+        return cached;
+    }
+
+    private void updateCachedIds(String cacheKey, Resource resource, boolean create) {
+        List<String> cached = this.cache.get(cacheKey);
+
+        if (cached == null) {
+            if (!create) {
+                return;
+            }
+            cached = new ArrayList<>();
+            this.cache.put(cacheKey, cached);
+        }
+
+        if (cached != null && !cached.contains(resource.getId())) {
+            cached.add(resource.getId());
+        }
+    }
+
+    private String getResourceOwnerCacheKey(String ownerId) {
+        return RESOURCE_OWNER_CACHE_PREFIX + ownerId;
+    }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedScopeStore.java b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedScopeStore.java
new file mode 100644
index 0000000..72f3f25
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/CachedScopeStore.java
@@ -0,0 +1,197 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.authorization.infinispan;
+
+import org.infinispan.Cache;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.store.ScopeStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.authorization.infinispan.InfinispanStoreFactoryProvider.CacheTransaction;
+import org.keycloak.models.authorization.infinispan.entities.CachedScope;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class CachedScopeStore implements ScopeStore {
+
+    private static final String SCOPE_ID_CACHE_PREFIX = "scp-id-";
+
+    private final Cache<String, List> cache;
+    private final KeycloakSession session;
+    private final CacheTransaction transaction;
+    private ScopeStore delegate;
+    private StoreFactory storeFactory;
+
+    public CachedScopeStore(KeycloakSession session, CacheTransaction transaction) {
+        this.session = session;
+        this.transaction = transaction;
+        InfinispanConnectionProvider provider = session.getProvider(InfinispanConnectionProvider.class);
+        this.cache = provider.getCache(InfinispanConnectionProvider.AUTHORIZATION_CACHE_NAME);
+    }
+
+    @Override
+    public Scope create(String name, ResourceServer resourceServer) {
+        Scope scope = getDelegate().create(name, getStoreFactory().getResourceServerStore().findById(resourceServer.getId()));
+
+        this.transaction.whenRollback(() -> cache.remove(getCacheKeyForScope(scope.getId())));
+
+        return createAdapter(new CachedScope(scope));
+    }
+
+    @Override
+    public void delete(String id) {
+        getDelegate().delete(id);
+        this.transaction.whenCommit(() -> cache.remove(getCacheKeyForScope(id)));
+    }
+
+    @Override
+    public Scope findById(String id) {
+        String cacheKeyForScope = getCacheKeyForScope(id);
+        List<CachedScope> cached = this.cache.get(cacheKeyForScope);
+
+        if (cached == null) {
+            Scope scope = getDelegate().findById(id);
+
+            if (scope != null) {
+                return createAdapter(updateScopeCache(scope));
+            }
+
+            return null;
+        }
+
+        return createAdapter(cached.get(0));
+    }
+
+    @Override
+    public Scope findByName(String name, String resourceServerId) {
+        for (Entry entry : this.cache.entrySet()) {
+            String cacheKey = (String) entry.getKey();
+
+            if (cacheKey.startsWith(SCOPE_ID_CACHE_PREFIX)) {
+                List<CachedScope> cache = (List<CachedScope>) entry.getValue();
+                CachedScope scope = cache.get(0);
+
+                if (scope.getResourceServerId().equals(resourceServerId) && scope.getName().equals(name)) {
+                    return findById(scope.getId());
+                }
+            }
+        }
+
+        Scope scope = getDelegate().findByName(name, resourceServerId);
+
+        if (scope != null) {
+            return findById(updateScopeCache(scope).getId());
+        }
+
+        return null;
+    }
+
+    @Override
+    public List<Scope> findByResourceServer(String id) {
+        return getDelegate().findByResourceServer(id);
+    }
+
+    private String getCacheKeyForScope(String id) {
+        return SCOPE_ID_CACHE_PREFIX + id;
+    }
+
+    private ScopeStore getDelegate() {
+        if (this.delegate == null) {
+            this.delegate = getStoreFactory().getScopeStore();
+        }
+
+        return this.delegate;
+    }
+
+    private StoreFactory getStoreFactory() {
+        if (this.storeFactory == null) {
+            this.storeFactory = session.getProvider(StoreFactory.class);
+        }
+
+        return this.storeFactory;
+    }
+
+    private Scope createAdapter(CachedScope cached) {
+        return new Scope() {
+
+            private Scope updated;
+
+            @Override
+            public String getId() {
+                return cached.getId();
+            }
+
+            @Override
+            public String getName() {
+                return cached.getName();
+            }
+
+            @Override
+            public void setName(String name) {
+                getDelegateForUpdate().setName(name);
+                cached.setName(name);
+            }
+
+            @Override
+            public String getIconUri() {
+                return cached.getIconUri();
+            }
+
+            @Override
+            public void setIconUri(String iconUri) {
+                getDelegateForUpdate().setIconUri(iconUri);
+                cached.setIconUri(iconUri);
+            }
+
+            @Override
+            public ResourceServer getResourceServer() {
+                return getStoreFactory().getResourceServerStore().findById(cached.getResourceServerId());
+            }
+
+            private Scope getDelegateForUpdate() {
+                if (this.updated == null) {
+                    this.updated = getDelegate().findById(getId());
+                    if (this.updated == null) throw new IllegalStateException("Not found in database");
+                    transaction.whenCommit(() -> cache.remove(getCacheKeyForScope(getId())));
+                }
+
+                return this.updated;
+            }
+        };
+    }
+
+    private CachedScope updateScopeCache(Scope scope) {
+        CachedScope cached = new CachedScope(scope);
+
+        List cache = new ArrayList();
+
+        cache.add(cached);
+
+        this.transaction.whenCommit(() -> this.cache.put(getCacheKeyForScope(scope.getId()), cache));
+
+        return cached;
+    }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/entities/CachedPolicy.java b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/entities/CachedPolicy.java
new file mode 100644
index 0000000..775cf64
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/entities/CachedPolicy.java
@@ -0,0 +1,217 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.authorization.infinispan.entities;
+
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.representations.idm.authorization.DecisionStrategy;
+import org.keycloak.representations.idm.authorization.Logic;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class CachedPolicy implements Policy, Serializable {
+
+    private static final long serialVersionUID = -144247681046298128L;
+
+    private String id;
+    private String type;
+    private DecisionStrategy decisionStrategy;
+    private Logic logic;
+    private Map<String, String> config;
+    private String name;
+    private String description;
+    private String resourceServerId;
+    private Set<String> associatedPoliciesIds;
+    private Set<String> resourcesIds;
+    private Set<String> scopesIds;
+
+    public CachedPolicy(Policy policy) {
+        this.id = policy.getId();
+        this.type = policy.getType();
+        this.decisionStrategy = policy.getDecisionStrategy();
+        this.logic = policy.getLogic();
+        this.config = new HashMap(policy.getConfig());
+        this.name = policy.getName();
+        this.description = policy.getDescription();
+        this.resourceServerId = policy.getResourceServer().getId();
+        this.associatedPoliciesIds = policy.getAssociatedPolicies().stream().map(Policy::getId).collect(Collectors.toSet());
+        this.resourcesIds = policy.getResources().stream().map(Resource::getId).collect(Collectors.toSet());
+        this.scopesIds = policy.getScopes().stream().map(Scope::getId).collect(Collectors.toSet());
+    }
+
+    public CachedPolicy(String id) {
+        this.id = id;
+    }
+
+    @Override
+    public String getId() {
+        return this.id;
+    }
+
+    @Override
+    public String getType() {
+        return this.type;
+    }
+
+    @Override
+    public DecisionStrategy getDecisionStrategy() {
+        return this.decisionStrategy;
+    }
+
+    @Override
+    public void setDecisionStrategy(DecisionStrategy decisionStrategy) {
+        this.decisionStrategy = decisionStrategy;
+    }
+
+    @Override
+    public Logic getLogic() {
+        return this.logic;
+    }
+
+    @Override
+    public void setLogic(Logic logic) {
+        this.logic = logic;
+    }
+
+    @Override
+    public Map<String, String> getConfig() {
+        return this.config;
+    }
+
+    @Override
+    public void setConfig(Map<String, String> config) {
+        this.config = config;
+    }
+
+    @Override
+    public String getName() {
+        return this.name;
+    }
+
+    @Override
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String getDescription() {
+        return this.description;
+    }
+
+    @Override
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    @Override
+    public ResourceServer getResourceServer() {
+        throw new RuntimeException("Not implemented");
+    }
+
+    @Override
+    public void addScope(Scope scope) {
+        this.scopesIds.add(scope.getId());
+    }
+
+    @Override
+    public void removeScope(Scope scope) {
+        this.scopesIds.remove(scope.getId());
+    }
+
+    @Override
+    public void addAssociatedPolicy(Policy associatedPolicy) {
+        this.associatedPoliciesIds.add(associatedPolicy.getId());
+    }
+
+    @Override
+    public void removeAssociatedPolicy(Policy associatedPolicy) {
+        this.associatedPoliciesIds.remove(associatedPolicy.getId());
+    }
+
+    @Override
+    public void addResource(Resource resource) {
+        this.resourcesIds.add(resource.getId());
+    }
+
+    @Override
+    public void removeResource(Resource resource) {
+        this.resourcesIds.add(resource.getId());
+    }
+
+    @Override
+    public Set<Policy> getAssociatedPolicies() {
+        throw new RuntimeException("Not implemented");
+    }
+
+    @Override
+    public Set<Resource> getResources() {
+        throw new RuntimeException("Not implemented");
+    }
+
+    @Override
+    public Set<Scope> getScopes() {
+        throw new RuntimeException("Not implemented");
+    }
+
+    public Set<String> getAssociatedPoliciesIds() {
+        return this.associatedPoliciesIds;
+    }
+
+    public Set<String> getResourcesIds() {
+        return this.resourcesIds;
+    }
+
+    public Set<String> getScopesIds() {
+        return this.scopesIds;
+    }
+
+    public String getResourceServerId() {
+        return this.resourceServerId;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) return true;
+
+        if (this.id == null) return false;
+
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Policy that = (Policy) o;
+
+        if (!getId().equals(that.getId())) return false;
+
+        return true;
+
+    }
+
+    @Override
+    public int hashCode() {
+        return id!=null ? id.hashCode() : super.hashCode();
+    }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/entities/CachedResource.java b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/entities/CachedResource.java
new file mode 100644
index 0000000..ee1212f
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/entities/CachedResource.java
@@ -0,0 +1,134 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.authorization.infinispan.entities;
+
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class CachedResource implements Resource, Serializable {
+
+    private static final long serialVersionUID = -6886179034626995165L;
+
+    private final String id;
+    private String resourceServerId;
+    private String iconUri;
+    private String owner;
+    private String type;
+    private String name;
+    private String uri;
+    private Set<String> scopesIds;
+
+    public CachedResource(Resource resource) {
+        this.id = resource.getId();
+        this.name = resource.getName();
+        this.uri = resource.getUri();
+        this.type = resource.getType();
+        this.owner = resource.getOwner();
+        this.iconUri = resource.getIconUri();
+        this.resourceServerId = resource.getResourceServer().getId();
+        this.scopesIds = resource.getScopes().stream().map(Scope::getId).collect(Collectors.toSet());
+    }
+
+    public CachedResource(String id) {
+        this.id = id;
+    }
+
+    @Override
+    public String getId() {
+        return this.id;
+    }
+
+    @Override
+    public String getName() {
+        return this.name;
+    }
+
+    @Override
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String getUri() {
+        return this.uri;
+    }
+
+    @Override
+    public void setUri(String uri) {
+        this.uri = uri;
+    }
+
+    @Override
+    public String getType() {
+        return this.type;
+    }
+
+    @Override
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    @Override
+    public List<Scope> getScopes() {
+        throw new RuntimeException("Not implemented");
+    }
+
+    @Override
+    public String getIconUri() {
+        return this.iconUri;
+    }
+
+    @Override
+    public void setIconUri(String iconUri) {
+        this.iconUri = iconUri;
+    }
+
+    @Override
+    public ResourceServer getResourceServer() {
+        throw new RuntimeException("Not implemented");
+    }
+
+    @Override
+    public String getOwner() {
+        return this.owner;
+    }
+
+    @Override
+    public void updateScopes(Set<Scope> scopes) {
+        this.scopesIds.clear();
+        this.scopesIds.addAll(scopes.stream().map(Scope::getId).collect(Collectors.toSet()));
+    }
+
+    public String getResourceServerId() {
+        return this.resourceServerId;
+    }
+
+    public Set<String> getScopesIds() {
+        return this.scopesIds;
+    }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/entities/CachedResourceServer.java b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/entities/CachedResourceServer.java
new file mode 100644
index 0000000..7dab0b2
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/entities/CachedResourceServer.java
@@ -0,0 +1,78 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.authorization.infinispan.entities;
+
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
+
+import java.io.Serializable;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class CachedResourceServer implements ResourceServer, Serializable {
+
+    private static final long serialVersionUID = 5054253390723121289L;
+
+    private final String id;
+    private String clientId;
+    private boolean allowRemoteResourceManagement;
+    private PolicyEnforcementMode policyEnforcementMode;
+
+    public CachedResourceServer(ResourceServer resourceServer) {
+        this.id = resourceServer.getId();
+        this.clientId = resourceServer.getClientId();
+        this.allowRemoteResourceManagement = resourceServer.isAllowRemoteResourceManagement();
+        this.policyEnforcementMode = resourceServer.getPolicyEnforcementMode();
+    }
+
+    public CachedResourceServer(String id) {
+        this.id = id;
+    }
+
+    @Override
+    public String getId() {
+        return this.id;
+    }
+
+    @Override
+    public String getClientId() {
+        return this.clientId;
+    }
+
+    @Override
+    public boolean isAllowRemoteResourceManagement() {
+        return this.allowRemoteResourceManagement;
+    }
+
+    @Override
+    public void setAllowRemoteResourceManagement(boolean allowRemoteResourceManagement) {
+        this.allowRemoteResourceManagement = allowRemoteResourceManagement;
+    }
+
+    @Override
+    public PolicyEnforcementMode getPolicyEnforcementMode() {
+        return this.policyEnforcementMode;
+    }
+
+    @Override
+    public void setPolicyEnforcementMode(PolicyEnforcementMode enforcementMode) {
+        this.policyEnforcementMode = enforcementMode;
+    }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/entities/CachedScope.java b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/entities/CachedScope.java
new file mode 100644
index 0000000..6450119
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/entities/CachedScope.java
@@ -0,0 +1,82 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.authorization.infinispan.entities;
+
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+
+import java.io.Serializable;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class CachedScope implements Scope, Serializable {
+
+    private static final long serialVersionUID = -3919706923417065454L;
+
+    private final String id;
+    private String resourceServerId;
+    private String name;
+    private String iconUri;
+
+    public CachedScope(Scope scope) {
+        this.id = scope.getId();
+        this.name = scope.getName();
+        this.iconUri = scope.getIconUri();
+        this.resourceServerId = scope.getResourceServer().getId();
+    }
+
+    public CachedScope(String id) {
+        this.id = id;
+    }
+
+    @Override
+    public String getId() {
+        return this.id;
+    }
+
+    @Override
+    public String getName() {
+        return this.name;
+    }
+
+    @Override
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String getIconUri() {
+        return this.iconUri;
+    }
+
+    @Override
+    public void setIconUri(String iconUri) {
+        this.iconUri = iconUri;
+    }
+
+    @Override
+    public ResourceServer getResourceServer() {
+        throw new RuntimeException("Not implemented");
+    }
+
+    public String getResourceServerId() {
+        return this.resourceServerId;
+    }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/InfinispanStoreFactoryProvider.java b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/InfinispanStoreFactoryProvider.java
new file mode 100644
index 0000000..56a385f
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/InfinispanStoreFactoryProvider.java
@@ -0,0 +1,114 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.authorization.infinispan;
+
+import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.authorization.store.ResourceServerStore;
+import org.keycloak.authorization.store.ResourceStore;
+import org.keycloak.authorization.store.ScopeStore;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakTransaction;
+import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class InfinispanStoreFactoryProvider implements CachedStoreFactoryProvider {
+
+    private final KeycloakSession session;
+    private final CacheTransaction transaction;
+
+    InfinispanStoreFactoryProvider(KeycloakSession delegate) {
+        this.session = delegate;
+        this.transaction = new CacheTransaction();
+        this.session.getTransactionManager().enlistAfterCompletion(transaction);
+    }
+
+    @Override
+    public ResourceStore getResourceStore() {
+        return new CachedResourceStore(this.session, this.transaction);
+    }
+
+    @Override
+    public ResourceServerStore getResourceServerStore() {
+        return new CachedResourceServerStore(this.session, this.transaction);
+    }
+
+    @Override
+    public ScopeStore getScopeStore() {
+        return new CachedScopeStore(this.session, this.transaction);
+    }
+
+    @Override
+    public PolicyStore getPolicyStore() {
+        return new CachedPolicyStore(this.session, this.transaction);
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    static class CacheTransaction implements KeycloakTransaction {
+
+        private List<Runnable> completeTasks = new ArrayList<>();
+        private List<Runnable> rollbackTasks = new ArrayList<>();
+
+        @Override
+        public void begin() {
+
+        }
+
+        @Override
+        public void commit() {
+            this.completeTasks.forEach(task -> task.run());
+        }
+
+        @Override
+        public void rollback() {
+            this.rollbackTasks.forEach(task -> task.run());
+        }
+
+        @Override
+        public void setRollbackOnly() {
+
+        }
+
+        @Override
+        public boolean getRollbackOnly() {
+            return false;
+        }
+
+        @Override
+        public boolean isActive() {
+            return false;
+        }
+
+        protected void whenCommit(Runnable task) {
+            this.completeTasks.add(task);
+        }
+
+        protected void whenRollback(Runnable task) {
+            this.rollbackTasks.add(task);
+        }
+    }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/InfinispanStoreProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/InfinispanStoreProviderFactory.java
new file mode 100644
index 0000000..8015fc2
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/authorization/infinispan/InfinispanStoreProviderFactory.java
@@ -0,0 +1,56 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.authorization.infinispan;
+
+import org.keycloak.Config;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
+import org.keycloak.models.cache.authorization.CachedStoreProviderFactory;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class InfinispanStoreProviderFactory implements CachedStoreProviderFactory {
+    @Override
+    public CachedStoreFactoryProvider create(KeycloakSession session) {
+        return new InfinispanStoreFactoryProvider(session);
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "infinispan-authz-store-factory";
+    }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/CacheManager.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/CacheManager.java
index e41913d..f077927 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/CacheManager.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/CacheManager.java
@@ -16,6 +16,40 @@ import java.util.Set;
 import java.util.function.Predicate;
 
 /**
+ *
+ * Some notes on how this works:
+
+ * This implementation manages optimistic locking and version checks itself.  The reason is Infinispan just does behave
+ * the way we need it to.  Not saying Infinispan is bad, just that we have specific caching requirements!
+ *
+ * This is an invalidation cache implementation and requires to caches:
+ * Cache 1 is an Invalidation Cache
+ * Cache 2 is a local-only revision number cache.
+ *
+ *
+ * Each node in the cluster maintains its own revision number cache for each entry in the main invalidation cache.  This revision
+ * cache holds the version counter for each cached entity.
+ *
+ * Cache listeners do not receive a @CacheEntryInvalidated event if that node does not have an entry for that item.  So, consider the following.
+
+ 1. Node 1 gets current counter for user.  There currently isn't one as this user isn't cached.
+ 2. Node 1 reads user from DB
+ 3. Node 2 updates user
+ 4. Node 2 calls cache.remove(user).  This does not result in an invalidation listener event to node 1!
+ 5. node 1 checks version counter, checks pass. Stale entry is cached.
+
+ The issue is that Node 1 doesn't have an entry for the user, so it never receives an invalidation listener event from Node 2 thus it can't bump the version.  So, when node 1 goes to cache the user it is stale as the version number was never bumped.
+
+ So how is this issue fixed?  here is pseudo code:
+
+ 1. Node 1 calls cacheManager.getCurrentRevision() to get the current local version counter of that User
+ 2. Node 1 getCurrentRevision() pulls current counter for that user
+ 3. Node 1 getCurrentRevision() adds a "invalidation.key.userid" to invalidation cache.  Its just a marker. nothing else
+ 4. Node 2 update user
+ 5. Node 2 does a cache.remove(user) cache.remove(invalidation.key.userid)
+ 6. Node 1 receives invalidation event for invalidation.key.userid. Bumps the version counter for that user
+ 7. node 1 version check fails, it doesn't cache the user
+ *
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
@@ -139,6 +173,7 @@ public abstract class CacheManager {
 
     public void clear() {
         cache.clear();
+        revisions.clear();
     }
 
     public void addInvalidations(Predicate<Map.Entry<String, Revisioned>> predicate, Set<String> invalidations) {
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealm.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealm.java
index b93da32..7eab0eb 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealm.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedRealm.java
@@ -18,6 +18,7 @@
 package org.keycloak.models.cache.infinispan.entities;
 
 import org.keycloak.common.enums.SslRequired;
+import org.keycloak.component.ComponentModel;
 import org.keycloak.models.AuthenticationExecutionModel;
 import org.keycloak.models.AuthenticationFlowModel;
 import org.keycloak.models.AuthenticatorConfigModel;
@@ -29,19 +30,14 @@ import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.OTPPolicy;
 import org.keycloak.models.PasswordPolicy;
 import org.keycloak.models.RealmModel;
-import org.keycloak.models.RealmProvider;
 import org.keycloak.models.RequiredActionProviderModel;
 import org.keycloak.models.RequiredCredentialModel;
-import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserFederationMapperModel;
 import org.keycloak.models.UserFederationProviderModel;
-import org.keycloak.models.cache.infinispan.RealmCache;
 import org.keycloak.common.util.MultivaluedHashMap;
 
-import java.io.Serializable;
 import java.security.PrivateKey;
 import java.security.PublicKey;
-import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -93,6 +89,7 @@ public class CachedRealm extends AbstractRevisioned {
     protected PasswordPolicy passwordPolicy;
     protected OTPPolicy otpPolicy;
 
+    protected transient String keyId;
     protected transient PublicKey publicKey;
     protected String publicKeyPem;
     protected transient PrivateKey privateKey;
@@ -109,6 +106,9 @@ public class CachedRealm extends AbstractRevisioned {
 
     protected List<RequiredCredentialModel> requiredCredentials;
     protected List<UserFederationProviderModel> userFederationProviders;
+    protected MultivaluedHashMap<String, ComponentModel> componentsByParent = new MultivaluedHashMap<>();
+    protected MultivaluedHashMap<String, ComponentModel> componentsByParentAndType = new MultivaluedHashMap<>();
+    protected Map<String, ComponentModel> components = new HashMap<>();
     protected MultivaluedHashMap<String, UserFederationMapperModel> userFederationMappers = new MultivaluedHashMap<String, UserFederationMapperModel>();
     protected Set<UserFederationMapperModel> userFederationMapperSet;
     protected List<IdentityProviderModel> identityProviders;
@@ -189,6 +189,7 @@ public class CachedRealm extends AbstractRevisioned {
         passwordPolicy = model.getPasswordPolicy();
         otpPolicy = model.getOTPPolicy();
 
+        keyId = model.getKeyId();
         publicKeyPem = model.getPublicKeyPem();
         publicKey = model.getPublicKey();
         privateKeyPem = model.getPrivateKeyPem();
@@ -274,6 +275,16 @@ public class CachedRealm extends AbstractRevisioned {
         resetCredentialsFlow = model.getResetCredentialsFlow();
         clientAuthenticationFlow = model.getClientAuthenticationFlow();
 
+        for (ComponentModel component : model.getComponents()) {
+            componentsByParentAndType.add(component.getParentId() + component.getProviderType(), component);
+        }
+        for (ComponentModel component : model.getComponents()) {
+            componentsByParent.add(component.getParentId(), component);
+        }
+        for (ComponentModel component : model.getComponents()) {
+            components.put(component.getId(), component);
+        }
+
     }
 
     protected void cacheClientTemplates(RealmModel model) {
@@ -397,6 +408,10 @@ public class CachedRealm extends AbstractRevisioned {
         return accessCodeLifespanLogin;
     }
 
+    public String getKeyId() {
+        return keyId;
+    }
+
     public String getPublicKeyPem() {
         return publicKeyPem;
     }
@@ -592,4 +607,16 @@ public class CachedRealm extends AbstractRevisioned {
     public List<RequiredActionProviderModel> getRequiredActionProviderList() {
         return requiredActionProviderList;
     }
+
+    public MultivaluedHashMap<String, ComponentModel> getComponentsByParent() {
+        return componentsByParent;
+    }
+
+    public MultivaluedHashMap<String, ComponentModel> getComponentsByParentAndType() {
+        return componentsByParentAndType;
+    }
+
+    public Map<String, ComponentModel> getComponents() {
+        return components;
+    }
 }
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedUser.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedUser.java
index f37ecf1..89049ca 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedUser.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedUser.java
@@ -53,7 +53,6 @@ public class CachedUser extends AbstractRevisioned implements InRealm  {
     private Set<String> requiredActions = new HashSet<>();
     private Set<String> roleMappings = new HashSet<>();
     private Set<String> groups = new HashSet<>();
-    private Map<String, CachedUserConsent> consents = new HashMap<>(); // Key is client DB Id
 
 
 
@@ -82,13 +81,6 @@ public class CachedUser extends AbstractRevisioned implements InRealm  {
                 groups.add(group.getId());
             }
         }
-
-        List<UserConsentModel> consents = user.getConsents();
-        if (consents != null) {
-            for (UserConsentModel consent : consents) {
-                this.consents.put(consent.getClient().getId(), new CachedUserConsent(consent));
-            }
-        }
     }
 
     public String getRealm() {
@@ -155,7 +147,4 @@ public class CachedUser extends AbstractRevisioned implements InRealm  {
         return groups;
     }
 
-    public Map<String, CachedUserConsent> getConsents() {
-        return consents;
-    }
 }
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedUserConsents.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedUserConsents.java
new file mode 100644
index 0000000..eaca957
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/entities/CachedUserConsents.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.models.cache.infinispan.entities;
+
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserConsentModel;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class CachedUserConsents extends AbstractRevisioned implements InRealm {
+    private HashMap<String, CachedUserConsent> consents = new HashMap<>();
+    private final String realmId;
+
+    public CachedUserConsents(Long revision, String id, RealmModel realm,
+                              List<UserConsentModel> consents) {
+        super(revision, id);
+        this.realmId = realm.getId();
+        if (consents != null) {
+            for (UserConsentModel consent : consents) {
+                this.consents.put(consent.getClient().getId(), new CachedUserConsent(consent));
+            }
+        }
+    }
+
+    @Override
+    public String getRealm() {
+        return realmId;
+    }
+
+
+    public HashMap<String, CachedUserConsent> getConsents() {
+        return consents;
+    }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheRealmProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheRealmProviderFactory.java
index f32ac69..40c4e09 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheRealmProviderFactory.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheRealmProviderFactory.java
@@ -48,7 +48,7 @@ public class InfinispanCacheRealmProviderFactory implements CacheRealmProviderFa
             synchronized (this) {
                 if (realmCache == null) {
                     Cache<String, Revisioned> cache = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.REALM_CACHE_NAME);
-                    Cache<String, Long> revisions = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.VERSION_CACHE_NAME);
+                    Cache<String, Long> revisions = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.REALM_REVISIONS_CACHE_NAME);
                     realmCache = new RealmCacheManager(cache, revisions);
                 }
             }
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java
index 9e93d55..e0409b1 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/InfinispanCacheUserProviderFactory.java
@@ -55,7 +55,7 @@ public class InfinispanCacheUserProviderFactory implements CacheUserProviderFact
             synchronized (this) {
                 if (userCache == null) {
                     Cache<String, Revisioned> cache = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.USER_CACHE_NAME);
-                    Cache<String, Long> revisions = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.VERSION_CACHE_NAME);
+                    Cache<String, Long> revisions = session.getProvider(InfinispanConnectionProvider.class).getCache(InfinispanConnectionProvider.USER_REVISIONS_CACHE_NAME);
                     userCache = new UserCacheManager(cache, revisions);
                 }
             }
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java
index be67c49..8256aa2 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmAdapter.java
@@ -19,8 +19,9 @@ package org.keycloak.models.cache.infinispan;
 
 import org.keycloak.Config;
 import org.keycloak.common.enums.SslRequired;
+import org.keycloak.common.util.StringPropertyReplacer;
+import org.keycloak.component.ComponentModel;
 import org.keycloak.models.*;
-import org.keycloak.models.cache.CacheRealmProvider;
 import org.keycloak.models.cache.infinispan.entities.CachedRealm;
 import org.keycloak.models.utils.KeycloakModelUtils;
 
@@ -403,6 +404,12 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
+    public String getKeyId() {
+        if (isUpdated()) return updated.getKeyId();
+        return cached.getKeyId();
+    }
+
+    @Override
     public String getPublicKeyPem() {
         if (isUpdated()) return updated.getPublicKeyPem();
         return cached.getPublicKeyPem();
@@ -1402,6 +1409,60 @@ public class RealmAdapter implements RealmModel {
         return cacheSession.getClientTemplateById(id, this);
     }
 
+    @Override
+    public ComponentModel addComponentModel(ComponentModel model) {
+        getDelegateForUpdate();
+        return updated.addComponentModel(model);
+    }
+
+    @Override
+    public void updateComponent(ComponentModel component) {
+        getDelegateForUpdate();
+        updated.updateComponent(component);
+
+    }
+
+    @Override
+    public void removeComponent(ComponentModel component) {
+        getDelegateForUpdate();
+        updated.removeComponent(component);
 
+    }
 
+    @Override
+    public void removeComponents(String parentId) {
+        getDelegateForUpdate();
+        updated.removeComponents(parentId);
+
+    }
+
+    @Override
+    public List<ComponentModel> getComponents(String parentId, String providerType) {
+        if (isUpdated()) return updated.getComponents(parentId, providerType);
+        List<ComponentModel> components = cached.getComponentsByParentAndType().getList(parentId + providerType);
+        if (components == null) return Collections.EMPTY_LIST;
+        return Collections.unmodifiableList(components);
+    }
+
+    @Override
+    public List<ComponentModel> getComponents(String parentId) {
+        if (isUpdated()) return updated.getComponents(parentId);
+        List<ComponentModel> components = cached.getComponentsByParent().getList(parentId);
+        if (components == null) return Collections.EMPTY_LIST;
+        return Collections.unmodifiableList(components);
+    }
+
+    @Override
+    public List<ComponentModel> getComponents() {
+        if (isUpdated()) return updated.getComponents();
+        List<ComponentModel> results = new LinkedList<>();
+        results.addAll(cached.getComponents().values());
+         return Collections.unmodifiableList(results);
+    }
+
+    @Override
+    public ComponentModel getComponent(String id) {
+        if (isUpdated()) return updated.getComponent(id);
+        return cached.getComponents().get(id);
+    }
 }
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java
index 2a3880d..7a72964 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/RealmCacheSession.java
@@ -132,8 +132,8 @@ public class RealmCacheSession implements CacheRealmProvider {
         this.cache = cache;
         this.session = session;
         this.startupRevision = cache.getCurrentCounter();
-        session.getTransaction().enlistPrepare(getPrepareTransaction());
-        session.getTransaction().enlistAfterCompletion(getAfterTransaction());
+        session.getTransactionManager().enlistPrepare(getPrepareTransaction());
+        session.getTransactionManager().enlistAfterCompletion(getAfterTransaction());
     }
 
     public long getStartupRevision() {
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserAdapter.java
index 2b02cee..d697ad2 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserAdapter.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserAdapter.java
@@ -389,70 +389,6 @@ public class UserAdapter implements UserModel {
     }
 
     @Override
-    public void addConsent(UserConsentModel consent) {
-        getDelegateForUpdate();
-        updated.addConsent(consent);
-    }
-
-    @Override
-    public UserConsentModel getConsentByClient(String clientId) {
-        if (updated != null) return updated.getConsentByClient(clientId);
-        CachedUserConsent cachedConsent = cached.getConsents().get(clientId);
-        if (cachedConsent == null) {
-            return null;
-        }
-
-        return toConsentModel(cachedConsent);
-    }
-
-    @Override
-    public List<UserConsentModel> getConsents() {
-        if (updated != null) return updated.getConsents();
-        Collection<CachedUserConsent> cachedConsents = cached.getConsents().values();
-
-        List<UserConsentModel> result = new LinkedList<>();
-        for (CachedUserConsent cachedConsent : cachedConsents) {
-            UserConsentModel consent = toConsentModel(cachedConsent);
-            if (consent != null) {
-                result.add(consent);
-            }
-        }
-        return result;
-    }
-
-    @Override
-    public void updateConsent(UserConsentModel consent) {
-        getDelegateForUpdate();
-        updated.updateConsent(consent);
-    }
-
-    @Override
-    public boolean revokeConsentForClient(String clientId) {
-        getDelegateForUpdate();
-        return updated.revokeConsentForClient(clientId);
-    }
-
-    private UserConsentModel toConsentModel(CachedUserConsent cachedConsent) {
-        ClientModel client = keycloakSession.realms().getClientById(cachedConsent.getClientDbId(), realm);
-        if (client == null) {
-            return null;
-        }
-
-        UserConsentModel consentModel = new UserConsentModel(client);
-
-        for (String roleId : cachedConsent.getRoleIds()) {
-            RoleModel role = keycloakSession.realms().getRoleById(roleId, realm);
-            if (role != null) {
-                consentModel.addGrantedRole(role);
-            }
-        }
-        for (ProtocolMapperModel protocolMapper : cachedConsent.getProtocolMappers()) {
-            consentModel.addGrantedProtocolMapper(protocolMapper);
-        }
-        return consentModel;
-    }
-
-    @Override
     public boolean equals(Object o) {
         if (this == o) return true;
         if (o == null || !(o instanceof UserModel)) return false;
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheManager.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheManager.java
index e1fb79c..d3564d0 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheManager.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheManager.java
@@ -45,6 +45,7 @@ public class UserCacheManager extends CacheManager {
     @Override
     public void clear() {
         cache.clear();
+        revisions.clear();
     }
 
     @Override
diff --git a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheSession.java b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheSession.java
index 1a489ad..8a62c33 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheSession.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/cache/infinispan/UserCacheSession.java
@@ -19,6 +19,7 @@ package org.keycloak.models.cache.infinispan;
 
 import org.jboss.logging.Logger;
 import org.keycloak.common.constants.ServiceAccountConstants;
+import org.keycloak.component.ComponentModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.CredentialValidationOutput;
 import org.keycloak.models.FederatedIdentityModel;
@@ -28,6 +29,7 @@ import org.keycloak.models.KeycloakTransaction;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserConsentModel;
 import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserModel;
@@ -35,6 +37,8 @@ import org.keycloak.models.UserProvider;
 import org.keycloak.models.cache.CacheUserProvider;
 import org.keycloak.models.cache.infinispan.entities.CachedFederatedIdentityLinks;
 import org.keycloak.models.cache.infinispan.entities.CachedUser;
+import org.keycloak.models.cache.infinispan.entities.CachedUserConsent;
+import org.keycloak.models.cache.infinispan.entities.CachedUserConsents;
 import org.keycloak.models.cache.infinispan.entities.UserListQuery;
 
 import java.util.*;
@@ -61,7 +65,7 @@ public class UserCacheSession implements CacheUserProvider {
         this.cache = cache;
         this.session = session;
         this.startupRevision = cache.getCurrentCounter();
-        session.getTransaction().enlistAfterCompletion(getTransaction());
+        session.getTransactionManager().enlistAfterCompletion(getTransaction());
     }
 
     @Override
@@ -73,7 +77,7 @@ public class UserCacheSession implements CacheUserProvider {
     public UserProvider getDelegate() {
         if (!transactionActive) throw new IllegalStateException("Cannot access delegate without a transaction");
         if (delegate != null) return delegate;
-        delegate = session.getProvider(UserProvider.class);
+        delegate = session.userStorageManager();
 
         return delegate;
     }
@@ -342,7 +346,7 @@ public class UserCacheSession implements CacheUserProvider {
     }
 
     @Override
-    public UserModel getUserByServiceAccountClient(ClientModel client) {
+    public UserModel getServiceAccount(ClientModel client) {
         // Just an attempt to find the user from cache by default serviceAccount username
         String username = ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + client.getClientId();
         UserModel user = getUserByUsername(username, client.getRealm());
@@ -350,7 +354,7 @@ public class UserCacheSession implements CacheUserProvider {
             return user;
         }
 
-        return getDelegate().getUserByServiceAccountClient(client);
+        return getDelegate().getServiceAccount(client);
     }
 
     @Override
@@ -369,6 +373,16 @@ public class UserCacheSession implements CacheUserProvider {
     }
 
     @Override
+    public List<UserModel> getUsers(RealmModel realm) {
+        return getUsers(realm, false);
+    }
+
+    @Override
+    public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) {
+        return getUsers(realm, firstResult, maxResults, false);
+    }
+
+    @Override
     public List<UserModel> searchForUser(String search, RealmModel realm) {
         return getDelegate().searchForUser(search, realm);
     }
@@ -379,13 +393,13 @@ public class UserCacheSession implements CacheUserProvider {
     }
 
     @Override
-    public List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm) {
-        return getDelegate().searchForUserByAttributes(attributes, realm);
+    public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm) {
+        return getDelegate().searchForUser(attributes, realm);
     }
 
     @Override
-    public List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
-        return getDelegate().searchForUserByAttributes(attributes, realm, firstResult, maxResults);
+    public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
+        return getDelegate().searchForUser(attributes, realm, firstResult, maxResults);
     }
 
     @Override
@@ -434,6 +448,101 @@ public class UserCacheSession implements CacheUserProvider {
     }
 
     @Override
+    public void updateConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
+        invalidations.add(getConsentCacheKey(user.getId()));
+        getDelegate().updateConsent(realm, user, consent);
+    }
+
+    @Override
+    public boolean revokeConsentForClient(RealmModel realm, UserModel user, String clientInternalId) {
+        invalidations.add(getConsentCacheKey(user.getId()));
+        return getDelegate().revokeConsentForClient(realm, user, clientInternalId);
+    }
+
+    public String getConsentCacheKey(String userId) {
+        return userId + ".consents";
+    }
+
+
+    @Override
+    public void addConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
+        invalidations.add(getConsentCacheKey(user.getId()));
+        getDelegate().addConsent(realm, user, consent);
+    }
+
+    @Override
+    public UserConsentModel getConsentByClient(RealmModel realm, UserModel user, String clientId) {
+        logger.tracev("getConsentByClient: {0}", user.getUsername());
+
+        String cacheKey = getConsentCacheKey(user.getId());
+        if (realmInvalidations.contains(realm.getId()) || invalidations.contains(user.getId()) || invalidations.contains(cacheKey)) {
+            return getDelegate().getConsentByClient(realm, user, clientId);
+        }
+
+        CachedUserConsents cached = cache.get(cacheKey, CachedUserConsents.class);
+
+        if (cached == null) {
+            Long loaded = cache.getCurrentRevision(cacheKey);
+            List<UserConsentModel> consents = getDelegate().getConsents(realm, user);
+            cached = new CachedUserConsents(loaded, cacheKey, realm, consents);
+            cache.addRevisioned(cached, startupRevision);
+        }
+        CachedUserConsent cachedConsent = cached.getConsents().get(clientId);
+        if (cachedConsent == null) return null;
+        return toConsentModel(realm, cachedConsent);
+    }
+
+    @Override
+    public List<UserConsentModel> getConsents(RealmModel realm, UserModel user) {
+        logger.tracev("getConsents: {0}", user.getUsername());
+
+        String cacheKey = getConsentCacheKey(user.getId());
+        if (realmInvalidations.contains(realm.getId()) || invalidations.contains(user.getId()) || invalidations.contains(cacheKey)) {
+            return getDelegate().getConsents(realm, user);
+        }
+
+        CachedUserConsents cached = cache.get(cacheKey, CachedUserConsents.class);
+
+        if (cached == null) {
+            Long loaded = cache.getCurrentRevision(cacheKey);
+            List<UserConsentModel> consents = getDelegate().getConsents(realm, user);
+            cached = new CachedUserConsents(loaded, cacheKey, realm, consents);
+            cache.addRevisioned(cached, startupRevision);
+            return consents;
+        } else {
+            List<UserConsentModel> result = new LinkedList<>();
+            for (CachedUserConsent cachedConsent : cached.getConsents().values()) {
+                UserConsentModel consent = toConsentModel(realm, cachedConsent);
+                if (consent != null) {
+                    result.add(consent);
+                }
+            }
+            return result;
+        }
+    }
+
+    private UserConsentModel toConsentModel(RealmModel realm, CachedUserConsent cachedConsent) {
+        ClientModel client = session.realms().getClientById(cachedConsent.getClientDbId(), realm);
+        if (client == null) {
+            return null;
+        }
+
+        UserConsentModel consentModel = new UserConsentModel(client);
+
+        for (String roleId : cachedConsent.getRoleIds()) {
+            RoleModel role = session.realms().getRoleById(roleId, realm);
+            if (role != null) {
+                consentModel.addGrantedRole(role);
+            }
+        }
+        for (ProtocolMapperModel protocolMapper : cachedConsent.getProtocolMappers()) {
+            consentModel.addGrantedProtocolMapper(protocolMapper);
+        }
+        return consentModel;
+    }
+
+
+    @Override
     public UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions) {
         UserModel user = getDelegate().addUser(realm, id, username, addDefaultRoles, addDefaultRoles);
         // just in case the transaction is rolled back you need to invalidate the user and all cache queries for that user
@@ -554,4 +663,10 @@ public class UserCacheSession implements CacheUserProvider {
     public void preRemove(ProtocolMapperModel protocolMapper) {
         getDelegate().preRemove(protocolMapper);
     }
+
+    @Override
+    public void preRemove(RealmModel realm, ComponentModel component) {
+        getDelegate().preRemove(realm, component);
+
+    }
 }
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/ClientRegistrationTrustedHostAdapter.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/ClientRegistrationTrustedHostAdapter.java
new file mode 100644
index 0000000..34e68cc
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/ClientRegistrationTrustedHostAdapter.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.sessions.infinispan;
+
+import org.infinispan.Cache;
+import org.keycloak.models.ClientRegistrationTrustedHostModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.sessions.infinispan.entities.ClientRegistrationTrustedHostEntity;
+import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ClientRegistrationTrustedHostAdapter implements ClientRegistrationTrustedHostModel {
+
+    private final KeycloakSession session;
+    private final InfinispanUserSessionProvider provider;
+    private final Cache<String, SessionEntity> cache;
+    private final RealmModel realm;
+    private final ClientRegistrationTrustedHostEntity entity;
+
+    public ClientRegistrationTrustedHostAdapter(KeycloakSession session, InfinispanUserSessionProvider provider, Cache<String, SessionEntity> cache, RealmModel realm, ClientRegistrationTrustedHostEntity entity) {
+        this.session = session;
+        this.provider = provider;
+        this.cache = cache;
+        this.realm = realm;
+        this.entity = entity;
+    }
+
+    @Override
+    public RealmModel getRealm() {
+        return realm;
+    }
+
+    @Override
+    public String getHostName() {
+        return entity.getHostName();
+    }
+
+    @Override
+    public int getCount() {
+        return entity.getCount();
+    }
+
+    @Override
+    public void setCount(int count) {
+        entity.setCount(count);
+        update();
+    }
+
+    @Override
+    public int getRemainingCount() {
+        return entity.getRemainingCount();
+    }
+
+    @Override
+    public void setRemainingCount(int remainingCount) {
+        entity.setRemainingCount(remainingCount);
+        update();
+    }
+
+    @Override
+    public void decreaseRemainingCount() {
+        entity.setRemainingCount(entity.getRemainingCount() - 1);
+        update();
+    }
+
+    void update() {
+        provider.getTx().replace(cache, entity.getId(), entity);
+    }
+}
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureEntity.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureEntity.java
index 65db3a8..d25f58b 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureEntity.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureEntity.java
@@ -24,19 +24,19 @@ import java.io.Serializable;
  */
 public class LoginFailureEntity implements Serializable {
 
-    private String username;
+    private String userId;
     private String realm;
     private int failedLoginNotBefore;
     private int numFailures;
     private long lastFailure;
     private String lastIPFailure;
 
-    public String getUsername() {
-        return username;
+    public String getUserId() {
+        return userId;
     }
 
-    public void setUsername(String username) {
-        this.username = username;
+    public void setUserId(String userId) {
+        this.userId = userId;
     }
 
     public String getRealm() {
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureKey.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureKey.java
index 21dc463..c452379 100644
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureKey.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/entities/LoginFailureKey.java
@@ -25,11 +25,11 @@ import java.io.Serializable;
 public class LoginFailureKey implements Serializable {
 
     private final String realm;
-    private final String username;
+    private final String userId;
 
-    public LoginFailureKey(String realm, String username) {
+    public LoginFailureKey(String realm, String userId) {
         this.realm = realm;
-        this.username = username;
+        this.userId = userId;
     }
 
     @Override
@@ -40,7 +40,7 @@ public class LoginFailureKey implements Serializable {
         LoginFailureKey key = (LoginFailureKey) o;
 
         if (realm != null ? !realm.equals(key.realm) : key.realm != null) return false;
-        if (username != null ? !username.equals(key.username) : key.username != null) return false;
+        if (userId != null ? !userId.equals(key.userId) : key.userId != null) return false;
 
         return true;
     }
@@ -48,7 +48,7 @@ public class LoginFailureKey implements Serializable {
     @Override
     public int hashCode() {
         int result = realm != null ? realm.hashCode() : 0;
-        result = 31 * result + (username != null ? username.hashCode() : 0);
+        result = 31 * result + (userId != null ? userId.hashCode() : 0);
         return result;
     }
 
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java
index 10d6205..5452869 100755
--- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java
@@ -23,22 +23,26 @@ import org.jboss.logging.Logger;
 import org.keycloak.common.util.Time;
 import org.keycloak.models.ClientInitialAccessModel;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientRegistrationTrustedHostModel;
 import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakTransaction;
+import org.keycloak.models.ModelDuplicateException;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.models.UserSessionProvider;
-import org.keycloak.models.UsernameLoginFailureModel;
+import org.keycloak.models.UserLoginFailureModel;
 import org.keycloak.models.session.UserSessionPersisterProvider;
 import org.keycloak.models.sessions.infinispan.entities.ClientInitialAccessEntity;
+import org.keycloak.models.sessions.infinispan.entities.ClientRegistrationTrustedHostEntity;
 import org.keycloak.models.sessions.infinispan.entities.ClientSessionEntity;
 import org.keycloak.models.sessions.infinispan.entities.LoginFailureEntity;
 import org.keycloak.models.sessions.infinispan.entities.LoginFailureKey;
 import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
 import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
 import org.keycloak.models.sessions.infinispan.stream.ClientInitialAccessPredicate;
+import org.keycloak.models.sessions.infinispan.stream.ClientRegistrationTrustedHostPredicate;
 import org.keycloak.models.sessions.infinispan.stream.ClientSessionPredicate;
 import org.keycloak.models.sessions.infinispan.stream.Comparators;
 import org.keycloak.models.sessions.infinispan.stream.Mappers;
@@ -81,7 +85,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
         this.loginFailureCache = loginFailureCache;
         this.tx = new InfinispanKeycloakTransaction();
 
-        session.getTransaction().enlistAfterCompletion(tx);
+        session.getTransactionManager().enlistAfterCompletion(tx);
     }
 
     protected Cache<String, SessionEntity> getCache(boolean offline) {
@@ -377,24 +381,24 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
     }
 
     @Override
-    public UsernameLoginFailureModel getUserLoginFailure(RealmModel realm, String username) {
-        LoginFailureKey key = new LoginFailureKey(realm.getId(), username);
+    public UserLoginFailureModel getUserLoginFailure(RealmModel realm, String userId) {
+        LoginFailureKey key = new LoginFailureKey(realm.getId(), userId);
         return wrap(key, loginFailureCache.get(key));
     }
 
     @Override
-    public UsernameLoginFailureModel addUserLoginFailure(RealmModel realm, String username) {
-        LoginFailureKey key = new LoginFailureKey(realm.getId(), username);
+    public UserLoginFailureModel addUserLoginFailure(RealmModel realm, String userId) {
+        LoginFailureKey key = new LoginFailureKey(realm.getId(), userId);
         LoginFailureEntity entity = new LoginFailureEntity();
         entity.setRealm(realm.getId());
-        entity.setUsername(username);
+        entity.setUserId(userId);
         tx.put(loginFailureCache, key, entity);
         return wrap(key, entity);
     }
 
     @Override
-    public void removeUserLoginFailure(RealmModel realm, String username) {
-        tx.remove(loginFailureCache, new LoginFailureKey(realm.getId(), username));
+    public void removeUserLoginFailure(RealmModel realm, String userId) {
+        tx.remove(loginFailureCache, new LoginFailureKey(realm.getId(), userId));
     }
 
     @Override
@@ -537,9 +541,14 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
         return entity != null ? new ClientInitialAccessAdapter(session, this, cache, realm, entity) : null;
     }
 
+    ClientRegistrationTrustedHostAdapter wrap(RealmModel realm, ClientRegistrationTrustedHostEntity entity) {
+        Cache<String, SessionEntity> cache = getCache(false);
+        return entity != null ? new ClientRegistrationTrustedHostAdapter(session, this, cache, realm, entity) : null;
+    }
+
 
-    UsernameLoginFailureModel wrap(LoginFailureKey key, LoginFailureEntity entity) {
-        return entity != null ? new UsernameLoginFailureAdapter(this, loginFailureCache, key, entity) : null;
+    UserLoginFailureModel wrap(LoginFailureKey key, LoginFailureEntity entity) {
+        return entity != null ? new UserLoginFailureAdapter(this, loginFailureCache, key, entity) : null;
     }
 
     List<ClientSessionModel> wrapClientSessions(RealmModel realm, Collection<ClientSessionEntity> entities, boolean offline) {
@@ -729,6 +738,63 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
         return list;
     }
 
+    @Override
+    public ClientRegistrationTrustedHostModel createClientRegistrationTrustedHostModel(RealmModel realm, String hostName, int count) {
+        if (getClientRegistrationTrustedHostModel(realm, hostName) != null) {
+            throw new ModelDuplicateException("Client registration already exists for this realm and hostName");
+        }
+
+        String id = computeClientRegistrationTrustedHostEntityId(realm, hostName);
+
+        ClientRegistrationTrustedHostEntity entity = new ClientRegistrationTrustedHostEntity();
+        entity.setId(id);
+        entity.setHostName(hostName);
+        entity.setRealm(realm.getId());
+        entity.setCount(count);
+        entity.setRemainingCount(count);
+
+        tx.put(sessionCache, id, entity);
+
+        return wrap(realm, entity);
+    }
+
+    @Override
+    public ClientRegistrationTrustedHostModel getClientRegistrationTrustedHostModel(RealmModel realm, String hostName) {
+        String id = computeClientRegistrationTrustedHostEntityId(realm, hostName);
+
+        Cache<String, SessionEntity> cache = getCache(false);
+        ClientRegistrationTrustedHostEntity entity = (ClientRegistrationTrustedHostEntity) cache.get(id);
+
+        // If created in this transaction
+        if (entity == null) {
+            entity = (ClientRegistrationTrustedHostEntity) tx.get(cache, id);
+        }
+
+        return wrap(realm, entity);
+    }
+
+    @Override
+    public void removeClientRegistrationTrustedHostModel(RealmModel realm, String hostName) {
+        String id = computeClientRegistrationTrustedHostEntityId(realm, hostName);
+        tx.remove(getCache(false), id);
+    }
+
+    @Override
+    public List<ClientRegistrationTrustedHostModel> listClientRegistrationTrustedHosts(RealmModel realm) {
+        Iterator<Map.Entry<String, SessionEntity>> itr = sessionCache.entrySet().stream().filter(ClientRegistrationTrustedHostPredicate.create(realm.getId())).iterator();
+        List<ClientRegistrationTrustedHostModel> list = new LinkedList<>();
+        while (itr.hasNext()) {
+            list.add(wrap(realm, (ClientRegistrationTrustedHostEntity) itr.next().getValue()));
+        }
+        return list;
+    }
+
+    private static final String CLIENT_REG_TRUSTED_HOST_ID_PREFIX = "reg:::";
+
+    private String computeClientRegistrationTrustedHostEntityId(RealmModel realm, String hostName) {
+        return CLIENT_REG_TRUSTED_HOST_ID_PREFIX + realm.getId() + ":::" + hostName;
+    }
+
     class InfinispanKeycloakTransaction implements KeycloakTransaction {
 
         private boolean active;
diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/ClientRegistrationTrustedHostPredicate.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/ClientRegistrationTrustedHostPredicate.java
new file mode 100644
index 0000000..8663c4e
--- /dev/null
+++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/ClientRegistrationTrustedHostPredicate.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.sessions.infinispan.stream;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.function.Predicate;
+
+import org.keycloak.models.sessions.infinispan.entities.ClientRegistrationTrustedHostEntity;
+import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ClientRegistrationTrustedHostPredicate implements Predicate<Map.Entry<String, SessionEntity>>, Serializable {
+
+    public static ClientRegistrationTrustedHostPredicate create(String realm) {
+        return new ClientRegistrationTrustedHostPredicate(realm);
+    }
+
+    private ClientRegistrationTrustedHostPredicate(String realm) {
+        this.realm = realm;
+    }
+
+    private String realm;
+
+
+    @Override
+    public boolean test(Map.Entry<String, SessionEntity> entry) {
+        SessionEntity e = entry.getValue();
+
+        if (!realm.equals(e.getRealm())) {
+            return false;
+        }
+
+        if (!(e instanceof ClientRegistrationTrustedHostEntity)) {
+            return false;
+        }
+
+        return true;
+    }
+
+}
diff --git a/model/infinispan/src/main/resources/META-INF/services/org.keycloak.models.cache.authorization.CachedStoreProviderFactory b/model/infinispan/src/main/resources/META-INF/services/org.keycloak.models.cache.authorization.CachedStoreProviderFactory
new file mode 100644
index 0000000..0a46bb3
--- /dev/null
+++ b/model/infinispan/src/main/resources/META-INF/services/org.keycloak.models.cache.authorization.CachedStoreProviderFactory
@@ -0,0 +1,19 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2016 Red Hat, Inc., and individual contributors
+# as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.keycloak.models.authorization.infinispan.InfinispanStoreProviderFactory
\ No newline at end of file
diff --git a/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/ClusteredCacheBehaviorTest.java b/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/ClusteredCacheBehaviorTest.java
index 3dcc913..de6e587 100755
--- a/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/ClusteredCacheBehaviorTest.java
+++ b/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/ClusteredCacheBehaviorTest.java
@@ -29,6 +29,8 @@ import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
 @Ignore
 public class ClusteredCacheBehaviorTest {
     public EmbeddedCacheManager createManager() {
+        System.setProperty("java.net.preferIPv4Stack", "true");
+        System.setProperty("jgroups.tcp.port", "53715");
         GlobalConfigurationBuilder gcb = new GlobalConfigurationBuilder();
 
         boolean clustered = true;
@@ -36,7 +38,8 @@ public class ClusteredCacheBehaviorTest {
         boolean allowDuplicateJMXDomains = true;
 
         if (clustered) {
-            gcb.transport().defaultTransport();
+            gcb = gcb.clusteredDefault();
+            gcb.transport().clusterName("test-clustering");
         }
         gcb.globalJmxStatistics().allowDuplicateDomains(allowDuplicateJMXDomains);
 
diff --git a/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/OutdatedTopologyExceptionReproducerTest.java b/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/OutdatedTopologyExceptionReproducerTest.java
new file mode 100644
index 0000000..9802934
--- /dev/null
+++ b/model/infinispan/src/test/java/org/keycloak/models/sessions/infinispan/initializer/OutdatedTopologyExceptionReproducerTest.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.sessions.infinispan.initializer;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.infinispan.Cache;
+import org.infinispan.configuration.cache.CacheMode;
+import org.infinispan.configuration.cache.Configuration;
+import org.infinispan.configuration.cache.ConfigurationBuilder;
+import org.infinispan.configuration.global.GlobalConfigurationBuilder;
+import org.infinispan.interceptors.locking.NonTransactionalLockingInterceptor;
+import org.infinispan.manager.DefaultCacheManager;
+import org.infinispan.manager.EmbeddedCacheManager;
+import org.infinispan.statetransfer.StateTransferInterceptor;
+import org.jboss.logging.Logger;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
+
+/**
+ * Reproducer for KEYCLOAK-3306. Uncomment the snippet for adding StateTransferInterceptor to have test fixed.
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@Ignore
+public class OutdatedTopologyExceptionReproducerTest {
+
+    protected static final Logger logger = Logger.getLogger(OutdatedTopologyExceptionReproducerTest.class);
+
+    private static final int THREADS_COUNT = 20;
+
+    @Test
+    public void testListener() throws Exception {
+        EmbeddedCacheManager node1 = null;
+        EmbeddedCacheManager node2 = null;
+
+        try {
+            node1 = createManager();
+            Cache<String, Object> node1Cache = node1.getCache(InfinispanConnectionProvider.REALM_CACHE_NAME);
+            logger.info("Node1Cache started");
+
+            List<CacheOperations> cacheOpsList = new ArrayList<>();
+            AtomicReference<Exception> exceptionHolder = new AtomicReference<>();
+
+            for (int i=0 ; i<THREADS_COUNT ; i++) {
+                String key = "key-" + i;
+                CacheOperations cacheOps = new CacheOperations(node1Cache, key, exceptionHolder);
+                cacheOps.start();
+                cacheOpsList.add(cacheOps);
+            }
+            logger.infof("All CacheOperations threads started");
+
+            node2 = createManager();
+            Cache<String, Object> node2Cache = node2.getCache(InfinispanConnectionProvider.REALM_CACHE_NAME);
+            logger.info("Node2Cache started");
+
+            for (CacheOperations cacheOps : cacheOpsList) {
+                cacheOps.stopMe();
+            }
+            for (CacheOperations cacheOps : cacheOpsList) {
+                cacheOps.join();
+            }
+
+            logger.info("All CacheOperations threads stopped");
+
+            Exception ex = exceptionHolder.get();
+            if (ex != null) {
+                Assert.fail("Some exception was thrown. It was: " + ex.getClass().getName() + ": " + ex.getMessage());
+            }
+
+            logger.info("Test finished successfuly");
+        } finally {
+            node2.stop();
+            node1.stop();
+        }
+    }
+
+    private EmbeddedCacheManager createManager() {
+        System.setProperty("java.net.preferIPv4Stack", "true");
+        System.setProperty("jgroups.tcp.port", "53715");
+        GlobalConfigurationBuilder gcb = new GlobalConfigurationBuilder();
+
+        boolean clustered = true;
+        boolean async = false;
+        boolean allowDuplicateJMXDomains = true;
+
+        if (clustered) {
+            gcb = gcb.clusteredDefault();
+            gcb.transport().clusterName("test-clustering");
+        }
+
+        gcb.globalJmxStatistics().allowDuplicateDomains(allowDuplicateJMXDomains);
+
+        EmbeddedCacheManager cacheManager = new DefaultCacheManager(gcb.build());
+
+
+        ConfigurationBuilder invalidationConfigBuilder = new ConfigurationBuilder();
+        if (clustered) {
+            invalidationConfigBuilder.clustering().cacheMode(async ? CacheMode.INVALIDATION_ASYNC : CacheMode.INVALIDATION_SYNC);
+        }
+
+        // Uncomment this to have test fixed!!!
+//        invalidationConfigBuilder.customInterceptors()
+//                .addInterceptor()
+//                .before(NonTransactionalLockingInterceptor.class)
+//                .interceptorClass(StateTransferInterceptor.class);
+
+        Configuration invalidationCacheConfiguration = invalidationConfigBuilder.build();
+
+        cacheManager.defineConfiguration(InfinispanConnectionProvider.REALM_CACHE_NAME, invalidationCacheConfiguration);
+        return cacheManager;
+
+    }
+
+    private class CacheOperations extends Thread {
+
+        private final Cache<String, Object> cache;
+        private final AtomicBoolean stopped = new AtomicBoolean(false);
+        private final AtomicReference<Exception> exceptionHolder;
+        private final String key;
+
+        public CacheOperations(Cache<String, Object> cache, String key, AtomicReference<Exception> exceptionHolder) {
+            this.cache = cache;
+            this.key = key;
+            this.exceptionHolder = exceptionHolder;
+        }
+
+        @Override
+        public void run() {
+            try {
+                while (!stopped.get()) {
+                    cache.putForExternalRead(key, new Object());
+                    cache.remove(key);
+                }
+            } catch (Exception e) {
+                exceptionHolder.set(e);
+                throw e;
+            }
+        }
+
+        public void stopMe() {
+            stopped.set(true);
+        }
+
+    }
+}

model/jpa/pom.xml 12(+11 -1)

diff --git a/model/jpa/pom.xml b/model/jpa/pom.xml
index c1176f3..4765a7a 100755
--- a/model/jpa/pom.xml
+++ b/model/jpa/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
@@ -30,6 +30,11 @@
     <name>Keycloak Model JPA</name>
     <description/>
 
+    <properties>
+        <maven.compiler.target>1.8</maven.compiler.target>
+        <maven.compiler.source>1.8</maven.compiler.source>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>org.bouncycastle</groupId>
@@ -97,6 +102,11 @@
             <artifactId>jackson-core</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/PolicyEntity.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/PolicyEntity.java
new file mode 100644
index 0000000..540dc31
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/PolicyEntity.java
@@ -0,0 +1,253 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.jpa.entities;
+
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.models.entities.AbstractIdentifiableEntity;
+import org.keycloak.representations.idm.authorization.DecisionStrategy;
+import org.keycloak.representations.idm.authorization.Logic;
+
+import javax.persistence.Access;
+import javax.persistence.AccessType;
+import javax.persistence.CollectionTable;
+import javax.persistence.Column;
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.MapKeyColumn;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@Entity
+@Table(name = "RESOURCE_SERVER_POLICY", uniqueConstraints = {
+        @UniqueConstraint(columnNames = {"NAME", "RESOURCE_SERVER_ID"})
+})
+public class PolicyEntity implements Policy {
+
+    @Id
+    @Column(name="ID", length = 36)
+    @Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity.  This avoids an extra SQL
+    private String id;
+
+    @Column(name = "NAME")
+    private String name;
+
+    @Column(name = "DESCRIPTION")
+    private String description;
+
+    @Column(name = "TYPE")
+    private String type;
+
+    @Column(name = "DECISION_STRATEGY")
+    private DecisionStrategy decisionStrategy = DecisionStrategy.UNANIMOUS;
+
+    @Column(name = "LOGIC")
+    private Logic logic = Logic.POSITIVE;
+
+    @ElementCollection
+    @MapKeyColumn(name="NAME")
+    @Column(name="VALUE", columnDefinition = "TEXT")
+    @CollectionTable(name="POLICY_CONFIG", joinColumns={ @JoinColumn(name="POLICY_ID") })
+    private Map<String, String> config = new HashMap();
+
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "RESOURCE_SERVER_ID")
+    private ResourceServerEntity resourceServer;
+
+    @ManyToMany(fetch = FetchType.LAZY, cascade = {})
+    @JoinTable(name = "ASSOCIATED_POLICY", joinColumns = @JoinColumn(name = "POLICY_ID"), inverseJoinColumns = @JoinColumn(name = "ASSOCIATED_POLICY_ID"))
+    private Set<PolicyEntity> associatedPolicies = new HashSet<>();
+
+    @ManyToMany(fetch = FetchType.LAZY, cascade = {})
+    @JoinTable(name = "RESOURCE_POLICY", joinColumns = @JoinColumn(name = "POLICY_ID"), inverseJoinColumns = @JoinColumn(name = "RESOURCE_ID"))
+    private Set<ResourceEntity> resources = new HashSet<>();
+
+    @ManyToMany(fetch = FetchType.EAGER, cascade = {})
+    @JoinTable(name = "SCOPE_POLICY", joinColumns = @JoinColumn(name = "POLICY_ID"), inverseJoinColumns = @JoinColumn(name = "SCOPE_ID"))
+    private Set<ScopeEntity> scopes = new HashSet<>();
+
+    @Override
+    public String getId() {
+        return this.id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    @Override
+    public String getType() {
+        return this.type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    @Override
+    public DecisionStrategy getDecisionStrategy() {
+        return this.decisionStrategy;
+    }
+
+    @Override
+    public void setDecisionStrategy(DecisionStrategy decisionStrategy) {
+        this.decisionStrategy = decisionStrategy;
+    }
+
+    @Override
+    public Logic getLogic() {
+        return this.logic;
+    }
+
+    @Override
+    public void setLogic(Logic logic) {
+        this.logic = logic;
+    }
+
+    @Override
+    public Map<String, String> getConfig() {
+        return this.config;
+    }
+
+    @Override
+    public void setConfig(Map<String, String> config) {
+        this.config = config;
+    }
+
+    @Override
+    public String getName() {
+        return this.name;
+    }
+
+    @Override
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String getDescription() {
+        return this.description;
+    }
+
+    @Override
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    @Override
+    public ResourceServerEntity getResourceServer() {
+        return this.resourceServer;
+    }
+
+    public void setResourceServer(ResourceServerEntity resourceServer) {
+        this.resourceServer = resourceServer;
+    }
+
+    @Override
+    public <P extends Policy> Set<P> getAssociatedPolicies() {
+        return (Set<P>) this.associatedPolicies;
+    }
+
+    public void setAssociatedPolicies(Set<PolicyEntity> associatedPolicies) {
+        this.associatedPolicies = associatedPolicies;
+    }
+
+    @Override
+    public Set<ResourceEntity> getResources() {
+        return this.resources;
+    }
+
+    public void setResources(Set<ResourceEntity> resources) {
+        this.resources = resources;
+    }
+
+    @Override
+    public Set<ScopeEntity> getScopes() {
+        return this.scopes;
+    }
+
+    public void setScopes(Set<ScopeEntity> scopes) {
+        this.scopes = scopes;
+    }
+
+    @Override
+    public void addScope(Scope scope) {
+        getScopes().add((ScopeEntity) scope);
+    }
+
+    @Override
+    public void removeScope(Scope scope) {
+        getScopes().remove(scope);
+    }
+
+    @Override
+    public void addAssociatedPolicy(Policy associatedPolicy) {
+        getAssociatedPolicies().add(associatedPolicy);
+    }
+
+    @Override
+    public void removeAssociatedPolicy(Policy associatedPolicy) {
+        getAssociatedPolicies().remove(associatedPolicy);
+    }
+
+    @Override
+    public void addResource(Resource resource) {
+        getResources().add((ResourceEntity) resource);
+    }
+
+    @Override
+    public void removeResource(Resource resource) {
+        getResources().remove(resource);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) return true;
+
+        if (this.id == null) return false;
+
+        if (!Policy.class.isInstance(o)) return false;
+
+        Policy that = (Policy) o;
+
+        if (!getId().equals(that.getId())) return false;
+
+        return true;
+
+    }
+
+    @Override
+    public int hashCode() {
+        return id!=null ? id.hashCode() : super.hashCode();
+    }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceEntity.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceEntity.java
new file mode 100644
index 0000000..7cb1a6f
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceEntity.java
@@ -0,0 +1,190 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.jpa.entities;
+
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.Scope;
+
+import javax.persistence.Access;
+import javax.persistence.AccessType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@Entity
+@Table(name = "RESOURCE_SERVER_RESOURCE", uniqueConstraints = {
+        @UniqueConstraint(columnNames = {"NAME", "RESOURCE_SERVER_ID", "OWNER"})
+})
+public class ResourceEntity implements Resource {
+
+    @Id
+    @Column(name="ID", length = 36)
+    @Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity.  This avoids an extra SQL
+    private String id;
+
+    @Column(name = "NAME")
+    private String name;
+
+    @Column(name = "URI")
+    private String uri;
+
+    @Column(name = "TYPE")
+    private String type;
+
+    @Column(name = "ICON_URI")
+    private String iconUri;
+
+    @Column(name = "OWNER")
+    private String owner;
+
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "RESOURCE_SERVER_ID")
+    private ResourceServerEntity resourceServer;
+
+    @ManyToMany(fetch = FetchType.LAZY, cascade = {})
+    @JoinTable(name = "RESOURCE_SCOPE", joinColumns = @JoinColumn(name = "RESOURCE_ID"), inverseJoinColumns = @JoinColumn(name = "SCOPE_ID"))
+    private List<ScopeEntity> scopes = new ArrayList<>();
+
+    @ManyToMany(fetch = FetchType.LAZY, cascade = {})
+    @JoinTable(name = "RESOURCE_POLICY", joinColumns = @JoinColumn(name = "RESOURCE_ID"), inverseJoinColumns = @JoinColumn(name = "POLICY_ID"))
+    private List<PolicyEntity> policies = new ArrayList<>();
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String getUri() {
+        return uri;
+    }
+
+    @Override
+    public void setUri(String uri) {
+        this.uri = uri;
+    }
+
+    @Override
+    public String getType() {
+        return type;
+    }
+
+    @Override
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    @Override
+    public List<ScopeEntity> getScopes() {
+        return this.scopes;
+    }
+
+    @Override
+    public String getIconUri() {
+        return iconUri;
+    }
+
+    @Override
+    public void setIconUri(String iconUri) {
+        this.iconUri = iconUri;
+    }
+
+    @Override
+    public ResourceServerEntity getResourceServer() {
+        return resourceServer;
+    }
+
+    public void setResourceServer(ResourceServerEntity resourceServer) {
+        this.resourceServer = resourceServer;
+    }
+
+    public String getOwner() {
+        return this.owner;
+    }
+
+    public void setOwner(String owner) {
+        this.owner = owner;
+    }
+
+    public List<PolicyEntity> getPolicies() {
+        return this.policies;
+    }
+
+    public void updateScopes(Set<Scope> toUpdate) {
+        for (Scope scope : toUpdate) {
+            boolean hasScope = false;
+
+            for (Scope existingScope : this.scopes) {
+                if (existingScope.equals(scope)) {
+                    hasScope = true;
+                }
+            }
+
+            if (!hasScope) {
+                this.scopes.add((ScopeEntity) scope);
+            }
+        }
+
+        for (Scope scopeModel : new HashSet<Scope>(this.scopes)) {
+            boolean hasScope = false;
+
+            for (Scope scope : toUpdate) {
+                if (scopeModel.equals(scope)) {
+                    hasScope = true;
+                }
+            }
+
+            if (!hasScope) {
+                this.scopes.remove(scopeModel);
+            }
+        }
+    }
+
+    public void setPolicies(List<PolicyEntity> policies) {
+        this.policies = policies;
+    }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceServerEntity.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceServerEntity.java
new file mode 100644
index 0000000..a0be18a
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ResourceServerEntity.java
@@ -0,0 +1,114 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.jpa.entities;
+
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
+
+import javax.persistence.Access;
+import javax.persistence.AccessType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@Entity
+@Table(name = "RESOURCE_SERVER", uniqueConstraints = {@UniqueConstraint(columnNames = "CLIENT_ID")})
+public class ResourceServerEntity implements ResourceServer {
+
+    @Id
+    @Column(name="ID", length = 36)
+    @Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity.  This avoids an extra SQL
+    private String id;
+
+    @Column(name = "CLIENT_ID")
+    private String clientId;
+
+    @Column(name = "ALLOW_RS_REMOTE_MGMT")
+    private boolean allowRemoteResourceManagement;
+
+    @Column(name = "POLICY_ENFORCE_MODE")
+    private PolicyEnforcementMode policyEnforcementMode = PolicyEnforcementMode.ENFORCING;
+
+    @OneToMany(mappedBy = "resourceServer")
+    private List<ResourceEntity> resources;
+
+    @OneToMany (mappedBy = "resourceServer")
+    private List<ScopeEntity> scopes;
+
+    @Override
+    public String getId() {
+        return this.id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    @Override
+    public String getClientId() {
+        return this.clientId;
+    }
+
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    @Override
+    public boolean isAllowRemoteResourceManagement() {
+        return this.allowRemoteResourceManagement;
+    }
+
+    @Override
+    public void setAllowRemoteResourceManagement(boolean allowRemoteResourceManagement) {
+        this.allowRemoteResourceManagement = allowRemoteResourceManagement;
+    }
+
+    @Override
+    public PolicyEnforcementMode getPolicyEnforcementMode() {
+        return this.policyEnforcementMode;
+    }
+
+    @Override
+    public void setPolicyEnforcementMode(PolicyEnforcementMode policyEnforcementMode) {
+        this.policyEnforcementMode = policyEnforcementMode;
+    }
+
+    public List<ResourceEntity> getResources() {
+        return this.resources;
+    }
+
+    public void setResources(final List<ResourceEntity> resources) {
+        this.resources = resources;
+    }
+
+    public List<ScopeEntity> getScopes() {
+        return this.scopes;
+    }
+
+    public void setScopes(final List<ScopeEntity> scopes) {
+        this.scopes = scopes;
+    }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ScopeEntity.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ScopeEntity.java
new file mode 100644
index 0000000..99f8b41
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/entities/ScopeEntity.java
@@ -0,0 +1,126 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.jpa.entities;
+
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Scope;
+
+import javax.persistence.Access;
+import javax.persistence.AccessType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@Entity
+@Table(name = "RESOURCE_SERVER_SCOPE", uniqueConstraints = {
+        @UniqueConstraint(columnNames = {"NAME", "RESOURCE_SERVER_ID"})
+})
+public class ScopeEntity implements Scope {
+
+    @Id
+    @Column(name="ID", length = 36)
+    @Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity.  This avoids an extra SQL
+    private String id;
+
+    @Column(name = "NAME")
+    private String name;
+
+    @Column(name = "ICON_URI")
+    private String iconUri;
+
+    @ManyToOne(optional = false)
+    @JoinColumn(name = "RESOURCE_SERVER_ID")
+    private ResourceServerEntity resourceServer;
+
+    @ManyToMany(fetch = FetchType.LAZY, cascade = {})
+    @JoinTable(name = "SCOPE_POLICY", joinColumns = @JoinColumn(name = "SCOPE_ID"), inverseJoinColumns = @JoinColumn(name = "POLICY_ID"))
+    private List<PolicyEntity> policies = new ArrayList<>();
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String getIconUri() {
+        return iconUri;
+    }
+
+    @Override
+    public void setIconUri(String iconUri) {
+        this.iconUri = iconUri;
+    }
+
+    @Override
+    public ResourceServerEntity getResourceServer() {
+        return resourceServer;
+    }
+
+    public List<? extends Policy> getPolicies() {
+        return this.policies;
+    }
+
+    public void setPolicies(List<PolicyEntity> policies) {
+        this.policies = policies;
+    }
+
+    public void setResourceServer(final ResourceServerEntity resourceServer) {
+        this.resourceServer = resourceServer;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        ScopeEntity that = (ScopeEntity) o;
+        return Objects.equals(id, that.id);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(id);
+    }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAAuthorizationStoreFactory.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAAuthorizationStoreFactory.java
new file mode 100644
index 0000000..8788884
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAAuthorizationStoreFactory.java
@@ -0,0 +1,56 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.jpa.store;
+
+import org.keycloak.Config;
+import org.keycloak.authorization.store.AuthorizationStoreFactory;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.connections.jpa.JpaConnectionProvider;
+import org.keycloak.models.KeycloakSession;
+
+import javax.persistence.EntityManager;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class JPAAuthorizationStoreFactory implements AuthorizationStoreFactory {
+    @Override
+    public StoreFactory  create(KeycloakSession session) {
+        return new JPAStoreFactory(getEntityManager(session));
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "jpa";
+    }
+
+    private EntityManager getEntityManager(KeycloakSession session) {
+        return session.getProvider(JpaConnectionProvider.class).getEntityManager();
+    }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPolicyStore.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPolicyStore.java
new file mode 100644
index 0000000..8b88ad1
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAPolicyStore.java
@@ -0,0 +1,164 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.jpa.store;
+
+import org.keycloak.authorization.jpa.entities.PolicyEntity;
+import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.models.utils.KeycloakModelUtils;
+
+import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+import javax.persistence.Query;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class JPAPolicyStore implements PolicyStore {
+
+    private final EntityManager entityManager;
+
+    public JPAPolicyStore(EntityManager entityManager) {
+        this.entityManager = entityManager;
+    }
+
+    @Override
+    public Policy create(String name, String type, ResourceServer resourceServer) {
+        PolicyEntity entity = new PolicyEntity();
+
+        entity.setId(KeycloakModelUtils.generateId());
+        entity.setName(name);
+        entity.setType(type);
+        entity.setResourceServer((ResourceServerEntity) resourceServer);
+
+        this.entityManager.persist(entity);
+
+        return entity;
+    }
+
+    public EntityManager getEntityManager() {
+        return this.entityManager;
+    }
+
+    @Override
+    public void delete(String id) {
+        Policy policy = findById(id);
+
+        if (policy != null) {
+            getEntityManager().remove(policy);
+        }
+    }
+
+
+    @Override
+    public Policy findById(String id) {
+        return getEntityManager().find(PolicyEntity.class, id);
+    }
+
+    @Override
+    public Policy findByName(String name, String resourceServerId) {
+        try {
+            Query query = getEntityManager().createQuery("from PolicyEntity where name = :name and resourceServer.id = :serverId");
+
+            query.setParameter("name", name);
+            query.setParameter("serverId", resourceServerId);
+
+            return (Policy) query.getSingleResult();
+        } catch (NoResultException nre) {
+            return null;
+        }
+    }
+
+    @Override
+    public List<Policy> findByResourceServer(final String resourceServerId) {
+        Query query = getEntityManager().createQuery("from PolicyEntity where resourceServer.id = :serverId");
+
+        query.setParameter("serverId", resourceServerId);
+
+        return query.getResultList();
+    }
+
+    @Override
+    public List<Policy> findByResource(final String resourceId) {
+        Query query = getEntityManager().createQuery("select p from PolicyEntity p inner join p.resources r where r.id = :resourceId");
+
+        query.setParameter("resourceId", resourceId);
+
+        return query.getResultList();
+    }
+
+    @Override
+    public List<Policy> findByResourceType(final String resourceType, String resourceServerId) {
+        List<Policy> policies = new ArrayList<>();
+        Query query = getEntityManager().createQuery("from PolicyEntity where resourceServer.id = :serverId");
+
+        query.setParameter("serverId", resourceServerId);
+
+        List<Policy> models = query.getResultList();
+
+        for (Policy policy : models) {
+            String defaultType = policy.getConfig().get("defaultResourceType");
+
+            if (defaultType != null && defaultType.equals(resourceType) && policy.getResources().isEmpty()) {
+                policies.add(policy);
+            }
+        }
+
+        return policies;
+    }
+
+    @Override
+    public List<Policy> findByScopeIds(List<String> scopeIds, String resourceServerId) {
+        if (scopeIds==null || scopeIds.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        // Use separate subquery to handle DB2 and MSSSQL
+        Query query = getEntityManager().createQuery("select pe from PolicyEntity pe where pe.id IN (select p.id from PolicyEntity p inner join p.scopes s where p.resourceServer.id = :serverId and s.id in (:scopeIds) and p.resources is empty group by p.id) order by pe.name");
+
+        query.setParameter("serverId", resourceServerId);
+        query.setParameter("scopeIds", scopeIds);
+
+        return query.getResultList();
+    }
+
+    @Override
+    public List<Policy> findByType(String type) {
+        Query query = getEntityManager().createQuery("select p from PolicyEntity p where p.type = :type");
+
+        query.setParameter("type", type);
+
+        return query.getResultList();
+    }
+
+    @Override
+    public List<Policy> findDependentPolicies(String policyId) {
+        Query query = getEntityManager().createQuery("select p from PolicyEntity p inner join p.associatedPolicies ap where ap.id in (:policyId)");
+
+        query.setParameter("policyId", Arrays.asList(policyId));
+
+        return query.getResultList();
+    }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceServerStore.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceServerStore.java
new file mode 100644
index 0000000..51d0369
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceServerStore.java
@@ -0,0 +1,75 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.jpa.store;
+
+import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.store.ResourceServerStore;
+import org.keycloak.models.utils.KeycloakModelUtils;
+
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class JPAResourceServerStore implements ResourceServerStore {
+
+    private final EntityManager entityManager;
+
+    public JPAResourceServerStore(EntityManager entityManager) {
+        this.entityManager = entityManager;
+    }
+
+    @Override
+    public ResourceServer create(String clientId) {
+        ResourceServerEntity entity = new ResourceServerEntity();
+
+        entity.setId(KeycloakModelUtils.generateId());
+        entity.setClientId(clientId);
+
+        this.entityManager.persist(entity);
+
+        return entity;
+    }
+
+    @Override
+    public void delete(String id) {
+        this.entityManager.remove(findById(id));
+    }
+
+    @Override
+    public ResourceServer findById(String id) {
+        return entityManager.find(ResourceServerEntity.class, id);
+    }
+
+    @Override
+    public ResourceServer findByClient(final String clientId) {
+        Query query = entityManager.createQuery("from ResourceServerEntity where clientId = :clientId");
+
+        query.setParameter("clientId", clientId);
+        List result = query.getResultList();
+
+        if (result.isEmpty()) {
+            return null;
+        }
+
+        return (ResourceServer) result.get(0);
+    }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java
new file mode 100644
index 0000000..986d007
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAResourceStore.java
@@ -0,0 +1,132 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.jpa.store;
+
+import org.keycloak.authorization.jpa.entities.ResourceEntity;
+import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.store.ResourceStore;
+import org.keycloak.models.utils.KeycloakModelUtils;
+
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class JPAResourceStore implements ResourceStore {
+
+    private final EntityManager entityManager;
+
+    public JPAResourceStore(EntityManager entityManager) {
+        this.entityManager = entityManager;
+    }
+
+    @Override
+    public Resource create(String name, ResourceServer resourceServer, String owner) {
+        if (!(resourceServer instanceof ResourceServerEntity)) {
+            throw new RuntimeException("Unexpected type [" + resourceServer.getClass() + "].");
+        }
+
+        ResourceEntity entity = new ResourceEntity();
+
+        entity.setId(KeycloakModelUtils.generateId());
+        entity.setName(name);
+        entity.setResourceServer((ResourceServerEntity) resourceServer);
+        entity.setOwner(owner);
+
+        this.entityManager.persist(entity);
+
+        return entity;
+    }
+
+    @Override
+    public void delete(String id) {
+        Resource resource = findById(id);
+
+        resource.getScopes().clear();
+
+        if (resource != null) {
+            this.entityManager.remove(resource);
+        }
+    }
+
+    @Override
+    public Resource findById(String id) {
+        if (id == null) {
+            return null;
+        }
+
+        return entityManager.find(ResourceEntity.class, id);
+    }
+
+    @Override
+    public List<Resource> findByOwner(String ownerId) {
+        Query query = entityManager.createQuery("from ResourceEntity where owner = :ownerId");
+
+        query.setParameter("ownerId", ownerId);
+
+        return query.getResultList();
+    }
+
+    @Override
+    public List findByResourceServer(String resourceServerId) {
+        Query query = entityManager.createQuery("from ResourceEntity where resourceServer.id = :serverId");
+
+        query.setParameter("serverId", resourceServerId);
+
+        return query.getResultList();
+    }
+
+    @Override
+    public List<Resource> findByScope(String... id) {
+        Query query = entityManager.createQuery("select r from ResourceEntity r inner join r.scopes s where s.id in (:scopeIds)");
+
+        query.setParameter("scopeIds", Arrays.asList(id));
+
+        return query.getResultList();
+    }
+
+    @Override
+    public Resource findByName(String name, String resourceServerId) {
+        Query query = entityManager.createQuery("from ResourceEntity where resourceServer.id = :serverId and name = :name");
+
+        query.setParameter("serverId", resourceServerId);
+        query.setParameter("name", name);
+
+        List<Resource> result = query.getResultList();
+
+        if (!result.isEmpty()) {
+            return result.get(0);
+        }
+
+        return null;
+    }
+
+    @Override
+    public List<Resource> findByType(String type) {
+        Query query = entityManager.createQuery("from ResourceEntity where type = :type");
+
+        query.setParameter("type", type);
+
+        return query.getResultList();
+    }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAScopeStore.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAScopeStore.java
new file mode 100644
index 0000000..cc9a956
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAScopeStore.java
@@ -0,0 +1,88 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.jpa.store;
+
+import org.keycloak.authorization.jpa.entities.ResourceServerEntity;
+import org.keycloak.authorization.jpa.entities.ScopeEntity;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.store.ScopeStore;
+import org.keycloak.models.utils.KeycloakModelUtils;
+
+import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+import javax.persistence.Query;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class JPAScopeStore implements ScopeStore {
+
+    private final EntityManager entityManager;
+
+    public JPAScopeStore(EntityManager entityManager) {
+        this.entityManager = entityManager;
+    }
+
+    @Override
+    public Scope create(final String name, final ResourceServer resourceServer) {
+        ScopeEntity entity = new ScopeEntity();
+
+        entity.setId(KeycloakModelUtils.generateId());
+        entity.setName(name);
+        entity.setResourceServer((ResourceServerEntity) resourceServer);
+
+        this.entityManager.persist(entity);
+
+        return entity;
+    }
+
+    @Override
+    public void delete(String id) {
+        this.entityManager.remove(findById(id));
+    }
+
+    @Override
+    public Scope findById(String id) {
+        return entityManager.find(ScopeEntity.class, id);
+    }
+
+    @Override
+    public Scope findByName(String name, String resourceServerId) {
+        try {
+            Query query = entityManager.createQuery("select s from ScopeEntity s inner join s.resourceServer rs where rs.id = :resourceServerId and name = :name");
+
+            query.setParameter("name", name);
+            query.setParameter("resourceServerId", resourceServerId);
+
+            return (Scope) query.getSingleResult();
+        } catch (NoResultException nre) {
+            return null;
+        }
+    }
+
+    @Override
+    public List<Scope> findByResourceServer(final String serverId) {
+        Query query = entityManager.createQuery("from ScopeEntity where resourceServer.id = :serverId");
+
+        query.setParameter("serverId", serverId);
+
+        return query.getResultList();
+    }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAStoreFactory.java b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAStoreFactory.java
new file mode 100644
index 0000000..5dad6af
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/authorization/jpa/store/JPAStoreFactory.java
@@ -0,0 +1,64 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.jpa.store;
+
+import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.authorization.store.ResourceServerStore;
+import org.keycloak.authorization.store.ResourceStore;
+import org.keycloak.authorization.store.ScopeStore;
+import org.keycloak.authorization.store.StoreFactory;
+
+import javax.persistence.EntityManager;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class JPAStoreFactory implements StoreFactory {
+
+    private final EntityManager entityManager;
+
+    public JPAStoreFactory(EntityManager entityManager) {
+        this.entityManager = entityManager;
+    }
+
+    @Override
+    public PolicyStore getPolicyStore() {
+        return new JPAPolicyStore(this.entityManager);
+    }
+
+    @Override
+    public ResourceServerStore getResourceServerStore() {
+        return new JPAResourceServerStore(this.entityManager);
+    }
+
+    @Override
+    public ResourceStore getResourceStore() {
+        return new JPAResourceStore(this.entityManager);
+    }
+
+    @Override
+    public ScopeStore getScopeStore() {
+        return new JPAScopeStore(this.entityManager);
+    }
+
+    @Override
+    public void close() {
+
+    }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java
index f1e6f04..4272fb8 100755
--- a/model/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java
+++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/DefaultJpaConnectionProviderFactory.java
@@ -20,32 +20,28 @@ package org.keycloak.connections.jpa;
 import java.sql.Connection;
 import java.sql.DatabaseMetaData;
 import java.sql.DriverManager;
-import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
-import java.util.List;
 import java.util.Map;
 
 import javax.naming.InitialContext;
 import javax.persistence.EntityManager;
 import javax.persistence.EntityManagerFactory;
-import javax.persistence.Persistence;
-import javax.persistence.spi.PersistenceUnitTransactionType;
 import javax.sql.DataSource;
 
-import org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl;
 import org.hibernate.ejb.AvailableSettings;
-import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor;
-import org.hibernate.jpa.boot.internal.PersistenceXmlParser;
-import org.hibernate.jpa.boot.spi.Bootstrap;
 import org.jboss.logging.Logger;
 import org.keycloak.Config;
 import org.keycloak.connections.jpa.updater.JpaUpdaterProvider;
 import org.keycloak.connections.jpa.util.JpaUtils;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.KeycloakSessionTask;
+import org.keycloak.models.dblock.DBLockProvider;
+import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.provider.ServerInfoAwareProviderFactory;
+import org.keycloak.models.dblock.DBLockManager;
 import org.keycloak.timer.TimerProvider;
 
 /**
@@ -67,7 +63,7 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
 
         EntityManager em = emf.createEntityManager();
         em = PersistenceExceptionConverter.create(em);
-        session.getTransaction().enlist(new JpaKeycloakTransaction(em));
+        session.getTransactionManager().enlist(new JpaKeycloakTransaction(em));
         return new DefaultJpaConnectionProvider(em);
     }
 
@@ -99,8 +95,6 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
                 if (emf == null) {
                     logger.debug("Initializing JPA connections");
 
-                    Connection connection = null;
-
                     Map<String, Object> properties = new HashMap<String, Object>();
 
                     String unitName = "keycloak-default";
@@ -132,23 +126,26 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
                     }
 
 
-                    String databaseSchema = config.get("databaseSchema");
-                    if (databaseSchema == null) {
+                    String databaseSchema;
+                    String databaseSchemaConf = config.get("databaseSchema");
+                    if (databaseSchemaConf == null) {
                         throw new RuntimeException("Property 'databaseSchema' needs to be specified in the configuration");
                     }
                     
-                    if (databaseSchema.equals("development-update")) {
+                    if (databaseSchemaConf.equals("development-update")) {
                         properties.put("hibernate.hbm2ddl.auto", "update");
                         databaseSchema = null;
-                    } else if (databaseSchema.equals("development-validate")) {
+                    } else if (databaseSchemaConf.equals("development-validate")) {
                         properties.put("hibernate.hbm2ddl.auto", "validate");
                         databaseSchema = null;
+                    } else {
+                        databaseSchema = databaseSchemaConf;
                     }
 
                     properties.put("hibernate.show_sql", config.getBoolean("showSql", false));
                     properties.put("hibernate.format_sql", config.getBoolean("formatSql", true));
 
-                    connection = getConnection();
+                    Connection connection = getConnection();
                     try{ 
 	                    prepareOperationalInfo(connection);
 
@@ -164,29 +161,30 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
 	                        if (updater == null) {
 	                            throw new RuntimeException("Can't update database: JPA updater provider not found");
 	                        }
-	
-	                        if (databaseSchema.equals("update")) {
-	                            String currentVersion = null;
-	                            try {
-	                                ResultSet resultSet = connection.createStatement().executeQuery(updater.getCurrentVersionSql(schema));
-	                                if (resultSet.next()) {
-	                                    currentVersion = resultSet.getString(1);
-	                                }
-	                            } catch (SQLException e) {
-	                            }
-	
-	                            if (currentVersion == null || !JpaUpdaterProvider.LAST_VERSION.equals(currentVersion)) {
-	                                updater.update(connection, schema);
-	                            } else {
-	                                logger.debug("Database is up to date");
-	                            }
-	                        } else if (databaseSchema.equals("validate")) {
-	                            updater.validate(connection, schema);
-	                        } else {
-	                            throw new RuntimeException("Invalid value for databaseSchema: " + databaseSchema);
-	                        }
-	
-	                        logger.trace("Database update completed");
+
+                            // Check if having DBLock before trying to initialize hibernate
+                            DBLockProvider dbLock = new DBLockManager(session).getDBLock();
+                            if (dbLock.hasLock()) {
+                                updateOrValidateDB(databaseSchema, connection, updater, schema);
+                            } else {
+                                logger.trace("Don't have DBLock retrieved before upgrade. Needs to acquire lock first in separate transaction");
+
+                                KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), new KeycloakSessionTask() {
+
+                                    @Override
+                                    public void run(KeycloakSession lockSession) {
+                                        DBLockManager dbLockManager = new DBLockManager(lockSession);
+                                        DBLockProvider dbLock2 = dbLockManager.getDBLock();
+                                        dbLock2.waitForLock();
+                                        try {
+                                            updateOrValidateDB(databaseSchema, connection, updater, schema);
+                                        } finally {
+                                            dbLock2.releaseLock();
+                                        }
+                                    }
+
+                                });
+                            }
 	                    }
 
                         int globalStatsInterval = config.getInt("globalStatsInterval", -1);
@@ -195,7 +193,7 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
                         }
 
 	                    logger.trace("Creating EntityManagerFactory");
-	                    emf = JpaUtils.createEntityManagerFactory(unitName, properties, getClass().getClassLoader());
+	                    emf = JpaUtils.createEntityManagerFactory(session, unitName, properties, getClass().getClassLoader());
 	                    logger.trace("EntityManagerFactory created");
 
                         if (globalStatsInterval != -1) {
@@ -285,6 +283,20 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
     }
 
 
+    // Needs to be called with acquired DBLock
+    protected void updateOrValidateDB(String databaseSchema, Connection connection, JpaUpdaterProvider updater, String schema) {
+        if (databaseSchema.equals("update")) {
+            updater.update(connection, schema);
+            logger.trace("Database update completed");
+        } else if (databaseSchema.equals("validate")) {
+            updater.validate(connection, schema);
+            logger.trace("Database validation completed");
+        } else {
+            throw new RuntimeException("Invalid value for databaseSchema: " + databaseSchema);
+        }
+    }
+
+
     @Override
     public Connection getConnection() {
         try {
diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/JpaEntityProvider.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/JpaEntityProvider.java
new file mode 100644
index 0000000..567080e
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/JpaEntityProvider.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.connections.jpa.entityprovider;
+
+import java.util.List;
+
+import org.keycloak.provider.Provider;
+
+/**
+ * @author <a href="mailto:erik.mulder@docdatapayments.com">Erik Mulder</a>
+ * 
+ * A JPA Entity Provider can supply extra JPA entities that the Keycloak system should include in it's entity manager. The
+ * entities should be provided as a list of Class objects.
+ */
+public interface JpaEntityProvider extends Provider {
+
+    /**
+     * Return the entities that should be added to the entity manager.
+     * 
+     * @return list of class objects
+     */
+	List<Class<?>> getEntities();
+	
+	/**
+	 * Return the location of the Liquibase changelog that facilitates the extra JPA entities.
+	 * This should be a location that can be found on the same classpath as the entity classes.
+	 * 
+	 * @return a changelog location or null if not needed
+	 */
+	String getChangelogLocation();
+
+	/**
+	 * Return the ID of provider factory, which created this provider. Might be used to "compute" the table name of liquibase changelog table.
+	 * @return ID of provider factory
+	 */
+	String getFactoryId();
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/JpaEntityProviderFactory.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/JpaEntityProviderFactory.java
new file mode 100644
index 0000000..8c08bf9
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/JpaEntityProviderFactory.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.connections.jpa.entityprovider;
+
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * @author <a href="mailto:erik.mulder@docdatapayments.com">Erik Mulder</a>
+ * 
+ * Extended interface for a provider factory for JpaEntityProvider's.
+ */
+public interface JpaEntityProviderFactory extends ProviderFactory<JpaEntityProvider> {
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/JpaEntitySpi.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/JpaEntitySpi.java
new file mode 100644
index 0000000..d89389f
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/JpaEntitySpi.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.connections.jpa.entityprovider;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:erik.mulder@docdatapayments.com">Erik Mulder</a>
+ * 
+ * Spi that allows for adding extra JPA entity's to the Keycloak entity manager.
+ */
+public class JpaEntitySpi implements Spi {
+
+	@Override
+	public boolean isInternal() {
+		return false;
+	}
+
+	@Override
+	public String getName() {
+		return "jpa-entity-provider";
+	}
+
+	@Override
+	public Class<? extends Provider> getProviderClass() {
+		return JpaEntityProvider.class;
+	}
+
+	@Override
+	public Class<? extends ProviderFactory> getProviderFactoryClass() {
+		return JpaEntityProviderFactory.class;
+	}
+	
+}
diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/ProxyClassLoader.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/ProxyClassLoader.java
new file mode 100644
index 0000000..e9b82a3
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/entityprovider/ProxyClassLoader.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.connections.jpa.entityprovider;
+
+import java.net.URL;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:erik.mulder@docdatapayments.com">Erik Mulder</a>
+ * 
+ * Classloader implementation to facilitate loading classes and resources from a collection of other classloaders.
+ * Effectively it forms a proxy to one or more other classloaders.
+ * 
+ * The way it works:
+ * - Get all (unique) classloaders from all provided classes
+ * - For each class or resource that is 'requested':
+ *   - First try all provided classloaders and if we have a match, return that
+ *   - If no match was found: proceed with 'normal' classloading in 'current classpath' scope
+ * 
+ * In this particular context: only loadClass and getResource overrides are needed, since those
+ * are the methods that a classloading and resource loading process will need.
+ */
+public class ProxyClassLoader extends ClassLoader {
+
+    private Set<ClassLoader> classloaders;
+
+    public ProxyClassLoader(Collection<Class<?>> classes, ClassLoader parentClassLoader) {
+    	super(parentClassLoader);
+    	init(classes);
+    }
+    
+    public ProxyClassLoader(Collection<Class<?>> classes) {
+    	init(classes);
+    }
+
+    private void init(Collection<Class<?>> classes) {
+        classloaders = new HashSet<>();
+        for (Class<?> clazz : classes) {
+            classloaders.add(clazz.getClassLoader());
+        }
+    }
+    
+    @Override
+    public Class<?> loadClass(String name) throws ClassNotFoundException {
+        for (ClassLoader classloader : classloaders) {
+            try {
+                return classloader.loadClass(name);
+            } catch (ClassNotFoundException e) {
+                // This particular class loader did not find the class. It's expected behavior that
+                // this can happen, so we'll just ignore the exception and let the next one try.
+            }
+        }
+        // We did not find the class in the proxy class loaders, so proceed with 'normal' behavior.
+        return super.loadClass(name);
+    }
+
+    @Override
+    public URL getResource(String name) {
+        for (ClassLoader classloader : classloaders) {
+            URL resource = classloader.getResource(name);
+            if (resource != null) {
+                return resource;
+            }
+            // Resource == null means not found, so let the next one try.
+        }
+        // We could not get the resource from the proxy class loaders, so proceed with 'normal' behavior.
+        return super.getResource(name);
+    }
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/JndiEntityManagerLookup.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/JndiEntityManagerLookup.java
new file mode 100644
index 0000000..5291793
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/JndiEntityManagerLookup.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.connections.jpa;
+
+import org.keycloak.models.KeycloakSession;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class JndiEntityManagerLookup {
+    public static EntityManager getSessionEntityManager(KeycloakSession session, String entityManagerFactoryJndiName) {
+        EntityManagerFactory factory = null;
+        try {
+            factory = (EntityManagerFactory)new InitialContext().lookup(entityManagerFactoryJndiName);
+        } catch (NamingException e) {
+            throw new RuntimeException(e);
+        }
+        EntityManager em = factory.createEntityManager();
+        session.getTransactionManager().enlist(new JpaKeycloakTransaction(em));
+        return em;
+    }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterProvider.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterProvider.java
index f253684..b087535 100755
--- a/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterProvider.java
+++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/JpaUpdaterProvider.java
@@ -28,10 +28,6 @@ public interface JpaUpdaterProvider extends Provider {
 
     public String FIRST_VERSION = "1.0.0.Final";
 
-    public String LAST_VERSION = "1.9.2";
-
-    public String getCurrentVersionSql(String defaultSchema);
-
     public void update(Connection connection, String defaultSchema);
 
     public void validate(Connection connection, String defaultSchema);
diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/conn/DefaultLiquibaseConnectionProvider.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/conn/DefaultLiquibaseConnectionProvider.java
index b9018f8..5a58702 100644
--- a/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/conn/DefaultLiquibaseConnectionProvider.java
+++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/conn/DefaultLiquibaseConnectionProvider.java
@@ -19,6 +19,16 @@ package org.keycloak.connections.jpa.updater.liquibase.conn;
 
 import java.sql.Connection;
 
+import org.jboss.logging.Logger;
+import org.keycloak.Config;
+import org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterProvider;
+import org.keycloak.connections.jpa.updater.liquibase.PostgresPlusDatabase;
+import org.keycloak.connections.jpa.updater.liquibase.lock.CustomInsertLockRecordGenerator;
+import org.keycloak.connections.jpa.updater.liquibase.lock.CustomLockDatabaseChangeLogGenerator;
+import org.keycloak.connections.jpa.updater.liquibase.lock.DummyLockService;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
 import liquibase.Liquibase;
 import liquibase.changelog.ChangeSet;
 import liquibase.changelog.DatabaseChangeLog;
@@ -27,23 +37,12 @@ import liquibase.database.DatabaseFactory;
 import liquibase.database.core.DB2Database;
 import liquibase.database.jvm.JdbcConnection;
 import liquibase.exception.LiquibaseException;
-import liquibase.lockservice.LockService;
-import liquibase.lockservice.LockServiceFactory;
 import liquibase.logging.LogFactory;
 import liquibase.logging.LogLevel;
 import liquibase.resource.ClassLoaderResourceAccessor;
+import liquibase.resource.ResourceAccessor;
 import liquibase.servicelocator.ServiceLocator;
 import liquibase.sqlgenerator.SqlGeneratorFactory;
-import org.jboss.logging.Logger;
-import org.keycloak.Config;
-import org.keycloak.connections.jpa.updater.liquibase.LiquibaseJpaUpdaterProvider;
-import org.keycloak.connections.jpa.updater.liquibase.PostgresPlusDatabase;
-import org.keycloak.connections.jpa.updater.liquibase.lock.CustomInsertLockRecordGenerator;
-import org.keycloak.connections.jpa.updater.liquibase.lock.CustomLockDatabaseChangeLogGenerator;
-import org.keycloak.connections.jpa.updater.liquibase.lock.CustomLockService;
-import org.keycloak.connections.jpa.updater.liquibase.lock.DummyLockService;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -53,7 +52,7 @@ public class DefaultLiquibaseConnectionProvider implements LiquibaseConnectionPr
     private static final Logger logger = Logger.getLogger(DefaultLiquibaseConnectionProvider.class);
 
     private volatile boolean initialized = false;
-
+    
     @Override
     public LiquibaseConnectionProvider create(KeycloakSession session) {
         if (!initialized) {
@@ -132,9 +131,26 @@ public class DefaultLiquibaseConnectionProvider implements LiquibaseConnectionPr
         }
 
         String changelog = (database instanceof DB2Database) ? LiquibaseJpaUpdaterProvider.DB2_CHANGELOG :  LiquibaseJpaUpdaterProvider.CHANGELOG;
-        logger.debugf("Using changelog file: %s", changelog);
+        ResourceAccessor resourceAccessor = new ClassLoaderResourceAccessor(getClass().getClassLoader());
+
+        logger.debugf("Using changelog file %s and changelogTableName %s", changelog, database.getDatabaseChangeLogTableName());
+        
+        return new Liquibase(changelog, resourceAccessor, database);
+    }
+
+    @Override
+    public Liquibase getLiquibaseForCustomUpdate(Connection connection, String defaultSchema, String changelogLocation, ClassLoader classloader, String changelogTableName) throws LiquibaseException {
+        Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
+        if (defaultSchema != null) {
+            database.setDefaultSchemaName(defaultSchema);
+        }
+
+        ResourceAccessor resourceAccessor = new ClassLoaderResourceAccessor(classloader);
+        database.setDatabaseChangeLogTableName(changelogTableName);
+
+        logger.debugf("Using changelog file %s and changelogTableName %s", changelogLocation, database.getDatabaseChangeLogTableName());
 
-        return new Liquibase(changelog, new ClassLoaderResourceAccessor(getClass().getClassLoader()), database);
+        return new Liquibase(changelogLocation, resourceAccessor, database);
     }
 
     private static class LogWrapper extends LogFactory {
diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/conn/LiquibaseConnectionProvider.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/conn/LiquibaseConnectionProvider.java
index 5aa81cc..215bd1d 100644
--- a/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/conn/LiquibaseConnectionProvider.java
+++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/conn/LiquibaseConnectionProvider.java
@@ -30,4 +30,6 @@ public interface LiquibaseConnectionProvider extends Provider {
 
     Liquibase getLiquibase(Connection connection, String defaultSchema) throws LiquibaseException;
 
+    Liquibase getLiquibaseForCustomUpdate(Connection connection, String defaultSchema, String changelogLocation, ClassLoader classloader, String changelogTableName) throws LiquibaseException;
+
 }
diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/LiquibaseJpaUpdaterProvider.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/LiquibaseJpaUpdaterProvider.java
index 4a505a3..2610174 100755
--- a/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/LiquibaseJpaUpdaterProvider.java
+++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/LiquibaseJpaUpdaterProvider.java
@@ -23,14 +23,17 @@ import liquibase.changelog.ChangeSet;
 import liquibase.changelog.RanChangeSet;
 import liquibase.exception.LiquibaseException;
 import org.jboss.logging.Logger;
+import org.keycloak.common.util.reflections.Reflections;
+import org.keycloak.connections.jpa.entityprovider.JpaEntityProvider;
 import org.keycloak.connections.jpa.updater.JpaUpdaterProvider;
 import org.keycloak.connections.jpa.updater.liquibase.conn.LiquibaseConnectionProvider;
+import org.keycloak.connections.jpa.util.JpaUtils;
 import org.keycloak.models.KeycloakSession;
 
+import java.lang.reflect.Method;
 import java.sql.Connection;
-import java.sql.SQLException;
-import java.sql.Statement;
 import java.util.List;
+import java.util.Set;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -49,11 +52,6 @@ public class LiquibaseJpaUpdaterProvider implements JpaUpdaterProvider {
     }
 
     @Override
-    public String getCurrentVersionSql(String defaultSchema) {
-        return "SELECT ID from " + getTable("DATABASECHANGELOG", defaultSchema) + " ORDER BY DATEEXECUTED DESC LIMIT 1";
-    }
-
-    @Override
     public void update(Connection connection, String defaultSchema) {
         logger.debug("Starting database update");
 
@@ -61,38 +59,51 @@ public class LiquibaseJpaUpdaterProvider implements JpaUpdaterProvider {
         ThreadLocalSessionContext.setCurrentSession(session);
 
         try {
-            Liquibase liquibase = getLiquibase(connection, defaultSchema);
-
-            List<ChangeSet> changeSets = liquibase.listUnrunChangeSets((Contexts) null);
-            if (!changeSets.isEmpty()) {
-                if (changeSets.get(0).getId().equals(FIRST_VERSION)) {
-                    Statement statement = connection.createStatement();
-                    try {
-                        statement.executeQuery("SELECT id FROM " + getTable("REALM", defaultSchema));
-
-                        logger.infov("Updating database from {0} to {1}", FIRST_VERSION, changeSets.get(changeSets.size() - 1).getId());
-                        liquibase.markNextChangeSetRan(null);
-                    } catch (SQLException e) {
-                        logger.info("Initializing database schema");
-                    }
-                } else {
-                    if (logger.isDebugEnabled()) {
-                        List<RanChangeSet> ranChangeSets = liquibase.getDatabase().getRanChangeSetList();
-                        logger.debugv("Updating database from {0} to {1}", ranChangeSets.get(ranChangeSets.size() - 1).getId(), changeSets.get(changeSets.size() - 1).getId());
-                    } else {
-                        logger.infov("Updating database");
-                    }
+            // Run update with keycloak master changelog first
+            Liquibase liquibase = getLiquibaseForKeycloakUpdate(connection, defaultSchema);
+            updateChangeSet(liquibase, liquibase.getChangeLogFile());
+
+            // Run update for each custom JpaEntityProvider
+            Set<JpaEntityProvider> jpaProviders = session.getAllProviders(JpaEntityProvider.class);
+            for (JpaEntityProvider jpaProvider : jpaProviders) {
+                String customChangelog = jpaProvider.getChangelogLocation();
+                if (customChangelog != null) {
+                    String factoryId = jpaProvider.getFactoryId();
+                    String changelogTableName = JpaUtils.getCustomChangelogTableName(factoryId);
+                    liquibase = getLiquibaseForCustomProviderUpdate(connection, defaultSchema, customChangelog, jpaProvider.getClass().getClassLoader(), changelogTableName);
+                    updateChangeSet(liquibase, liquibase.getChangeLogFile());
                 }
-
-                liquibase.update((Contexts) null);
             }
         } catch (Exception e) {
             throw new RuntimeException("Failed to update database", e);
         } finally {
             ThreadLocalSessionContext.removeCurrentSession();
         }
+    }
+
+    protected void updateChangeSet(Liquibase liquibase, String changelog) throws LiquibaseException {
+        List<ChangeSet> changeSets = liquibase.listUnrunChangeSets((Contexts) null);
+        if (!changeSets.isEmpty()) {
+            List<RanChangeSet> ranChangeSets = liquibase.getDatabase().getRanChangeSetList();
+            if (ranChangeSets.isEmpty()) {
+                logger.infov("Initializing database schema. Using changelog {0}", changelog);
+            } else {
+                if (logger.isDebugEnabled()) {
+                    logger.debugv("Updating database from {0} to {1}. Using changelog {2}", ranChangeSets.get(ranChangeSets.size() - 1).getId(), changeSets.get(changeSets.size() - 1).getId(), changelog);
+                } else {
+                    logger.infov("Updating database. Using changelog {0}", changelog);
+                }
+            }
 
-        logger.debug("Completed database update");
+            liquibase.update((Contexts) null);
+            logger.debugv("Completed database update for changelog {0}", changelog);
+        } else {
+            logger.debugv("Database is up to date for changelog {0}", changelog);
+
+            // Needs to restart liquibase services to clear changeLogHistory.
+            Method resetServices = Reflections.findDeclaredMethod(Liquibase.class, "resetServices");
+            Reflections.invokeMethod(true, resetServices, liquibase);
+        }
     }
 
     @Override
@@ -100,16 +111,20 @@ public class LiquibaseJpaUpdaterProvider implements JpaUpdaterProvider {
         logger.debug("Validating if database is updated");
 
         try {
-            Liquibase liquibase = getLiquibase(connection, defaultSchema);
-
-            List<ChangeSet> changeSets = liquibase.listUnrunChangeSets((Contexts) null);
-            if (!changeSets.isEmpty()) {
-                List<RanChangeSet> ranChangeSets = liquibase.getDatabase().getRanChangeSetList();
-                String errorMessage = String.format("Failed to validate database schema. Schema needs updating database from %s to %s. Please change databaseSchema to 'update' or use other database",
-                        ranChangeSets.get(ranChangeSets.size() - 1).getId(), changeSets.get(changeSets.size() - 1).getId());
-                throw new RuntimeException(errorMessage);
-            } else {
-                logger.debug("Validation passed. Database is up-to-date");
+            // Validate with keycloak master changelog first
+            Liquibase liquibase = getLiquibaseForKeycloakUpdate(connection, defaultSchema);
+            validateChangeSet(liquibase, liquibase.getChangeLogFile());
+
+            // Validate each custom JpaEntityProvider
+            Set<JpaEntityProvider> jpaProviders = session.getAllProviders(JpaEntityProvider.class);
+            for (JpaEntityProvider jpaProvider : jpaProviders) {
+                String customChangelog = jpaProvider.getChangelogLocation();
+                if (customChangelog != null) {
+                    String factoryId = jpaProvider.getFactoryId();
+                    String changelogTableName = JpaUtils.getCustomChangelogTableName(factoryId);
+                    liquibase = getLiquibaseForCustomProviderUpdate(connection, defaultSchema, customChangelog, jpaProvider.getClass().getClassLoader(), changelogTableName);
+                    validateChangeSet(liquibase, liquibase.getChangeLogFile());
+                }
             }
 
         } catch (LiquibaseException e) {
@@ -117,11 +132,28 @@ public class LiquibaseJpaUpdaterProvider implements JpaUpdaterProvider {
         }
     }
 
-    private Liquibase getLiquibase(Connection connection, String defaultSchema) throws LiquibaseException {
+    protected void validateChangeSet(Liquibase liquibase, String changelog) throws LiquibaseException {
+        List<ChangeSet> changeSets = liquibase.listUnrunChangeSets((Contexts) null);
+        if (!changeSets.isEmpty()) {
+            List<RanChangeSet> ranChangeSets = liquibase.getDatabase().getRanChangeSetList();
+            String errorMessage = String.format("Failed to validate database schema. Schema needs updating database from %s to %s. Please change databaseSchema to 'update' or use other database. Used changelog was %s",
+                    ranChangeSets.get(ranChangeSets.size() - 1).getId(), changeSets.get(changeSets.size() - 1).getId(), changelog);
+            throw new RuntimeException(errorMessage);
+        } else {
+            logger.debugf("Validation passed. Database is up-to-date for changelog %s", changelog);
+        }
+    }
+
+    private Liquibase getLiquibaseForKeycloakUpdate(Connection connection, String defaultSchema) throws LiquibaseException {
         LiquibaseConnectionProvider liquibaseProvider = session.getProvider(LiquibaseConnectionProvider.class);
         return liquibaseProvider.getLiquibase(connection, defaultSchema);
     }
 
+    private Liquibase getLiquibaseForCustomProviderUpdate(Connection connection, String defaultSchema, String changelogLocation, ClassLoader classloader, String changelogTableName) throws LiquibaseException {
+        LiquibaseConnectionProvider liquibaseProvider = session.getProvider(LiquibaseConnectionProvider.class);
+        return liquibaseProvider.getLiquibaseForCustomUpdate(connection, defaultSchema, changelogLocation, classloader, changelogTableName);
+    }
+
     @Override
     public void close() {
     }
diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/lock/LiquibaseDBLockProvider.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/lock/LiquibaseDBLockProvider.java
index f44641e..7c48499 100644
--- a/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/lock/LiquibaseDBLockProvider.java
+++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/lock/LiquibaseDBLockProvider.java
@@ -48,32 +48,35 @@ public class LiquibaseDBLockProvider implements DBLockProvider {
 
     private CustomLockService lockService;
     private Connection dbConnection;
+    private boolean initialized = false;
 
     private int maxAttempts = DEFAULT_MAX_ATTEMPTS;
 
     public LiquibaseDBLockProvider(LiquibaseDBLockProviderFactory factory, KeycloakSession session) {
         this.factory = factory;
         this.session = session;
-        init();
     }
 
-    private void init() {
-        LiquibaseConnectionProvider liquibaseProvider = session.getProvider(LiquibaseConnectionProvider.class);
-        JpaConnectionProviderFactory jpaProviderFactory = (JpaConnectionProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(JpaConnectionProvider.class);
+    private void lazyInit() {
+        if (!initialized) {
+            LiquibaseConnectionProvider liquibaseProvider = session.getProvider(LiquibaseConnectionProvider.class);
+            JpaConnectionProviderFactory jpaProviderFactory = (JpaConnectionProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(JpaConnectionProvider.class);
 
-        this.dbConnection = jpaProviderFactory.getConnection();
-        String defaultSchema = jpaProviderFactory.getSchema();
+            this.dbConnection = jpaProviderFactory.getConnection();
+            String defaultSchema = jpaProviderFactory.getSchema();
 
-        try {
-            Liquibase liquibase = liquibaseProvider.getLiquibase(dbConnection, defaultSchema);
+            try {
+                Liquibase liquibase = liquibaseProvider.getLiquibase(dbConnection, defaultSchema);
 
-            this.lockService = new CustomLockService();
-            lockService.setChangeLogLockWaitTime(factory.getLockWaitTimeoutMillis());
-            lockService.setDatabase(liquibase.getDatabase());
-        } catch (LiquibaseException exception) {
-            safeRollbackConnection();
-            safeCloseConnection();
-            throw new IllegalStateException(exception);
+                this.lockService = new CustomLockService();
+                lockService.setChangeLogLockWaitTime(factory.getLockWaitTimeoutMillis());
+                lockService.setDatabase(liquibase.getDatabase());
+                initialized = true;
+            } catch (LiquibaseException exception) {
+                safeRollbackConnection();
+                safeCloseConnection();
+                throw new IllegalStateException(exception);
+            }
         }
     }
 
@@ -82,15 +85,19 @@ public class LiquibaseDBLockProvider implements DBLockProvider {
         safeCloseConnection();
         this.dbConnection = null;
         this.lockService = null;
-        init();
+        initialized = false;
+        lazyInit();
     }
 
 
     @Override
     public void waitForLock() {
+        lazyInit();
+
         while (maxAttempts > 0) {
             try {
                 lockService.waitForLock();
+                factory.setHasLock(true);
                 this.maxAttempts = DEFAULT_MAX_ATTEMPTS;
                 return;
             } catch (LockRetryException le) {
@@ -109,8 +116,16 @@ public class LiquibaseDBLockProvider implements DBLockProvider {
 
     @Override
     public void releaseLock() {
+        lazyInit();
+
         lockService.releaseLock();
         lockService.reset();
+        factory.setHasLock(false);
+    }
+
+    @Override
+    public boolean hasLock() {
+        return factory.hasLock();
     }
 
     @Override
@@ -121,6 +136,8 @@ public class LiquibaseDBLockProvider implements DBLockProvider {
 
     @Override
     public void destroyLockInfo() {
+        lazyInit();
+
         try {
             this.lockService.destroy();
             dbConnection.commit();
@@ -147,7 +164,7 @@ public class LiquibaseDBLockProvider implements DBLockProvider {
     }
 
     private void safeCloseConnection() {
-        // Close after creating EntityManagerFactory to prevent in-mem databases from closing
+        // Close to prevent in-mem databases from closing
         if (dbConnection != null) {
             try {
                 dbConnection.close();
diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/lock/LiquibaseDBLockProviderFactory.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/lock/LiquibaseDBLockProviderFactory.java
index 3026f7d..ef1fae1 100644
--- a/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/lock/LiquibaseDBLockProviderFactory.java
+++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/updater/liquibase/lock/LiquibaseDBLockProviderFactory.java
@@ -17,6 +17,8 @@
 
 package org.keycloak.connections.jpa.updater.liquibase.lock;
 
+import java.util.concurrent.atomic.AtomicBoolean;
+
 import org.jboss.logging.Logger;
 import org.keycloak.Config;
 import org.keycloak.common.util.Time;
@@ -33,6 +35,9 @@ public class LiquibaseDBLockProviderFactory implements DBLockProviderFactory {
 
     private long lockWaitTimeoutMillis;
 
+    // True if this node has a lock acquired
+    private AtomicBoolean hasLock = new AtomicBoolean(false);
+
     protected long getLockWaitTimeoutMillis() {
         return lockWaitTimeoutMillis;
     }
@@ -68,4 +73,12 @@ public class LiquibaseDBLockProviderFactory implements DBLockProviderFactory {
     public String getId() {
         return "jpa";
     }
+
+    public boolean hasLock() {
+        return hasLock.get();
+    }
+
+    public void setHasLock(boolean hasLock) {
+        this.hasLock.set(hasLock);
+    }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/connections/jpa/util/JpaUtils.java b/model/jpa/src/main/java/org/keycloak/connections/jpa/util/JpaUtils.java
index de07fd5..5ac7d2f 100644
--- a/model/jpa/src/main/java/org/keycloak/connections/jpa/util/JpaUtils.java
+++ b/model/jpa/src/main/java/org/keycloak/connections/jpa/util/JpaUtils.java
@@ -21,12 +21,18 @@ import org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl;
 import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor;
 import org.hibernate.jpa.boot.internal.PersistenceXmlParser;
 import org.hibernate.jpa.boot.spi.Bootstrap;
+import org.keycloak.connections.jpa.entityprovider.JpaEntityProvider;
+import org.keycloak.connections.jpa.entityprovider.ProxyClassLoader;
+import org.keycloak.models.KeycloakSession;
 
 import javax.persistence.EntityManager;
 import javax.persistence.EntityManagerFactory;
 import javax.persistence.spi.PersistenceUnitTransactionType;
+
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -40,14 +46,52 @@ public class JpaUtils {
         return (schema==null) ? tableName : schema + "." + tableName;
     }
 
-    public static EntityManagerFactory createEntityManagerFactory(String unitName, Map<String, Object> properties, ClassLoader classLoader) {
+    public static EntityManagerFactory createEntityManagerFactory(KeycloakSession session, String unitName, Map<String, Object> properties, ClassLoader classLoader) {
         PersistenceXmlParser parser = new PersistenceXmlParser(new ClassLoaderServiceImpl(classLoader), PersistenceUnitTransactionType.RESOURCE_LOCAL);
         List<ParsedPersistenceXmlDescriptor> persistenceUnits = parser.doResolve(properties);
         for (ParsedPersistenceXmlDescriptor persistenceUnit : persistenceUnits) {
             if (persistenceUnit.getName().equals(unitName)) {
-                return Bootstrap.getEntityManagerFactoryBuilder(persistenceUnit, properties, classLoader).build();
+                List<Class<?>> providedEntities = getProvidedEntities(session);
+                for (Class<?> entityClass : providedEntities) {
+                    // Add all extra entity classes to the persistence unit.
+                    persistenceUnit.addClasses(entityClass.getName());
+                }
+                // Now build the entity manager factory, supplying a proxy classloader, so Hibernate will be able
+                // to find and load the extra provided entities. Set the provided classloader as parent classloader.
+                return Bootstrap.getEntityManagerFactoryBuilder(persistenceUnit, properties,
+                        new ProxyClassLoader(providedEntities, classLoader)).build();
             }
         }
         throw new RuntimeException("Persistence unit '" + unitName + "' not found");
     }
+
+    /**
+     * Get a list of all provided entities by looping over all configured entity providers.
+     * 
+     * @param session the keycloak session
+     * @return a list of all provided entities (can be an empty list)
+     */
+    public static List<Class<?>> getProvidedEntities(KeycloakSession session) {
+        List<Class<?>> providedEntityClasses = new ArrayList<>();
+        // Get all configured entity providers.
+        Set<JpaEntityProvider> entityProviders = session.getAllProviders(JpaEntityProvider.class);
+        // For every provider, add all entity classes to the list.
+        for (JpaEntityProvider entityProvider : entityProviders) {
+            providedEntityClasses.addAll(entityProvider.getEntities());
+        }
+        return providedEntityClasses;
+    }
+
+    /**
+     * Get the name of custom table for liquibase updates for give ID of JpaEntityProvider
+     * @param jpaEntityProviderFactoryId
+     * @return table name
+     */
+    public static String getCustomChangelogTableName(String jpaEntityProviderFactoryId) {
+        String upperCased = jpaEntityProviderFactoryId.toUpperCase();
+        upperCased = upperCased.replaceAll("-", "_");
+        upperCased = upperCased.replaceAll("[^A-Z_]", "");
+        return "DATABASECHANGELOG_" + upperCased.substring(0, Math.min(10, upperCased.length()));
+    }
+
 }
diff --git a/model/jpa/src/main/java/org/keycloak/events/jpa/AdminEventEntity.java b/model/jpa/src/main/java/org/keycloak/events/jpa/AdminEventEntity.java
index 6ecebf6..e6cf934 100644
--- a/model/jpa/src/main/java/org/keycloak/events/jpa/AdminEventEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/events/jpa/AdminEventEntity.java
@@ -17,8 +17,12 @@
 
 package org.keycloak.events.jpa;
 
+import org.keycloak.events.admin.ResourceType;
+
 import javax.persistence.Column;
 import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
 import javax.persistence.Id;
 import javax.persistence.Table;
 
@@ -41,6 +45,9 @@ public class AdminEventEntity {
     
     @Column(name="OPERATION_TYPE")
     private String operationType;
+
+    @Column(name="RESOURCE_TYPE", length = 64)
+    private String resourceType;
     
     @Column(name="AUTH_REALM_ID")
     private String authRealmId;
@@ -151,4 +158,11 @@ public class AdminEventEntity {
         this.error = error;
     }
 
+    public String getResourceType() {
+        return resourceType;
+    }
+
+    public void setResourceType(String resourceType) {
+        this.resourceType = resourceType;
+    }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/events/jpa/JpaAdminEventQuery.java b/model/jpa/src/main/java/org/keycloak/events/jpa/JpaAdminEventQuery.java
index b26bef6..9cccd7d 100755
--- a/model/jpa/src/main/java/org/keycloak/events/jpa/JpaAdminEventQuery.java
+++ b/model/jpa/src/main/java/org/keycloak/events/jpa/JpaAdminEventQuery.java
@@ -33,6 +33,7 @@ import javax.persistence.criteria.Root;
 import org.keycloak.events.admin.AdminEvent;
 import org.keycloak.events.admin.AdminEventQuery;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 
 /**
  * @author <a href="mailto:giriraj.sharma27@gmail.com">Giriraj Sharma</a>
@@ -71,7 +72,19 @@ public class JpaAdminEventQuery implements AdminEventQuery {
         predicates.add(root.get("operationType").in(operationStrings));
         return this;
     }
-    
+
+    @Override
+    public AdminEventQuery resourceType(ResourceType... resourceTypes) {
+
+        List<String> resourceTypeStrings = new LinkedList<String>();
+        for (ResourceType e : resourceTypes) {
+            resourceTypeStrings.add(e.toString());
+        }
+        predicates.add(root.get("resourceType").in(resourceTypeStrings));
+
+        return this;
+    }
+
     @Override
     public AdminEventQuery authRealm(String authRealmId) {
         predicates.add(cb.equal(root.get("authRealmId"), authRealmId));
diff --git a/model/jpa/src/main/java/org/keycloak/events/jpa/JpaEventStoreProvider.java b/model/jpa/src/main/java/org/keycloak/events/jpa/JpaEventStoreProvider.java
index 017ba6c..b86d838 100755
--- a/model/jpa/src/main/java/org/keycloak/events/jpa/JpaEventStoreProvider.java
+++ b/model/jpa/src/main/java/org/keycloak/events/jpa/JpaEventStoreProvider.java
@@ -28,6 +28,7 @@ import org.keycloak.events.Event;
 import org.keycloak.events.EventQuery;
 import org.keycloak.events.EventStoreProvider;
 import org.keycloak.events.EventType;
+import org.keycloak.events.admin.ResourceType;
 
 import javax.persistence.EntityManager;
 
@@ -150,6 +151,11 @@ public class JpaEventStoreProvider implements EventStoreProvider {
         adminEventEntity.setRealmId(adminEvent.getRealmId());
         setAuthDetails(adminEventEntity, adminEvent.getAuthDetails());
         adminEventEntity.setOperationType(adminEvent.getOperationType().toString());
+
+        if (adminEvent.getResourceType() != null) {
+            adminEventEntity.setResourceType(adminEvent.getResourceType().toString());
+        }
+
         adminEventEntity.setResourcePath(adminEvent.getResourcePath());
         adminEventEntity.setError(adminEvent.getError());
         
@@ -165,6 +171,11 @@ public class JpaEventStoreProvider implements EventStoreProvider {
         adminEvent.setRealmId(adminEventEntity.getRealmId());
         setAuthDetails(adminEvent, adminEventEntity);
         adminEvent.setOperationType(OperationType.valueOf(adminEventEntity.getOperationType()));
+
+        if (adminEventEntity.getResourceType() != null) {
+            adminEvent.setResourceType(ResourceType.valueOf(adminEventEntity.getResourceType()));
+        }
+
         adminEvent.setResourcePath(adminEventEntity.getResourcePath());
         adminEvent.setError(adminEventEntity.getError());
         
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ComponentConfigEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ComponentConfigEntity.java
new file mode 100755
index 0000000..bf141a8
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ComponentConfigEntity.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.jpa.entities;
+
+import javax.persistence.Access;
+import javax.persistence.AccessType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@NamedQueries({
+        @NamedQuery(name="getComponentConfig", query="select attr from ComponentConfigEntity attr where attr.component = :component"),
+        @NamedQuery(name="deleteComponentConfigByComponent", query="delete from  ComponentConfigEntity attr where attr.component = :component"),
+        @NamedQuery(name="deleteComponentConfigByRealm", query="delete from  ComponentConfigEntity attr where attr.component IN (select u from ComponentEntity u where u.realm=:realm)"),
+        @NamedQuery(name="deleteComponentConfigByParent", query="delete from  ComponentConfigEntity attr where attr.component IN (select u from ComponentEntity u where u.parentId=:parentId)"),
+})
+@Table(name="COMPONENT_CONFIG")
+@Entity
+public class ComponentConfigEntity {
+
+    @Id
+    @Column(name="ID", length = 36)
+    @Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity.  This avoids an extra SQL
+    protected String id;
+
+    @ManyToOne(fetch= FetchType.LAZY)
+    @JoinColumn(name = "COMPONENT_ID")
+    protected ComponentEntity component;
+
+    @Column(name = "NAME")
+    protected String name;
+    @Column(name = "VALUE")
+    protected String value;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    public ComponentEntity getComponent() {
+        return component;
+    }
+
+    public void setComponent(ComponentEntity component) {
+        this.component = component;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null) return false;
+        if (!(o instanceof ComponentConfigEntity)) return false;
+
+        ComponentConfigEntity that = (ComponentConfigEntity) o;
+
+        if (!id.equals(that.getId())) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return id.hashCode();
+    }
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ComponentEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ComponentEntity.java
new file mode 100755
index 0000000..a857978
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ComponentEntity.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.jpa.entities;
+
+import javax.persistence.Access;
+import javax.persistence.AccessType;
+import javax.persistence.CascadeType;
+import javax.persistence.CollectionTable;
+import javax.persistence.Column;
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.MapKeyColumn;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bburke@redhat.com">Bill Burke</a>
+ */
+@NamedQueries({
+        @NamedQuery(name="getComponents", query="select attr from ComponentEntity attr where attr.realm = :realm"),
+        @NamedQuery(name="getComponentsByParentAndType", query="select attr from ComponentEntity attr where attr.realm = :realm and attr.providerType = :providerType and attr.parentId = :parentId"),
+        @NamedQuery(name="getComponentByParent", query="select attr from ComponentEntity attr where attr.realm = :realm and attr.parentId = :parentId"),
+        @NamedQuery(name="getComponentIdsByParent", query="select attr.id from ComponentEntity attr where attr.realm = :realm and attr.parentId = :parentId"),
+        @NamedQuery(name="deleteComponentByRealm", query="delete from  ComponentEntity c where c.realm = :realm"),
+        @NamedQuery(name="deleteComponentByParent", query="delete from  ComponentEntity c where c.parentId = :parentId")
+})
+@Entity
+@Table(name="COMPONENT")
+public class ComponentEntity {
+
+    @Id
+    @Column(name="ID", length = 36)
+    @Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity.  This avoids an extra SQL
+    protected String id;
+
+    @ManyToOne(fetch = FetchType.LAZY)
+    @JoinColumn(name = "REALM_ID")
+    protected RealmEntity realm;
+
+    @Column(name="NAME")
+    protected String name;
+
+    @Column(name="PROVIDER_TYPE")
+    protected String providerType;
+
+    @Column(name="PROVIDER_ID")
+    protected String providerId;
+
+    @Column(name="PARENT_ID")
+    protected String parentId;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getProviderType() {
+        return providerType;
+    }
+
+    public void setProviderType(String providerType) {
+        this.providerType = providerType;
+    }
+
+    public String getProviderId() {
+        return providerId;
+    }
+
+    public void setProviderId(String providerId) {
+        this.providerId = providerId;
+    }
+
+    public String getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(String parentId) {
+        this.parentId = parentId;
+    }
+
+    public RealmEntity getRealm() {
+        return realm;
+    }
+
+    public void setRealm(RealmEntity realm) {
+        this.realm = realm;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null) return false;
+        if (!(o instanceof ComponentEntity)) return false;
+
+        ComponentEntity that = (ComponentEntity) o;
+
+        if (!id.equals(that.getId())) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return id.hashCode();
+    }
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
index 5ad023a..e45d819 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/RealmEntity.java
@@ -136,13 +136,13 @@ public class RealmEntity {
     protected String emailTheme;
 
     @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
-    Collection<RealmAttributeEntity> attributes = new ArrayList<RealmAttributeEntity>();
+    Collection<RealmAttributeEntity> attributes = new ArrayList<>();
 
     @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
-    Collection<RequiredCredentialEntity> requiredCredentials = new ArrayList<RequiredCredentialEntity>();
+    Collection<RequiredCredentialEntity> requiredCredentials = new ArrayList<>();
 
     @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
-    List<UserFederationProviderEntity> userFederationProviders = new ArrayList<UserFederationProviderEntity>();
+    List<UserFederationProviderEntity> userFederationProviders = new ArrayList<>();
 
     @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "realm")
     Collection<UserFederationMapperEntity> userFederationMappers = new ArrayList<UserFederationMapperEntity>();
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserAttributeEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserAttributeEntity.java
index 263757f..2b5d35c 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserAttributeEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/UserAttributeEntity.java
@@ -42,6 +42,7 @@ import java.util.Set;
 @NamedQueries({
         @NamedQuery(name="getAttributesByNameAndValue", query="select attr from UserAttributeEntity attr where attr.name = :name and attr.value = :value"),
         @NamedQuery(name="deleteUserAttributesByRealm", query="delete from  UserAttributeEntity attr where attr.user IN (select u from UserEntity u where u.realmId=:realmId)"),
+        @NamedQuery(name="deleteUserAttributesByNameAndUser", query="delete from  UserAttributeEntity attr where attr.user.id = :userId and attr.name = :name"),
         @NamedQuery(name="deleteUserAttributesByRealmAndLink", query="delete from  UserAttributeEntity attr where attr.user IN (select u from UserEntity u where u.realmId=:realmId and u.federationLink=:link)")
 })
 @Table(name="USER_ATTRIBUTE")
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java
index e504f2b..f5d2666 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaRealmProvider.java
@@ -39,11 +39,9 @@ import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
 /**
@@ -127,7 +125,7 @@ public class JpaRealmProvider implements RealmProvider {
             return false;
         }
         em.refresh(realm);
-        RealmAdapter adapter = new RealmAdapter(session, em, realm);
+        final RealmAdapter adapter = new RealmAdapter(session, em, realm);
         session.users().preRemove(adapter);
 
         realm.getDefaultGroups().clear();
@@ -139,6 +137,10 @@ public class JpaRealmProvider implements RealmProvider {
                 .setParameter("realm", realm).executeUpdate();
         num = em.createNamedQuery("deleteGroupsByRealm")
                 .setParameter("realm", realm).executeUpdate();
+        num = em.createNamedQuery("deleteComponentConfigByRealm")
+                .setParameter("realm", realm).executeUpdate();
+        num = em.createNamedQuery("deleteComponentByRealm")
+                .setParameter("realm", realm).executeUpdate();
 
         TypedQuery<String> query = em.createNamedQuery("getClientIdsByRealm", String.class);
         query.setParameter("realm", realm.getId());
@@ -155,10 +157,24 @@ public class JpaRealmProvider implements RealmProvider {
             session.realms().removeRole(adapter, role);
         }
 
+
         em.remove(realm);
 
         em.flush();
         em.clear();
+
+        session.getKeycloakSessionFactory().publish(new RealmModel.RealmRemovedEvent() {
+            @Override
+            public RealmModel getRealm() {
+                return adapter;
+            }
+
+            @Override
+            public KeycloakSession getKeycloakSession() {
+                return session;
+            }
+        });
+
         return true;
     }
 
@@ -268,6 +284,19 @@ public class JpaRealmProvider implements RealmProvider {
         int val = em.createNamedQuery("deleteGroupRoleMappingsByRole").setParameter("roleId", roleEntity.getId()).executeUpdate();
 
         em.remove(roleEntity);
+
+        session.getKeycloakSessionFactory().publish(new RoleContainerModel.RoleRemovedEvent() {
+            @Override
+            public RoleModel getRole() {
+                return role;
+            }
+
+            @Override
+            public KeycloakSession getKeycloakSession() {
+                return session;
+            }
+        });
+
         em.flush();
         return true;
 
@@ -451,7 +480,7 @@ public class JpaRealmProvider implements RealmProvider {
 
     @Override
     public boolean removeClient(String id, RealmModel realm) {
-        ClientModel client = getClientById(id, realm);
+        final ClientModel client = getClientById(id, realm);
         if (client == null) return false;
 
         session.users().preRemove(realm, client);
@@ -460,17 +489,32 @@ public class JpaRealmProvider implements RealmProvider {
             client.removeRole(role);
         }
 
-
         ClientEntity clientEntity = ((ClientAdapter)client).getEntity();
+
         em.createNamedQuery("deleteScopeMappingByClient").setParameter("client", clientEntity).executeUpdate();
         em.flush();
+
+        session.getKeycloakSessionFactory().publish(new RealmModel.ClientRemovedEvent() {
+            @Override
+            public ClientModel getClient() {
+                return client;
+            }
+
+            @Override
+            public KeycloakSession getKeycloakSession() {
+                return session;
+            }
+        });
+
         em.remove(clientEntity);  // i have no idea why, but this needs to come before deleteScopeMapping
+
         try {
             em.flush();
         } catch (RuntimeException e) {
             logger.errorv("Unable to delete client entity: {0} from realm {1}", client.getClientId(), realm.getName());
             throw e;
         }
+
         return true;
     }
 
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaUserProvider.java b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaUserProvider.java
index 040d6eb..0d938d6 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/JpaUserProvider.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/JpaUserProvider.java
@@ -17,29 +17,39 @@
 
 package org.keycloak.models.jpa;
 
+import org.keycloak.component.ComponentModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.CredentialValidationOutput;
 import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.GroupModel;
 import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ModelDuplicateException;
+import org.keycloak.models.ModelException;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RequiredActionProviderModel;
 import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserConsentModel;
 import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserProvider;
 import org.keycloak.models.jpa.entities.FederatedIdentityEntity;
 import org.keycloak.models.jpa.entities.UserAttributeEntity;
+import org.keycloak.models.jpa.entities.UserConsentEntity;
+import org.keycloak.models.jpa.entities.UserConsentProtocolMapperEntity;
+import org.keycloak.models.jpa.entities.UserConsentRoleEntity;
 import org.keycloak.models.jpa.entities.UserEntity;
 import org.keycloak.models.utils.CredentialValidation;
+import org.keycloak.models.utils.DefaultRoles;
 import org.keycloak.models.utils.KeycloakModelUtils;
 
 import javax.persistence.EntityManager;
 import javax.persistence.TypedQuery;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -79,15 +89,7 @@ public class JpaUserProvider implements UserProvider {
         UserAdapter userModel = new UserAdapter(session, realm, em, entity);
 
         if (addDefaultRoles) {
-            for (String r : realm.getDefaultRoles()) {
-                userModel.grantRoleImpl(realm.getRole(r)); // No need to check if user has role as it's new user
-            }
-
-            for (ClientModel application : realm.getClients()) {
-                for (String r : application.getDefaultRoles()) {
-                    userModel.grantRoleImpl(application.getRole(r)); // No need to check if user has role as it's new user
-                }
-            }
+            DefaultRoles.addDefaultRoles(realm, userModel);
 
             for (GroupModel g : realm.getDefaultGroups()) {
                 userModel.joinGroupImpl(g); // No need to check if user has group as it's new user
@@ -115,6 +117,17 @@ public class JpaUserProvider implements UserProvider {
         UserEntity userEntity = em.find(UserEntity.class, user.getId());
         if (userEntity == null) return false;
         removeUser(userEntity);
+        session.getKeycloakSessionFactory().publish(new UserModel.UserRemovedEvent() {
+            @Override
+            public UserModel getUser() {
+                return user;
+            }
+
+            @Override
+            public KeycloakSession getKeycloakSession() {
+                return session;
+            }
+        });
         return true;
     }
 
@@ -134,6 +147,7 @@ public class JpaUserProvider implements UserProvider {
         if (user != null) {
             em.remove(user);
         }
+
         em.flush();
     }
 
@@ -174,6 +188,164 @@ public class JpaUserProvider implements UserProvider {
     }
 
     @Override
+    public void addConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
+        String clientId = consent.getClient().getId();
+
+        UserConsentEntity consentEntity = getGrantedConsentEntity(user, clientId);
+        if (consentEntity != null) {
+            throw new ModelDuplicateException("Consent already exists for client [" + clientId + "] and user [" + user.getId() + "]");
+        }
+
+        consentEntity = new UserConsentEntity();
+        consentEntity.setId(KeycloakModelUtils.generateId());
+        consentEntity.setUser(em.getReference(UserEntity.class, user.getId()));
+        consentEntity.setClientId(clientId);
+        em.persist(consentEntity);
+        em.flush();
+
+        updateGrantedConsentEntity(consentEntity, consent);
+    }
+
+    @Override
+    public UserConsentModel getConsentByClient(RealmModel realm, UserModel user, String clientId) {
+        UserConsentEntity entity = getGrantedConsentEntity(user, clientId);
+        return toConsentModel(realm, entity);
+    }
+
+    @Override
+    public List<UserConsentModel> getConsents(RealmModel realm, UserModel user) {
+        TypedQuery<UserConsentEntity> query = em.createNamedQuery("userConsentsByUser", UserConsentEntity.class);
+        query.setParameter("userId", user.getId());
+        List<UserConsentEntity> results = query.getResultList();
+
+        List<UserConsentModel> consents = new ArrayList<UserConsentModel>();
+        for (UserConsentEntity entity : results) {
+            UserConsentModel model = toConsentModel(realm, entity);
+            consents.add(model);
+        }
+        return consents;
+    }
+
+    @Override
+    public void updateConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
+        String clientId = consent.getClient().getId();
+
+        UserConsentEntity consentEntity = getGrantedConsentEntity(user, clientId);
+        if (consentEntity == null) {
+            throw new ModelException("Consent not found for client [" + clientId + "] and user [" + user.getId() + "]");
+        }
+
+        updateGrantedConsentEntity(consentEntity, consent);
+    }
+
+    public boolean revokeConsentForClient(RealmModel realm, UserModel user, String clientId) {
+        UserConsentEntity consentEntity = getGrantedConsentEntity(user, clientId);
+        if (consentEntity == null) return false;
+
+        em.remove(consentEntity);
+        em.flush();
+        return true;
+    }
+
+
+    private UserConsentEntity getGrantedConsentEntity(UserModel user, String clientId) {
+        TypedQuery<UserConsentEntity> query = em.createNamedQuery("userConsentByUserAndClient", UserConsentEntity.class);
+        query.setParameter("userId", user.getId());
+        query.setParameter("clientId", clientId);
+        List<UserConsentEntity> results = query.getResultList();
+        if (results.size() > 1) {
+            throw new ModelException("More results found for user [" + user.getUsername() + "] and client [" + clientId + "]");
+        } else if (results.size() == 1) {
+            return results.get(0);
+        } else {
+            return null;
+        }
+    }
+
+    private UserConsentModel toConsentModel(RealmModel realm, UserConsentEntity entity) {
+        if (entity == null) {
+            return null;
+        }
+
+        ClientModel client = realm.getClientById(entity.getClientId());
+        if (client == null) {
+            throw new ModelException("Client with id " + entity.getClientId() + " is not available");
+        }
+        UserConsentModel model = new UserConsentModel(client);
+
+        Collection<UserConsentRoleEntity> grantedRoleEntities = entity.getGrantedRoles();
+        if (grantedRoleEntities != null) {
+            for (UserConsentRoleEntity grantedRole : grantedRoleEntities) {
+                RoleModel grantedRoleModel = realm.getRoleById(grantedRole.getRoleId());
+                if (grantedRoleModel != null) {
+                    model.addGrantedRole(grantedRoleModel);
+                }
+            }
+        }
+
+        Collection<UserConsentProtocolMapperEntity> grantedProtocolMapperEntities = entity.getGrantedProtocolMappers();
+        if (grantedProtocolMapperEntities != null) {
+            for (UserConsentProtocolMapperEntity grantedProtMapper : grantedProtocolMapperEntities) {
+                ProtocolMapperModel protocolMapper = client.getProtocolMapperById(grantedProtMapper.getProtocolMapperId());
+                model.addGrantedProtocolMapper(protocolMapper );
+            }
+        }
+
+        return model;
+    }
+
+    // Update roles and protocolMappers to given consentEntity from the consentModel
+    private void updateGrantedConsentEntity(UserConsentEntity consentEntity, UserConsentModel consentModel) {
+        Collection<UserConsentProtocolMapperEntity> grantedProtocolMapperEntities = consentEntity.getGrantedProtocolMappers();
+        Collection<UserConsentProtocolMapperEntity> mappersToRemove = new HashSet<UserConsentProtocolMapperEntity>(grantedProtocolMapperEntities);
+
+        for (ProtocolMapperModel protocolMapper : consentModel.getGrantedProtocolMappers()) {
+            UserConsentProtocolMapperEntity grantedProtocolMapperEntity = new UserConsentProtocolMapperEntity();
+            grantedProtocolMapperEntity.setUserConsent(consentEntity);
+            grantedProtocolMapperEntity.setProtocolMapperId(protocolMapper.getId());
+
+            // Check if it's already there
+            if (!grantedProtocolMapperEntities.contains(grantedProtocolMapperEntity)) {
+                em.persist(grantedProtocolMapperEntity);
+                em.flush();
+                grantedProtocolMapperEntities.add(grantedProtocolMapperEntity);
+            } else {
+                mappersToRemove.remove(grantedProtocolMapperEntity);
+            }
+        }
+        // Those mappers were no longer on consentModel and will be removed
+        for (UserConsentProtocolMapperEntity toRemove : mappersToRemove) {
+            grantedProtocolMapperEntities.remove(toRemove);
+            em.remove(toRemove);
+        }
+
+        Collection<UserConsentRoleEntity> grantedRoleEntities = consentEntity.getGrantedRoles();
+        Set<UserConsentRoleEntity> rolesToRemove = new HashSet<UserConsentRoleEntity>(grantedRoleEntities);
+        for (RoleModel role : consentModel.getGrantedRoles()) {
+            UserConsentRoleEntity consentRoleEntity = new UserConsentRoleEntity();
+            consentRoleEntity.setUserConsent(consentEntity);
+            consentRoleEntity.setRoleId(role.getId());
+
+            // Check if it's already there
+            if (!grantedRoleEntities.contains(consentRoleEntity)) {
+                em.persist(consentRoleEntity);
+                em.flush();
+                grantedRoleEntities.add(consentRoleEntity);
+            } else {
+                rolesToRemove.remove(consentRoleEntity);
+            }
+        }
+        // Those roles were no longer on consentModel and will be removed
+        for (UserConsentRoleEntity toRemove : rolesToRemove) {
+            grantedRoleEntities.remove(toRemove);
+            em.remove(toRemove);
+        }
+
+        em.flush();
+    }
+
+
+    @Override
     public void grantToAllUsers(RealmModel realm, RoleModel role) {
         int num = em.createNamedQuery("grantRoleToAllUsers")
                 .setParameter("realmId", realm.getId())
@@ -324,7 +496,7 @@ public class JpaUserProvider implements UserProvider {
     }
 
     @Override
-    public UserModel getUserByServiceAccountClient(ClientModel client) {
+    public UserModel getServiceAccount(ClientModel client) {
         TypedQuery<UserEntity> query = em.createNamedQuery("getRealmUserByServiceAccount", UserEntity.class);
         query.setParameter("realmId", client.getRealm().getId());
         query.setParameter("clientInternalId", client.getId());
@@ -354,6 +526,16 @@ public class JpaUserProvider implements UserProvider {
     }
 
     @Override
+    public List<UserModel> getUsers(RealmModel realm) {
+        return getUsers(realm, false);
+    }
+
+    @Override
+    public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) {
+        return getUsers(realm, firstResult, maxResults, false);
+    }
+
+    @Override
     public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults, boolean includeServiceAccounts) {
         String queryName = includeServiceAccounts ? "getAllUsersByRealm" : "getAllUsersByRealmExcludeServiceAccount" ;
 
@@ -366,7 +548,7 @@ public class JpaUserProvider implements UserProvider {
             query.setMaxResults(maxResults);
         }
         List<UserEntity> results = query.getResultList();
-        List<UserModel> users = new ArrayList<UserModel>();
+        List<UserModel> users = new LinkedList<>();
         for (UserEntity entity : results) users.add(new UserAdapter(session, realm, em, entity));
         return users;
     }
@@ -383,7 +565,7 @@ public class JpaUserProvider implements UserProvider {
         }
         List<UserEntity> results = query.getResultList();
 
-        List<UserModel> users = new ArrayList<UserModel>();
+        List<UserModel> users = new LinkedList<>();
         for (UserEntity user : results) {
             users.add(new UserAdapter(session, realm, em, user));
         }
@@ -407,18 +589,18 @@ public class JpaUserProvider implements UserProvider {
             query.setMaxResults(maxResults);
         }
         List<UserEntity> results = query.getResultList();
-        List<UserModel> users = new ArrayList<UserModel>();
+        List<UserModel> users = new LinkedList<>();
         for (UserEntity entity : results) users.add(new UserAdapter(session, realm, em, entity));
         return users;
     }
 
     @Override
-    public List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm) {
-        return searchForUserByAttributes(attributes, realm, -1, -1);
+    public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm) {
+        return searchForUser(attributes, realm, -1, -1);
     }
 
     @Override
-    public List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
+    public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
         StringBuilder builder = new StringBuilder("select u from UserEntity u where u.realmId = :realmId");
         for (Map.Entry<String, String> entry : attributes.entrySet()) {
             String attribute = null;
@@ -529,4 +711,9 @@ public class JpaUserProvider implements UserProvider {
         // Not supported yet
         return null;
     }
+
+    @Override
+    public void preRemove(RealmModel realm, ComponentModel component) {
+
+    }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
index 4167ebc..46df41a 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
@@ -18,8 +18,11 @@
 package org.keycloak.models.jpa;
 
 import org.jboss.logging.Logger;
-import org.keycloak.connections.jpa.util.JpaUtils;
+import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.common.util.StringPropertyReplacer;
+import org.keycloak.component.ComponentModel;
 import org.keycloak.common.enums.SslRequired;
+import org.keycloak.jose.jwk.JWKBuilder;
 import org.keycloak.models.AuthenticationExecutionModel;
 import org.keycloak.models.AuthenticationFlowModel;
 import org.keycloak.models.AuthenticatorConfigModel;
@@ -460,6 +463,12 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
     }
 
     @Override
+    public String getKeyId() {
+        PublicKey publicKey = getPublicKey();
+        return publicKey != null ? JWKBuilder.create().rs256(publicKey).getKeyId() : null;
+    }
+
+    @Override
     public String getPublicKeyPem() {
         return realm.getPublicKeyPem();
     }
@@ -805,6 +814,15 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
         em.flush();
     }
 
+
+    private void removeFederationMappersForProvider(String federationProviderId) {
+        Set<UserFederationMapperEntity> mappers = getUserFederationMapperEntitiesByFederationProvider(federationProviderId);
+        for (UserFederationMapperEntity mapper : mappers) {
+            realm.getUserFederationMappers().remove(mapper);
+            em.remove(mapper);
+        }
+    }
+
     @Override
     public List<UserFederationProviderModel> getUserFederationProviders() {
         List<UserFederationProviderEntity> entities = realm.getUserFederationProviders();
@@ -875,15 +893,6 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
             }
         }
     }
-
-    private void removeFederationMappersForProvider(String federationProviderId) {
-        Set<UserFederationMapperEntity> mappers = getUserFederationMapperEntitiesByFederationProvider(federationProviderId);
-        for (UserFederationMapperEntity mapper : mappers) {
-            realm.getUserFederationMappers().remove(mapper);
-            em.remove(mapper);
-        }
-    }
-
     @Override
     public void updateUserFederationProvider(UserFederationProviderModel model) {
         KeycloakModelUtils.ensureUniqueDisplayName(model.getDisplayName(), model, getUserFederationProviders());
@@ -1034,7 +1043,7 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
     @Override
     public PasswordPolicy getPasswordPolicy() {
         if (passwordPolicy == null) {
-            passwordPolicy = new PasswordPolicy(realm.getPasswordPolicy());
+            passwordPolicy = PasswordPolicy.parse(session, realm.getPasswordPolicy());
         }
         return passwordPolicy;
     }
@@ -2098,4 +2107,146 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
         return session.realms().getClientTemplateById(id, this);
     }
 
+    @Override
+    public ComponentModel addComponentModel(ComponentModel model) {
+        ComponentEntity c = new ComponentEntity();
+        if (model.getId() == null) {
+            c.setId(KeycloakModelUtils.generateId());
+        } else {
+            c.setId(model.getId());
+        }
+        c.setName(model.getName());
+        c.setParentId(model.getParentId());
+        c.setProviderType(model.getProviderType());
+        c.setProviderId(model.getProviderId());
+        c.setRealm(realm);
+        em.persist(c);
+        setConfig(model, c);
+        model.setId(c.getId());
+        return model;
+    }
+
+    protected void setConfig(ComponentModel model, ComponentEntity c) {
+        for (String key : model.getConfig().keySet()) {
+            List<String> vals = model.getConfig().get(key);
+            for (String val : vals) {
+                ComponentConfigEntity config = new ComponentConfigEntity();
+                config.setId(KeycloakModelUtils.generateId());
+                config.setName(key);
+                config.setValue(val);
+                config.setComponent(c);
+                em.persist(config);
+            }
+        }
+    }
+
+    @Override
+    public void updateComponent(ComponentModel component) {
+        ComponentEntity c = em.find(ComponentEntity.class, component.getId());
+        if (c == null) return;
+        c.setName(component.getName());
+        c.setProviderId(component.getProviderId());
+        c.setProviderType(component.getProviderType());
+        c.setParentId(component.getParentId());
+        em.createNamedQuery("deleteComponentConfigByComponent").setParameter("component", c).executeUpdate();
+        em.flush();
+        setConfig(component, c);
+
+
+    }
+
+    @Override
+    public void removeComponent(ComponentModel component) {
+        ComponentEntity c = em.find(ComponentEntity.class, component.getId());
+        if (c == null) return;
+        session.users().preRemove(this, component);
+        em.createNamedQuery("deleteComponentConfigByComponent").setParameter("component", c).executeUpdate();
+        em.remove(c);
+    }
+
+    @Override
+    public void removeComponents(String parentId) {
+        TypedQuery<String> query = em.createNamedQuery("getComponentIdsByParent", String.class)
+                .setParameter("realm", realm)
+                .setParameter("parentId", parentId);
+        List<String> results = query.getResultList();
+        if (results.isEmpty()) return;
+        for (String id : results) {
+            session.users().preRemove(this, getComponent(id));
+        }
+        em.createNamedQuery("deleteComponentConfigByParent").setParameter("parentId", parentId).executeUpdate();
+        em.createNamedQuery("deleteComponentByParent").setParameter("parentId", parentId).executeUpdate();
+
+    }
+
+    @Override
+    public List<ComponentModel> getComponents(String parentId, String providerType) {
+        if (parentId == null) parentId = getId();
+        TypedQuery<ComponentEntity> query = em.createNamedQuery("getComponentsByParentAndType", ComponentEntity.class)
+                .setParameter("realm", realm)
+                .setParameter("parentId", parentId)
+                .setParameter("providerType", providerType);
+        List<ComponentEntity> results = query.getResultList();
+        List<ComponentModel> rtn = new LinkedList<>();
+        for (ComponentEntity c : results) {
+            ComponentModel model = entityToModel(c);
+            rtn.add(model);
+
+        }
+        return rtn;
+    }
+
+    @Override
+    public List<ComponentModel> getComponents(String parentId) {
+        TypedQuery<ComponentEntity> query = em.createNamedQuery("getComponentsByParent", ComponentEntity.class)
+                .setParameter("realm", realm)
+                .setParameter("parentId", parentId);
+        List<ComponentEntity> results = query.getResultList();
+        List<ComponentModel> rtn = new LinkedList<>();
+        for (ComponentEntity c : results) {
+            ComponentModel model = entityToModel(c);
+            rtn.add(model);
+
+        }
+        return rtn;
+    }
+
+    protected ComponentModel entityToModel(ComponentEntity c) {
+        ComponentModel model = new ComponentModel();
+        model.setId(c.getId());
+        model.setName(c.getName());
+        model.setProviderType(c.getProviderType());
+        model.setProviderId(c.getProviderId());
+        model.setParentId(c.getParentId());
+        MultivaluedHashMap<String, String> config = new MultivaluedHashMap<>();
+        TypedQuery<ComponentConfigEntity> configQuery = em.createNamedQuery("getComponentConfig", ComponentConfigEntity.class)
+                .setParameter("component", c);
+        List<ComponentConfigEntity> configResults = configQuery.getResultList();
+        for (ComponentConfigEntity configEntity : configResults) {
+            config.add(configEntity.getName(), configEntity.getValue());
+        }
+        model.setConfig(config);
+        return model;
+    }
+
+    @Override
+    public List<ComponentModel> getComponents() {
+        TypedQuery<ComponentEntity> query = em.createNamedQuery("getComponents", ComponentEntity.class)
+                .setParameter("realm", realm);
+        List<ComponentEntity> results = query.getResultList();
+        List<ComponentModel> rtn = new LinkedList<>();
+        for (ComponentEntity c : results) {
+            ComponentModel model = entityToModel(c);
+            rtn.add(model);
+
+        }
+        return rtn;
+    }
+
+    @Override
+    public ComponentModel getComponent(String id) {
+        ComponentEntity c = em.find(ComponentEntity.class, id);
+        if (c == null) return null;
+        return entityToModel(c);
+    }
 }
\ No newline at end of file
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
index 9cce404..2ea12fd 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/UserAdapter.java
@@ -47,6 +47,7 @@ import org.keycloak.common.util.MultivaluedHashMap;
 import org.keycloak.common.util.Time;
 
 import javax.persistence.EntityManager;
+import javax.persistence.Query;
 import javax.persistence.TypedQuery;
 
 import java.util.ArrayList;
@@ -172,14 +173,11 @@ public class UserAdapter implements UserModel, JpaModel<UserEntity> {
 
     @Override
     public void removeAttribute(String name) {
-        Iterator<UserAttributeEntity> it = user.getAttributes().iterator();
-        while (it.hasNext()) {
-            UserAttributeEntity attr = it.next();
-            if (attr.getName().equals(name)) {
-                it.remove();
-                em.remove(attr);
-            }
-        }
+        // KEYCLOAK-3296 : Remove attribute through HQL to avoid StaleUpdateException
+        Query query = em.createNamedQuery("deleteUserAttributesByNameAndUser");
+        query.setParameter("name", name);
+        query.setParameter("userId", user.getId());
+        int numUpdated = query.executeUpdate();
     }
 
     @Override
@@ -668,163 +666,6 @@ public class UserAdapter implements UserModel, JpaModel<UserEntity> {
         user.setServiceAccountClientLink(clientInternalId);
     }
 
-    @Override
-    public void addConsent(UserConsentModel consent) {
-        String clientId = consent.getClient().getId();
-
-        UserConsentEntity consentEntity = getGrantedConsentEntity(clientId);
-        if (consentEntity != null) {
-            throw new ModelDuplicateException("Consent already exists for client [" + clientId + "] and user [" + user.getId() + "]");
-        }
-
-        consentEntity = new UserConsentEntity();
-        consentEntity.setId(KeycloakModelUtils.generateId());
-        consentEntity.setUser(user);
-        consentEntity.setClientId(clientId);
-        em.persist(consentEntity);
-        em.flush();
-
-        updateGrantedConsentEntity(consentEntity, consent);
-    }
-
-    @Override
-    public UserConsentModel getConsentByClient(String clientId) {
-        UserConsentEntity entity = getGrantedConsentEntity(clientId);
-        return toConsentModel(entity);
-    }
-
-    @Override
-    public List<UserConsentModel> getConsents() {
-        TypedQuery<UserConsentEntity> query = em.createNamedQuery("userConsentsByUser", UserConsentEntity.class);
-        query.setParameter("userId", getId());
-        List<UserConsentEntity> results = query.getResultList();
-
-        List<UserConsentModel> consents = new ArrayList<UserConsentModel>();
-        for (UserConsentEntity entity : results) {
-            UserConsentModel model = toConsentModel(entity);
-            consents.add(model);
-        }
-        return consents;
-    }
-
-    @Override
-    public void updateConsent(UserConsentModel consent) {
-        String clientId = consent.getClient().getId();
-
-        UserConsentEntity consentEntity = getGrantedConsentEntity(clientId);
-        if (consentEntity == null) {
-            throw new ModelException("Consent not found for client [" + clientId + "] and user [" + user.getId() + "]");
-        }
-
-        updateGrantedConsentEntity(consentEntity, consent);
-    }
-
-    @Override
-    public boolean revokeConsentForClient(String clientId) {
-        UserConsentEntity consentEntity = getGrantedConsentEntity(clientId);
-        if (consentEntity == null) return false;
-
-        em.remove(consentEntity);
-        em.flush();
-        return true;
-    }
-
-
-    private UserConsentEntity getGrantedConsentEntity(String clientId) {
-        TypedQuery<UserConsentEntity> query = em.createNamedQuery("userConsentByUserAndClient", UserConsentEntity.class);
-        query.setParameter("userId", getId());
-        query.setParameter("clientId", clientId);
-        List<UserConsentEntity> results = query.getResultList();
-        if (results.size() > 1) {
-            throw new ModelException("More results found for user [" + getUsername() + "] and client [" + clientId + "]");
-        } else if (results.size() == 1) {
-            return results.get(0);
-        } else {
-            return null;
-        }
-    }
-
-    private UserConsentModel toConsentModel(UserConsentEntity entity) {
-        if (entity == null) {
-            return null;
-        }
-
-        ClientModel client = realm.getClientById(entity.getClientId());
-        if (client == null) {
-            throw new ModelException("Client with id " + entity.getClientId() + " is not available");
-        }
-        UserConsentModel model = new UserConsentModel(client);
-
-        Collection<UserConsentRoleEntity> grantedRoleEntities = entity.getGrantedRoles();
-        if (grantedRoleEntities != null) {
-            for (UserConsentRoleEntity grantedRole : grantedRoleEntities) {
-                RoleModel grantedRoleModel = realm.getRoleById(grantedRole.getRoleId());
-                if (grantedRoleModel != null) {
-                    model.addGrantedRole(grantedRoleModel);
-                }
-            }
-        }
-
-        Collection<UserConsentProtocolMapperEntity> grantedProtocolMapperEntities = entity.getGrantedProtocolMappers();
-        if (grantedProtocolMapperEntities != null) {
-            for (UserConsentProtocolMapperEntity grantedProtMapper : grantedProtocolMapperEntities) {
-                ProtocolMapperModel protocolMapper = client.getProtocolMapperById(grantedProtMapper.getProtocolMapperId());
-                model.addGrantedProtocolMapper(protocolMapper );
-            }
-        }
-
-        return model;
-    }
-
-    // Update roles and protocolMappers to given consentEntity from the consentModel
-    private void updateGrantedConsentEntity(UserConsentEntity consentEntity, UserConsentModel consentModel) {
-        Collection<UserConsentProtocolMapperEntity> grantedProtocolMapperEntities = consentEntity.getGrantedProtocolMappers();
-        Collection<UserConsentProtocolMapperEntity> mappersToRemove = new HashSet<UserConsentProtocolMapperEntity>(grantedProtocolMapperEntities);
-
-        for (ProtocolMapperModel protocolMapper : consentModel.getGrantedProtocolMappers()) {
-            UserConsentProtocolMapperEntity grantedProtocolMapperEntity = new UserConsentProtocolMapperEntity();
-            grantedProtocolMapperEntity.setUserConsent(consentEntity);
-            grantedProtocolMapperEntity.setProtocolMapperId(protocolMapper.getId());
-
-            // Check if it's already there
-            if (!grantedProtocolMapperEntities.contains(grantedProtocolMapperEntity)) {
-                em.persist(grantedProtocolMapperEntity);
-                em.flush();
-                grantedProtocolMapperEntities.add(grantedProtocolMapperEntity);
-            } else {
-                mappersToRemove.remove(grantedProtocolMapperEntity);
-            }
-        }
-        // Those mappers were no longer on consentModel and will be removed
-        for (UserConsentProtocolMapperEntity toRemove : mappersToRemove) {
-            grantedProtocolMapperEntities.remove(toRemove);
-            em.remove(toRemove);
-        }
-
-        Collection<UserConsentRoleEntity> grantedRoleEntities = consentEntity.getGrantedRoles();
-        Set<UserConsentRoleEntity> rolesToRemove = new HashSet<UserConsentRoleEntity>(grantedRoleEntities);
-        for (RoleModel role : consentModel.getGrantedRoles()) {
-            UserConsentRoleEntity consentRoleEntity = new UserConsentRoleEntity();
-            consentRoleEntity.setUserConsent(consentEntity);
-            consentRoleEntity.setRoleId(role.getId());
-
-            // Check if it's already there
-            if (!grantedRoleEntities.contains(consentRoleEntity)) {
-                em.persist(consentRoleEntity);
-                em.flush();
-                grantedRoleEntities.add(consentRoleEntity);
-            } else {
-                rolesToRemove.remove(consentRoleEntity);
-            }
-        }
-        // Those roles were no longer on consentModel and will be removed
-        for (UserConsentRoleEntity toRemove : rolesToRemove) {
-            grantedRoleEntities.remove(toRemove);
-            em.remove(toRemove);
-        }
-
-        em.flush();
-    }
 
     @Override
     public boolean equals(Object o) {
diff --git a/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/BrokerLinkEntity.java b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/BrokerLinkEntity.java
new file mode 100755
index 0000000..a6b05cd
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/BrokerLinkEntity.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.storage.jpa.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.IdClass;
+import javax.persistence.JoinColumn;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import java.io.Serializable;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@NamedQueries({
+        @NamedQuery(name= "findBrokerLinkByUser", query="select link from BrokerLinkEntity link where link.userId = :userId"),
+        @NamedQuery(name= "findBrokerLinkByUserAndProvider", query="select link from BrokerLinkEntity link where link.userId = :userId and link.identityProvider = :identityProvider and link.realmId = :realmId"),
+        @NamedQuery(name= "findUserByBrokerLinkAndRealm", query="select link.userId from BrokerLinkEntity link where link.realmId = :realmId and link.identityProvider = :identityProvider and link.brokerUserId = :brokerUserId"),
+        @NamedQuery(name= "deleteBrokerLinkByStorageProvider", query="delete from BrokerLinkEntity social where social.storageProviderId = :storageProviderId"),
+        @NamedQuery(name= "deleteBrokerLinkByRealm", query="delete from BrokerLinkEntity social where social.realmId = :realmId"),
+        @NamedQuery(name= "deleteBrokerLinkByRealmAndLink", query="delete from BrokerLinkEntity social where social.userId IN (select u.id from UserEntity u where realmId=:realmId and u.federationLink=:link)"),
+        @NamedQuery(name= "deleteBrokerLinkByUser", query="delete from BrokerLinkEntity social where social.userId = :userId and social.realmId = :realmId")
+})
+@Table(name="BROKER_LINK")
+@Entity
+@IdClass(BrokerLinkEntity.Key.class)
+public class BrokerLinkEntity {
+
+    @Id
+    @Column(name = "USER_ID")
+    private String userId;
+
+    @Id
+    @Column(name = "IDENTITY_PROVIDER")
+    protected String identityProvider;
+
+    @Column(name = "REALM_ID")
+    protected String realmId;
+
+    @Column(name = "STORAGE_PROVIDER_ID")
+    protected String storageProviderId;
+
+    @Column(name = "BROKER_USER_ID")
+    protected String brokerUserId;
+    @Column(name = "BROKER_USERNAME")
+    protected String brokerUserName;
+
+    @Column(name = "TOKEN")
+    protected String token;
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getIdentityProvider() {
+        return identityProvider;
+    }
+
+    public void setIdentityProvider(String identityProvider) {
+        this.identityProvider = identityProvider;
+    }
+
+    public String getBrokerUserId() {
+        return brokerUserId;
+    }
+
+    public void setBrokerUserId(String brokerUserId) {
+        this.brokerUserId = brokerUserId;
+    }
+
+    public String getBrokerUserName() {
+        return brokerUserName;
+    }
+
+    public void setBrokerUserName(String brokerUserName) {
+        this.brokerUserName = brokerUserName;
+    }
+
+    public String getStorageProviderId() {
+        return storageProviderId;
+    }
+
+    public void setStorageProviderId(String storageProviderId) {
+        this.storageProviderId = storageProviderId;
+    }
+
+    public String getRealmId() {
+        return realmId;
+    }
+
+    public void setRealmId(String realmId) {
+        this.realmId = realmId;
+    }
+
+    public void setToken(String token) {
+        this.token = token;
+    }
+
+    public String getToken() {
+        return token;
+    }
+
+    public static class Key implements Serializable {
+
+        protected String userId;
+
+        protected String identityProvider;
+
+        public Key() {
+        }
+
+        public Key(String userId, String identityProvider) {
+            this.userId = userId;
+            this.identityProvider = identityProvider;
+        }
+
+        public String getUserId() {
+            return userId;
+        }
+
+        public String getIdentityProvider() {
+            return identityProvider;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            Key key = (Key) o;
+
+            if (identityProvider != null ? !identityProvider.equals(key.identityProvider) : key.identityProvider != null)
+                return false;
+            if (userId != null ? !userId.equals(key.userId != null ? key.userId : null) : key.userId != null) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = userId != null ? userId.hashCode() : 0;
+            result = 31 * result + (identityProvider != null ? identityProvider.hashCode() : 0);
+            return result;
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null) return false;
+        if (!(o instanceof BrokerLinkEntity)) return false;
+
+        BrokerLinkEntity key = (BrokerLinkEntity) o;
+
+        if (identityProvider != null ? !identityProvider.equals(key.identityProvider) : key.identityProvider != null)
+            return false;
+        if (userId != null ? !userId.equals(key.userId != null ? key.userId : null) : key.userId != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = userId != null ? userId.hashCode() : 0;
+        result = 31 * result + (identityProvider != null ? identityProvider.hashCode() : 0);
+        return result;
+    }
+
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserAttributeEntity.java b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserAttributeEntity.java
new file mode 100755
index 0000000..c5e6193
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserAttributeEntity.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.storage.jpa.entity;
+
+import javax.persistence.Access;
+import javax.persistence.AccessType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@NamedQueries({
+        @NamedQuery(name="getFederatedAttributesByNameAndValue", query="select attr.userId from FederatedUserAttributeEntity attr where attr.name = :name and attr.value = :value and attr.realmId=:realmId"),
+        @NamedQuery(name="getFederatedAttributesByUser", query="select attr from FederatedUserAttributeEntity attr where attr.userId = :userId and attr.realmId=:realmId"),
+        @NamedQuery(name="deleteUserFederatedAttributesByUser", query="delete from  FederatedUserAttributeEntity attr where attr.userId = :userId and attr.realmId=:realmId"),
+        @NamedQuery(name="deleteUserFederatedAttributesByUserAndName", query="delete from  FederatedUserAttributeEntity attr where attr.userId = :userId and attr.name=:name and attr.realmId=:realmId"),
+        @NamedQuery(name="deleteUserFederatedAttributesByRealm", query="delete from  FederatedUserAttributeEntity attr where attr.realmId=:realmId"),
+        @NamedQuery(name="deleteFederatedAttributesByStorageProvider", query="delete from FederatedUserAttributeEntity e where e.storageProviderId=:storageProviderId"),
+        @NamedQuery(name="deleteUserFederatedAttributesByRealmAndLink", query="delete from  FederatedUserAttributeEntity attr where attr.userId IN (select u.id from UserEntity u where u.realmId=:realmId and u.federationLink=:link)")
+})
+@Table(name="FED_USER_ATTRIBUTE")
+@Entity
+public class FederatedUserAttributeEntity {
+
+    @Id
+    @Column(name="ID", length = 36)
+    @Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity.  This avoids an extra SQL
+    protected String id;
+
+    @Column(name = "USER_ID")
+    protected String userId;
+
+    @Column(name = "REALM_ID")
+    protected String realmId;
+
+    @Column(name = "STORAGE_PROVIDER_ID")
+    protected String storageProviderId;
+
+    @Column(name = "NAME")
+    protected String name;
+    @Column(name = "VALUE")
+    protected String value;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getRealmId() {
+        return realmId;
+    }
+
+    public void setRealmId(String realmId) {
+        this.realmId = realmId;
+    }
+
+    public String getStorageProviderId() {
+        return storageProviderId;
+    }
+
+    public void setStorageProviderId(String storageProviderId) {
+        this.storageProviderId = storageProviderId;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null) return false;
+        if (!(o instanceof FederatedUserAttributeEntity)) return false;
+
+        FederatedUserAttributeEntity that = (FederatedUserAttributeEntity) o;
+
+        if (!id.equals(that.getId())) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return id.hashCode();
+    }
+
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserConsentEntity.java b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserConsentEntity.java
new file mode 100755
index 0000000..8066310
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserConsentEntity.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.storage.jpa.entity;
+
+import javax.persistence.Access;
+import javax.persistence.AccessType;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@Entity
+@Table(name="FED_USER_CONSENT", uniqueConstraints = {
+        @UniqueConstraint(columnNames = {"USER_ID", "CLIENT_ID"})
+})
+@NamedQueries({
+        @NamedQuery(name="userFederatedConsentByUserAndClient", query="select consent from FederatedUserConsentEntity consent where consent.userId = :userId and consent.clientId = :clientId"),
+        @NamedQuery(name="userFederatedConsentsByUser", query="select consent from FederatedUserConsentEntity consent where consent.userId = :userId"),
+        @NamedQuery(name="deleteFederatedUserConsentsByRealm", query="delete from FederatedUserConsentEntity consent where consent.realmId=:realmId"),
+        @NamedQuery(name="deleteFederatedUserConsentsByStorageProvider", query="delete from FederatedUserConsentEntity e where e.storageProviderId=:storageProviderId"),
+        @NamedQuery(name="deleteFederatedUserConsentsByUser", query="delete from FederatedUserConsentEntity consent where consent.userId = :userId and consent.realmId = :realmId"),
+        @NamedQuery(name="deleteFederatedUserConsentsByClient", query="delete from FederatedUserConsentEntity consent where consent.clientId = :clientId"),
+})
+public class FederatedUserConsentEntity {
+
+    @Id
+    @Column(name="ID", length = 36)
+    @Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity.  This avoids an extra SQL
+    protected String id;
+
+    @Column(name = "USER_ID")
+    protected String userId;
+
+    @Column(name = "REALM_ID")
+    protected String realmId;
+
+    @Column(name = "STORAGE_PROVIDER_ID")
+    protected String storageProviderId;
+
+    @Column(name="CLIENT_ID")
+    protected String clientId;
+
+    @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "userConsent")
+    Collection<FederatedUserConsentRoleEntity> grantedRoles = new ArrayList<FederatedUserConsentRoleEntity>();
+
+    @OneToMany(cascade ={CascadeType.REMOVE}, orphanRemoval = true, mappedBy = "userConsent")
+    Collection<FederatedUserConsentProtocolMapperEntity> grantedProtocolMappers = new ArrayList<FederatedUserConsentProtocolMapperEntity>();
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getRealmId() {
+        return realmId;
+    }
+
+    public void setRealmId(String realmId) {
+        this.realmId = realmId;
+    }
+
+    public String getStorageProviderId() {
+        return storageProviderId;
+    }
+
+    public void setStorageProviderId(String storageProviderId) {
+        this.storageProviderId = storageProviderId;
+    }
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    public Collection<FederatedUserConsentRoleEntity> getGrantedRoles() {
+        return grantedRoles;
+    }
+
+    public void setGrantedRoles(Collection<FederatedUserConsentRoleEntity> grantedRoles) {
+        this.grantedRoles = grantedRoles;
+    }
+
+    public Collection<FederatedUserConsentProtocolMapperEntity> getGrantedProtocolMappers() {
+        return grantedProtocolMappers;
+    }
+
+    public void setGrantedProtocolMappers(Collection<FederatedUserConsentProtocolMapperEntity> grantedProtocolMappers) {
+        this.grantedProtocolMappers = grantedProtocolMappers;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null) return false;
+        if (!(o instanceof FederatedUserConsentEntity)) return false;
+
+        FederatedUserConsentEntity that = (FederatedUserConsentEntity) o;
+
+        if (!id.equals(that.getId())) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return id.hashCode();
+    }
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserConsentProtocolMapperEntity.java b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserConsentProtocolMapperEntity.java
new file mode 100755
index 0000000..f7da2cc
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserConsentProtocolMapperEntity.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.storage.jpa.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.IdClass;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import java.io.Serializable;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@NamedQueries({
+        @NamedQuery(name="deleteFederatedUserConsentProtMappersByRealm", query=
+                "delete from FederatedUserConsentProtocolMapperEntity csm where csm.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.realmId = :realmId)"),
+        @NamedQuery(name="deleteFederatedUserConsentProtMappersByUser", query="delete from FederatedUserConsentProtocolMapperEntity csm where csm.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.userId = :userId and consent.realmId = :realmId)"),
+        @NamedQuery(name="deleteFederatedUserConsentProtMappersByStorageProvider", query="delete from FederatedUserConsentProtocolMapperEntity csm where csm.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.storageProviderId = :storageProviderId)"),
+        @NamedQuery(name="deleteFederatedUserConsentProtMappersByProtocolMapper", query="delete from FederatedUserConsentProtocolMapperEntity csm where csm.protocolMapperId = :protocolMapperId"),
+        @NamedQuery(name="deleteFederatedUserConsentProtMappersByClient", query="delete from FederatedUserConsentProtocolMapperEntity csm where csm.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.clientId = :clientId)"),
+})
+@Entity
+@Table(name="FED_USER_CONSENT_PROT_MAPPER")
+@IdClass(FederatedUserConsentProtocolMapperEntity.Key.class)
+public class FederatedUserConsentProtocolMapperEntity {
+
+    @Id
+    @ManyToOne(fetch= FetchType.LAZY)
+    @JoinColumn(name = "USER_CONSENT_ID")
+    protected FederatedUserConsentEntity userConsent;
+
+    @Id
+    @Column(name="PROTOCOL_MAPPER_ID")
+    protected String protocolMapperId;
+
+    public FederatedUserConsentEntity getUserConsent() {
+        return userConsent;
+    }
+
+    public void setUserConsent(FederatedUserConsentEntity userConsent) {
+        this.userConsent = userConsent;
+    }
+
+    public String getProtocolMapperId() {
+        return protocolMapperId;
+    }
+
+    public void setProtocolMapperId(String protocolMapperId) {
+        this.protocolMapperId = protocolMapperId;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null) return false;
+        if (!(o instanceof FederatedUserConsentProtocolMapperEntity)) return false;
+
+        FederatedUserConsentProtocolMapperEntity that = (FederatedUserConsentProtocolMapperEntity)o;
+        Key myKey = new Key(this.userConsent, this.protocolMapperId);
+        Key hisKey = new Key(that.userConsent, that.protocolMapperId);
+        return myKey.equals(hisKey);
+    }
+
+    @Override
+    public int hashCode() {
+        Key myKey = new Key(this.userConsent, this.protocolMapperId);
+        return myKey.hashCode();
+    }
+
+    public static class Key implements Serializable {
+
+        protected FederatedUserConsentEntity userConsent;
+
+        protected String protocolMapperId;
+
+        public Key() {
+        }
+
+        public Key(FederatedUserConsentEntity userConsent, String protocolMapperId) {
+            this.userConsent = userConsent;
+            this.protocolMapperId = protocolMapperId;
+        }
+
+        public FederatedUserConsentEntity getUserConsent() {
+            return userConsent;
+        }
+
+        public String getProtocolMapperId() {
+            return protocolMapperId;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            Key key = (Key) o;
+
+            if (userConsent != null ? !userConsent.getId().equals(key.userConsent != null ? key.userConsent.getId() : null) : key.userConsent != null) return false;
+            if (protocolMapperId != null ? !protocolMapperId.equals(key.protocolMapperId) : key.protocolMapperId != null) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = userConsent != null ? userConsent.getId().hashCode() : 0;
+            result = 31 * result + (protocolMapperId != null ? protocolMapperId.hashCode() : 0);
+            return result;
+        }
+    }
+
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserConsentRoleEntity.java b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserConsentRoleEntity.java
new file mode 100755
index 0000000..d74865d
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserConsentRoleEntity.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.storage.jpa.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.IdClass;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import java.io.Serializable;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@NamedQueries({
+        @NamedQuery(name="deleteFederatedUserConsentRolesByRealm", query="delete from FederatedUserConsentRoleEntity grantedRole where grantedRole.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.realmId = :realmId)"),
+        @NamedQuery(name="deleteFederatedUserConsentRolesByUser", query="delete from FederatedUserConsentRoleEntity grantedRole where grantedRole.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.userId = :userId and consent.realmId = :realmId)"),
+        @NamedQuery(name="deleteFederatedUserConsentRolesByStorageProvider", query="delete from FederatedUserConsentRoleEntity grantedRole where grantedRole.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.storageProviderId = :storageProviderId)"),
+        @NamedQuery(name="deleteFederatedUserConsentRolesByRole", query="delete from FederatedUserConsentRoleEntity grantedRole where grantedRole.roleId = :roleId"),
+        @NamedQuery(name="deleteFederatedUserConsentRolesByClient", query="delete from FederatedUserConsentRoleEntity grantedRole where grantedRole.userConsent IN (select consent from FederatedUserConsentEntity consent where consent.clientId = :clientId)"),
+})
+@Entity
+@Table(name="FED_USER_CONSENT_ROLE")
+@IdClass(FederatedUserConsentRoleEntity.Key.class)
+public class FederatedUserConsentRoleEntity {
+
+    @Id
+    @ManyToOne(fetch= FetchType.LAZY)
+    @JoinColumn(name = "USER_CONSENT_ID")
+    protected FederatedUserConsentEntity userConsent;
+
+    @Id
+    @Column(name="ROLE_ID")
+    protected String roleId;
+
+    public FederatedUserConsentEntity getUserConsent() {
+        return userConsent;
+    }
+
+    public void setUserConsent(FederatedUserConsentEntity userConsent) {
+        this.userConsent = userConsent;
+    }
+
+    public String getRoleId() {
+        return roleId;
+    }
+
+    public void setRoleId(String roleId) {
+        this.roleId = roleId;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null) return false;
+        if (!(o instanceof FederatedUserConsentRoleEntity)) return false;
+
+        FederatedUserConsentRoleEntity that = (FederatedUserConsentRoleEntity)o;
+        Key myKey = new Key(this.userConsent, this.roleId);
+        Key hisKey = new Key(that.userConsent, that.roleId);
+        return myKey.equals(hisKey);
+    }
+
+    @Override
+    public int hashCode() {
+        Key myKey = new Key(this.userConsent, this.roleId);
+        return myKey.hashCode();
+    }
+
+    public static class Key implements Serializable {
+
+        protected FederatedUserConsentEntity userConsent;
+
+        protected String roleId;
+
+        public Key() {
+        }
+
+        public Key(FederatedUserConsentEntity userConsent, String roleId) {
+            this.userConsent = userConsent;
+            this.roleId = roleId;
+        }
+
+        public FederatedUserConsentEntity getUserConsent() {
+            return userConsent;
+        }
+
+        public String getRoleId() {
+            return roleId;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            Key key = (Key) o;
+
+            if (userConsent != null ? !userConsent.getId().equals(key.userConsent != null ? key.userConsent.getId() : null) : key.userConsent != null) return false;
+            if (roleId != null ? !roleId.equals(key.roleId) : key.roleId != null) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = userConsent != null ? userConsent.getId().hashCode() : 0;
+            result = 31 * result + (roleId != null ? roleId.hashCode() : 0);
+            return result;
+        }
+    }
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserCredentialEntity.java b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserCredentialEntity.java
new file mode 100755
index 0000000..996608b
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserCredentialEntity.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.storage.jpa.entity;
+
+import org.keycloak.models.jpa.entities.UserEntity;
+
+import javax.persistence.Access;
+import javax.persistence.AccessType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@NamedQueries({
+        @NamedQuery(name="federatedUserCredentialByUser", query="select cred from FederatedUserCredentialEntity cred where cred.userId = :userId"),
+        @NamedQuery(name="federatedUserCredentialByUserAndType", query="select cred from FederatedUserCredentialEntity cred where cred.userId = :userId and cred.type = :type"),
+        @NamedQuery(name="deleteFederatedUserCredentialByUser", query="delete from FederatedUserCredentialEntity cred where cred.userId = :userId and cred.realmId = :realmId"),
+        @NamedQuery(name="deleteFederatedUserCredentialByUserAndType", query="delete from FederatedUserCredentialEntity cred where cred.userId = :userId and cred.type = :type"),
+        @NamedQuery(name="deleteFederatedUserCredentialByUserAndTypeAndDevice", query="delete from FederatedUserCredentialEntity cred where cred.userId = :userId and cred.type = :type and cred.device = :device"),
+        @NamedQuery(name="deleteFederatedUserCredentialsByRealm", query="delete from FederatedUserCredentialEntity cred where cred.realmId=:realmId"),
+        @NamedQuery(name="deleteFederatedUserCredentialsByStorageProvider", query="delete from FederatedUserCredentialEntity cred where cred.storageProviderId=:storageProviderId"),
+        @NamedQuery(name="deleteFederatedUserCredentialsByRealmAndLink", query="delete from FederatedUserCredentialEntity cred where cred.userId IN (select u.id from UserEntity u where u.realmId=:realmId and u.federationLink=:link)")
+
+})
+@Table(name="FED_USER_CREDENTIAL")
+@Entity
+public class FederatedUserCredentialEntity {
+    @Id
+    @Column(name="ID", length = 36)
+    @Access(AccessType.PROPERTY) // we do this because relationships often fetch id, but not entity.  This avoids an extra SQL
+    protected String id;
+
+    @Column(name="TYPE")
+    protected String type;
+    @Column(name="VALUE")
+    protected String value;
+    @Column(name="DEVICE")
+    protected String device;
+    @Column(name="SALT")
+    protected byte[] salt;
+    @Column(name="HASH_ITERATIONS")
+    protected int hashIterations;
+    @Column(name="CREATED_DATE")
+    protected Long createdDate;
+    
+    @Column(name="USER_ID")
+    protected String userId;
+
+    @Column(name = "REALM_ID")
+    protected String realmId;
+
+    @Column(name = "STORAGE_PROVIDER_ID")
+    protected String storageProviderId;
+
+
+
+    @Column(name="COUNTER")
+    protected int counter;
+
+    @Column(name="ALGORITHM")
+    protected String algorithm;
+    @Column(name="DIGITS")
+    protected int digits;
+    @Column(name="PERIOD")
+    protected int period;
+
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getDevice() {
+        return device;
+    }
+
+    public void setDevice(String device) {
+        this.device = device;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getRealmId() {
+        return realmId;
+    }
+
+    public void setRealmId(String realmId) {
+        this.realmId = realmId;
+    }
+
+    public String getStorageProviderId() {
+        return storageProviderId;
+    }
+
+    public void setStorageProviderId(String storageProviderId) {
+        this.storageProviderId = storageProviderId;
+    }
+
+    public byte[] getSalt() {
+        return salt;
+    }
+
+    public void setSalt(byte[] salt) {
+        this.salt = salt;
+    }
+
+    public int getHashIterations() {
+        return hashIterations;
+    }
+
+    public void setHashIterations(int hashIterations) {
+        this.hashIterations = hashIterations;
+    }
+
+    public Long getCreatedDate() {
+        return createdDate;
+    }
+
+    public void setCreatedDate(Long createdDate) {
+        this.createdDate = createdDate;
+    }
+
+    public int getCounter() {
+        return counter;
+    }
+
+    public void setCounter(int counter) {
+        this.counter = counter;
+    }
+
+    public String getAlgorithm() {
+        return algorithm;
+    }
+
+    public void setAlgorithm(String algorithm) {
+        this.algorithm = algorithm;
+    }
+
+    public int getDigits() {
+        return digits;
+    }
+
+    public void setDigits(int digits) {
+        this.digits = digits;
+    }
+
+    public int getPeriod() {
+        return period;
+    }
+
+    public void setPeriod(int period) {
+        this.period = period;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null) return false;
+        if (!(o instanceof FederatedUserCredentialEntity)) return false;
+
+        FederatedUserCredentialEntity that = (FederatedUserCredentialEntity) o;
+
+        if (!id.equals(that.getId())) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return id.hashCode();
+    }
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserGroupMembershipEntity.java b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserGroupMembershipEntity.java
new file mode 100755
index 0000000..3116a0a
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserGroupMembershipEntity.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.storage.jpa.entity;
+
+import org.keycloak.models.jpa.entities.UserEntity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.IdClass;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import java.io.Serializable;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@NamedQueries({
+        @NamedQuery(name="feduserMemberOf", query="select m from FederatedUserGroupMembershipEntity m where m.userId = :userId and m.groupId = :groupId"),
+        @NamedQuery(name="feduserGroupMembership", query="select m from FederatedUserGroupMembershipEntity m where m.userId = :userId"),
+        @NamedQuery(name="fedgroupMembership", query="select g.userId from FederatedUserGroupMembershipEntity g where g.groupId = :groupId and g.realmId = :realmId"),
+        @NamedQuery(name="feduserGroupIds", query="select m.groupId from FederatedUserGroupMembershipEntity m where m.userId = :userId"),
+        @NamedQuery(name="deleteFederatedUserGroupMembershipByRealm", query="delete from  FederatedUserGroupMembershipEntity mapping where mapping.realmId=:realmId"),
+        @NamedQuery(name="deleteFederatedUserGroupMembershipByStorageProvider", query="delete from FederatedUserGroupMembershipEntity e where e.storageProviderId=:storageProviderId"),
+        @NamedQuery(name="deleteFederatedUserGroupMembershipsByRealmAndLink", query="delete from  FederatedUserGroupMembershipEntity mapping where mapping.userId IN (select u.id from UserEntity u where u.realmId=:realmId and u.federationLink=:link)"),
+        @NamedQuery(name="deleteFederatedUserGroupMembershipsByGroup", query="delete from FederatedUserGroupMembershipEntity m where m.groupId = :groupId"),
+        @NamedQuery(name="deleteFederatedUserGroupMembershipsByUser", query="delete from FederatedUserGroupMembershipEntity m where m.userId = :userId and m.realmId = :realmId")
+
+})
+@Table(name="FED_USER_GROUP_MEMBERSHIP")
+@Entity
+@IdClass(FederatedUserGroupMembershipEntity.Key.class)
+public class FederatedUserGroupMembershipEntity {
+
+    @Id
+    @Column(name = "USER_ID")
+    protected String userId;
+
+    @Id
+    @Column(name = "GROUP_ID")
+    protected String groupId;
+
+    @Column(name = "REALM_ID")
+    protected String realmId;
+
+    @Column(name = "STORAGE_PROVIDER_ID")
+    protected String storageProviderId;
+
+    public String getGroupId() {
+        return groupId;
+    }
+
+    public void setGroupId(String groupId) {
+        this.groupId = groupId;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getRealmId() {
+        return realmId;
+    }
+
+    public void setRealmId(String realmId) {
+        this.realmId = realmId;
+    }
+
+    public String getStorageProviderId() {
+        return storageProviderId;
+    }
+
+    public void setStorageProviderId(String storageProviderId) {
+        this.storageProviderId = storageProviderId;
+    }
+
+    public static class Key implements Serializable {
+
+        protected String userId;
+
+        protected String groupId;
+
+        public Key() {
+        }
+
+        public Key(String userId, String groupId) {
+            this.userId = userId;
+            this.groupId = groupId;
+        }
+
+        public String getUserId() {
+            return userId;
+        }
+
+        public String getGroupId() {
+            return groupId;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            Key key = (Key) o;
+
+            if (!groupId.equals(key.groupId)) return false;
+            if (!userId.equals(key.userId)) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = userId.hashCode();
+            result = 31 * result + groupId.hashCode();
+            return result;
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null) return false;
+        if (!(o instanceof FederatedUserGroupMembershipEntity)) return false;
+
+        FederatedUserGroupMembershipEntity key = (FederatedUserGroupMembershipEntity) o;
+
+        if (!groupId.equals(key.groupId)) return false;
+        if (!userId.equals(key.userId)) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = userId.hashCode();
+        result = 31 * result + groupId.hashCode();
+        return result;
+    }
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserRequiredActionEntity.java b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserRequiredActionEntity.java
new file mode 100755
index 0000000..f30aee6
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserRequiredActionEntity.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.storage.jpa.entity;
+
+import org.keycloak.models.jpa.entities.UserEntity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.Id;
+import javax.persistence.IdClass;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import java.io.Serializable;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@NamedQueries({
+        @NamedQuery(name="getFederatedUserRequiredActionsByUser", query="select action from FederatedUserRequiredActionEntity action where action.userId = :userId and action.realmId=:realmId"),
+        @NamedQuery(name="deleteFederatedUserRequiredActionsByUser", query="delete from FederatedUserRequiredActionEntity action where action.realmId=:realmId and action.userId = :userId"),
+        @NamedQuery(name="deleteFederatedUserRequiredActionsByRealm", query="delete from FederatedUserRequiredActionEntity action where action.realmId=:realmId"),
+        @NamedQuery(name="deleteFederatedUserRequiredActionsByStorageProvider", query="delete from FederatedUserRequiredActionEntity e where e.storageProviderId=:storageProviderId"),
+        @NamedQuery(name="deleteFederatedUserRequiredActionsByRealmAndLink", query="delete from FederatedUserRequiredActionEntity action where action.userId IN (select u.id from UserEntity u where u.realmId=:realmId and u.federationLink=:link)")
+})
+@Entity
+@Table(name="FED_USER_REQUIRED_ACTION")
+@IdClass(FederatedUserRequiredActionEntity.Key.class)
+public class FederatedUserRequiredActionEntity {
+
+    @Id
+    @Column(name="USER_ID")
+    protected String userId;
+
+    @Id
+    @Column(name="REQUIRED_ACTION")
+    protected String action;
+
+    @Column(name = "REALM_ID")
+    protected String realmId;
+
+    @Column(name = "STORAGE_PROVIDER_ID")
+    protected String storageProviderId;
+
+    public String getAction() {
+        return action;
+    }
+
+    public void setAction(String action) {
+        this.action = action;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getRealmId() {
+        return realmId;
+    }
+
+    public void setRealmId(String realmId) {
+        this.realmId = realmId;
+    }
+
+    public String getStorageProviderId() {
+        return storageProviderId;
+    }
+
+    public void setStorageProviderId(String storageProviderId) {
+        this.storageProviderId = storageProviderId;
+    }
+
+    public static class Key implements Serializable {
+
+        protected String userId;
+
+        protected String action;
+
+        public Key() {
+        }
+
+        public Key(String user, String action) {
+            this.userId = user;
+            this.action = action;
+        }
+
+        public String getUserId() {
+            return userId;
+        }
+
+        public String getAction() {
+            return action;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            Key key = (Key) o;
+
+            if (action != key.action) return false;
+            if (userId != null ? !userId.equals(key.userId != null ? key.userId : null) : key.userId != null) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = userId != null ? userId.hashCode() : 0;
+            result = 31 * result + (action != null ? action.hashCode() : 0);
+            return result;
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null) return false;
+        if (!(o instanceof FederatedUserRequiredActionEntity)) return false;
+
+        FederatedUserRequiredActionEntity key = (FederatedUserRequiredActionEntity) o;
+
+        if (action != key.action) return false;
+        if (userId != null ? !userId.equals(key.userId != null ? key.userId : null) : key.userId != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = userId != null ? userId.hashCode() : 0;
+        result = 31 * result + (action != null ? action.hashCode() : 0);
+        return result;
+    }
+
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserRoleMappingEntity.java b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserRoleMappingEntity.java
new file mode 100755
index 0000000..719fce6
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/storage/jpa/entity/FederatedUserRoleMappingEntity.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.storage.jpa.entity;
+
+import org.keycloak.models.jpa.entities.UserEntity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.IdClass;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import java.io.Serializable;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@NamedQueries({
+        @NamedQuery(name="feduserHasRole", query="select m from FederatedUserRoleMappingEntity m where m.userId = :userId and m.roleId = :roleId"),
+        @NamedQuery(name="feduserRoleMappings", query="select m from FederatedUserRoleMappingEntity m where m.userId = :userId"),
+        @NamedQuery(name="deleteFederatedUserRoleMappingsByRealm", query="delete from  FederatedUserRoleMappingEntity mapping where mapping.realmId=:realmId"),
+        @NamedQuery(name="deleteFederatedUserRoleMappingsByStorageProvider", query="delete from FederatedUserRoleMappingEntity e where e.storageProviderId=:storageProviderId"),
+        @NamedQuery(name="deleteFederatedUserRoleMappingsByRealmAndLink", query="delete from  FederatedUserRoleMappingEntity mapping where mapping.userId IN (select u.id from UserEntity u where u.realmId=:realmId and u.federationLink=:link)"),
+        @NamedQuery(name="deleteFederatedUserRoleMappingsByRole", query="delete from FederatedUserRoleMappingEntity m where m.roleId = :roleId"),
+        @NamedQuery(name="deleteFederatedUserRoleMappingsByUser", query="delete from FederatedUserRoleMappingEntity m where m.userId = :userId and m.realmId = :realmId"),
+
+})
+@Table(name="FED_USER_ROLE_MAPPING")
+@Entity
+@IdClass(FederatedUserRoleMappingEntity.Key.class)
+public class FederatedUserRoleMappingEntity {
+
+    @Id
+    @Column(name = "USER_ID")
+    protected String userId;
+
+    @Id
+    @Column(name = "ROLE_ID")
+    protected String roleId;
+
+    @Column(name = "REALM_ID")
+    protected String realmId;
+
+    @Column(name = "STORAGE_PROVIDER_ID")
+    protected String storageProviderId;
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getRealmId() {
+        return realmId;
+    }
+
+    public void setRealmId(String realmId) {
+        this.realmId = realmId;
+    }
+
+    public String getStorageProviderId() {
+        return storageProviderId;
+    }
+
+    public void setStorageProviderId(String storageProviderId) {
+        this.storageProviderId = storageProviderId;
+    }
+
+    public String getRoleId() {
+        return roleId;
+    }
+
+    public void setRoleId(String roleId) {
+        this.roleId = roleId;
+    }
+
+
+    public static class Key implements Serializable {
+
+        protected String userId;
+
+        protected String roleId;
+
+        public Key() {
+        }
+
+        public Key(String userId, String roleId) {
+            this.userId = userId;
+            this.roleId = roleId;
+        }
+
+        public String getUserId() {
+            return userId;
+        }
+
+        public String getRoleId() {
+            return roleId;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+
+            Key key = (Key) o;
+
+            if (!roleId.equals(key.roleId)) return false;
+            if (!userId.equals(key.userId)) return false;
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = userId.hashCode();
+            result = 31 * result + roleId.hashCode();
+            return result;
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null) return false;
+        if (!(o instanceof FederatedUserRoleMappingEntity)) return false;
+
+        FederatedUserRoleMappingEntity key = (FederatedUserRoleMappingEntity) o;
+
+        if (!roleId.equals(key.roleId)) return false;
+        if (!userId.equals(key.userId)) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = userId.hashCode();
+        result = 31 * result + roleId.hashCode();
+        return result;
+    }
+
+}
diff --git a/model/jpa/src/main/java/org/keycloak/storage/jpa/JpaUserFederatedStorageProvider.java b/model/jpa/src/main/java/org/keycloak/storage/jpa/JpaUserFederatedStorageProvider.java
new file mode 100644
index 0000000..f6710dd
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/storage/jpa/JpaUserFederatedStorageProvider.java
@@ -0,0 +1,754 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.jpa;
+
+import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.component.ComponentModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.FederatedIdentityModel;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ModelDuplicateException;
+import org.keycloak.models.ModelException;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserConsentModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserCredentialValueModel;
+import org.keycloak.models.UserFederationProviderModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.FederatedCredentials;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.storage.StorageId;
+import org.keycloak.storage.UserStorageProvider;
+import org.keycloak.storage.federated.UserAttributeFederatedStorage;
+import org.keycloak.storage.federated.UserBrokerLinkFederatedStorage;
+import org.keycloak.storage.federated.UserConsentFederatedStorage;
+import org.keycloak.storage.federated.UserCredentialsFederatedStorage;
+import org.keycloak.storage.federated.UserFederatedStorageProvider;
+import org.keycloak.storage.federated.UserGroupMembershipFederatedStorage;
+import org.keycloak.storage.federated.UserRequiredActionsFederatedStorage;
+import org.keycloak.storage.federated.UserRoleMappingsFederatedStorage;
+import org.keycloak.storage.jpa.entity.BrokerLinkEntity;
+import org.keycloak.storage.jpa.entity.FederatedUserAttributeEntity;
+import org.keycloak.storage.jpa.entity.FederatedUserConsentEntity;
+import org.keycloak.storage.jpa.entity.FederatedUserConsentProtocolMapperEntity;
+import org.keycloak.storage.jpa.entity.FederatedUserConsentRoleEntity;
+import org.keycloak.storage.jpa.entity.FederatedUserCredentialEntity;
+import org.keycloak.storage.jpa.entity.FederatedUserGroupMembershipEntity;
+import org.keycloak.storage.jpa.entity.FederatedUserRequiredActionEntity;
+import org.keycloak.storage.jpa.entity.FederatedUserRoleMappingEntity;
+
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class JpaUserFederatedStorageProvider implements
+        UserFederatedStorageProvider,
+        UserAttributeFederatedStorage,
+        UserBrokerLinkFederatedStorage,
+        UserConsentFederatedStorage,
+        UserCredentialsFederatedStorage,
+        UserGroupMembershipFederatedStorage,
+        UserRequiredActionsFederatedStorage,
+        UserRoleMappingsFederatedStorage {
+
+    private final KeycloakSession session;
+    protected EntityManager em;
+
+    public JpaUserFederatedStorageProvider(KeycloakSession session, EntityManager em) {
+        this.session = session;
+        this.em = em;
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+
+    @Override
+    public void setAttribute(RealmModel realm, UserModel user, String name, List<String> values) {
+        deleteAttribute(realm, user, name);
+        em.flush();
+        for (String value : values) {
+            persistAttributeValue(realm, user, name, value);
+        }
+    }
+
+    private void deleteAttribute(RealmModel realm, UserModel user, String name) {
+        em.createNamedQuery("deleteUserFederatedAttributesByUserAndName")
+                .setParameter("userId", user.getId())
+                .setParameter("realmId", realm.getId())
+                .setParameter("name", name)
+                .executeUpdate();
+    }
+
+    private void persistAttributeValue(RealmModel realm, UserModel user, String name, String value) {
+        FederatedUserAttributeEntity attr = new FederatedUserAttributeEntity();
+        attr.setId(KeycloakModelUtils.generateId());
+        attr.setName(name);
+        attr.setValue(value);
+        attr.setUserId(user.getId());
+        attr.setRealmId(realm.getId());
+        attr.setStorageProviderId(StorageId.resolveProviderId(user));
+        em.persist(attr);
+    }
+
+    @Override
+    public void setSingleAttribute(RealmModel realm, UserModel user, String name, String value) {
+        deleteAttribute(realm, user, name);
+        em.flush();
+        persistAttributeValue(realm, user, name, value);
+    }
+
+    @Override
+    public void removeAttribute(RealmModel realm, UserModel user, String name) {
+        deleteAttribute(realm, user, name);
+        em.flush();
+    }
+
+    @Override
+    public MultivaluedHashMap<String, String> getAttributes(RealmModel realm, UserModel user) {
+        TypedQuery<FederatedUserAttributeEntity> query = em.createNamedQuery("getFederatedAttributesByUser", FederatedUserAttributeEntity.class);
+        List<FederatedUserAttributeEntity> list = query
+                .setParameter("userId", user.getId())
+                .setParameter("realmId", realm.getId())
+                .getResultList();
+        MultivaluedHashMap<String, String> result = new MultivaluedHashMap<>();
+        for (FederatedUserAttributeEntity entity : list) {
+            result.add(entity.getName(), entity.getValue());
+
+        }
+        return result;
+    }
+
+    @Override
+    public List<String> getUsersByUserAttribute(RealmModel realm, String name, String value) {
+        TypedQuery<String> query = em.createNamedQuery("getFederatedAttributesByNameAndValue", String.class)
+                .setParameter("realmId", realm.getId())
+                .setParameter("name", name)
+                .setParameter("value", value);
+        return query.getResultList();
+    }
+
+    @Override
+    public String getUserByFederatedIdentity(FederatedIdentityModel link, RealmModel realm) {
+        TypedQuery<String> query = em.createNamedQuery("findUserByBrokerLinkAndRealm", String.class)
+                .setParameter("realmId", realm.getId())
+                .setParameter("identityProvider", link.getIdentityProvider())
+                .setParameter("brokerUserId", link.getUserId());
+        List<String> results = query.getResultList();
+        if (results.isEmpty()) {
+            return null;
+        } else if (results.size() > 1) {
+            throw new IllegalStateException("More results found for identityProvider=" + link.getIdentityProvider() +
+                    ", userId=" + link.getUserId() + ", results=" + results);
+        } else {
+            return results.get(0);
+        }
+    }
+
+    @Override
+    public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel link) {
+        BrokerLinkEntity entity = new BrokerLinkEntity();
+        entity.setRealmId(realm.getId());
+        entity.setUserId(user.getId());
+        entity.setBrokerUserId(link.getUserId());
+        entity.setIdentityProvider(link.getIdentityProvider());
+        entity.setToken(link.getToken());
+        entity.setBrokerUserName(link.getUserName());
+        entity.setStorageProviderId(StorageId.resolveProviderId(user));
+        em.persist(entity);
+
+    }
+
+    @Override
+    public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider) {
+        BrokerLinkEntity entity = getBrokerLinkEntity(realm, user, socialProvider);
+        if (entity == null) return false;
+        em.remove(entity);
+        return true;
+    }
+
+    private BrokerLinkEntity getBrokerLinkEntity(RealmModel realm, UserModel user, String socialProvider) {
+        TypedQuery<BrokerLinkEntity> query = em.createNamedQuery("findBrokerLinkByUserAndProvider", BrokerLinkEntity.class)
+                .setParameter("userId", user.getId())
+                .setParameter("realmId", realm.getId())
+                .setParameter("identityProvider", socialProvider);
+        List<BrokerLinkEntity> results = query.getResultList();
+        return results.size() > 0 ? results.get(0) : null;
+    }
+
+    @Override
+    public void updateFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel model) {
+        BrokerLinkEntity entity = getBrokerLinkEntity(realm, user, model.getIdentityProvider());
+        if (entity == null) return;
+        entity.setBrokerUserName(model.getUserName());
+        entity.setBrokerUserId(model.getUserId());
+        entity.setToken(model.getToken());
+        em.persist(entity);
+        em.flush();
+
+    }
+
+    @Override
+    public Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm) {
+        TypedQuery<BrokerLinkEntity> query = em.createNamedQuery("findBrokerLinkByUser", BrokerLinkEntity.class)
+                .setParameter("userId", user.getId());
+        List<BrokerLinkEntity> results = query.getResultList();
+        Set<FederatedIdentityModel> set = new HashSet<>();
+        for (BrokerLinkEntity entity : results) {
+            FederatedIdentityModel model = new FederatedIdentityModel(entity.getIdentityProvider(), entity.getBrokerUserId(), entity.getBrokerUserName(), entity.getToken());
+            set.add(model);
+        }
+        return set;
+    }
+
+    @Override
+    public FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm) {
+        BrokerLinkEntity entity = getBrokerLinkEntity(realm, user, socialProvider);
+        if (entity == null) return null;
+        return new FederatedIdentityModel(entity.getIdentityProvider(), entity.getBrokerUserId(), entity.getBrokerUserName(), entity.getToken());
+    }
+
+    @Override
+    public void addConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
+        String clientId = consent.getClient().getId();
+
+        FederatedUserConsentEntity consentEntity = getGrantedConsentEntity(user, clientId);
+        if (consentEntity != null) {
+            throw new ModelDuplicateException("Consent already exists for client [" + clientId + "] and user [" + user.getId() + "]");
+        }
+
+        consentEntity = new FederatedUserConsentEntity();
+        consentEntity.setId(KeycloakModelUtils.generateId());
+        consentEntity.setUserId(user.getId());
+        consentEntity.setClientId(clientId);
+        consentEntity.setRealmId(realm.getId());
+        consentEntity.setStorageProviderId(StorageId.resolveProviderId(user));
+        em.persist(consentEntity);
+        em.flush();
+
+        updateGrantedConsentEntity(consentEntity, consent);
+
+    }
+
+    @Override
+    public UserConsentModel getConsentByClient(RealmModel realm, UserModel user, String clientInternalId) {
+        FederatedUserConsentEntity entity = getGrantedConsentEntity(user, clientInternalId);
+        return toConsentModel(realm, entity);
+    }
+
+    @Override
+    public List<UserConsentModel> getConsents(RealmModel realm, UserModel user) {
+        TypedQuery<FederatedUserConsentEntity> query = em.createNamedQuery("userFederatedConsentsByUser", FederatedUserConsentEntity.class);
+        query.setParameter("userId", user.getId());
+        List<FederatedUserConsentEntity> results = query.getResultList();
+
+        List<UserConsentModel> consents = new ArrayList<UserConsentModel>();
+        for (FederatedUserConsentEntity entity : results) {
+            UserConsentModel model = toConsentModel(realm, entity);
+            consents.add(model);
+        }
+        return consents;
+    }
+
+    @Override
+    public void updateConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
+        String clientId = consent.getClient().getId();
+
+        FederatedUserConsentEntity consentEntity = getGrantedConsentEntity(user, clientId);
+        if (consentEntity == null) {
+            throw new ModelException("Consent not found for client [" + clientId + "] and user [" + user.getId() + "]");
+        }
+
+        updateGrantedConsentEntity(consentEntity, consent);
+
+    }
+
+    @Override
+    public boolean revokeConsentForClient(RealmModel realm, UserModel user, String clientInternalId) {
+        FederatedUserConsentEntity consentEntity = getGrantedConsentEntity(user, clientInternalId);
+        if (consentEntity == null) return false;
+
+        em.remove(consentEntity);
+        em.flush();
+        return true;
+    }
+
+    private FederatedUserConsentEntity getGrantedConsentEntity(UserModel user, String clientId) {
+        TypedQuery<FederatedUserConsentEntity> query = em.createNamedQuery("userFederatedConsentByUserAndClient", FederatedUserConsentEntity.class);
+        query.setParameter("userId", user.getId());
+        query.setParameter("clientId", clientId);
+        List<FederatedUserConsentEntity> results = query.getResultList();
+        if (results.size() > 1) {
+            throw new ModelException("More results found for user [" + user.getUsername() + "] and client [" + clientId + "]");
+        } else if (results.size() == 1) {
+            return results.get(0);
+        } else {
+            return null;
+        }
+    }
+
+
+    private UserConsentModel toConsentModel(RealmModel realm, FederatedUserConsentEntity entity) {
+        if (entity == null) {
+            return null;
+        }
+
+        ClientModel client = realm.getClientById(entity.getClientId());
+        if (client == null) {
+            throw new ModelException("Client with id " + entity.getClientId() + " is not available");
+        }
+        UserConsentModel model = new UserConsentModel(client);
+
+        Collection<FederatedUserConsentRoleEntity> grantedRoleEntities = entity.getGrantedRoles();
+        if (grantedRoleEntities != null) {
+            for (FederatedUserConsentRoleEntity grantedRole : grantedRoleEntities) {
+                RoleModel grantedRoleModel = realm.getRoleById(grantedRole.getRoleId());
+                if (grantedRoleModel != null) {
+                    model.addGrantedRole(grantedRoleModel);
+                }
+            }
+        }
+
+        Collection<FederatedUserConsentProtocolMapperEntity> grantedProtocolMapperEntities = entity.getGrantedProtocolMappers();
+        if (grantedProtocolMapperEntities != null) {
+            for (FederatedUserConsentProtocolMapperEntity grantedProtMapper : grantedProtocolMapperEntities) {
+                ProtocolMapperModel protocolMapper = client.getProtocolMapperById(grantedProtMapper.getProtocolMapperId());
+                model.addGrantedProtocolMapper(protocolMapper);
+            }
+        }
+
+        return model;
+    }
+
+    // Update roles and protocolMappers to given consentEntity from the consentModel
+    private void updateGrantedConsentEntity(FederatedUserConsentEntity consentEntity, UserConsentModel consentModel) {
+        Collection<FederatedUserConsentProtocolMapperEntity> grantedProtocolMapperEntities = consentEntity.getGrantedProtocolMappers();
+        Collection<FederatedUserConsentProtocolMapperEntity> mappersToRemove = new HashSet<>(grantedProtocolMapperEntities);
+
+        for (ProtocolMapperModel protocolMapper : consentModel.getGrantedProtocolMappers()) {
+            FederatedUserConsentProtocolMapperEntity grantedProtocolMapperEntity = new FederatedUserConsentProtocolMapperEntity();
+            grantedProtocolMapperEntity.setUserConsent(consentEntity);
+            grantedProtocolMapperEntity.setProtocolMapperId(protocolMapper.getId());
+
+            // Check if it's already there
+            if (!grantedProtocolMapperEntities.contains(grantedProtocolMapperEntity)) {
+                em.persist(grantedProtocolMapperEntity);
+                em.flush();
+                grantedProtocolMapperEntities.add(grantedProtocolMapperEntity);
+            } else {
+                mappersToRemove.remove(grantedProtocolMapperEntity);
+            }
+        }
+        // Those mappers were no longer on consentModel and will be removed
+        for (FederatedUserConsentProtocolMapperEntity toRemove : mappersToRemove) {
+            grantedProtocolMapperEntities.remove(toRemove);
+            em.remove(toRemove);
+        }
+
+        Collection<FederatedUserConsentRoleEntity> grantedRoleEntities = consentEntity.getGrantedRoles();
+        Set<FederatedUserConsentRoleEntity> rolesToRemove = new HashSet<>(grantedRoleEntities);
+        for (RoleModel role : consentModel.getGrantedRoles()) {
+            FederatedUserConsentRoleEntity consentRoleEntity = new FederatedUserConsentRoleEntity();
+            consentRoleEntity.setUserConsent(consentEntity);
+            consentRoleEntity.setRoleId(role.getId());
+
+            // Check if it's already there
+            if (!grantedRoleEntities.contains(consentRoleEntity)) {
+                em.persist(consentRoleEntity);
+                em.flush();
+                grantedRoleEntities.add(consentRoleEntity);
+            } else {
+                rolesToRemove.remove(consentRoleEntity);
+            }
+        }
+        // Those roles were no longer on consentModel and will be removed
+        for (FederatedUserConsentRoleEntity toRemove : rolesToRemove) {
+            grantedRoleEntities.remove(toRemove);
+            em.remove(toRemove);
+        }
+
+        em.flush();
+    }
+
+
+
+    @Override
+    public List<UserCredentialValueModel> getCredentials(RealmModel realm, UserModel user) {
+        TypedQuery<FederatedUserCredentialEntity> query = em.createNamedQuery("federatedUserCredentialByUser", FederatedUserCredentialEntity.class)
+                .setParameter("userId", user.getId());
+        List<FederatedUserCredentialEntity> results = query.getResultList();
+        List<UserCredentialValueModel> list = new LinkedList<>();
+        for (FederatedUserCredentialEntity credEntity : results) {
+            UserCredentialValueModel credModel = new UserCredentialValueModel();
+            credModel.setId(credEntity.getId());
+            credModel.setType(credEntity.getType());
+            credModel.setDevice(credEntity.getDevice());
+            credModel.setValue(credEntity.getValue());
+            credModel.setCreatedDate(credEntity.getCreatedDate());
+            credModel.setSalt(credEntity.getSalt());
+            credModel.setHashIterations(credEntity.getHashIterations());
+            credModel.setCounter(credEntity.getCounter());
+            credModel.setAlgorithm(credEntity.getAlgorithm());
+            credModel.setDigits(credEntity.getDigits());
+            credModel.setPeriod(credEntity.getPeriod());
+
+            list.add(credModel);
+        }
+        return list;
+    }
+
+    @Override
+    public void updateCredential(RealmModel realm, UserModel user, UserCredentialModel cred) {
+        FederatedCredentials.updateCredential(session, this, realm, user, cred);
+
+    }
+
+    @Override
+    public void updateCredential(RealmModel realm, UserModel user, UserCredentialValueModel cred) {
+        FederatedUserCredentialEntity entity = null;
+        if (cred.getId() != null) entity = em.find(FederatedUserCredentialEntity.class, cred.getId());
+        boolean newEntity = false;
+        if (entity == null) {
+            entity = new FederatedUserCredentialEntity();
+            entity.setId(KeycloakModelUtils.generateId());
+            newEntity = true;
+        }
+        entity.setUserId(user.getId());
+        entity.setRealmId(realm.getId());
+        entity.setStorageProviderId(StorageId.resolveProviderId(user));
+        entity.setAlgorithm(cred.getAlgorithm());
+        entity.setCounter(cred.getCounter());
+        Long createdDate = cred.getCreatedDate();
+        if (createdDate == null) createdDate = System.currentTimeMillis();
+        entity.setCreatedDate(createdDate);
+        entity.setDevice(cred.getDevice());
+        entity.setDigits(cred.getDigits());
+        entity.setHashIterations(cred.getHashIterations());
+        entity.setPeriod(cred.getPeriod());
+        entity.setSalt(cred.getSalt());
+        entity.setType(cred.getType());
+        entity.setValue(cred.getValue());
+        if (newEntity) {
+            em.persist(entity);
+        }
+
+    }
+
+    @Override
+    public void removeCredential(RealmModel realm, UserModel user, UserCredentialValueModel cred) {
+        FederatedUserCredentialEntity entity = em.find(FederatedUserCredentialEntity.class, cred.getId());
+        em.remove(entity);
+    }
+
+    @Override
+    public Set<GroupModel> getGroups(RealmModel realm, UserModel user) {
+        Set<GroupModel> set = new HashSet<>();
+        TypedQuery<FederatedUserGroupMembershipEntity> query = em.createNamedQuery("feduserGroupMembership", FederatedUserGroupMembershipEntity.class);
+        query.setParameter("userId", user.getId());
+        List<FederatedUserGroupMembershipEntity> results = query.getResultList();
+        if (results.size() == 0) return set;
+        for (FederatedUserGroupMembershipEntity entity : results) {
+            GroupModel group = realm.getGroupById(entity.getGroupId());
+            set.add(group);
+        }
+        return set;
+    }
+
+    @Override
+    public void joinGroup(RealmModel realm, UserModel user, GroupModel group) {
+        if (isMemberOf(realm, user, group)) return;
+        FederatedUserGroupMembershipEntity entity = new FederatedUserGroupMembershipEntity();
+        entity.setUserId(user.getId());
+        entity.setStorageProviderId(StorageId.resolveProviderId(user));
+        entity.setGroupId(group.getId());
+        entity.setRealmId(realm.getId());
+        em.persist(entity);
+
+    }
+
+    public boolean isMemberOf(RealmModel realm, UserModel user, GroupModel group) {
+        Set<GroupModel> roles = user.getGroups();
+        return KeycloakModelUtils.isMember(roles, group);
+    }
+
+
+    @Override
+    public void leaveGroup(RealmModel realm, UserModel user, GroupModel group) {
+        if (user == null || group == null) return;
+
+        TypedQuery<FederatedUserGroupMembershipEntity> query1 = em.createNamedQuery("feduserMemberOf", FederatedUserGroupMembershipEntity.class);
+        query1.setParameter("userId", user.getId());
+        query1.setParameter("groupId", group.getId());
+        TypedQuery<FederatedUserGroupMembershipEntity> query = query1;
+        List<FederatedUserGroupMembershipEntity> results = query.getResultList();
+        if (results.size() == 0) return;
+        for (FederatedUserGroupMembershipEntity entity : results) {
+            em.remove(entity);
+        }
+        em.flush();
+
+    }
+
+    @Override
+    public List<String> getMembership(RealmModel realm, GroupModel group, int firstResult, int max) {
+        TypedQuery<String> query = em.createNamedQuery("fedgroupMembership", String.class)
+                .setParameter("realmId", realm.getId())
+                .setParameter("groupId", group.getId());
+        query.setFirstResult(firstResult);
+        query.setMaxResults(max);
+        return query.getResultList();
+    }
+
+    @Override
+    public Set<String> getRequiredActions(RealmModel realm, UserModel user) {
+        Set<String> set = new HashSet<>();
+        List<FederatedUserRequiredActionEntity> values = getRequiredActionEntities(realm, user);
+        for (FederatedUserRequiredActionEntity entity : values) {
+            set.add(entity.getAction());
+        }
+
+        return set;
+
+    }
+
+    private List<FederatedUserRequiredActionEntity> getRequiredActionEntities(RealmModel realm, UserModel user) {
+        TypedQuery<FederatedUserRequiredActionEntity> query = em.createNamedQuery("getFederatedUserRequiredActionsByUser", FederatedUserRequiredActionEntity.class)
+                .setParameter("userId", user.getId())
+                .setParameter("realmId", realm.getId());
+        return query.getResultList();
+    }
+
+    @Override
+    public void addRequiredAction(RealmModel realm, UserModel user, String action) {
+        if (user.getRequiredActions().contains(action)) return;
+        FederatedUserRequiredActionEntity entity = new FederatedUserRequiredActionEntity();
+        entity.setUserId(user.getId());
+        entity.setRealmId(realm.getId());
+        entity.setStorageProviderId(StorageId.resolveProviderId(user));
+        entity.setAction(action);
+        em.persist(entity);
+
+    }
+
+    @Override
+    public void removeRequiredAction(RealmModel realm, UserModel user, String action) {
+        List<FederatedUserRequiredActionEntity> values = getRequiredActionEntities(realm, user);
+        for (FederatedUserRequiredActionEntity entity : values) {
+            if (action.equals(entity.getAction())) em.remove(entity);
+        }
+        em.flush();
+
+    }
+
+    @Override
+    public void grantRole(RealmModel realm, UserModel user, RoleModel role) {
+        if (user.hasRole(role)) return;
+        FederatedUserRoleMappingEntity entity = new FederatedUserRoleMappingEntity();
+        entity.setUserId(user.getId());
+        entity.setStorageProviderId(StorageId.resolveProviderId(user));
+        entity.setRealmId(realm.getId());
+        entity.setRoleId(role.getId());
+        em.persist(entity);
+
+    }
+
+    @Override
+    public Set<RoleModel> getRoleMappings(RealmModel realm, UserModel user) {
+        Set<RoleModel> set = new HashSet<>();
+        TypedQuery<FederatedUserRoleMappingEntity> query = em.createNamedQuery("feduserRoleMappings", FederatedUserRoleMappingEntity.class);
+        query.setParameter("userId", user.getId());
+        List<FederatedUserRoleMappingEntity> results = query.getResultList();
+        if (results.size() == 0) return set;
+        for (FederatedUserRoleMappingEntity entity : results) {
+            RoleModel role = realm.getRoleById(entity.getRoleId());
+            set.add(role);
+        }
+        return set;
+    }
+
+    @Override
+    public void deleteRoleMapping(RealmModel realm, UserModel user, RoleModel role) {
+        TypedQuery<FederatedUserRoleMappingEntity> query = em.createNamedQuery("feduserRoleMappings", FederatedUserRoleMappingEntity.class);
+        query.setParameter("userId", user.getId());
+        List<FederatedUserRoleMappingEntity> results = query.getResultList();
+        for (FederatedUserRoleMappingEntity entity : results) {
+            if (entity.getRoleId().equals(role.getId())) em.remove(entity);
+
+        }
+        em.flush();
+    }
+
+    @Override
+    public void preRemove(RealmModel realm) {
+        int num = em.createNamedQuery("deleteFederatedUserConsentRolesByRealm")
+                .setParameter("realmId", realm.getId()).executeUpdate();
+        num = em.createNamedQuery("deleteFederatedUserConsentProtMappersByRealm")
+                .setParameter("realmId", realm.getId()).executeUpdate();
+        num = em.createNamedQuery("deleteFederatedUserConsentsByRealm")
+                .setParameter("realmId", realm.getId()).executeUpdate();
+        num = em.createNamedQuery("deleteFederatedUserRoleMappingsByRealm")
+                .setParameter("realmId", realm.getId()).executeUpdate();
+        num = em.createNamedQuery("deleteFederatedUserRequiredActionsByRealm")
+                .setParameter("realmId", realm.getId()).executeUpdate();
+        num = em.createNamedQuery("deleteBrokerLinkByRealm")
+                .setParameter("realmId", realm.getId()).executeUpdate();
+        num = em.createNamedQuery("deleteFederatedUserCredentialsByRealm")
+                .setParameter("realmId", realm.getId()).executeUpdate();
+        num = em.createNamedQuery("deleteUserFederatedAttributesByRealm")
+                .setParameter("realmId", realm.getId()).executeUpdate();
+        num = em.createNamedQuery("deleteFederatedUserGroupMembershipByRealm")
+                .setParameter("realmId", realm.getId()).executeUpdate();
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, UserFederationProviderModel link) {
+        int num = em.createNamedQuery("deleteFederatedUserRoleMappingsByRealmAndLink")
+                .setParameter("realmId", realm.getId())
+                .setParameter("link", link.getId())
+                .executeUpdate();
+        num = em.createNamedQuery("deleteFederatedUserRequiredActionsByRealmAndLink")
+                .setParameter("realmId", realm.getId())
+                .setParameter("link", link.getId())
+                .executeUpdate();
+        num = em.createNamedQuery("deleteBrokerLinkByRealmAndLink")
+                .setParameter("realmId", realm.getId())
+                .setParameter("link", link.getId())
+                .executeUpdate();
+        num = em.createNamedQuery("deleteFederatedUserCredentialsByRealmAndLink")
+                .setParameter("realmId", realm.getId())
+                .setParameter("link", link.getId())
+                .executeUpdate();
+        num = em.createNamedQuery("deleteUserFederatedAttributesByRealmAndLink")
+                .setParameter("realmId", realm.getId())
+                .setParameter("link", link.getId())
+                .executeUpdate();
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, RoleModel role) {
+        em.createNamedQuery("deleteFederatedUserRoleMappingsByRole").setParameter("roleId", role.getId()).executeUpdate();
+        em.createNamedQuery("deleteFederatedUserRoleMappingsByRole").setParameter("roleId", role.getId()).executeUpdate();
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, GroupModel group) {
+        em.createNamedQuery("deleteFederatedUserGroupMembershipsByGroup").setParameter("groupId", group.getId()).executeUpdate();
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, ClientModel client) {
+        em.createNamedQuery("deleteFederatedUserConsentProtMappersByClient").setParameter("clientId", client.getId()).executeUpdate();
+        em.createNamedQuery("deleteFederatedUserConsentRolesByClient").setParameter("clientId", client.getId()).executeUpdate();
+        em.createNamedQuery("deleteFederatedUserConsentsByClient").setParameter("clientId", client.getId()).executeUpdate();
+    }
+
+    @Override
+    public void preRemove(ProtocolMapperModel protocolMapper) {
+        em.createNamedQuery("deleteFederatedUserConsentProtMappersByProtocolMapper")
+                .setParameter("protocolMapperId", protocolMapper.getId())
+                .executeUpdate();
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, UserModel user) {
+        em.createNamedQuery("deleteBrokerLinkByUser")
+                .setParameter("userId", user.getId())
+                .setParameter("realmId", realm.getId())
+                .executeUpdate();
+        em.createNamedQuery("deleteUserFederatedAttributesByUser")
+                .setParameter("userId", user.getId())
+                .setParameter("realmId", realm.getId())
+                .executeUpdate();
+        em.createNamedQuery("deleteFederatedUserConsentProtMappersByUser")
+                .setParameter("userId", user.getId())
+                .setParameter("realmId", realm.getId())
+                .executeUpdate();
+        em.createNamedQuery("deleteFederatedUserConsentRolesByUser")
+                .setParameter("userId", user.getId())
+                .setParameter("realmId", realm.getId())
+                .executeUpdate();
+        em.createNamedQuery("deleteFederatedUserConsentsByUser")
+                .setParameter("userId", user.getId())
+                .setParameter("realmId", realm.getId())
+                .executeUpdate();
+        em.createNamedQuery("deleteFederatedUserCredentialByUser")
+                .setParameter("userId", user.getId())
+                .setParameter("realmId", realm.getId())
+                .executeUpdate();
+        em.createNamedQuery("deleteFederatedUserGroupMembershipsByUser")
+                .setParameter("userId", user.getId())
+                .setParameter("realmId", realm.getId())
+                .executeUpdate();
+        em.createNamedQuery("deleteFederatedUserRequiredActionsByUser")
+                .setParameter("userId", user.getId())
+                .setParameter("realmId", realm.getId())
+                .executeUpdate();
+        em.createNamedQuery("deleteFederatedUserRoleMappingsByUser")
+                .setParameter("userId", user.getId())
+                .setParameter("realmId", realm.getId())
+                .executeUpdate();
+
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, ComponentModel model) {
+        if (!model.getProviderType().equals(UserStorageProvider.class.getName())) return;
+
+        em.createNamedQuery("deleteBrokerLinkByStorageProvider")
+                .setParameter("storageProviderId", model.getId())
+                .executeUpdate();
+        em.createNamedQuery("deleteFederatedAttributesByStorageProvider")
+                .setParameter("storageProviderId", model.getId())
+                .executeUpdate();
+        em.createNamedQuery("deleteFederatedUserConsentProtMappersByStorageProvider")
+                .setParameter("storageProviderId", model.getId())
+                .executeUpdate();
+        em.createNamedQuery("deleteFederatedUserRoleMappingsByStorageProvider")
+                .setParameter("storageProviderId", model.getId())
+                .executeUpdate();
+        em.createNamedQuery("deleteFederatedUserConsentsByStorageProvider")
+                .setParameter("storageProviderId", model.getId())
+                .executeUpdate();
+        em.createNamedQuery("deleteFederatedUserCredentialsByStorageProvider")
+                .setParameter("storageProviderId", model.getId())
+                .executeUpdate();
+        em.createNamedQuery("deleteFederatedUserGroupMembershipByStorageProvider")
+                .setParameter("storageProviderId", model.getId())
+                .executeUpdate();
+        em.createNamedQuery("deleteFederatedUserRequiredActionsByStorageProvider")
+                .setParameter("storageProviderId", model.getId())
+                .executeUpdate();
+        em.createNamedQuery("deleteFederatedUserRoleMappingsByStorageProvider")
+                .setParameter("storageProviderId", model.getId())
+                .executeUpdate();
+
+    }
+}
diff --git a/model/jpa/src/main/java/org/keycloak/storage/jpa/JpaUserFederatedStorageProviderFactory.java b/model/jpa/src/main/java/org/keycloak/storage/jpa/JpaUserFederatedStorageProviderFactory.java
new file mode 100644
index 0000000..0a3218c
--- /dev/null
+++ b/model/jpa/src/main/java/org/keycloak/storage/jpa/JpaUserFederatedStorageProviderFactory.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.jpa;
+
+import org.keycloak.Config;
+import org.keycloak.connections.jpa.JpaConnectionProvider;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.storage.federated.UserFederatedStorageProvider;
+import org.keycloak.storage.federated.UserFederatedStorageProviderFactory;
+
+import javax.persistence.EntityManager;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class JpaUserFederatedStorageProviderFactory implements UserFederatedStorageProviderFactory {
+    @Override
+    public UserFederatedStorageProvider create(KeycloakSession session) {
+        EntityManager em = session.getProvider(JpaConnectionProvider.class).getEntityManager();
+        return new JpaUserFederatedStorageProvider(session, em);
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "jpa";
+    }
+}
diff --git a/model/jpa/src/main/resources/META-INF/db2-jpa-changelog-master.xml b/model/jpa/src/main/resources/META-INF/db2-jpa-changelog-master.xml
index 2d0117e..e6d2753 100644
--- a/model/jpa/src/main/resources/META-INF/db2-jpa-changelog-master.xml
+++ b/model/jpa/src/main/resources/META-INF/db2-jpa-changelog-master.xml
@@ -32,4 +32,8 @@
     <include file="META-INF/jpa-changelog-1.9.0.xml"/>
     <include file="META-INF/db2-jpa-changelog-1.9.1.xml"/>
     <include file="META-INF/jpa-changelog-1.9.2.xml"/>
+
+    <include file="META-INF/jpa-changelog-authz-master.xml"/>
+    <include file="META-INF/jpa-changelog-2.1.0.xml"/>
+    <include file="META-INF/jpa-changelog-2.2.0.xml"/>
 </databaseChangeLog>
diff --git a/model/jpa/src/main/resources/META-INF/jpa-changelog-2.1.0.xml b/model/jpa/src/main/resources/META-INF/jpa-changelog-2.1.0.xml
new file mode 100755
index 0000000..eb4dd1f
--- /dev/null
+++ b/model/jpa/src/main/resources/META-INF/jpa-changelog-2.1.0.xml
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
+    <changeSet author="bburke@redhat.com" id="2.1.0">
+
+        <createTable tableName="BROKER_LINK">
+            <column name="IDENTITY_PROVIDER" type="VARCHAR(255)">
+                <constraints nullable="false" />
+            </column>
+            <column name="STORAGE_PROVIDER_ID" type="VARCHAR(255)">
+            </column>
+            <column name="REALM_ID" type="VARCHAR(36)">
+                <constraints nullable="false" />
+            </column>
+            <column name="BROKER_USER_ID" type="VARCHAR(255)" />
+            <column name="BROKER_USERNAME" type="VARCHAR(255)" />
+            <column name="TOKEN" type="TEXT" />
+            <column name="USER_ID" type="VARCHAR(255)">
+                <constraints nullable="false" />
+            </column>
+        </createTable>
+        <createTable tableName="FED_USER_ATTRIBUTE">
+            <column name="ID" type="VARCHAR(36)">
+                <constraints nullable="false" />
+            </column>
+            <column name="NAME" type="VARCHAR(255)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="USER_ID" type="VARCHAR(255)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="REALM_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="STORAGE_PROVIDER_ID" type="VARCHAR(36)"/>
+            <column name="VALUE" type="VARCHAR(2024)"/>
+        </createTable>
+        <createTable tableName="FED_USER_CONSENT">
+            <column name="ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="CLIENT_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="USER_ID" type="VARCHAR(255)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="REALM_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="STORAGE_PROVIDER_ID" type="VARCHAR(36)"/>
+        </createTable>
+        <createTable tableName="FED_USER_CONSENT_ROLE">
+            <column name="USER_CONSENT_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="ROLE_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+        </createTable>
+        <createTable tableName="FED_USER_CONSENT_PROT_MAPPER">
+            <column name="USER_CONSENT_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="PROTOCOL_MAPPER_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+        </createTable>
+        <createTable tableName="FED_USER_CREDENTIAL">
+            <column name="ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="DEVICE" type="VARCHAR(255)"/>
+            <column name="HASH_ITERATIONS" type="INT"/>
+            <column name="SALT" type="BLOB(16)"/>
+            <column name="TYPE" type="VARCHAR(255)"/>
+            <column name="VALUE" type="VARCHAR(255)"/>
+            <column name="CREATED_DATE" type="BIGINT"/>
+            <column name="COUNTER" type="INT" defaultValueNumeric="0">
+                <constraints nullable="true"/>
+            </column>
+            <column name="DIGITS" type="INT" defaultValueNumeric="6">
+                <constraints nullable="true"/>
+            </column>
+            <column name="PERIOD" type="INT" defaultValueNumeric="30">
+                <constraints nullable="true"/>
+            </column>
+            <column name="ALGORITHM" type="VARCHAR(36)" defaultValue="HmacSHA1">
+                <constraints nullable="true"/>
+            </column>
+            <column name="USER_ID" type="VARCHAR(255)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="REALM_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="STORAGE_PROVIDER_ID" type="VARCHAR(36)"/>
+        </createTable>
+        <createTable tableName="FED_USER_GROUP_MEMBERSHIP">
+            <column name="GROUP_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="USER_ID" type="VARCHAR(255)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="REALM_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="STORAGE_PROVIDER_ID" type="VARCHAR(36)"/>
+        </createTable>
+        <createTable tableName="FED_USER_REQUIRED_ACTION">
+            <column name="REQUIRED_ACTION" type="VARCHAR(255)" defaultValue=" ">
+                <constraints nullable="false"/>
+            </column>
+            <column name="USER_ID" type="VARCHAR(255)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="REALM_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="STORAGE_PROVIDER_ID" type="VARCHAR(36)"/>
+        </createTable>
+        <createTable tableName="FED_USER_ROLE_MAPPING">
+            <column name="ROLE_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="USER_ID" type="VARCHAR(255)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="REALM_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="STORAGE_PROVIDER_ID" type="VARCHAR(36)"/>
+        </createTable>
+
+        <createTable tableName="COMPONENT_CONFIG">
+            <column name="ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="COMPONENT_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="NAME" type="VARCHAR(255)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="VALUE" type="VARCHAR(4000)"/>
+        </createTable>
+        <createTable tableName="COMPONENT">
+            <column name="ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="NAME" type="VARCHAR(255)"/>
+            <column name="PARENT_ID" type="VARCHAR(36)"/>
+            <column name="PROVIDER_ID" type="VARCHAR(36)"/>
+            <column name="PROVIDER_TYPE" type="VARCHAR(255)"/>
+            <column name="REALM_ID" type="VARCHAR(36)"/>
+        </createTable>
+
+
+
+
+        <addPrimaryKey columnNames="IDENTITY_PROVIDER, USER_ID" constraintName="CONSTR_BROKER_LINK_PK" tableName="BROKER_LINK" />
+        <addPrimaryKey columnNames="ID" constraintName="CONSTR_FED_USER_ATTR_PK" tableName="FED_USER_ATTRIBUTE"/>
+        <addPrimaryKey columnNames="ID" constraintName="CONSTR_FED_USER_CONSENT_PK" tableName="FED_USER_CONSENT"/>
+        <addPrimaryKey columnNames="USER_CONSENT_ID, ROLE_ID" constraintName="CONSTR_USER_CONSENT_ROLE_PK" tableName="FED_USER_CONSENT_ROLE"/>
+        <addPrimaryKey columnNames="USER_CONSENT_ID, PROTOCOL_MAPPER_ID" constraintName="CONSTR_USER_CONSENT_PROTM_PK" tableName="FED_USER_CONSENT_PROT_MAPPER"/>
+        <!--
+        <addForeignKeyConstraint baseColumnNames="USER_CONSENT_ID" baseTableName="FED_USER_CONSENT_ROLE" constraintName="FK_FED_GRNTCSNT_ROLE_GR" referencedColumnNames="ID" referencedTableName="FED_USER_CONSENT"/>
+        <addForeignKeyConstraint baseColumnNames="USER_CONSENT_ID" baseTableName="FED_USER_CONSENT_PROT_MAPPER" constraintName="FK_FED_GRNTCSNT_PRM_GR" referencedColumnNames="ID" referencedTableName="FED_USER_CONSENT"/>
+ -->
+        <addPrimaryKey columnNames="ID" constraintName="CONSTR_FED_USER_CRED_PK" tableName="FED_USER_CREDENTIAL"/>
+        <addPrimaryKey columnNames="GROUP_ID, USER_ID" constraintName="CONSTR_FED_USER_GROUP" tableName="FED_USER_GROUP_MEMBERSHIP"/>
+        <addPrimaryKey columnNames="ROLE_ID, USER_ID" constraintName="CONSTR_FED_USER_ROLE" tableName="FED_USER_ROLE_MAPPING"/>
+        <addPrimaryKey columnNames="REQUIRED_ACTION, USER_ID" constraintName="CONSTR_FED_REQUIRED_ACTION" tableName="FED_USER_REQUIRED_ACTION"/>
+
+        <addPrimaryKey columnNames="ID" constraintName="CONSTR_COMPONENT_PK" tableName="COMPONENT"/>
+        <addPrimaryKey columnNames="ID" constraintName="CONSTR_COMPONENT_CONFIG_PK" tableName="COMPONENT_CONFIG"/>
+        <addForeignKeyConstraint baseColumnNames="REALM_ID" baseTableName="COMPONENT" constraintName="FK_COMPONENT_REALM" referencedColumnNames="ID" referencedTableName="REALM"/>
+        <addForeignKeyConstraint baseColumnNames="COMPONENT_ID" baseTableName="COMPONENT_CONFIG" constraintName="FK_COMPONENT_CONFIG" referencedColumnNames="ID" referencedTableName="COMPONENT"/>
+
+    </changeSet>
+
+</databaseChangeLog>
\ No newline at end of file
diff --git a/model/jpa/src/main/resources/META-INF/jpa-changelog-authz-2.0.0.xml b/model/jpa/src/main/resources/META-INF/jpa-changelog-authz-2.0.0.xml
new file mode 100755
index 0000000..6e7d606
--- /dev/null
+++ b/model/jpa/src/main/resources/META-INF/jpa-changelog-authz-2.0.0.xml
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+  ~ JBoss, Home of Professional Open Source.
+  ~ Copyright 2016 Red Hat, Inc., and individual contributors
+  ~ as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.2.xsd">
+    <changeSet author="psilva@redhat.com" id="authz-2.0.0">
+        <createTable tableName="RESOURCE_SERVER">
+            <column name="ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="CLIENT_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="ALLOW_RS_REMOTE_MGMT" type="BOOLEAN" defaultValueBoolean="false">
+                <constraints nullable="false"/>
+            </column>
+            <column name="POLICY_ENFORCE_MODE" type="VARCHAR(15)">
+                <constraints nullable="false"/>
+            </column>
+        </createTable>
+
+        <addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_FARS" tableName="RESOURCE_SERVER"/>
+        <addUniqueConstraint columnNames="CLIENT_ID" constraintName="UK_AU8TT6T700S9V50BU18WS5HA6" tableName="RESOURCE_SERVER"/>
+
+        <createTable tableName="RESOURCE_SERVER_RESOURCE">
+            <column name="ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="NAME" type="VARCHAR(255)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="URI" type="VARCHAR(255)"/>
+            <column name="TYPE" type="VARCHAR(255)"/>
+            <column name="ICON_URI" type="VARCHAR(255)"/>
+            <column name="OWNER" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="RESOURCE_SERVER_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+        </createTable>
+
+        <addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_FARSR" tableName="RESOURCE_SERVER_RESOURCE"/>
+        <addForeignKeyConstraint baseColumnNames="RESOURCE_SERVER_ID" baseTableName="RESOURCE_SERVER_RESOURCE" constraintName="FK_FRSRHO213XCX4WNKOG82SSRFY" referencedColumnNames="ID" referencedTableName="RESOURCE_SERVER"/>
+        <addUniqueConstraint columnNames="NAME,OWNER,RESOURCE_SERVER_ID" constraintName="UK_FRSR6T700S9V50BU18WS5HA6" tableName="RESOURCE_SERVER_RESOURCE"/>
+
+        <createTable tableName="RESOURCE_SERVER_SCOPE">
+            <column name="ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="NAME" type="VARCHAR(255)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="ICON_URI" type="VARCHAR(255)"/>
+            <column name="RESOURCE_SERVER_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+        </createTable>
+
+        <addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_FARSRS" tableName="RESOURCE_SERVER_SCOPE"/>
+        <addForeignKeyConstraint baseColumnNames="RESOURCE_SERVER_ID" baseTableName="RESOURCE_SERVER_SCOPE" constraintName="FK_FRSRSO213XCX4WNKOG82SSRFY" referencedColumnNames="ID" referencedTableName="RESOURCE_SERVER"/>
+        <addUniqueConstraint columnNames="NAME,RESOURCE_SERVER_ID" constraintName="UK_FRSRST700S9V50BU18WS5HA6" tableName="RESOURCE_SERVER_SCOPE"/>
+
+        <createTable tableName="RESOURCE_SERVER_POLICY">
+            <column name="ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="NAME" type="VARCHAR(255)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="DESCRIPTION" type="VARCHAR(255)"/>
+            <column name="TYPE" type="VARCHAR(255)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="DECISION_STRATEGY" type="VARCHAR(20)"/>
+            <column name="LOGIC" type="VARCHAR(20)"/>
+            <column name="RESOURCE_SERVER_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+        </createTable>
+
+        <addPrimaryKey columnNames="ID" constraintName="CONSTRAINT_FARSRP" tableName="RESOURCE_SERVER_POLICY"/>
+        <addForeignKeyConstraint baseColumnNames="RESOURCE_SERVER_ID" baseTableName="RESOURCE_SERVER_POLICY" constraintName="FK_FRSRPO213XCX4WNKOG82SSRFY" referencedColumnNames="ID" referencedTableName="RESOURCE_SERVER"/>
+        <addUniqueConstraint columnNames="NAME,RESOURCE_SERVER_ID" constraintName="UK_FRSRPT700S9V50BU18WS5HA6" tableName="RESOURCE_SERVER_POLICY"/>
+
+        <createTable tableName="POLICY_CONFIG">
+            <column name="POLICY_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="NAME" type="VARCHAR(255)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="VALUE" type="CLOB"/>
+        </createTable>
+
+        <addPrimaryKey columnNames="POLICY_ID, NAME" constraintName="CONSTRAINT_DPC" tableName="POLICY_CONFIG"/>
+        <addForeignKeyConstraint baseColumnNames="POLICY_ID" baseTableName="POLICY_CONFIG" constraintName="FKDC34197CF864C4E43" referencedColumnNames="ID" referencedTableName="RESOURCE_SERVER_POLICY"/>
+
+        <createTable tableName="RESOURCE_SCOPE">
+            <column name="RESOURCE_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="SCOPE_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+        </createTable>
+
+        <addPrimaryKey columnNames="RESOURCE_ID,SCOPE_ID" constraintName="CONSTRAINT_FARSRSP" tableName="RESOURCE_SCOPE"/>
+        <addForeignKeyConstraint baseColumnNames="RESOURCE_ID" baseTableName="RESOURCE_SCOPE" constraintName="FK_FRSRPOS13XCX4WNKOG82SSRFY" referencedColumnNames="ID" referencedTableName="RESOURCE_SERVER_RESOURCE"/>
+        <addForeignKeyConstraint baseColumnNames="SCOPE_ID" baseTableName="RESOURCE_SCOPE" constraintName="FK_FRSRPS213XCX4WNKOG82SSRFY" referencedColumnNames="ID" referencedTableName="RESOURCE_SERVER_SCOPE"/>
+
+        <createTable tableName="RESOURCE_POLICY">
+            <column name="RESOURCE_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="POLICY_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+        </createTable>
+
+        <addPrimaryKey columnNames="RESOURCE_ID,POLICY_ID" constraintName="CONSTRAINT_FARSRPP" tableName="RESOURCE_POLICY"/>
+        <addForeignKeyConstraint baseColumnNames="RESOURCE_ID" baseTableName="RESOURCE_POLICY" constraintName="FK_FRSRPOS53XCX4WNKOG82SSRFY" referencedColumnNames="ID" referencedTableName="RESOURCE_SERVER_RESOURCE"/>
+        <addForeignKeyConstraint baseColumnNames="POLICY_ID" baseTableName="RESOURCE_POLICY" constraintName="FK_FRSRPP213XCX4WNKOG82SSRFY" referencedColumnNames="ID" referencedTableName="RESOURCE_SERVER_POLICY"/>
+
+        <createTable tableName="SCOPE_POLICY">
+            <column name="SCOPE_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="POLICY_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+        </createTable>
+
+        <addPrimaryKey columnNames="SCOPE_ID,POLICY_ID" constraintName="CONSTRAINT_FARSRSPS" tableName="SCOPE_POLICY"/>
+        <addForeignKeyConstraint baseColumnNames="SCOPE_ID" baseTableName="SCOPE_POLICY" constraintName="FK_FRSRPASS3XCX4WNKOG82SSRFY" referencedColumnNames="ID" referencedTableName="RESOURCE_SERVER_SCOPE"/>
+        <addForeignKeyConstraint baseColumnNames="POLICY_ID" baseTableName="SCOPE_POLICY" constraintName="FK_FRSRASP13XCX4WNKOG82SSRFY" referencedColumnNames="ID" referencedTableName="RESOURCE_SERVER_POLICY"/>
+
+        <createTable tableName="ASSOCIATED_POLICY">
+            <column name="POLICY_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="ASSOCIATED_POLICY_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+        </createTable>
+
+        <addPrimaryKey columnNames="POLICY_ID,ASSOCIATED_POLICY_ID" constraintName="CONSTRAINT_FARSRPAP" tableName="ASSOCIATED_POLICY"/>
+        <addForeignKeyConstraint baseColumnNames="POLICY_ID" baseTableName="ASSOCIATED_POLICY" constraintName="FK_FRSRPAS14XCX4WNKOG82SSRFY" referencedColumnNames="ID" referencedTableName="RESOURCE_SERVER_POLICY"/>
+        <addForeignKeyConstraint baseColumnNames="ASSOCIATED_POLICY_ID" baseTableName="ASSOCIATED_POLICY" constraintName="FK_FRSR5S213XCX4WNKOG82SSRFY" referencedColumnNames="ID" referencedTableName="RESOURCE_SERVER_POLICY"/>
+    </changeSet>
+</databaseChangeLog>
diff --git a/model/jpa/src/main/resources/META-INF/jpa-changelog-master.xml b/model/jpa/src/main/resources/META-INF/jpa-changelog-master.xml
index fd1f0f6..55a52b6 100755
--- a/model/jpa/src/main/resources/META-INF/jpa-changelog-master.xml
+++ b/model/jpa/src/main/resources/META-INF/jpa-changelog-master.xml
@@ -32,4 +32,8 @@
     <include file="META-INF/jpa-changelog-1.9.0.xml"/>
     <include file="META-INF/jpa-changelog-1.9.1.xml"/>
     <include file="META-INF/jpa-changelog-1.9.2.xml"/>
+
+    <include file="META-INF/jpa-changelog-authz-master.xml"/>
+    <include file="META-INF/jpa-changelog-2.1.0.xml"/>
+    <include file="META-INF/jpa-changelog-2.2.0.xml"/>
 </databaseChangeLog>
diff --git a/model/jpa/src/main/resources/META-INF/persistence.xml b/model/jpa/src/main/resources/META-INF/persistence.xml
index 7b6ee37..0b2ff23 100755
--- a/model/jpa/src/main/resources/META-INF/persistence.xml
+++ b/model/jpa/src/main/resources/META-INF/persistence.xml
@@ -25,6 +25,8 @@
         <class>org.keycloak.models.jpa.entities.RealmEntity</class>
         <class>org.keycloak.models.jpa.entities.RealmAttributeEntity</class>
         <class>org.keycloak.models.jpa.entities.RequiredCredentialEntity</class>
+        <class>org.keycloak.models.jpa.entities.ComponentConfigEntity</class>
+        <class>org.keycloak.models.jpa.entities.ComponentEntity</class>
         <class>org.keycloak.models.jpa.entities.UserFederationProviderEntity</class>
         <class>org.keycloak.models.jpa.entities.UserFederationMapperEntity</class>
         <class>org.keycloak.models.jpa.entities.RoleEntity</class>
@@ -58,6 +60,23 @@
         <!-- JpaAuditProviders -->
         <class>org.keycloak.events.jpa.EventEntity</class>
         <class>org.keycloak.events.jpa.AdminEventEntity</class>
+
+        <!-- Authorization -->
+        <class>org.keycloak.authorization.jpa.entities.ResourceServerEntity</class>
+        <class>org.keycloak.authorization.jpa.entities.ResourceEntity</class>
+        <class>org.keycloak.authorization.jpa.entities.ScopeEntity</class>
+        <class>org.keycloak.authorization.jpa.entities.PolicyEntity</class>
+
+        <!-- User Federation Storage -->
+        <class>org.keycloak.storage.jpa.entity.BrokerLinkEntity</class>
+        <class>org.keycloak.storage.jpa.entity.FederatedUserAttributeEntity</class>
+        <class>org.keycloak.storage.jpa.entity.FederatedUserConsentEntity</class>
+        <class>org.keycloak.storage.jpa.entity.FederatedUserConsentRoleEntity</class>
+        <class>org.keycloak.storage.jpa.entity.FederatedUserConsentProtocolMapperEntity</class>
+        <class>org.keycloak.storage.jpa.entity.FederatedUserCredentialEntity</class>
+        <class>org.keycloak.storage.jpa.entity.FederatedUserGroupMembershipEntity</class>
+        <class>org.keycloak.storage.jpa.entity.FederatedUserRequiredActionEntity</class>
+        <class>org.keycloak.storage.jpa.entity.FederatedUserRoleMappingEntity</class>
         
         <exclude-unlisted-classes>true</exclude-unlisted-classes>
 
diff --git a/model/jpa/src/main/resources/META-INF/services/org.keycloak.authorization.store.AuthorizationStoreFactory b/model/jpa/src/main/resources/META-INF/services/org.keycloak.authorization.store.AuthorizationStoreFactory
new file mode 100644
index 0000000..46463ee
--- /dev/null
+++ b/model/jpa/src/main/resources/META-INF/services/org.keycloak.authorization.store.AuthorizationStoreFactory
@@ -0,0 +1,19 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2016 Red Hat, Inc., and individual contributors
+# as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.keycloak.authorization.jpa.store.JPAAuthorizationStoreFactory
\ No newline at end of file
diff --git a/model/jpa/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/model/jpa/src/main/resources/META-INF/services/org.keycloak.provider.Spi
index 94c6512..5aba7ba 100644
--- a/model/jpa/src/main/resources/META-INF/services/org.keycloak.provider.Spi
+++ b/model/jpa/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -17,4 +17,5 @@
 
 org.keycloak.connections.jpa.JpaConnectionSpi
 org.keycloak.connections.jpa.updater.JpaUpdaterSpi
-org.keycloak.connections.jpa.updater.liquibase.conn.LiquibaseConnectionSpi
\ No newline at end of file
+org.keycloak.connections.jpa.updater.liquibase.conn.LiquibaseConnectionSpi
+org.keycloak.connections.jpa.entityprovider.JpaEntitySpi
diff --git a/model/jpa/src/main/resources/META-INF/services/org.keycloak.storage.federated.UserFederatedStorageProviderFactory b/model/jpa/src/main/resources/META-INF/services/org.keycloak.storage.federated.UserFederatedStorageProviderFactory
new file mode 100644
index 0000000..c67277c
--- /dev/null
+++ b/model/jpa/src/main/resources/META-INF/services/org.keycloak.storage.federated.UserFederatedStorageProviderFactory
@@ -0,0 +1 @@
+org.keycloak.storage.jpa.JpaUserFederatedStorageProviderFactory
\ No newline at end of file
diff --git a/model/jpa/src/test/java/org/keycloak/connections/jpa/util/JpaUtilsTest.java b/model/jpa/src/test/java/org/keycloak/connections/jpa/util/JpaUtilsTest.java
new file mode 100644
index 0000000..838f1c0
--- /dev/null
+++ b/model/jpa/src/test/java/org/keycloak/connections/jpa/util/JpaUtilsTest.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.connections.jpa.util;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class JpaUtilsTest {
+
+    @Test
+    public void testConvertTableName() {
+        Assert.assertEquals("DATABASECHANGELOG_FOO", JpaUtils.getCustomChangelogTableName("foo"));
+        Assert.assertEquals("DATABASECHANGELOG_FOOBAR", JpaUtils.getCustomChangelogTableName("foo123bar"));
+        Assert.assertEquals("DATABASECHANGELOG_FOO_BAR", JpaUtils.getCustomChangelogTableName("foo_bar568"));
+        Assert.assertEquals("DATABASECHANGELOG_FOO_BAR_C", JpaUtils.getCustomChangelogTableName("foo-bar-c568"));
+        Assert.assertEquals("DATABASECHANGELOG_EXAMPLE_EN", JpaUtils.getCustomChangelogTableName("example-entity-provider"));
+    }
+}
diff --git a/model/mongo/pom.xml b/model/mongo/pom.xml
index db24473..f599f00 100755
--- a/model/mongo/pom.xml
+++ b/model/mongo/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
@@ -31,6 +31,11 @@
     <name>Keycloak Model Mongo</name>
     <description/>
 
+    <properties>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>org.bouncycastle</groupId>
diff --git a/model/mongo/src/main/java/org/keycloak/authorization/mongo/adapter/PolicyAdapter.java b/model/mongo/src/main/java/org/keycloak/authorization/mongo/adapter/PolicyAdapter.java
new file mode 100644
index 0000000..2b28f16
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/authorization/mongo/adapter/PolicyAdapter.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.mongo.adapter;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.mongo.entities.PolicyEntity;
+import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
+import org.keycloak.models.mongo.keycloak.adapters.AbstractMongoAdapter;
+import org.keycloak.representations.idm.authorization.DecisionStrategy;
+import org.keycloak.representations.idm.authorization.Logic;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class PolicyAdapter extends AbstractMongoAdapter<PolicyEntity> implements Policy {
+
+    private final PolicyEntity entity;
+    private final AuthorizationProvider authorizationProvider;
+
+    public PolicyAdapter(PolicyEntity entity, MongoStoreInvocationContext invocationContext, AuthorizationProvider authorizationProvider) {
+        super(invocationContext);
+        this.entity = entity;
+        this.authorizationProvider = authorizationProvider;
+    }
+
+    @Override
+    protected PolicyEntity getMongoEntity() {
+        return entity;
+    }
+
+    @Override
+    public String getId() {
+        return getMongoEntity().getId();
+    }
+
+    @Override
+    public String getType() {
+        return getMongoEntity().getType();
+    }
+
+    @Override
+    public DecisionStrategy getDecisionStrategy() {
+        return getMongoEntity().getDecisionStrategy();
+    }
+
+    @Override
+    public void setDecisionStrategy(DecisionStrategy decisionStrategy) {
+        getMongoEntity().setDecisionStrategy(decisionStrategy);
+        updateMongoEntity();
+    }
+
+    @Override
+    public Logic getLogic() {
+        return getMongoEntity().getLogic();
+    }
+
+    @Override
+    public void setLogic(Logic logic) {
+        getMongoEntity().setLogic(logic);
+        updateMongoEntity();
+    }
+
+    @Override
+    public Map<String, String> getConfig() {
+        return getMongoEntity().getConfig();
+    }
+
+    @Override
+    public void setConfig(Map<String, String> config) {
+        getMongoEntity().setConfig(config);
+        updateMongoEntity();
+    }
+
+    @Override
+    public String getName() {
+        return getMongoEntity().getName();
+    }
+
+    @Override
+    public void setName(String name) {
+        getMongoEntity().setName(name);
+        updateMongoEntity();
+    }
+
+    @Override
+    public String getDescription() {
+        return getMongoEntity().getDescription();
+    }
+
+    @Override
+    public void setDescription(String description) {
+        getMongoEntity().setDescription(description);
+        updateMongoEntity();
+    }
+
+    @Override
+    public ResourceServer getResourceServer() {
+        return this.authorizationProvider.getStoreFactory().getResourceServerStore().findById(getMongoEntity().getResourceServerId());
+    }
+
+    @Override
+    public Set<Policy> getAssociatedPolicies() {
+        return getMongoEntity().getAssociatedPolicies().stream()
+                .map((Function<String, Policy>) id -> authorizationProvider.getStoreFactory().getPolicyStore().findById(id))
+                .collect(Collectors.toSet());
+    }
+
+    @Override
+    public Set<Resource> getResources() {
+        return getMongoEntity().getResources().stream()
+                .map((Function<String, Resource>) id -> authorizationProvider.getStoreFactory().getResourceStore().findById(id))
+                .collect(Collectors.toSet());
+    }
+
+    @Override
+    public Set<Scope> getScopes() {
+        return getMongoEntity().getScopes().stream()
+                .map((Function<String, Scope>) id -> authorizationProvider.getStoreFactory().getScopeStore().findById(id))
+                .collect(Collectors.toSet());
+    }
+
+    @Override
+    public void addScope(Scope scope) {
+        getMongoEntity().addScope(scope.getId());
+        updateMongoEntity();
+    }
+
+    @Override
+    public void removeScope(Scope scope) {
+        getMongoEntity().removeScope(scope.getId());
+        updateMongoEntity();
+    }
+
+    @Override
+    public void addAssociatedPolicy(Policy associatedPolicy) {
+        getMongoEntity().addAssociatedPolicy(associatedPolicy.getId());
+        updateMongoEntity();
+    }
+
+    @Override
+    public void removeAssociatedPolicy(Policy associatedPolicy) {
+        getMongoEntity().removeAssociatedPolicy(associatedPolicy.getId());
+        updateMongoEntity();
+    }
+
+    @Override
+    public void addResource(Resource resource) {
+        getMongoEntity().addResource(resource.getId());
+        updateMongoEntity();
+    }
+
+    @Override
+    public void removeResource(Resource resource) {
+        getMongoEntity().removeResource(resource.getId());
+        updateMongoEntity();
+    }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/authorization/mongo/adapter/ResourceAdapter.java b/model/mongo/src/main/java/org/keycloak/authorization/mongo/adapter/ResourceAdapter.java
new file mode 100644
index 0000000..7c67f6e
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/authorization/mongo/adapter/ResourceAdapter.java
@@ -0,0 +1,106 @@
+package org.keycloak.authorization.mongo.adapter;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.mongo.entities.ResourceEntity;
+import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
+import org.keycloak.models.mongo.keycloak.adapters.AbstractMongoAdapter;
+
+import java.util.List;
+import java.util.Set;
+
+import static java.util.stream.Collectors.toList;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ResourceAdapter extends AbstractMongoAdapter<ResourceEntity> implements Resource {
+
+    private final ResourceEntity entity;
+    private final AuthorizationProvider authorizationProvider;
+
+    public ResourceAdapter(ResourceEntity entity, MongoStoreInvocationContext invocationContext, AuthorizationProvider authorizationProvider) {
+        super(invocationContext);
+        this.entity = entity;
+        this.authorizationProvider = authorizationProvider;
+    }
+
+    @Override
+    public String getId() {
+        return getMongoEntity().getId();
+    }
+
+    @Override
+    public String getName() {
+        return getMongoEntity().getName();
+    }
+
+    @Override
+    public void setName(String name) {
+        getMongoEntity().setName(name);
+        updateMongoEntity();
+    }
+
+    @Override
+    public String getUri() {
+        return getMongoEntity().getUri();
+    }
+
+    @Override
+    public void setUri(String uri) {
+        getMongoEntity().setUri(uri);
+        updateMongoEntity();
+    }
+
+    @Override
+    public String getType() {
+        return getMongoEntity().getType();
+    }
+
+    @Override
+    public void setType(String type) {
+        getMongoEntity().setType(type);
+        updateMongoEntity();
+    }
+
+    @Override
+    public List<Scope> getScopes() {
+        return getMongoEntity().getScopes().stream()
+                .map(id -> authorizationProvider.getStoreFactory().getScopeStore().findById(id))
+                .collect(toList());
+    }
+
+    @Override
+    public String getIconUri() {
+        return getMongoEntity().getIconUri();
+    }
+
+    @Override
+    public void setIconUri(String iconUri) {
+        getMongoEntity().setIconUri(iconUri);
+        updateMongoEntity();
+    }
+
+    @Override
+    public ResourceServer getResourceServer() {
+        return this.authorizationProvider.getStoreFactory().getResourceServerStore().findById(getMongoEntity().getResourceServerId());
+    }
+
+    @Override
+    public String getOwner() {
+        return getMongoEntity().getOwner();
+    }
+
+    @Override
+    public void updateScopes(Set<Scope> scopes) {
+        getMongoEntity().updateScopes(scopes);
+        updateMongoEntity();
+    }
+
+    @Override
+    protected ResourceEntity getMongoEntity() {
+        return this.entity;
+    }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/authorization/mongo/adapter/ResourceServerAdapter.java b/model/mongo/src/main/java/org/keycloak/authorization/mongo/adapter/ResourceServerAdapter.java
new file mode 100644
index 0000000..1bfbf3f
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/authorization/mongo/adapter/ResourceServerAdapter.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.mongo.adapter;
+
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.mongo.entities.ResourceServerEntity;
+import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
+import org.keycloak.models.mongo.keycloak.adapters.AbstractMongoAdapter;
+import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ResourceServerAdapter extends AbstractMongoAdapter<ResourceServerEntity> implements ResourceServer{
+
+    private final ResourceServerEntity entity;
+
+    public ResourceServerAdapter(ResourceServerEntity entity, MongoStoreInvocationContext invocationContext) {
+        super(invocationContext);
+        this.entity = entity;
+    }
+
+    @Override
+    public String getId() {
+        return getMongoEntity().getId();
+    }
+
+    @Override
+    public String getClientId() {
+        return getMongoEntity().getClientId();
+    }
+
+    @Override
+    public boolean isAllowRemoteResourceManagement() {
+        return getMongoEntity().isAllowRemoteResourceManagement();
+    }
+
+    @Override
+    public void setAllowRemoteResourceManagement(boolean allowRemoteResourceManagement) {
+        getMongoEntity().setAllowRemoteResourceManagement(allowRemoteResourceManagement);
+        updateMongoEntity();
+    }
+
+    @Override
+    public PolicyEnforcementMode getPolicyEnforcementMode() {
+        return getMongoEntity().getPolicyEnforcementMode();
+    }
+
+    @Override
+    public void setPolicyEnforcementMode(PolicyEnforcementMode enforcementMode) {
+        getMongoEntity().setPolicyEnforcementMode(enforcementMode);
+        updateMongoEntity();
+    }
+
+    @Override
+    protected ResourceServerEntity getMongoEntity() {
+        return this.entity;
+    }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/authorization/mongo/adapter/ScopeAdapter.java b/model/mongo/src/main/java/org/keycloak/authorization/mongo/adapter/ScopeAdapter.java
new file mode 100644
index 0000000..72196ca
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/authorization/mongo/adapter/ScopeAdapter.java
@@ -0,0 +1,60 @@
+package org.keycloak.authorization.mongo.adapter;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.mongo.entities.ScopeEntity;
+import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
+import org.keycloak.models.mongo.keycloak.adapters.AbstractMongoAdapter;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ScopeAdapter extends AbstractMongoAdapter<ScopeEntity> implements Scope {
+
+    private final ScopeEntity entity;
+    private final AuthorizationProvider authorizationProvider;
+
+    public ScopeAdapter(ScopeEntity entity, MongoStoreInvocationContext invocationContext, AuthorizationProvider authorizationProvider) {
+        super(invocationContext);
+        this.entity = entity;
+        this.authorizationProvider = authorizationProvider;
+    }
+
+    @Override
+    public String getId() {
+        return getMongoEntity().getId();
+    }
+
+    @Override
+    public String getName() {
+        return getMongoEntity().getName();
+    }
+
+    @Override
+    public void setName(String name) {
+        getMongoEntity().setName(name);
+        updateMongoEntity();
+    }
+
+    @Override
+    public String getIconUri() {
+        return getMongoEntity().getIconUri();
+    }
+
+    @Override
+    public void setIconUri(String iconUri) {
+        getMongoEntity().setIconUri(iconUri);
+        updateMongoEntity();
+    }
+
+    @Override
+    public ResourceServer getResourceServer() {
+        return this.authorizationProvider.getStoreFactory().getResourceServerStore().findById(getMongoEntity().getResourceServerId());
+    }
+
+    @Override
+    protected ScopeEntity getMongoEntity() {
+        return this.entity;
+    }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/authorization/mongo/entities/PolicyEntity.java b/model/mongo/src/main/java/org/keycloak/authorization/mongo/entities/PolicyEntity.java
new file mode 100644
index 0000000..c489542
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/authorization/mongo/entities/PolicyEntity.java
@@ -0,0 +1,166 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.mongo.entities;
+
+import org.keycloak.connections.mongo.api.MongoCollection;
+import org.keycloak.connections.mongo.api.MongoIdentifiableEntity;
+import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
+import org.keycloak.models.entities.AbstractIdentifiableEntity;
+import org.keycloak.representations.idm.authorization.DecisionStrategy;
+import org.keycloak.representations.idm.authorization.Logic;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@MongoCollection(collectionName = "policies")
+public class PolicyEntity extends AbstractIdentifiableEntity implements MongoIdentifiableEntity {
+
+    private String name;
+
+    private String description;
+
+    private String type;
+
+    private DecisionStrategy decisionStrategy = DecisionStrategy.UNANIMOUS;
+
+    private Logic logic = Logic.POSITIVE;
+
+    private Map<String, String> config = new HashMap();
+
+    private String resourceServerId;
+
+    private Set<String> associatedPolicies = new HashSet<>();
+
+    private Set<String> resources = new HashSet<>();
+
+    private Set<String> scopes = new HashSet<>();
+
+    public String getType() {
+        return this.type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public DecisionStrategy getDecisionStrategy() {
+        return this.decisionStrategy;
+    }
+
+    public void setDecisionStrategy(DecisionStrategy decisionStrategy) {
+        this.decisionStrategy = decisionStrategy;
+    }
+
+    public Logic getLogic() {
+        return this.logic;
+    }
+
+    public void setLogic(Logic logic) {
+        this.logic = logic;
+    }
+
+    public Map<String, String> getConfig() {
+        return this.config;
+    }
+
+    public void setConfig(Map<String, String> config) {
+        this.config = config;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return this.description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getResourceServerId() {
+        return this.resourceServerId;
+    }
+
+    public void setResourceServerId(String resourceServerId) {
+        this.resourceServerId = resourceServerId;
+    }
+
+    public Set<String> getAssociatedPolicies() {
+        return this.associatedPolicies;
+    }
+
+    public void setAssociatedPolicies(Set<String> associatedPolicies) {
+        this.associatedPolicies = associatedPolicies;
+    }
+
+    public Set<String> getResources() {
+        return this.resources;
+    }
+
+    public void setResources(Set<String> resources) {
+        this.resources = resources;
+    }
+
+    public Set<String> getScopes() {
+        return this.scopes;
+    }
+
+    public void setScopes(Set<String> scopes) {
+        this.scopes = scopes;
+    }
+
+    public void addScope(String scopeId) {
+        getScopes().add(scopeId);
+    }
+
+    public void removeScope(String scopeId) {
+        getScopes().remove(scopeId);
+    }
+
+    public void addAssociatedPolicy(String policyId) {
+        getAssociatedPolicies().add(policyId);
+    }
+
+    public void removeAssociatedPolicy(String policyId) {
+        getAssociatedPolicies().remove(policyId);
+    }
+
+    public void addResource(String resourceId) {
+        getResources().add(resourceId);
+    }
+
+    public void removeResource(String resourceId) {
+        getResources().remove(resourceId);
+    }
+
+    public void afterRemove(MongoStoreInvocationContext invocationContext) {
+
+    }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/authorization/mongo/entities/ResourceEntity.java b/model/mongo/src/main/java/org/keycloak/authorization/mongo/entities/ResourceEntity.java
new file mode 100644
index 0000000..b2e15da
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/authorization/mongo/entities/ResourceEntity.java
@@ -0,0 +1,142 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.mongo.entities;
+
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.connections.mongo.api.MongoCollection;
+import org.keycloak.connections.mongo.api.MongoIdentifiableEntity;
+import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
+import org.keycloak.models.entities.AbstractIdentifiableEntity;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@MongoCollection(collectionName = "resources")
+public class ResourceEntity extends AbstractIdentifiableEntity implements MongoIdentifiableEntity {
+
+    private String name;
+
+    private String uri;
+
+    private String type;
+
+    private String iconUri;
+
+    private String owner;
+
+    private String resourceServerId;
+
+    private List<String> scopes = new ArrayList<>();
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getUri() {
+        return uri;
+    }
+
+    public void setUri(String uri) {
+        this.uri = uri;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public List<String> getScopes() {
+        return this.scopes;
+    }
+
+    public void setScopes(List<String> scopes) {
+        this.scopes = scopes;
+    }
+
+    public String getIconUri() {
+        return iconUri;
+    }
+
+    public void setIconUri(String iconUri) {
+        this.iconUri = iconUri;
+    }
+
+    public String getResourceServerId() {
+        return resourceServerId;
+    }
+
+    public void setResourceServerId(String resourceServerId) {
+        this.resourceServerId = resourceServerId;
+    }
+
+    public String getOwner() {
+        return this.owner;
+    }
+
+    public void setOwner(String owner) {
+        this.owner = owner;
+    }
+
+    public void updateScopes(Set<Scope> toUpdate) {
+        for (Scope scope : toUpdate) {
+            boolean hasScope = false;
+
+            for (String existingScope : this.scopes) {
+                if (existingScope.equals(scope.getId())) {
+                    hasScope = true;
+                }
+            }
+
+            if (!hasScope) {
+                this.scopes.add(scope.getId());
+            }
+        }
+
+        for (String scopeId : new HashSet<String>(this.scopes)) {
+            boolean hasScope = false;
+
+            for (Scope scope : toUpdate) {
+                if (scopeId.equals(scope.getId())) {
+                    hasScope = true;
+                }
+            }
+
+            if (!hasScope) {
+                this.scopes.remove(scopeId);
+            }
+        }
+    }
+
+    @Override
+    public void afterRemove(MongoStoreInvocationContext invocationContext) {
+
+    }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/authorization/mongo/entities/ResourceServerEntity.java b/model/mongo/src/main/java/org/keycloak/authorization/mongo/entities/ResourceServerEntity.java
new file mode 100644
index 0000000..8167c42
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/authorization/mongo/entities/ResourceServerEntity.java
@@ -0,0 +1,67 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.mongo.entities;
+
+import org.keycloak.connections.mongo.api.MongoCollection;
+import org.keycloak.connections.mongo.api.MongoIdentifiableEntity;
+import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
+import org.keycloak.models.entities.AbstractIdentifiableEntity;
+import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@MongoCollection(collectionName = "resource-servers")
+public class ResourceServerEntity extends AbstractIdentifiableEntity implements MongoIdentifiableEntity {
+
+    private String clientId;
+
+    private boolean allowRemoteResourceManagement;
+
+    private PolicyEnforcementMode policyEnforcementMode = PolicyEnforcementMode.ENFORCING;
+
+    public String getClientId() {
+        return this.clientId;
+    }
+
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    public boolean isAllowRemoteResourceManagement() {
+        return this.allowRemoteResourceManagement;
+    }
+
+    public void setAllowRemoteResourceManagement(boolean allowRemoteResourceManagement) {
+        this.allowRemoteResourceManagement = allowRemoteResourceManagement;
+    }
+
+    public PolicyEnforcementMode getPolicyEnforcementMode() {
+        return this.policyEnforcementMode;
+    }
+
+    public void setPolicyEnforcementMode(PolicyEnforcementMode policyEnforcementMode) {
+        this.policyEnforcementMode = policyEnforcementMode;
+    }
+
+    @Override
+    public void afterRemove(MongoStoreInvocationContext invocationContext) {
+
+    }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/authorization/mongo/entities/ScopeEntity.java b/model/mongo/src/main/java/org/keycloak/authorization/mongo/entities/ScopeEntity.java
new file mode 100644
index 0000000..152127d
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/authorization/mongo/entities/ScopeEntity.java
@@ -0,0 +1,66 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.mongo.entities;
+
+import org.keycloak.connections.mongo.api.MongoCollection;
+import org.keycloak.connections.mongo.api.MongoIdentifiableEntity;
+import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
+import org.keycloak.models.entities.AbstractIdentifiableEntity;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@MongoCollection(collectionName = "scopes")
+public class ScopeEntity extends AbstractIdentifiableEntity implements MongoIdentifiableEntity {
+
+    private String name;
+
+    private String iconUri;
+
+    private String resourceServerId;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getIconUri() {
+        return iconUri;
+    }
+
+    public void setIconUri(String iconUri) {
+        this.iconUri = iconUri;
+    }
+
+    public String getResourceServerId() {
+        return resourceServerId;
+    }
+
+    public void setResourceServerId(String resourceServerId) {
+        this.resourceServerId = resourceServerId;
+    }
+
+    @Override
+    public void afterRemove(MongoStoreInvocationContext invocationContext) {
+
+    }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoAuthorizationStoreFactory.java b/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoAuthorizationStoreFactory.java
new file mode 100644
index 0000000..9a484ad
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoAuthorizationStoreFactory.java
@@ -0,0 +1,53 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.mongo.store;
+
+import org.keycloak.Config;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.store.AuthorizationStoreFactory;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.connections.mongo.MongoConnectionProvider;
+import org.keycloak.models.KeycloakSession;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class MongoAuthorizationStoreFactory implements AuthorizationStoreFactory {
+    @Override
+    public StoreFactory  create(KeycloakSession session) {
+        MongoConnectionProvider connection = session.getProvider(MongoConnectionProvider.class);
+        AuthorizationProvider provider = session.getProvider(AuthorizationProvider.class);
+        return new MongoStoreFactory(connection.getInvocationContext(), provider);
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "mongo";
+    }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoPolicyStore.java b/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoPolicyStore.java
new file mode 100644
index 0000000..6f0ba5d
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoPolicyStore.java
@@ -0,0 +1,171 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.mongo.store;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.DBObject;
+import com.mongodb.QueryBuilder;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.mongo.adapter.PolicyAdapter;
+import org.keycloak.authorization.mongo.entities.PolicyEntity;
+import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.connections.mongo.api.MongoStore;
+import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
+import org.keycloak.models.utils.KeycloakModelUtils;
+
+import java.util.List;
+
+import static java.util.stream.Collectors.toList;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class MongoPolicyStore implements PolicyStore {
+
+    private final MongoStoreInvocationContext invocationContext;
+    private final AuthorizationProvider authorizationProvider;
+
+    public MongoPolicyStore(MongoStoreInvocationContext invocationContext, AuthorizationProvider authorizationProvider) {
+        this.invocationContext = invocationContext;
+        this.authorizationProvider = authorizationProvider;
+    }
+
+    @Override
+    public Policy create(String name, String type, ResourceServer resourceServer) {
+        PolicyEntity entity = new PolicyEntity();
+
+        entity.setId(KeycloakModelUtils.generateId());
+        entity.setName(name);
+        entity.setType(type);
+        entity.setResourceServerId(resourceServer.getId());
+
+        getMongoStore().insertEntity(entity, getInvocationContext());
+
+        return new PolicyAdapter(entity, getInvocationContext(), this.authorizationProvider) ;
+    }
+
+    @Override
+    public void delete(String id) {
+        getMongoStore().removeEntity(PolicyEntity.class, id, getInvocationContext());
+    }
+
+    @Override
+    public Policy findById(String id) {
+        PolicyEntity entity = getMongoStore().loadEntity(PolicyEntity.class, id, getInvocationContext());
+
+        if (entity == null) {
+            return null;
+        }
+
+        return new PolicyAdapter(entity, getInvocationContext(), this.authorizationProvider);
+    }
+
+
+    @Override
+    public Policy findByName(String name, String resourceServerId) {
+        DBObject query = new QueryBuilder()
+                .and("resourceServerId").is(resourceServerId)
+                .and("name").is(name)
+                .get();
+
+        return getMongoStore().loadEntities(PolicyEntity.class, query, getInvocationContext()).stream()
+                .map(policyEntity -> findById(policyEntity.getId())).findFirst().orElse(null);
+    }
+
+    @Override
+    public List<Policy> findByResourceServer(String resourceServerId) {
+        DBObject query = new QueryBuilder()
+                .and("resourceServerId").is(resourceServerId)
+                .get();
+
+        return getMongoStore().loadEntities(PolicyEntity.class, query, getInvocationContext()).stream()
+                .map(policyEntity -> findById(policyEntity.getId()))
+                .collect(toList());
+    }
+
+    @Override
+    public List<Policy> findByResource(String resourceId) {
+        DBObject query = new QueryBuilder()
+                .and("resources").is(resourceId)
+                .get();
+
+        return getMongoStore().loadEntities(PolicyEntity.class, query, getInvocationContext()).stream()
+                .map(policyEntity -> findById(policyEntity.getId()))
+                .collect(toList());
+    }
+
+    @Override
+    public List<Policy> findByResourceType(String resourceType, String resourceServerId) {
+        DBObject query = new QueryBuilder()
+                .and("resourceServerId").is(resourceServerId)
+                .get();
+
+        return getMongoStore().loadEntities(PolicyEntity.class, query, getInvocationContext()).stream()
+                .filter(policyEntity -> {
+                    String defaultResourceType = policyEntity.getConfig().get("defaultResourceType");
+                    return defaultResourceType != null && defaultResourceType.equals(resourceType);
+                })
+                .map(policyEntity -> findById(policyEntity.getId()))
+                .collect(toList());
+    }
+
+    @Override
+    public List<Policy> findByScopeIds(List<String> scopeIds, String resourceServerId) {
+        DBObject query = new QueryBuilder()
+                .and("resourceServerId").is(resourceServerId)
+                .and("scopes").in(scopeIds)
+                .get();
+
+        return getMongoStore().loadEntities(PolicyEntity.class, query, getInvocationContext()).stream()
+                .map(policyEntity -> findById(policyEntity.getId()))
+                .collect(toList());
+    }
+
+    @Override
+    public List<Policy> findByType(String type) {
+        DBObject query = new QueryBuilder()
+                .and("type").is(type)
+                .get();
+
+        return getMongoStore().loadEntities(PolicyEntity.class, query, getInvocationContext()).stream()
+                .map(policyEntity -> findById(policyEntity.getId()))
+                .collect(toList());
+    }
+
+    @Override
+    public List<Policy> findDependentPolicies(String policyId) {
+        DBObject query = new QueryBuilder()
+                .and("associatedPolicies").is(policyId)
+                .get();
+
+        return getMongoStore().loadEntities(PolicyEntity.class, query, getInvocationContext()).stream()
+                .map(policyEntity -> findById(policyEntity.getId()))
+                .collect(toList());
+    }
+
+    private MongoStoreInvocationContext getInvocationContext() {
+        return this.invocationContext;
+    }
+
+    private MongoStore getMongoStore() {
+        return getInvocationContext().getMongoStore();
+    }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoResourceServerStore.java b/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoResourceServerStore.java
new file mode 100644
index 0000000..25e5f67
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoResourceServerStore.java
@@ -0,0 +1,90 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.mongo.store;
+
+import com.mongodb.DBObject;
+import com.mongodb.QueryBuilder;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.mongo.adapter.ResourceServerAdapter;
+import org.keycloak.authorization.mongo.entities.ResourceServerEntity;
+import org.keycloak.authorization.store.ResourceServerStore;
+import org.keycloak.connections.mongo.api.MongoStore;
+import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
+import org.keycloak.models.utils.KeycloakModelUtils;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class MongoResourceServerStore implements ResourceServerStore {
+
+    private final MongoStoreInvocationContext invocationContext;
+    private final AuthorizationProvider authorizationProvider;
+
+    public MongoResourceServerStore(MongoStoreInvocationContext invocationContext, AuthorizationProvider authorizationProvider) {
+        this.invocationContext = invocationContext;
+        this.authorizationProvider = authorizationProvider;
+    }
+
+    @Override
+    public ResourceServer create(String clientId) {
+        ResourceServerEntity entity = new ResourceServerEntity();
+
+        entity.setId(KeycloakModelUtils.generateId());
+        entity.setClientId(clientId);
+
+        getMongoStore().insertEntity(entity, getInvocationContext());
+
+        return new ResourceServerAdapter(entity, getInvocationContext());
+    }
+
+    @Override
+    public void delete(String id) {
+        getMongoStore().removeEntity(ResourceServerEntity.class, id, getInvocationContext());
+    }
+
+    @Override
+    public ResourceServer findById(String id) {
+        ResourceServerEntity entity = getMongoStore().loadEntity(ResourceServerEntity.class, id, getInvocationContext());
+
+        if (entity == null) {
+            return null;
+        }
+
+        return new ResourceServerAdapter(entity, getInvocationContext());
+    }
+
+    @Override
+    public ResourceServer findByClient(String clientId) {
+        DBObject query = new QueryBuilder()
+                .and("clientId").is(clientId)
+                .get();
+
+        return getMongoStore().loadEntities(ResourceServerEntity.class, query, getInvocationContext()).stream()
+                .map(resourceServer -> findById(resourceServer.getId())).findFirst().orElse(null);
+    }
+
+    private MongoStoreInvocationContext getInvocationContext() {
+        return this.invocationContext;
+    }
+
+    private MongoStore getMongoStore() {
+        return getInvocationContext().getMongoStore();
+    }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoResourceStore.java b/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoResourceStore.java
new file mode 100644
index 0000000..11b735b
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoResourceStore.java
@@ -0,0 +1,141 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.mongo.store;
+
+import com.mongodb.DBObject;
+import com.mongodb.QueryBuilder;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.mongo.adapter.ResourceAdapter;
+import org.keycloak.authorization.mongo.entities.ResourceEntity;
+import org.keycloak.authorization.store.ResourceStore;
+import org.keycloak.connections.mongo.api.MongoIdentifiableEntity;
+import org.keycloak.connections.mongo.api.MongoStore;
+import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
+import org.keycloak.models.utils.KeycloakModelUtils;
+
+import java.util.List;
+
+import static java.util.stream.Collectors.toList;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class MongoResourceStore implements ResourceStore {
+
+    private final MongoStoreInvocationContext invocationContext;
+    private final AuthorizationProvider authorizationProvider;
+
+    public MongoResourceStore(MongoStoreInvocationContext invocationContext, AuthorizationProvider authorizationProvider) {
+        this.invocationContext = invocationContext;
+        this.authorizationProvider = authorizationProvider;
+    }
+
+    @Override
+    public Resource create(String name, ResourceServer resourceServer, String owner) {
+        ResourceEntity entity = new ResourceEntity();
+
+        entity.setId(KeycloakModelUtils.generateId());
+        entity.setName(name);
+        entity.setResourceServerId(resourceServer.getId());
+        entity.setOwner(owner);
+
+        getMongoStore().insertEntity(entity, getInvocationContext());
+
+        return new ResourceAdapter(entity, getInvocationContext(), this.authorizationProvider);
+    }
+
+    @Override
+    public void delete(String id) {
+        getMongoStore().removeEntity(ResourceEntity.class, id, getInvocationContext());
+    }
+
+    @Override
+    public Resource findById(String id) {
+        ResourceEntity entity = getMongoStore().loadEntity(ResourceEntity.class, id, getInvocationContext());
+
+        if (entity == null) {
+            return null;
+        }
+
+        return new ResourceAdapter(entity, getInvocationContext(), this.authorizationProvider);
+    }
+
+    @Override
+    public List<Resource> findByOwner(String ownerId) {
+        DBObject query = new QueryBuilder()
+                .and("owner").is(ownerId)
+                .get();
+
+        return getMongoStore().loadEntities(ResourceEntity.class, query, getInvocationContext()).stream()
+                .map(scope -> findById(scope.getId())).collect(toList());
+    }
+
+    @Override
+    public List findByResourceServer(String resourceServerId) {
+        DBObject query = new QueryBuilder()
+                .and("resourceServerId").is(resourceServerId)
+                .get();
+
+        return getMongoStore().loadEntities(ResourceEntity.class, query, getInvocationContext()).stream()
+                .map(scope -> findById(scope.getId())).collect(toList());
+    }
+
+    @Override
+    public List<Resource> findByScope(String... id) {
+        DBObject query = new QueryBuilder()
+                .and("scopes.id").in(id)
+                .get();
+
+        return getMongoStore().loadEntities(ResourceEntity.class, query, getInvocationContext()).stream()
+                .map(policyEntity -> findById(policyEntity.getId()))
+                .collect(toList());
+    }
+
+    @Override
+    public Resource findByName(String name, String resourceServerId) {
+        DBObject query = new QueryBuilder()
+                .and("name").is(name)
+                .and("resourceServerId").is(resourceServerId)
+                .get();
+
+        return getMongoStore().loadEntities(ResourceEntity.class, query, getInvocationContext()).stream()
+                .map(policyEntity -> findById(policyEntity.getId())).findFirst().orElse(null);
+    }
+
+    @Override
+    public List<Resource> findByType(String type) {
+        DBObject query = new QueryBuilder()
+                .and("type").is(type)
+                .get();
+
+        return getMongoStore().loadEntities(ResourceEntity.class, query, getInvocationContext()).stream()
+                .map(policyEntity -> findById(policyEntity.getId()))
+                .collect(toList());
+    }
+
+    private MongoStoreInvocationContext getInvocationContext() {
+        return this.invocationContext;
+    }
+
+    private MongoStore getMongoStore() {
+        return getInvocationContext().getMongoStore();
+    }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoScopeStore.java b/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoScopeStore.java
new file mode 100644
index 0000000..e57b69b
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoScopeStore.java
@@ -0,0 +1,108 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.mongo.store;
+
+import com.mongodb.DBObject;
+import com.mongodb.QueryBuilder;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.mongo.adapter.ScopeAdapter;
+import org.keycloak.authorization.mongo.entities.ScopeEntity;
+import org.keycloak.authorization.store.ScopeStore;
+import org.keycloak.connections.mongo.api.MongoStore;
+import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
+import org.keycloak.models.utils.KeycloakModelUtils;
+
+import java.util.List;
+
+import static java.util.stream.Collectors.toList;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class MongoScopeStore implements ScopeStore {
+
+    private final MongoStoreInvocationContext invocationContext;
+    private final AuthorizationProvider authorizationProvider;
+
+    public MongoScopeStore(MongoStoreInvocationContext invocationContext, AuthorizationProvider authorizationProvider) {
+        this.invocationContext = invocationContext;
+        this.authorizationProvider = authorizationProvider;
+    }
+
+    @Override
+    public Scope create(final String name, final ResourceServer resourceServer) {
+        ScopeEntity entity = new ScopeEntity();
+
+        entity.setId(KeycloakModelUtils.generateId());
+        entity.setName(name);
+        entity.setResourceServerId(resourceServer.getId());
+
+        getMongoStore().insertEntity(entity, getInvocationContext());
+
+        return new ScopeAdapter(entity, getInvocationContext(), this.authorizationProvider);
+    }
+
+    @Override
+    public void delete(String id) {
+        getMongoStore().removeEntity(ScopeEntity.class, id, getInvocationContext());
+    }
+
+    @Override
+    public Scope findById(String id) {
+        ScopeEntity entity = getMongoStore().loadEntity(ScopeEntity.class, id, getInvocationContext());
+
+        if (entity == null) {
+            return null;
+        }
+
+        return new ScopeAdapter(entity, getInvocationContext(), this.authorizationProvider);
+    }
+
+    @Override
+    public Scope findByName(String name, String resourceServerId) {
+        DBObject query = new QueryBuilder()
+                .and("resourceServerId").is(resourceServerId)
+                .and("name").is(name)
+                .get();
+
+        return getMongoStore().loadEntities(ScopeEntity.class, query, getInvocationContext()).stream()
+                .map(scope -> findById(scope.getId())).findFirst().orElse(null);
+    }
+
+    @Override
+    public List<Scope> findByResourceServer(String resourceServerId) {
+        DBObject query = new QueryBuilder()
+                .and("resourceServerId").is(resourceServerId)
+                .get();
+
+        return getMongoStore().loadEntities(ScopeEntity.class, query, getInvocationContext()).stream()
+                .map(policyEntity -> findById(policyEntity.getId()))
+                .collect(toList());
+    }
+
+    private MongoStoreInvocationContext getInvocationContext() {
+        return this.invocationContext;
+    }
+
+    private MongoStore getMongoStore() {
+        return getInvocationContext().getMongoStore();
+    }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoStoreFactory.java b/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoStoreFactory.java
new file mode 100644
index 0000000..7a94ba5
--- /dev/null
+++ b/model/mongo/src/main/java/org/keycloak/authorization/mongo/store/MongoStoreFactory.java
@@ -0,0 +1,66 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.mongo.store;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.authorization.store.ResourceServerStore;
+import org.keycloak.authorization.store.ResourceStore;
+import org.keycloak.authorization.store.ScopeStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class MongoStoreFactory implements StoreFactory {
+
+    private final MongoStoreInvocationContext invocationContext;
+    private final AuthorizationProvider authorizationProvider;
+
+    public MongoStoreFactory(MongoStoreInvocationContext invocationContext, AuthorizationProvider authorizationProvider) {
+        this.invocationContext = invocationContext;
+        this.authorizationProvider = authorizationProvider;
+    }
+
+    @Override
+    public PolicyStore getPolicyStore() {
+        return new MongoPolicyStore(this.invocationContext, this.authorizationProvider);
+    }
+
+    @Override
+    public ResourceServerStore getResourceServerStore() {
+        return new MongoResourceServerStore(this.invocationContext, this.authorizationProvider);
+    }
+
+    @Override
+    public ResourceStore getResourceStore() {
+        return new MongoResourceStore(this.invocationContext, this.authorizationProvider);
+    }
+
+    @Override
+    public ScopeStore getScopeStore() {
+        return new MongoScopeStore(this.invocationContext, this.authorizationProvider);
+    }
+
+    @Override
+    public void close() {
+
+    }
+}
diff --git a/model/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java b/model/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
index 3bc9c7a..b899e0d 100755
--- a/model/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
+++ b/model/mongo/src/main/java/org/keycloak/connections/mongo/DefaultMongoConnectionFactoryProvider.java
@@ -33,6 +33,10 @@ import org.keycloak.connections.mongo.impl.context.TransactionMongoStoreInvocati
 import org.keycloak.connections.mongo.updater.MongoUpdaterProvider;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.KeycloakSessionTask;
+import org.keycloak.models.dblock.DBLockManager;
+import org.keycloak.models.dblock.DBLockProvider;
+import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.provider.ServerInfoAwareProviderFactory;
 
 import com.mongodb.DB;
@@ -74,6 +78,11 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
             "org.keycloak.models.entities.RequiredActionProviderEntity",
             "org.keycloak.models.entities.PersistentUserSessionEntity",
             "org.keycloak.models.entities.PersistentClientSessionEntity",
+            "org.keycloak.models.entities.ComponentEntity",
+            "org.keycloak.authorization.mongo.entities.PolicyEntity",
+            "org.keycloak.authorization.mongo.entities.ResourceEntity",
+            "org.keycloak.authorization.mongo.entities.ResourceServerEntity",
+            "org.keycloak.authorization.mongo.entities.ScopeEntity"
     };
 
     private static final Logger logger = Logger.getLogger(DefaultMongoConnectionFactoryProvider.class);
@@ -132,7 +141,7 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
         lazyInit(session);
 
         TransactionMongoStoreInvocationContext invocationContext = new TransactionMongoStoreInvocationContext(mongoStore);
-        session.getTransaction().enlist(new MongoKeycloakTransaction(invocationContext));
+        session.getTransactionManager().enlist(new MongoKeycloakTransaction(invocationContext));
         return new DefaultMongoConnectionProvider(db, mongoStore, invocationContext);
     }
 
@@ -166,6 +175,29 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
                 throw new RuntimeException("Can't update database: Mongo updater provider not found");
             }
 
+            DBLockProvider dbLock = new DBLockManager(session).getDBLock();
+            if (dbLock.hasLock()) {
+                updateOrValidateDB(databaseSchema, session, mongoUpdater);
+            } else {
+                logger.trace("Don't have DBLock retrieved before upgrade. Needs to acquire lock first in separate transaction");
+
+                KeycloakModelUtils.runJobInTransaction(session.getKeycloakSessionFactory(), new KeycloakSessionTask() {
+
+                    @Override
+                    public void run(KeycloakSession lockSession) {
+                        DBLockManager dbLockManager = new DBLockManager(lockSession);
+                        DBLockProvider dbLock2 = dbLockManager.getDBLock();
+                        dbLock2.waitForLock();
+                        try {
+                            updateOrValidateDB(databaseSchema, session, mongoUpdater);
+                        } finally {
+                            dbLock2.releaseLock();
+                        }
+                    }
+
+                });
+            }
+
             if (databaseSchema.equals("update")) {
                 mongoUpdater.update(session, db);
             } else if (databaseSchema.equals("validate")) {
@@ -185,6 +217,16 @@ public class DefaultMongoConnectionFactoryProvider implements MongoConnectionPro
         return entityClasses;
     }
 
+    protected void updateOrValidateDB(String databaseSchema, KeycloakSession session, MongoUpdaterProvider mongoUpdater) {
+        if (databaseSchema.equals("update")) {
+            mongoUpdater.update(session, db);
+        } else if (databaseSchema.equals("validate")) {
+            mongoUpdater.validate(session, db);
+        } else {
+            throw new RuntimeException("Invalid value for databaseSchema: " + databaseSchema);
+        }
+    }
+
     @Override
     public void close() {
         if (client != null) {
diff --git a/model/mongo/src/main/java/org/keycloak/connections/mongo/lock/MongoDBLockProvider.java b/model/mongo/src/main/java/org/keycloak/connections/mongo/lock/MongoDBLockProvider.java
index 1b36889..a11f729 100644
--- a/model/mongo/src/main/java/org/keycloak/connections/mongo/lock/MongoDBLockProvider.java
+++ b/model/mongo/src/main/java/org/keycloak/connections/mongo/lock/MongoDBLockProvider.java
@@ -91,6 +91,7 @@ public class MongoDBLockProvider implements DBLockProvider {
             WriteResult wr = db.getCollection(DB_LOCK_COLLECTION).update(query, update, true, false);
             if (wr.getN() == 1) {
                 logger.debugf("Successfully acquired DB lock");
+                factory.setHasLock(true);
                 return true;
             } else {
                 return false;
@@ -115,6 +116,7 @@ public class MongoDBLockProvider implements DBLockProvider {
         try {
             WriteResult wr = db.getCollection(DB_LOCK_COLLECTION).update(query, update, true, false);
             if (wr.getN() > 0) {
+                factory.setHasLock(false);
                 logger.debugf("Successfully released DB lock");
             } else {
                 logger.warnf("Attempt to release DB lock, but nothing was released");
@@ -125,6 +127,11 @@ public class MongoDBLockProvider implements DBLockProvider {
     }
 
     @Override
+    public boolean hasLock() {
+        return factory.hasLock();
+    }
+
+    @Override
     public boolean supportsForcedUnlock() {
         return true;
     }
diff --git a/model/mongo/src/main/java/org/keycloak/connections/mongo/lock/MongoDBLockProviderFactory.java b/model/mongo/src/main/java/org/keycloak/connections/mongo/lock/MongoDBLockProviderFactory.java
index 7bd6e02..64f65f6 100644
--- a/model/mongo/src/main/java/org/keycloak/connections/mongo/lock/MongoDBLockProviderFactory.java
+++ b/model/mongo/src/main/java/org/keycloak/connections/mongo/lock/MongoDBLockProviderFactory.java
@@ -17,6 +17,8 @@
 
 package org.keycloak.connections.mongo.lock;
 
+import java.util.concurrent.atomic.AtomicBoolean;
+
 import com.mongodb.DB;
 import org.jboss.logging.Logger;
 import org.keycloak.Config;
@@ -37,6 +39,9 @@ public class MongoDBLockProviderFactory implements DBLockProviderFactory {
     private long lockRecheckTimeMillis;
     private long lockWaitTimeoutMillis;
 
+    // True if this node has a lock acquired
+    private AtomicBoolean hasLock = new AtomicBoolean(false);
+
     protected long getLockRecheckTimeMillis() {
         return lockRecheckTimeMillis;
     }
@@ -81,4 +86,13 @@ public class MongoDBLockProviderFactory implements DBLockProviderFactory {
     public String getId() {
         return "mongo";
     }
+
+    public boolean hasLock() {
+        return hasLock.get();
+    }
+
+    public void setHasLock(boolean hasLock) {
+        this.hasLock.set(hasLock);
+    }
+
 }
diff --git a/model/mongo/src/main/java/org/keycloak/events/mongo/MongoAdminEventQuery.java b/model/mongo/src/main/java/org/keycloak/events/mongo/MongoAdminEventQuery.java
index b24db9e..bf58082 100755
--- a/model/mongo/src/main/java/org/keycloak/events/mongo/MongoAdminEventQuery.java
+++ b/model/mongo/src/main/java/org/keycloak/events/mongo/MongoAdminEventQuery.java
@@ -29,6 +29,7 @@ import org.keycloak.events.admin.OperationType;
 import com.mongodb.BasicDBObject;
 import com.mongodb.DBCollection;
 import com.mongodb.DBCursor;
+import org.keycloak.events.admin.ResourceType;
 
 public class MongoAdminEventQuery implements AdminEventQuery{
     
@@ -57,6 +58,18 @@ public class MongoAdminEventQuery implements AdminEventQuery{
         query.put("operationType", new BasicDBObject("$in", operationStrings));
         return this;
     }
+
+    @Override
+    public AdminEventQuery resourceType(ResourceType... resourceTypes) {
+
+        List<String> resourceTypeStrings = new LinkedList<String>();
+        for (ResourceType e : resourceTypes) {
+            resourceTypeStrings.add(e.toString());
+        }
+        query.put("resourceType", new BasicDBObject("$in", resourceTypeStrings));
+
+        return this;
+    }
     
     @Override
     public AdminEventQuery authRealm(String authRealmId) {
diff --git a/model/mongo/src/main/java/org/keycloak/events/mongo/MongoEventStoreProvider.java b/model/mongo/src/main/java/org/keycloak/events/mongo/MongoEventStoreProvider.java
index 3e5c768..e0f8512 100755
--- a/model/mongo/src/main/java/org/keycloak/events/mongo/MongoEventStoreProvider.java
+++ b/model/mongo/src/main/java/org/keycloak/events/mongo/MongoEventStoreProvider.java
@@ -29,6 +29,7 @@ import org.keycloak.events.Event;
 import org.keycloak.events.EventQuery;
 import org.keycloak.events.EventStoreProvider;
 import org.keycloak.events.EventType;
+import org.keycloak.events.admin.ResourceType;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -172,6 +173,9 @@ public class MongoEventStoreProvider implements EventStoreProvider {
         adminEvent.setTime(o.getLong("time"));
         adminEvent.setRealmId(o.getString("realmId"));
         adminEvent.setOperationType(OperationType.valueOf(o.getString("operationType")));
+        if (o.getString("resourceType") != null) {
+            adminEvent.setResourceType(ResourceType.valueOf(o.getString("resourceType")));
+        }
         setAuthDetails(adminEvent, o);
         adminEvent.setResourcePath(o.getString("resourcePath"));
         adminEvent.setError(o.getString("error"));
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoRealmProvider.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoRealmProvider.java
index cef8a5a..14e5b03 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoRealmProvider.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoRealmProvider.java
@@ -129,10 +129,26 @@ public class MongoRealmProvider implements RealmProvider {
 
     @Override
     public boolean removeRealm(String id) {
-        RealmModel realm = getRealm(id);
+        final RealmModel realm = getRealm(id);
         if (realm == null) return false;
         session.users().preRemove(realm);
-        return getMongoStore().removeEntity(MongoRealmEntity.class, id, invocationContext);
+        boolean removed = getMongoStore().removeEntity(MongoRealmEntity.class, id, invocationContext);
+
+        if (removed) {
+            session.getKeycloakSessionFactory().publish(new RealmModel.RealmRemovedEvent() {
+                @Override
+                public RealmModel getRealm() {
+                    return realm;
+                }
+
+                @Override
+                public KeycloakSession getKeycloakSession() {
+                    return session;
+                }
+            });
+        }
+
+        return removed;
     }
 
     protected MongoStore getMongoStore() {
@@ -408,12 +424,27 @@ public class MongoRealmProvider implements RealmProvider {
     @Override
     public boolean removeClient(String id, RealmModel realm) {
         if (id == null) return false;
-        ClientModel client = getClientById(id, realm);
+        final ClientModel client = getClientById(id, realm);
         if (client == null) return false;
 
         session.users().preRemove(realm, client);
+        boolean removed = getMongoStore().removeEntity(MongoClientEntity.class, id, invocationContext);
+
+        if (removed) {
+            session.getKeycloakSessionFactory().publish(new RealmModel.ClientRemovedEvent() {
+                @Override
+                public ClientModel getClient() {
+                    return client;
+                }
+
+                @Override
+                public KeycloakSession getKeycloakSession() {
+                    return session;
+                }
+            });
+        }
 
-        return getMongoStore().removeEntity(MongoClientEntity.class, id, invocationContext);
+        return removed;
     }
 
     @Override
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoUserProvider.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoUserProvider.java
index 1f26239..c0537ba 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoUserProvider.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/MongoUserProvider.java
@@ -21,6 +21,7 @@ import com.mongodb.BasicDBObject;
 import com.mongodb.DBObject;
 import com.mongodb.QueryBuilder;
 
+import org.keycloak.component.ComponentModel;
 import org.keycloak.connections.mongo.api.MongoStore;
 import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
 import org.keycloak.models.ClientModel;
@@ -28,15 +29,19 @@ import org.keycloak.models.CredentialValidationOutput;
 import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.GroupModel;
 import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ModelDuplicateException;
+import org.keycloak.models.ModelException;
 import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RequiredActionProviderModel;
 import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserConsentModel;
 import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserProvider;
 import org.keycloak.models.entities.FederatedIdentityEntity;
+import org.keycloak.models.entities.UserConsentEntity;
 import org.keycloak.models.mongo.keycloak.entities.MongoUserConsentEntity;
 import org.keycloak.models.mongo.keycloak.entities.MongoUserEntity;
 import org.keycloak.models.utils.CredentialValidation;
@@ -44,6 +49,7 @@ import org.keycloak.models.utils.CredentialValidation;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -140,7 +146,7 @@ public class MongoUserProvider implements UserProvider {
     }
 
     @Override
-    public UserModel getUserByServiceAccountClient(ClientModel client) {
+    public UserModel getServiceAccount(ClientModel client) {
         DBObject query = new QueryBuilder()
                 .and("serviceAccountClientLink").is(client.getId())
                 .and("realmId").is(client.getRealm().getId())
@@ -157,6 +163,17 @@ public class MongoUserProvider implements UserProvider {
         return userModels;
     }
 
+    @Override
+    public List<UserModel> getUsers(RealmModel realm) {
+        return getUsers(realm, false);
+    }
+
+    @Override
+    public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) {
+        return getUsers(realm, firstResult, maxResults, false);
+    }
+
+
 
     @Override
     public List<UserModel> getUsers(RealmModel realm, boolean includeServiceAccounts) {
@@ -192,7 +209,8 @@ public class MongoUserProvider implements UserProvider {
     }
 
     @Override
-    public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) {
+    public List<UserModel>
+    searchForUser(String search, RealmModel realm, int firstResult, int maxResults) {
         search = search.trim();
         Pattern caseInsensitivePattern = Pattern.compile("(?i:" + search + ")");
 
@@ -235,12 +253,12 @@ public class MongoUserProvider implements UserProvider {
     }
 
     @Override
-    public List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm) {
-        return searchForUserByAttributes(attributes, realm, -1, -1);
+    public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm) {
+        return searchForUser(attributes, realm, -1, -1);
     }
 
     @Override
-    public List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
+    public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
         QueryBuilder queryBuilder = new QueryBuilder()
                 .and("realmId").is(realm.getId());
 
@@ -509,4 +527,112 @@ public class MongoUserProvider implements UserProvider {
         // Not supported yet
         return null;
     }
+
+    @Override
+    public void addConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
+        String clientId = consent.getClient().getId();
+        if (getConsentEntityByClientId(user, clientId) != null) {
+            throw new ModelDuplicateException("Consent already exists for client [" + clientId + "] and user [" + user.getId() + "]");
+        }
+
+        MongoUserConsentEntity consentEntity = new MongoUserConsentEntity();
+        consentEntity.setUserId(user.getId());
+        consentEntity.setClientId(clientId);
+        fillEntityFromModel(consent, consentEntity);
+        getMongoStore().insertEntity(consentEntity, invocationContext);
+    }
+
+    @Override
+    public UserConsentModel getConsentByClient(RealmModel realm, UserModel user, String clientId) {
+        UserConsentEntity consentEntity = getConsentEntityByClientId(user, clientId);
+        return consentEntity!=null ? toConsentModel(realm, consentEntity) : null;
+    }
+
+    @Override
+    public List<UserConsentModel> getConsents(RealmModel realm, UserModel user) {
+        List<UserConsentModel> result = new ArrayList<UserConsentModel>();
+
+        DBObject query = new QueryBuilder()
+                .and("userId").is(user.getId())
+                .get();
+        List<MongoUserConsentEntity> grantedConsents = getMongoStore().loadEntities(MongoUserConsentEntity.class, query, invocationContext);
+
+        for (UserConsentEntity consentEntity : grantedConsents) {
+            UserConsentModel model = toConsentModel(realm, consentEntity);
+            result.add(model);
+        }
+
+        return result;
+    }
+
+    private MongoUserConsentEntity getConsentEntityByClientId(UserModel user, String clientId) {
+        DBObject query = new QueryBuilder()
+                .and("userId").is(user.getId())
+                .and("clientId").is(clientId)
+                .get();
+        return getMongoStore().loadSingleEntity(MongoUserConsentEntity.class, query, invocationContext);
+    }
+
+    private UserConsentModel toConsentModel(RealmModel realm, UserConsentEntity entity) {
+        ClientModel client = realm.getClientById(entity.getClientId());
+        if (client == null) {
+            throw new ModelException("Client with id " + entity.getClientId() + " is not available");
+        }
+        UserConsentModel model = new UserConsentModel(client);
+
+        for (String roleId : entity.getGrantedRoles()) {
+            RoleModel roleModel = realm.getRoleById(roleId);
+            if (roleModel != null) {
+                model.addGrantedRole(roleModel);
+            }
+        }
+
+        for (String protMapperId : entity.getGrantedProtocolMappers()) {
+            ProtocolMapperModel protocolMapper = client.getProtocolMapperById(protMapperId);
+            model.addGrantedProtocolMapper(protocolMapper);
+        }
+        return model;
+    }
+
+    // Fill roles and protocolMappers to entity
+    private void fillEntityFromModel(UserConsentModel consent, MongoUserConsentEntity consentEntity) {
+        List<String> roleIds = new LinkedList<String>();
+        for (RoleModel role : consent.getGrantedRoles()) {
+            roleIds.add(role.getId());
+        }
+        consentEntity.setGrantedRoles(roleIds);
+
+        List<String> protMapperIds = new LinkedList<String>();
+        for (ProtocolMapperModel protMapperModel : consent.getGrantedProtocolMappers()) {
+            protMapperIds.add(protMapperModel.getId());
+        }
+        consentEntity.setGrantedProtocolMappers(protMapperIds);
+    }
+
+    @Override
+    public void updateConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
+        String clientId = consent.getClient().getId();
+        MongoUserConsentEntity consentEntity = getConsentEntityByClientId(user, clientId);
+        if (consentEntity == null) {
+            throw new ModelException("Consent not found for client [" + clientId + "] and user [" + user.getId() + "]");
+        } else {
+            fillEntityFromModel(consent, consentEntity);
+            getMongoStore().updateEntity(consentEntity, invocationContext);
+        }
+    }
+
+    @Override
+    public boolean revokeConsentForClient(RealmModel realm, UserModel user, String clientId) {
+        MongoUserConsentEntity entity = getConsentEntityByClientId(user, clientId);
+        if (entity == null) {
+            return false;
+        }
+
+        return getMongoStore().removeEntity(entity, invocationContext);
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, ComponentModel component) {
+
+    }
 }
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
index 6fff8d5..e7dc5f6 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/RealmAdapter.java
@@ -20,8 +20,12 @@ package org.keycloak.models.mongo.keycloak.adapters;
 import com.mongodb.DBObject;
 import com.mongodb.QueryBuilder;
 
+import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.common.util.StringPropertyReplacer;
+import org.keycloak.component.ComponentModel;
 import org.keycloak.connections.mongo.api.context.MongoStoreInvocationContext;
 import org.keycloak.common.enums.SslRequired;
+import org.keycloak.jose.jwk.JWKBuilder;
 import org.keycloak.models.AuthenticationExecutionModel;
 import org.keycloak.models.AuthenticationFlowModel;
 import org.keycloak.models.AuthenticatorConfigModel;
@@ -46,6 +50,7 @@ import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.entities.AuthenticationExecutionEntity;
 import org.keycloak.models.entities.AuthenticationFlowEntity;
 import org.keycloak.models.entities.AuthenticatorConfigEntity;
+import org.keycloak.models.entities.ComponentEntity;
 import org.keycloak.models.entities.IdentityProviderEntity;
 import org.keycloak.models.entities.IdentityProviderMapperEntity;
 import org.keycloak.models.entities.RequiredActionProviderEntity;
@@ -54,7 +59,6 @@ import org.keycloak.models.entities.UserFederationMapperEntity;
 import org.keycloak.models.entities.UserFederationProviderEntity;
 import org.keycloak.models.mongo.keycloak.entities.MongoClientEntity;
 import org.keycloak.models.mongo.keycloak.entities.MongoClientTemplateEntity;
-import org.keycloak.models.mongo.keycloak.entities.MongoGroupEntity;
 import org.keycloak.models.mongo.keycloak.entities.MongoRealmEntity;
 import org.keycloak.models.mongo.keycloak.entities.MongoRoleEntity;
 import org.keycloak.models.utils.KeycloakModelUtils;
@@ -305,7 +309,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
     @Override
     public PasswordPolicy getPasswordPolicy() {
         if (passwordPolicy == null) {
-            passwordPolicy = new PasswordPolicy(realm.getPasswordPolicy());
+            passwordPolicy = PasswordPolicy.parse(session, realm.getPasswordPolicy());
         }
         return passwordPolicy;
     }
@@ -454,6 +458,12 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
     }
 
     @Override
+    public String getKeyId() {
+        PublicKey publicKey = getPublicKey();
+        return publicKey != null ? JWKBuilder.create().rs256(publicKey).getKeyId() : null;
+    }
+
+    @Override
     public String getPublicKeyPem() {
         return realm.getPublicKeyPem();
     }
@@ -984,6 +994,14 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         updateRealm();
     }
 
+
+    private void removeFederationMappersForProvider(String federationProviderId) {
+        Set<UserFederationMapperEntity> mappers = getUserFederationMapperEntitiesByFederationProvider(federationProviderId);
+        for (UserFederationMapperEntity mapper : mappers) {
+            getMongoEntity().getUserFederationMappers().remove(mapper);
+        }
+    }
+
     @Override
     public UserFederationProviderModel addUserFederationProvider(String providerName, Map<String, String> config, int priority, String displayName, int fullSyncPeriod, int changedSyncPeriod, int lastSync) {
         KeycloakModelUtils.ensureUniqueDisplayName(displayName, null, getUserFederationProviders());
@@ -1025,14 +1043,6 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         }
         updateRealm();
     }
-
-    private void removeFederationMappersForProvider(String federationProviderId) {
-        Set<UserFederationMapperEntity> mappers = getUserFederationMapperEntitiesByFederationProvider(federationProviderId);
-        for (UserFederationMapperEntity mapper : mappers) {
-            getMongoEntity().getUserFederationMappers().remove(mapper);
-        }
-    }
-
     @Override
     public void updateUserFederationProvider(UserFederationProviderModel model) {
         KeycloakModelUtils.ensureUniqueDisplayName(model.getDisplayName(), model, getUserFederationProviders());
@@ -1832,6 +1842,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         RequiredActionProviderEntity entity = getRequiredActionProviderEntity(model.getId());
         if (entity == null) return;
         entity.setAlias(model.getAlias());
+        entity.setName(model.getName());
         entity.setProviderId(model.getProviderId());
         entity.setEnabled(model.isEnabled());
         entity.setDefaultAction(model.isDefaultAction());
@@ -2048,5 +2059,126 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
         return model.getClientTemplateById(id, this);
     }
 
+    @Override
+    public ComponentModel addComponentModel(ComponentModel model) {
+        ComponentEntity entity = new ComponentEntity();
+        if (model.getId() == null) {
+            entity.setId(KeycloakModelUtils.generateId());
+        } else {
+            entity.setId(model.getId());
+        }
+        entity.setConfig(model.getConfig());
+        entity.setParentId(model.getParentId());
+        entity.setProviderType(model.getProviderType());
+        entity.setProviderId(model.getProviderId());
+        entity.setName(model.getName());
+        model.setId(entity.getId());
+        realm.getComponentEntities().add(entity);
+        updateRealm();
 
+        return model;
+    }
+
+    @Override
+    public void updateComponent(ComponentModel model) {
+        for (ComponentEntity entity : realm.getComponentEntities()) {
+            if (entity.getId().equals(model.getId())) {
+                entity.setConfig(model.getConfig());
+                entity.setParentId(model.getParentId());
+                entity.setProviderType(model.getProviderType());
+                entity.setProviderId(model.getProviderId());
+                entity.setName(model.getName());
+
+            }
+        }
+        updateRealm();
+
+    }
+
+    @Override
+    public void removeComponent(ComponentModel component) {
+        Iterator<ComponentEntity> it = realm.getComponentEntities().iterator();
+        while(it.hasNext()) {
+            if (it.next().getId().equals(component.getId())) {
+                session.users().preRemove(this, component);
+                it.remove();
+                break;
+            }
+        }
+        updateRealm();
+
+    }
+
+    @Override
+    public void removeComponents(String parentId) {
+        Iterator<ComponentEntity> it = realm.getComponentEntities().iterator();
+        while(it.hasNext()) {
+            ComponentEntity next = it.next();
+            if (next.getParentId().equals(parentId)) {
+                session.users().preRemove(this, entityToModel(next));
+                it.remove();
+            }
+        }
+        updateRealm();
+
+    }
+
+    @Override
+    public List<ComponentModel> getComponents(String parentId, String providerType) {
+        List<ComponentModel> results = new LinkedList<>();
+        for (ComponentEntity entity : realm.getComponentEntities()) {
+            if (entity.getParentId().equals(parentId) && entity.getProviderType().equals(providerType)) {
+                ComponentModel model = entityToModel(entity);
+                results.add(model);
+            }
+
+        }
+        return results;
+    }
+
+    @Override
+    public List<ComponentModel> getComponents(String parentId) {
+        List<ComponentModel> results = new LinkedList<>();
+        for (ComponentEntity entity : realm.getComponentEntities()) {
+            if (entity.getParentId().equals(parentId)) {
+                ComponentModel model = entityToModel(entity);
+                results.add(model);
+            }
+
+        }
+        return results;
+    }
+
+    protected ComponentModel entityToModel(ComponentEntity entity) {
+        ComponentModel model = new ComponentModel();
+        model.setId(entity.getId());
+        model.setName(entity.getName());
+        model.setParentId(entity.getParentId());
+        model.setProviderId(entity.getProviderId());
+        model.setProviderType(entity.getProviderType());
+        MultivaluedHashMap<String, String> map = new MultivaluedHashMap<>();
+        map.putAll(entity.getConfig());
+        model.setConfig(map);
+        return model;
+    }
+
+    @Override
+    public List<ComponentModel> getComponents() {
+        List<ComponentModel> results = new LinkedList<>();
+        for (ComponentEntity entity : realm.getComponentEntities()) {
+            ComponentModel model = entityToModel(entity);
+            results.add(model);
+        }
+        return results;
+    }
+
+    @Override
+    public ComponentModel getComponent(String id) {
+        for (ComponentEntity entity : realm.getComponentEntities()) {
+            if (entity.getId() == entity.getId()) {
+                return entityToModel(entity);
+            }
+        }
+        return null;
+    }
 }
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java
index 601bc4a..b89ab01 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/UserAdapter.java
@@ -566,108 +566,6 @@ public class UserAdapter extends AbstractMongoAdapter<MongoUserEntity> implement
         updateUser();
     }
 
-    @Override
-    public void addConsent(UserConsentModel consent) {
-        String clientId = consent.getClient().getId();
-        if (getConsentEntityByClientId(clientId) != null) {
-            throw new ModelDuplicateException("Consent already exists for client [" + clientId + "] and user [" + user.getId() + "]");
-        }
-
-        MongoUserConsentEntity consentEntity = new MongoUserConsentEntity();
-        consentEntity.setUserId(getId());
-        consentEntity.setClientId(clientId);
-        fillEntityFromModel(consent, consentEntity);
-        getMongoStore().insertEntity(consentEntity, invocationContext);
-    }
-
-    @Override
-    public UserConsentModel getConsentByClient(String clientId) {
-        UserConsentEntity consentEntity = getConsentEntityByClientId(clientId);
-        return consentEntity!=null ? toConsentModel(consentEntity) : null;
-    }
-
-    @Override
-    public List<UserConsentModel> getConsents() {
-        List<UserConsentModel> result = new ArrayList<UserConsentModel>();
-
-        DBObject query = new QueryBuilder()
-                .and("userId").is(getId())
-                .get();
-        List<MongoUserConsentEntity> grantedConsents = getMongoStore().loadEntities(MongoUserConsentEntity.class, query, invocationContext);
-
-        for (UserConsentEntity consentEntity : grantedConsents) {
-            UserConsentModel model = toConsentModel(consentEntity);
-            result.add(model);
-        }
-
-        return result;
-    }
-
-    private MongoUserConsentEntity getConsentEntityByClientId(String clientId) {
-        DBObject query = new QueryBuilder()
-                .and("userId").is(getId())
-                .and("clientId").is(clientId)
-                .get();
-        return getMongoStore().loadSingleEntity(MongoUserConsentEntity.class, query, invocationContext);
-    }
-
-    private UserConsentModel toConsentModel(UserConsentEntity entity) {
-        ClientModel client = realm.getClientById(entity.getClientId());
-        if (client == null) {
-            throw new ModelException("Client with id " + entity.getClientId() + " is not available");
-        }
-        UserConsentModel model = new UserConsentModel(client);
-
-        for (String roleId : entity.getGrantedRoles()) {
-            RoleModel roleModel = realm.getRoleById(roleId);
-            if (roleModel != null) {
-                model.addGrantedRole(roleModel);
-            }
-        }
-
-        for (String protMapperId : entity.getGrantedProtocolMappers()) {
-            ProtocolMapperModel protocolMapper = client.getProtocolMapperById(protMapperId);
-            model.addGrantedProtocolMapper(protocolMapper);
-        }
-        return model;
-    }
-
-    // Fill roles and protocolMappers to entity
-    private void fillEntityFromModel(UserConsentModel consent, MongoUserConsentEntity consentEntity) {
-        List<String> roleIds = new LinkedList<String>();
-        for (RoleModel role : consent.getGrantedRoles()) {
-            roleIds.add(role.getId());
-        }
-        consentEntity.setGrantedRoles(roleIds);
-
-        List<String> protMapperIds = new LinkedList<String>();
-        for (ProtocolMapperModel protMapperModel : consent.getGrantedProtocolMappers()) {
-            protMapperIds.add(protMapperModel.getId());
-        }
-        consentEntity.setGrantedProtocolMappers(protMapperIds);
-    }
-
-    @Override
-    public void updateConsent(UserConsentModel consent) {
-        String clientId = consent.getClient().getId();
-        MongoUserConsentEntity consentEntity = getConsentEntityByClientId(clientId);
-        if (consentEntity == null) {
-            throw new ModelException("Consent not found for client [" + clientId + "] and user [" + user.getId() + "]");
-        } else {
-            fillEntityFromModel(consent, consentEntity);
-            getMongoStore().updateEntity(consentEntity, invocationContext);
-        }
-    }
-
-    @Override
-    public boolean revokeConsentForClient(String clientId) {
-        MongoUserConsentEntity entity = getConsentEntityByClientId(clientId);
-        if (entity == null) {
-            return false;
-        }
-
-        return getMongoStore().removeEntity(entity, invocationContext);
-    }
 
     @Override
     public boolean equals(Object o) {
diff --git a/model/mongo/src/main/resources/META-INF/services/org.keycloak.authorization.store.AuthorizationStoreFactory b/model/mongo/src/main/resources/META-INF/services/org.keycloak.authorization.store.AuthorizationStoreFactory
new file mode 100644
index 0000000..e1d801c
--- /dev/null
+++ b/model/mongo/src/main/resources/META-INF/services/org.keycloak.authorization.store.AuthorizationStoreFactory
@@ -0,0 +1,37 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2016 Red Hat, Inc., and individual contributors
+# as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2016 Red Hat, Inc., and individual contributors
+# as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.keycloak.authorization.mongo.store.MongoAuthorizationStoreFactory
\ No newline at end of file

model/pom.xml 2(+1 -1)

diff --git a/model/pom.xml b/model/pom.xml
index f33f76f..b7759a4 100755
--- a/model/pom.xml
+++ b/model/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <name>Keycloak Model Parent</name>

pom.xml 71(+68 -3)

diff --git a/pom.xml b/pom.xml
index 38efdcf..7208837 100755
--- a/pom.xml
+++ b/pom.xml
@@ -31,7 +31,7 @@
     </description>
     <groupId>org.keycloak</groupId>
     <artifactId>keycloak-parent</artifactId>
-    <version>2.0.0.CR1-SNAPSHOT</version>
+    <version>2.2.0-SNAPSHOT</version>
     <packaging>pom</packaging>
 
     <properties>
@@ -63,6 +63,7 @@
         <jboss.logging.tools.version>2.0.1.Final</jboss.logging.tools.version>
         <jboss.logging.tools.wf8.version>1.2.0.Final</jboss.logging.tools.wf8.version>
         <jboss-jaxrs-api_2.0_spec>1.0.0.Final</jboss-jaxrs-api_2.0_spec>
+        <jboss-transaction-api_1.2_spec>1.0.0.Final</jboss-transaction-api_1.2_spec>
         <jboss.spec.javax.xml.bind.jboss-jaxb-api_2.2_spec.version>1.0.4.Final</jboss.spec.javax.xml.bind.jboss-jaxb-api_2.2_spec.version>
         <log4j.version>1.2.16</log4j.version>
         <resteasy.version>3.0.14.Final</resteasy.version>
@@ -75,6 +76,9 @@
         <wildfly.build-tools.version>1.1.0.Final</wildfly.build-tools.version>
         <xmlsec.version>2.0.5</xmlsec.version>
 
+        <!-- Authorization Drools Policy Provider -->
+        <version.org.drools>6.4.0.Final</version.org.drools>
+
         <!-- Others -->
         <apacheds.version>2.0.0-M17</apacheds.version>
         <apacheds.codec.version>1.0.0-M23</apacheds.codec.version>
@@ -99,6 +103,7 @@
         <picketlink.version>2.7.0.Final</picketlink.version>
         <selenium.version>2.35.0</selenium.version>
         <xml-apis.version>1.4.01</xml-apis.version>
+        <subethasmtp.version>3.1.7</subethasmtp.version>
 
         <!-- Maven Plugins -->
         <embedmongo.plugin.version>0.1.12</embedmongo.plugin.version>
@@ -176,6 +181,7 @@
         <module>wildfly</module>
         <module>integration</module>
         <module>adapters</module>
+        <module>authz</module>
         <module>examples</module>
         <module>testsuite</module>
     </modules>
@@ -223,6 +229,11 @@
                 <version>${javax.mail.version}</version>
             </dependency>
             <dependency>
+                <groupId>org.jboss.spec.javax.transaction</groupId>
+                <artifactId>jboss-transaction-api_1.2_spec</artifactId>
+                <version>${jboss-transaction-api_1.2_spec}</version>
+            </dependency>
+            <dependency>
                 <groupId>org.jboss.spec.javax.ws.rs</groupId>
                 <artifactId>jboss-jaxrs-api_2.0_spec</artifactId>
                 <version>${jboss-jaxrs-api_2.0_spec}</version>
@@ -412,6 +423,15 @@
                 <version>${google.zxing.version}</version>
             </dependency>
 
+            <!-- Authorization Drools Policy Provider -->
+            <dependency>
+                <groupId>org.drools</groupId>
+                <artifactId>drools-bom</artifactId>
+                <type>pom</type>
+                <version>${version.org.drools}</version>
+                <scope>import</scope>
+            </dependency>
+
             <!-- Email Test Servers -->
             <dependency>
                 <groupId>com.icegreen</groupId>
@@ -419,6 +439,12 @@
                 <version>${greenmail.version}</version>
                 <scope>test</scope>
             </dependency>
+            <dependency>
+                <groupId>org.subethamail</groupId>
+                <artifactId>subethasmtp</artifactId>
+                <version>${subethasmtp.version}</version>
+                <scope>test</scope>
+            </dependency>
 
             <!-- Apache DS -->
             <dependency>
@@ -753,6 +779,11 @@
             </dependency>
             <dependency>
                 <groupId>org.keycloak</groupId>
+                <artifactId>keycloak-jetty93-adapter</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.keycloak</groupId>
                 <artifactId>keycloak-as7-subsystem</artifactId>
                 <version>${project.version}</version>
             </dependency>
@@ -968,6 +999,11 @@
             </dependency>
             <dependency>
                 <groupId>org.keycloak</groupId>
+                <artifactId>keycloak-saml-jetty93-adapter</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.keycloak</groupId>
                 <artifactId>keycloak-saml-undertow-adapter</artifactId>
                 <version>${project.version}</version>
             </dependency>
@@ -976,6 +1012,24 @@
                 <artifactId>keycloak-services</artifactId>
                 <version>${project.version}</version>
             </dependency>
+
+            <!-- Authorization -->
+            <dependency>
+                <groupId>org.keycloak</groupId>
+                <artifactId>keycloak-authz-client</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.keycloak</groupId>
+                <artifactId>keycloak-authz-policy-drools</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.keycloak</groupId>
+                <artifactId>keycloak-authz-policy-common</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+
             <dependency>
                 <groupId>org.keycloak</groupId>
                 <artifactId>keycloak-saml-as7-modules</artifactId>
@@ -1043,7 +1097,7 @@
             </dependency>
             <dependency>
                 <groupId>org.keycloak</groupId>
-                <artifactId>keycloak-docs-dist</artifactId>
+                <artifactId>keycloak-api-docs-dist</artifactId>
                 <version>${project.version}</version>
                 <type>zip</type>
             </dependency>
@@ -1109,6 +1163,12 @@
             </dependency>
             <dependency>
                 <groupId>org.keycloak</groupId>
+                <artifactId>keycloak-jetty93-adapter-dist</artifactId>
+                <version>${project.version}</version>
+                <type>zip</type>
+            </dependency>
+            <dependency>
+                <groupId>org.keycloak</groupId>
                 <artifactId>keycloak-js-adapter-dist</artifactId>
                 <version>${project.version}</version>
                 <type>zip</type>
@@ -1163,6 +1223,12 @@
             </dependency>
             <dependency>
                 <groupId>org.keycloak</groupId>
+                <artifactId>keycloak-saml-jetty93-adapter-dist</artifactId>
+                <version>${project.version}</version>
+                <type>zip</type>
+            </dependency>
+            <dependency>
+                <groupId>org.keycloak</groupId>
                 <artifactId>keycloak-saml-as7-adapter-dist</artifactId>
                 <version>${project.version}</version>
                 <type>zip</type>
@@ -1357,7 +1423,6 @@
         <profile>
             <id>jboss-release</id>
             <modules>
-                <module>docbook</module>
                 <module>distribution</module>
             </modules>
         </profile>
diff --git a/proxy/launcher/pom.xml b/proxy/launcher/pom.xml
index d584353..10c055e 100755
--- a/proxy/launcher/pom.xml
+++ b/proxy/launcher/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>

proxy/pom.xml 2(+1 -1)

diff --git a/proxy/pom.xml b/proxy/pom.xml
index e27a3bf..8fa8378 100755
--- a/proxy/pom.xml
+++ b/proxy/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <name>Model Parent</name>
diff --git a/proxy/proxy-server/pom.xml b/proxy/proxy-server/pom.xml
index 41967de..f442987 100755
--- a/proxy/proxy-server/pom.xml
+++ b/proxy/proxy-server/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/proxy/proxy-server/src/main/java/org/keycloak/proxy/ProxyServerBuilder.java b/proxy/proxy-server/src/main/java/org/keycloak/proxy/ProxyServerBuilder.java
index 4b99e9e..62b1814 100755
--- a/proxy/proxy-server/src/main/java/org/keycloak/proxy/ProxyServerBuilder.java
+++ b/proxy/proxy-server/src/main/java/org/keycloak/proxy/ProxyServerBuilder.java
@@ -247,8 +247,7 @@ public class ProxyServerBuilder {
         }
 
         private HttpHandler addSecurity(final HttpHandler toWrap) {
-            HttpHandler handler = toWrap;
-            handler = new UndertowAuthenticatedActionsHandler(deploymentContext, toWrap);
+            HttpHandler handler = new UndertowAuthenticatedActionsHandler(deploymentContext, toWrap);
             if (errorPage != null) {
                 if (base.endsWith("/")) {
                     errorPage = base + errorPage;
@@ -256,6 +255,7 @@ public class ProxyServerBuilder {
                     errorPage = base + "/" + errorPage;
                 }
             }
+            handler = new TokenRequestPreHandler(handler);
             handler = new ConstraintAuthorizationHandler(handler, errorPage, sendAccessToken, headerNameConfig);
             handler = new ProxyAuthenticationCallHandler(handler);
             handler = new ConstraintMatcherHandler(matches, handler, toWrap, errorPage);
diff --git a/proxy/proxy-server/src/main/java/org/keycloak/proxy/TokenRequestPreHandler.java b/proxy/proxy-server/src/main/java/org/keycloak/proxy/TokenRequestPreHandler.java
new file mode 100644
index 0000000..312bd20
--- /dev/null
+++ b/proxy/proxy-server/src/main/java/org/keycloak/proxy/TokenRequestPreHandler.java
@@ -0,0 +1,27 @@
+package org.keycloak.proxy;
+
+import io.undertow.server.HttpHandler;
+import io.undertow.server.HttpServerExchange;
+import org.keycloak.constants.AdapterConstants;
+
+/**
+ * Dispatches requests for k_query_bearer_token through a worker thread (handler for this
+ * resource performs blocking IO).
+ */
+public class TokenRequestPreHandler implements HttpHandler {
+
+    private final HttpHandler next;
+
+    public TokenRequestPreHandler(HttpHandler next) {
+        this.next = next;
+    }
+
+    @Override
+    public void handleRequest(HttpServerExchange exchange) throws Exception {
+        if (exchange.getRequestURI().endsWith(AdapterConstants.K_QUERY_BEARER_TOKEN)) {
+            exchange.dispatch(next);
+        } else {
+            next.handleRequest(exchange);
+        }
+    }
+}
diff --git a/saml-core/pom.xml b/saml-core/pom.xml
index 5473780..ef8b341 100755
--- a/saml-core/pom.xml
+++ b/saml-core/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/saml-core/src/main/java/org/keycloak/saml/common/util/DocumentUtil.java b/saml-core/src/main/java/org/keycloak/saml/common/util/DocumentUtil.java
index 7838859..b46220b 100755
--- a/saml-core/src/main/java/org/keycloak/saml/common/util/DocumentUtil.java
+++ b/saml-core/src/main/java/org/keycloak/saml/common/util/DocumentUtil.java
@@ -519,7 +519,7 @@ public class DocumentUtil {
                 }
                 documentBuilderFactory = DocumentBuilderFactory.newInstance();
                 documentBuilderFactory.setNamespaceAware(true);
-                documentBuilderFactory.setXIncludeAware(true);
+                documentBuilderFactory.setXIncludeAware(false);
                 String feature = "";
                 try {
                     feature = feature_disallow_doctype_decl;
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/writers/BaseWriter.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/writers/BaseWriter.java
index dfe0b90..7df18bd 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/writers/BaseWriter.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/saml/v2/writers/BaseWriter.java
@@ -172,6 +172,8 @@ public class BaseWriter {
                 if (attributeValue != null) {
                     if (attributeValue instanceof String) {
                         writeStringAttributeValue((String) attributeValue);
+                    } else if (attributeValue instanceof NameIDType) {
+                    	writeNameIDTypeAttributeValue((NameIDType) attributeValue);
                     } else
                         throw logger.writerUnsupportedAttributeValueError(attributeValue.getClass().getName());
                 }
@@ -179,6 +181,12 @@ public class BaseWriter {
         }
     }
 
+    public void writeNameIDTypeAttributeValue(NameIDType attributeValue) throws ProcessingException {
+        StaxUtil.writeStartElement(writer, ASSERTION_PREFIX, JBossSAMLConstants.ATTRIBUTE_VALUE.get(), ASSERTION_NSURI.get());
+    	write((NameIDType)attributeValue, new QName(ASSERTION_NSURI.get(), JBossSAMLConstants.NAMEID.get(), ASSERTION_PREFIX));
+        StaxUtil.writeEndElement(writer);
+    }
+
     public void writeStringAttributeValue(String attributeValue) throws ProcessingException {
         StaxUtil.writeStartElement(writer, ASSERTION_PREFIX, JBossSAMLConstants.ATTRIBUTE_VALUE.get(), ASSERTION_NSURI.get());
 
diff --git a/saml-core/src/main/java/org/keycloak/saml/processing/core/util/XMLSignatureUtil.java b/saml-core/src/main/java/org/keycloak/saml/processing/core/util/XMLSignatureUtil.java
index c1b5ef0..bd07882 100755
--- a/saml-core/src/main/java/org/keycloak/saml/processing/core/util/XMLSignatureUtil.java
+++ b/saml-core/src/main/java/org/keycloak/saml/processing/core/util/XMLSignatureUtil.java
@@ -370,7 +370,8 @@ public class XMLSignatureUtil {
         NodeList nl = signedDoc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
 
         if (nl == null || nl.getLength() == 0) {
-            throw logger.nullValueError("Cannot find Signature element");
+            logger.debug("Cannot find Signature element");
+            return false;
         }
 
         if (publicKey == null)
diff --git a/saml-core/src/main/java/org/keycloak/saml/SPMetadataDescriptor.java b/saml-core/src/main/java/org/keycloak/saml/SPMetadataDescriptor.java
index e65b788..e6c10af 100755
--- a/saml-core/src/main/java/org/keycloak/saml/SPMetadataDescriptor.java
+++ b/saml-core/src/main/java/org/keycloak/saml/SPMetadataDescriptor.java
@@ -26,24 +26,25 @@ public class SPMetadataDescriptor {
         String descriptor =
                 "<EntityDescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" entityID=\"" + entityId + "\">\n" +
                 "    <SPSSODescriptor AuthnRequestsSigned=\"" + wantAuthnRequestsSigned + "\"\n" +
-                "            protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol urn:oasis:names:tc:SAML:1.1:protocol http://schemas.xmlsoap.org/ws/2003/07/secext\">\n" +
+                "            protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol urn:oasis:names:tc:SAML:1.1:protocol http://schemas.xmlsoap.org/ws/2003/07/secext\">\n";
+        if (wantAuthnRequestsSigned) {
+            descriptor +=
+                    "        <KeyDescriptor use=\"signing\">\n" +
+                            "            <dsig:KeyInfo xmlns:dsig=\"http://www.w3.org/2000/09/xmldsig#\">\n" +
+                            "                <dsig:X509Data>\n" +
+                            "                    <dsig:X509Certificate>\n" + certificatePem + "\n" +
+                            "                    </dsig:X509Certificate>\n" +
+                            "                </dsig:X509Data>\n" +
+                            "            </dsig:KeyInfo>\n" +
+                            "        </KeyDescriptor>\n";
+        }
+        descriptor +=
+                "        <SingleLogoutService Binding=\"" + binding + "\" Location=\"" + logoutEndpoint + "\"/>\n" +
                 "        <NameIDFormat>" + nameIDPolicyFormat + "\n" +
                 "        </NameIDFormat>\n" +
-                "        <SingleLogoutService Binding=\"" + binding + "\" Location=\"" + logoutEndpoint + "\"/>\n" +
                 "        <AssertionConsumerService\n" +
                 "                Binding=\"" + binding + "\" Location=\"" + assertionEndpoint + "\"\n" +
                 "                index=\"1\" isDefault=\"true\" />\n";
-        if (wantAuthnRequestsSigned) {
-            descriptor +=
-                "        <KeyDescriptor use=\"signing\">\n" +
-                "            <dsig:KeyInfo xmlns:dsig=\"http://www.w3.org/2000/09/xmldsig#\">\n" +
-                "                <dsig:X509Data>\n" +
-                "                    <dsig:X509Certificate>\n" + certificatePem + "\n" +
-                "                    </dsig:X509Certificate>\n" +
-                "                </dsig:X509Data>\n" +
-                "            </dsig:KeyInfo>\n" +
-                "        </KeyDescriptor>\n";
-        }
         descriptor +=
                 "    </SPSSODescriptor>\n" +
                 "</EntityDescriptor>\n";
diff --git a/saml-core-api/pom.xml b/saml-core-api/pom.xml
index ec37228..08a628b 100755
--- a/saml-core-api/pom.xml
+++ b/saml-core-api/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>

server-spi/pom.xml 12(+11 -1)

diff --git a/server-spi/pom.xml b/server-spi/pom.xml
index 047a065..b6f415a 100755
--- a/server-spi/pom.xml
+++ b/server-spi/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
@@ -30,8 +30,18 @@
     <name>Keycloak Server SPI</name>
     <description/>
 
+    <properties>
+        <maven.compiler.target>1.8</maven.compiler.target>
+        <maven.compiler.source>1.8</maven.compiler.source>
+    </properties>
+
     <dependencies>
         <dependency>
+            <groupId>org.jboss.spec.javax.transaction</groupId>
+            <artifactId>jboss-transaction-api_1.2_spec</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.jboss.resteasy</groupId>
             <artifactId>resteasy-jaxrs</artifactId>
             <scope>provided</scope>
diff --git a/server-spi/src/main/java/org/keycloak/authentication/ClientAuthenticatorFactory.java b/server-spi/src/main/java/org/keycloak/authentication/ClientAuthenticatorFactory.java
index 9c3e098..8e3e658 100644
--- a/server-spi/src/main/java/org/keycloak/authentication/ClientAuthenticatorFactory.java
+++ b/server-spi/src/main/java/org/keycloak/authentication/ClientAuthenticatorFactory.java
@@ -19,6 +19,7 @@ package org.keycloak.authentication;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.keycloak.models.ClientModel;
 import org.keycloak.provider.ProviderConfigProperty;
@@ -60,4 +61,12 @@ public interface ClientAuthenticatorFactory extends ProviderFactory<ClientAuthen
      */
     Map<String, Object> getAdapterConfiguration(ClientModel client);
 
+    /**
+     * Get authentication methods for the specified protocol
+     *
+     * @param loginProtocol corresponds to {@link org.keycloak.protocol.LoginProtocolFactory#getId}
+     * @return name of supported client authenticator methods in the protocol specific "language"
+     */
+    Set<String> getProtocolAuthenticatorMethods(String loginProtocol);
+
 }
diff --git a/server-spi/src/main/java/org/keycloak/authorization/attribute/Attributes.java b/server-spi/src/main/java/org/keycloak/authorization/attribute/Attributes.java
new file mode 100644
index 0000000..a0a7b6c
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/attribute/Attributes.java
@@ -0,0 +1,144 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.attribute;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Map;
+
+import static java.util.Collections.emptyList;
+
+/**
+ * <p>Holds attributes, their values and provides utlity methods to manage them.
+ *
+ * <p>In the future, it may be useful to provide different implementations for this interface in order to plug or integrate with different
+ * Policy Information Point (PIP).</p>
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface Attributes {
+
+    static Attributes from(Map<String, Collection<String>> attributes) {
+        return () -> attributes;
+    }
+
+    /**
+     * Converts to a {@link Map}.
+     *
+     * @return
+     */
+    Map<String, Collection<String>> toMap();
+
+    /**
+     * Checks if there is an attribute with the given <code>name</code>.
+     *
+     * @param name the attribute name
+     * @return true if any attribute with <code>name</code> exist. Otherwise, returns false.
+     */
+    default boolean exists(String name) {
+        return toMap().containsKey(name);
+    }
+
+    /**
+     * Checks if there is an attribute with the given <code>name</code> and <code>value</code>.
+     *
+     * @param name the attribute name
+     * @param value the attribute value
+     * @return true if any attribute with <code>name</code> and <code>value</code> exist. Otherwise, returns false.
+     */
+    default boolean containsValue(String name, String value) {
+        Collection<String> values = toMap().get(name);
+        return values != null && values.stream().anyMatch(value::equals);
+    }
+
+    /**
+     * Returns a {@link Entry} from where values can be obtained and parsed accordingly.
+     *
+     * @param name the attribute name
+     * @return an {@link Entry} holding the values for an attribute
+     */
+    default Entry getValue(String name) {
+        Collection<String> value = toMap().get(name);
+
+        if (value != null) {
+            return new Entry(name, value);
+        }
+
+        return null;
+    }
+
+    /**
+     * Holds an attribute and its values, providing useful methods for obtaining and formatting values. Specially useful
+     * for writing rule-based policies.
+     */
+    class Entry {
+
+        private final String[] values;
+        private final String name;
+
+        public Entry(String name, Collection<String> values) {
+            this.name = name;
+            this.values = values.toArray(new String[values.size()]);
+        }
+
+        private String getName() {
+            return this.name;
+        }
+
+        public int size() {
+            return values.length;
+        }
+
+        public String asString(int idx) {
+            if (idx >= values.length) {
+                throw new IllegalArgumentException("Invalid index [" + idx + "]. Values are [" + values + "].");
+            }
+
+            return values[idx];
+        }
+
+        public int asInt(int idx) {
+            return Integer.parseInt(asString(idx));
+        }
+
+        public Date asDate(int idx, String pattern) {
+            try {
+                return new SimpleDateFormat(pattern).parse(asString(idx));
+            } catch (ParseException e) {
+                throw new RuntimeException("Error parsing date.", e);
+            }
+        }
+
+        public InetAddress asInetAddress(int idx) {
+            try {
+                return InetAddress.getByName(asString(idx));
+            } catch (UnknownHostException e) {
+                throw new RuntimeException("Error parsing address.", e);
+            }
+        }
+
+        public long asLong(int idx) {
+            return Long.parseLong(asString(idx));
+        }
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/attribute/package-info.java b/server-spi/src/main/java/org/keycloak/authorization/attribute/package-info.java
new file mode 100644
index 0000000..c75b520
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/attribute/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Provides classes related with the representation of attributes and their manipulation.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+package org.keycloak.authorization.attribute;
\ No newline at end of file
diff --git a/server-spi/src/main/java/org/keycloak/authorization/AuthorizationProvider.java b/server-spi/src/main/java/org/keycloak/authorization/AuthorizationProvider.java
new file mode 100644
index 0000000..fb7c91b
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/AuthorizationProvider.java
@@ -0,0 +1,144 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization;
+
+import org.keycloak.authorization.permission.evaluator.Evaluators;
+import org.keycloak.authorization.policy.evaluation.DefaultPolicyEvaluator;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.stream.Collectors;
+
+/**
+ * <p>The main contract here is the creation of {@link org.keycloak.authorization.permission.evaluator.PermissionEvaluator} instances.  Usually
+ * an application has a single {@link AuthorizationProvider} instance and threads servicing client requests obtain {@link org.keycloak.authorization.core.permission.evaluator.PermissionEvaluator}
+ * from the {@link #evaluators()} method.
+ *
+ * <p>The internal state of a {@link AuthorizationProvider} is immutable.  This internal state includes all of the metadata
+ * used during the evaluation of policies.
+ *
+ * <p>Once created, {@link org.keycloak.authorization.permission.evaluator.PermissionEvaluator} instances can be obtained from the {@link #evaluators()} method:
+ *
+ * <pre>
+ *     List<ResourcePermission> permissionsToEvaluate = getPermissions(); // the permissions to evaluate
+ *     EvaluationContext evaluationContext = createEvaluationContext(); // the context with runtime environment information
+ *     PermissionEvaluator evaluator = authorization.evaluators().from(permissionsToEvaluate, context);
+ *
+ *     evaluator.evaluate(new Decision() {
+ *
+ *         public void onDecision(Evaluation evaluation) {
+ *              // do something on grant
+ *         }
+ *
+ *     });
+ * </pre>
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public final class AuthorizationProvider implements Provider {
+
+    private final DefaultPolicyEvaluator policyEvaluator;
+    private final Executor scheduller;
+    private final StoreFactory storeFactory;
+    private final List<PolicyProviderFactory> policyProviderFactories;
+    private final KeycloakSession keycloakSession;
+    private final RealmModel realm;
+
+    public AuthorizationProvider(KeycloakSession session, RealmModel realm, StoreFactory storeFactory, Executor scheduller) {
+        this.keycloakSession = session;
+        this.realm = realm;
+        this.storeFactory = storeFactory;
+        this.scheduller = scheduller;
+        this.policyProviderFactories = configurePolicyProviderFactories(session);
+        this.policyEvaluator = new DefaultPolicyEvaluator(this, this.policyProviderFactories);
+    }
+
+    public AuthorizationProvider(KeycloakSession session, RealmModel realm, StoreFactory storeFactory) {
+        this(session, realm, storeFactory, Runnable::run);
+    }
+
+    /**
+     * Returns a {@link Evaluators} instance from where {@link org.keycloak.authorization.policy.evaluation.PolicyEvaluator} instances
+     * can be obtained.
+     *
+     * @return a {@link Evaluators} instance
+     */
+    public Evaluators evaluators() {
+        return new Evaluators(this.policyProviderFactories, this.policyEvaluator, this.scheduller);
+    }
+
+    /**
+     * Returns a {@link StoreFactory}.
+     *
+     * @return the {@link StoreFactory}
+     */
+    public StoreFactory getStoreFactory() {
+        return this.storeFactory;
+    }
+
+    /**
+     * Returns the registered {@link PolicyProviderFactory}.
+     *
+     * @return a {@link List} containing all registered {@link PolicyProviderFactory}
+     */
+    public List<PolicyProviderFactory> getProviderFactories() {
+        return this.policyProviderFactories;
+    }
+
+    /**
+     * Returns a {@link PolicyProviderFactory} given a <code>type</code>.
+     *
+     * @param type the type of the policy provider
+     * @param <F> the expected type of the provider
+     * @return a {@link PolicyProviderFactory} with the given <code>type</code>
+     */
+    public <F extends PolicyProviderFactory> F getProviderFactory(String type) {
+        return (F) getProviderFactories().stream().filter(policyProviderFactory -> policyProviderFactory.getId().equals(type)).findFirst().orElse(null);
+    }
+
+    public KeycloakSession getKeycloakSession() {
+        return this.keycloakSession;
+    }
+
+    public RealmModel getRealm() {
+        return realm;
+    }
+
+    private List<PolicyProviderFactory> configurePolicyProviderFactories(KeycloakSession session) {
+        List<ProviderFactory> providerFactories = session.getKeycloakSessionFactory().getProviderFactories(PolicyProvider.class);
+
+        if (providerFactories.isEmpty()) {
+            throw new RuntimeException("Could not find any policy provider.");
+        }
+
+        return providerFactories.stream().map(providerFactory -> (PolicyProviderFactory) providerFactory).collect(Collectors.toList());
+    }
+
+    @Override
+    public void close() {
+
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/AuthorizationProviderFactory.java b/server-spi/src/main/java/org/keycloak/authorization/AuthorizationProviderFactory.java
new file mode 100644
index 0000000..7ca684c
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/AuthorizationProviderFactory.java
@@ -0,0 +1,31 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface AuthorizationProviderFactory extends ProviderFactory<AuthorizationProvider> {
+
+    AuthorizationProvider create(KeycloakSession session, RealmModel realm);
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/AuthorizationSpi.java b/server-spi/src/main/java/org/keycloak/authorization/AuthorizationSpi.java
new file mode 100644
index 0000000..65028b3
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/AuthorizationSpi.java
@@ -0,0 +1,48 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AuthorizationSpi implements Spi {
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "authorization";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return AuthorizationProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return AuthorizationProviderFactory.class;
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/Decision.java b/server-spi/src/main/java/org/keycloak/authorization/Decision.java
new file mode 100644
index 0000000..6ebd086
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/Decision.java
@@ -0,0 +1,41 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization;
+
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface Decision<D extends Evaluation> {
+
+    enum Effect {
+        PERMIT,
+        DENY
+    }
+
+    void onDecision(D evaluation);
+
+    default void onError(Throwable cause) {
+        throw new RuntimeException("Not implemented.", cause);
+    }
+
+    default void onComplete() {
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/identity/Identity.java b/server-spi/src/main/java/org/keycloak/authorization/identity/Identity.java
new file mode 100644
index 0000000..f16e6c3
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/identity/Identity.java
@@ -0,0 +1,101 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.identity;
+
+import org.keycloak.authorization.attribute.Attributes;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.function.Predicate;
+
+/**
+ * <p>Represents a security identity, which can be a person or non-person entity that was previously authenticated.
+ *
+ * <p>An {@link Identity} plays an important role during the evaluation of policies as they represent the entity to which one or more permissions
+ * should be granted or not, providing additional information and attributes that can be relevant to the different
+ * access control methods involved during the evaluation of policies.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface Identity {
+
+    /**
+     * Returns the unique identifier of this identity.
+     *
+     * @return the unique identifier of this identity
+     */
+    String getId();
+
+    /**
+     * Returns the attributes or claims associated with this identity.
+     *
+     * @return the attributes or claims associated with this identity
+     */
+    Attributes getAttributes();
+
+    /**
+     * Indicates if this identity is granted with a role (realm or client) with the given <code>roleName</code>.
+     *
+     * @param roleName the name of the role
+     *
+     * @return true if the identity has the given role. Otherwise, it returns false.
+     */
+    default boolean hasRole(String roleName) {
+        return hasRealmRole(roleName) || hasClientRole(roleName);
+    }
+
+    /**
+     * Indicates if this identity is granted with a realm role with the given <code>roleName</code>.
+     *
+     * @param roleName the name of the role
+     *
+     * @return true if the identity has the given role. Otherwise, it returns false.
+     */
+    default boolean hasRealmRole(String roleName) {
+        return getAttributes().containsValue("kc.realm.roles", roleName);
+    }
+
+    /**
+     * Indicates if this identity is granted with a client role with the given <code>roleName</code>.
+     *
+     * @param clientId the client id
+     * @param roleName the name of the role
+     *
+     * @return true if the identity has the given role. Otherwise, it returns false.
+     */
+    default boolean hasClientRole(String clientId, String roleName) {
+        return getAttributes().containsValue("kc.client." + clientId + ".roles", roleName);
+    }
+
+    /**
+     * Indicates if this identity is granted with a client role with the given <code>roleName</code>.
+     *
+     * @param roleName the name of the role
+     *
+     * @return true if the identity has the given role. Otherwise, it returns false.
+     */
+    default boolean hasClientRole(String roleName) {
+        return getAttributes().toMap().entrySet().stream().filter(entry -> {
+            String key = entry.getKey();
+            if (key.startsWith("kc.client") && key.endsWith(".roles")) {
+                return getAttributes().containsValue(key, roleName);
+            }
+            return false;
+        }).findFirst().isPresent();
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/identity/package-info.java b/server-spi/src/main/java/org/keycloak/authorization/identity/package-info.java
new file mode 100644
index 0000000..47a5746
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/identity/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Provides classes related with the representation and management of identities.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+package org.keycloak.authorization.identity;
\ No newline at end of file
diff --git a/server-spi/src/main/java/org/keycloak/authorization/model/package-info.java b/server-spi/src/main/java/org/keycloak/authorization/model/package-info.java
new file mode 100644
index 0000000..38f9a8f
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/model/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Provides the domain model and any other type related with it
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+package org.keycloak.authorization.model;
\ No newline at end of file
diff --git a/server-spi/src/main/java/org/keycloak/authorization/model/Policy.java b/server-spi/src/main/java/org/keycloak/authorization/model/Policy.java
new file mode 100644
index 0000000..03596d9
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/model/Policy.java
@@ -0,0 +1,158 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.model;
+
+import org.keycloak.representations.idm.authorization.DecisionStrategy;
+import org.keycloak.representations.idm.authorization.Logic;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Represents an authorization policy and all the configuration associated with it.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface Policy {
+
+    /**
+     * Returns the unique identifier for this instance.
+     *
+     * @return the unique identifier for this instance
+     */
+    String getId();
+
+    /**
+     * Returns the type of this policy.
+     *
+     * @return the type of this policy
+     */
+    String getType();
+
+    /**
+     * Returns the {@link DecisionStrategy} for this policy.
+     *
+     * @return the decision strategy defined for this policy
+     */
+    DecisionStrategy getDecisionStrategy();
+
+    /**
+     * Sets the {DecisionStrategy} for this policy.
+     *
+     * @return the decision strategy for this policy
+     */
+    void setDecisionStrategy(DecisionStrategy decisionStrategy);
+
+    /**
+     * Returns the {@link Logic} for this policy.
+     *
+     * @return the decision strategy defined for this policy
+     */
+    Logic getLogic();
+
+    /**
+     * Sets the {Logic} for this policy.
+     *
+     * @return the decision strategy for this policy
+     */
+    void setLogic(Logic logic);
+
+    /**
+     * Returns a {@link Map} holding string-based key/value pairs representing any additional configuration for this policy.
+     *
+     * @return a map with any additional configuration defined for this policy.
+     */
+    Map<String, String> getConfig();
+
+    /**
+     * Sets a {@link Map} with string-based key/value pairs representing any additional configuration for this policy.
+     *
+     * @return a map with any additional configuration for this policy.
+     */
+    void setConfig(Map<String, String> config);
+
+    /**
+     * Returns the name of this policy.
+     *
+     * @return the name of this policy
+     */
+    String getName();
+
+    /**
+     * Sets an unique name to this policy.
+     *
+     * @param name an unique name
+     */
+    void setName(String name);
+
+    /**
+     * Returns the description of this policy.
+     *
+     * @return a description or null of there is no description
+     */
+    String getDescription();
+
+    /**
+     * Sets the description for this policy.
+     *
+     * @param description a description
+     */
+    void setDescription(String description);
+
+    /**
+     * Returns the {@link ResourceServer} where this policy belongs to.
+     *
+     * @return a resource server
+     */
+    <R extends ResourceServer> R getResourceServer();
+
+    /**
+     * Returns the {@link Policy} instances associated with this policy and used to evaluate authorization decisions when
+     * this policy applies.
+     *
+     * @return the associated policies or an empty set if no policy is associated with this policy
+     */
+    <P extends Policy> Set<P> getAssociatedPolicies();
+
+    /**
+     * Returns the {@link Resource} instances where this policy applies.
+     *
+     * @return a set with all resource instances where this policy applies. Or an empty set if there is no resource associated with this policy
+     */
+    <R extends Resource> Set<R> getResources();
+
+    /**
+     * Returns the {@link Scope} instances where this policy applies.
+     *
+     * @return a set with all scope instances where this policy applies. Or an empty set if there is no scope associated with this policy
+     */
+    <S extends Scope> Set<S> getScopes();
+
+    void addScope(Scope scope);
+
+    void removeScope(Scope scope);
+
+    void addAssociatedPolicy(Policy associatedPolicy);
+
+    void removeAssociatedPolicy(Policy associatedPolicy);
+
+    void addResource(Resource resource);
+
+    void removeResource(Resource resource);
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/model/Resource.java b/server-spi/src/main/java/org/keycloak/authorization/model/Resource.java
new file mode 100644
index 0000000..2bf2c6f
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/model/Resource.java
@@ -0,0 +1,116 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.model;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Represents a resource, which is usually protected by a set of policies within a resource server.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface Resource {
+
+    /**
+     * Returns the unique identifier for this instance.
+     *
+     * @return the unique identifier for this instance
+     */
+    String getId();
+
+    /**
+     * Returns the resource's name.
+     *
+     * @return the name of this resource
+     */
+    String getName();
+
+    /**
+     * Sets a name for this resource. The name must be unique.
+     *
+     * @param name the name of this resource
+     */
+    void setName(String name);
+
+    /**
+     * Returns a {@link java.net.URI} that uniquely identify this resource.
+     *
+     * @return an {@link java.net.URI} for this resource or null if not defined.
+     */
+    String getUri();
+
+    /**
+     * Sets a {@link java.net.URI} that uniquely identify this resource.
+     *
+     * @param uri an {@link java.net.URI} for this resource
+     */
+    void setUri(String uri);
+
+    /**
+     * Returns a string representing the type of this resource.
+     *
+     * @return the type of this resource or null if not defined
+     */
+    String getType();
+
+    /**
+     * Sets a string representing the type of this resource.
+     *
+     * @return the type of this resource or null if not defined
+     */
+    void setType(String type);
+
+    /**
+     * Returns a {@link List} containing all the {@link Scope} associated with this resource.
+     *
+     * @return a list with all scopes associated with this resource
+     */
+    <S extends Scope> List<S> getScopes();
+
+    /**
+     * Returns an icon {@link java.net.URI} for this resource.
+     *
+     * @return a uri for an icon
+     */
+    String getIconUri();
+
+    /**
+     * Sets an icon {@link java.net.URI} for this resource.
+     *
+     * @return a uri for an icon
+     */
+    void setIconUri(String iconUri);
+
+    /**
+     * Returns the {@link ResourceServer} to where this resource belongs to.
+     *
+     * @return the resource server associated with this resource
+     */
+    <R extends ResourceServer> R getResourceServer();
+
+    /**
+     * Returns the resource's owner, which is usually an identifier that uniquely identifies the resource's owner.
+     *
+     * @return the owner of this resource
+     */
+    String getOwner();
+
+    void updateScopes(Set<Scope> scopes);
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/model/ResourceServer.java b/server-spi/src/main/java/org/keycloak/authorization/model/ResourceServer.java
new file mode 100644
index 0000000..d5b9ac4
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/model/ResourceServer.java
@@ -0,0 +1,73 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.model;
+
+import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
+
+/**
+ * Represents a resource server, whose resources are managed and protected. A resource server is basically an existing
+ * client application in Keycloak that will also act as a resource server.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface ResourceServer {
+
+    /**
+     * Returns the unique identifier for this instance.
+     *
+     * @return the unique identifier for this instance
+     */
+    String getId();
+
+    /**
+     * Returns the identifier of the client application (which already exists in Keycloak) that is also acting as a resource
+     * server.
+     *
+     * @return the identifier of the client application associated with this instance.
+     */
+    String getClientId();
+
+    /**
+     * Indicates if the resource server is allowed to manage its own resources remotely using the Protection API.
+     *
+     * {@code true} if the resource server is allowed to managed them remotely
+     */
+    boolean isAllowRemoteResourceManagement();
+
+    /**
+     * Indicates if the resource server is allowed to manage its own resources remotely using the Protection API.
+     *
+     * @param allowRemoteResourceManagement {@code true} if the resource server is allowed to managed them remotely
+     */
+    void setAllowRemoteResourceManagement(boolean allowRemoteResourceManagement);
+
+    /**
+     * Returns the {@code PolicyEnforcementMode} configured for this instance.
+     *
+     * @return the {@code PolicyEnforcementMode} configured for this instance.
+     */
+    PolicyEnforcementMode getPolicyEnforcementMode();
+
+    /**
+     * Defines a {@code PolicyEnforcementMode} for this instance.
+     *
+     * @param enforcementMode one of the available options in {@code PolicyEnforcementMode}
+     */
+    void setPolicyEnforcementMode(PolicyEnforcementMode enforcementMode);
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/model/Scope.java b/server-spi/src/main/java/org/keycloak/authorization/model/Scope.java
new file mode 100644
index 0000000..e13a789
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/model/Scope.java
@@ -0,0 +1,70 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.model;
+
+/**
+ * Represents a scope, which is usually associated with one or more resources in order to define the actions that can be performed
+ * or a specific access context.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface Scope {
+
+    /**
+     * Returns the unique identifier for this instance.
+     *
+     * @return the unique identifier for this instance
+     */
+    String getId();
+
+    /**
+     * Returns the name of this scope.
+     *
+     * @return the name of this scope
+     */
+    String getName();
+
+    /**
+     * Sets a name for this scope. The name must be unique.
+     *
+     * @param name the name of this scope
+     */
+    void setName(String name);
+
+    /**
+     * Returns an icon {@link java.net.URI} for this scope.
+     *
+     * @return a uri for an icon
+     */
+    String getIconUri();
+
+    /**
+     * Sets an icon {@link java.net.URI} for this scope.
+     *
+     * @return a uri for an icon
+     */
+    void setIconUri(String iconUri);
+
+    /**
+     * Returns the {@link ResourceServer} instance to where this scope belongs to.
+     *
+     * @return
+     */
+    ResourceServer getResourceServer();
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/package-info.java b/server-spi/src/main/java/org/keycloak/authorization/package-info.java
new file mode 100644
index 0000000..6ff51af
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Fine-grained Authorization SPI.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+package org.keycloak.authorization;
\ No newline at end of file
diff --git a/server-spi/src/main/java/org/keycloak/authorization/permission/evaluator/Evaluators.java b/server-spi/src/main/java/org/keycloak/authorization/permission/evaluator/Evaluators.java
new file mode 100644
index 0000000..e26ad1c
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/permission/evaluator/Evaluators.java
@@ -0,0 +1,53 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.permission.evaluator;
+
+import org.keycloak.authorization.permission.ResourcePermission;
+import org.keycloak.authorization.policy.evaluation.DefaultPolicyEvaluator;
+import org.keycloak.authorization.policy.evaluation.EvaluationContext;
+import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * A factory for the different {@link PermissionEvaluator} implementations.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public final class Evaluators {
+
+    private final List<PolicyProviderFactory> policyProviderFactories;
+    private final DefaultPolicyEvaluator policyEvaluator;
+    private final Executor scheduler;
+
+    public Evaluators(List<PolicyProviderFactory> policyProviderFactories, DefaultPolicyEvaluator policyEvaluator, Executor scheduler) {
+        this.policyProviderFactories = policyProviderFactories;
+        this.policyEvaluator = policyEvaluator;
+        this.scheduler = scheduler;
+    }
+
+    public PermissionEvaluator from(List<ResourcePermission> permissions, EvaluationContext evaluationContext) {
+        return schedule(permissions, evaluationContext);
+    }
+
+    public PermissionEvaluator schedule(List<ResourcePermission> permissions, EvaluationContext evaluationContext) {
+        return new ScheduledPermissionEvaluator(new IterablePermissionEvaluator(permissions.iterator(), evaluationContext, this.policyEvaluator), this.scheduler);
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/permission/evaluator/IterablePermissionEvaluator.java b/server-spi/src/main/java/org/keycloak/authorization/permission/evaluator/IterablePermissionEvaluator.java
new file mode 100644
index 0000000..dfda6a7
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/permission/evaluator/IterablePermissionEvaluator.java
@@ -0,0 +1,53 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.permission.evaluator;
+
+import org.keycloak.authorization.Decision;
+import org.keycloak.authorization.permission.ResourcePermission;
+import org.keycloak.authorization.policy.evaluation.EvaluationContext;
+import org.keycloak.authorization.policy.evaluation.PolicyEvaluator;
+
+import java.util.Iterator;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+class IterablePermissionEvaluator implements PermissionEvaluator {
+
+    private final Iterator<ResourcePermission> permissions;
+    private final EvaluationContext executionContext;
+    private final PolicyEvaluator policyEvaluator;
+
+    IterablePermissionEvaluator(Iterator<ResourcePermission> permissions, EvaluationContext executionContext, PolicyEvaluator policyEvaluator) {
+        this.permissions = permissions;
+        this.executionContext = executionContext;
+        this.policyEvaluator = policyEvaluator;
+    }
+
+    @Override
+    public void evaluate(Decision decision) {
+        try {
+            while (this.permissions.hasNext()) {
+                this.policyEvaluator.evaluate(this.permissions.next(), this.executionContext, decision);
+            }
+            decision.onComplete();
+        } catch (Throwable cause) {
+            decision.onError(cause);
+        }
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/permission/evaluator/PermissionEvaluator.java b/server-spi/src/main/java/org/keycloak/authorization/permission/evaluator/PermissionEvaluator.java
new file mode 100644
index 0000000..c129caf
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/permission/evaluator/PermissionEvaluator.java
@@ -0,0 +1,31 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.permission.evaluator;
+
+import org.keycloak.authorization.Decision;
+
+/**
+ * An {@link PermissionEvaluator} represents a source of {@link org.keycloak.authorization.permission.ResourcePermission}, responsible for emitting these permissions
+ * to a consumer in order to evaluate the authorization policies based on a {@link org.keycloak.authorization.policy.evaluation.EvaluationContext}.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface PermissionEvaluator {
+
+    void evaluate(Decision decision);
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/permission/evaluator/ScheduledPermissionEvaluator.java b/server-spi/src/main/java/org/keycloak/authorization/permission/evaluator/ScheduledPermissionEvaluator.java
new file mode 100644
index 0000000..13e08e4
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/permission/evaluator/ScheduledPermissionEvaluator.java
@@ -0,0 +1,43 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.permission.evaluator;
+
+import org.keycloak.authorization.Decision;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ * @see PermissionEvaluator
+ */
+class ScheduledPermissionEvaluator implements PermissionEvaluator {
+
+    private final PermissionEvaluator publisher;
+    private final Executor scheduler;
+
+    ScheduledPermissionEvaluator(PermissionEvaluator publisher, Executor scheduler) {
+        this.publisher = publisher;
+        this.scheduler = scheduler;
+    }
+
+    @Override
+    public void evaluate(Decision decision) {
+        CompletableFuture.runAsync(() -> publisher.evaluate(decision), scheduler);
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/permission/ResourcePermission.java b/server-spi/src/main/java/org/keycloak/authorization/permission/ResourcePermission.java
new file mode 100644
index 0000000..1eef22a
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/permission/ResourcePermission.java
@@ -0,0 +1,71 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.permission;
+
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Represents a permission for a given resource.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ResourcePermission {
+
+    private final Resource resource;
+    private final List<Scope> scopes;
+    private ResourceServer resourceServer;
+
+    public ResourcePermission(Resource resource, List<Scope> scopes, ResourceServer resourceServer) {
+        this.resource = resource;
+        this.scopes = scopes;
+        this.resourceServer = resourceServer;
+    }
+
+    /**
+     * Returns the resource to which this permission applies.
+     *
+     * @return the resource to which this permission applies
+     */
+    public Resource getResource() {
+        return this.resource;
+    }
+
+    /**
+     * Returns a list of permitted scopes associated with the resource
+     *
+     * @return a lit of permitted scopes
+     */
+    public List<Scope> getScopes() {
+        return Collections.unmodifiableList(this.scopes);
+    }
+
+    /**
+     * Returns the resource server associated with this permission.
+     *
+     * @return the resource server
+     */
+    public ResourceServer getResourceServer() {
+        return this.resourceServer;
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/DecisionResultCollector.java b/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/DecisionResultCollector.java
new file mode 100644
index 0000000..abd3f93
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/DecisionResultCollector.java
@@ -0,0 +1,103 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.policy.evaluation;
+
+import org.keycloak.authorization.Decision;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.permission.ResourcePermission;
+import org.keycloak.representations.idm.authorization.DecisionStrategy;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public abstract class DecisionResultCollector implements Decision<DefaultEvaluation> {
+
+    private Map<ResourcePermission, Result> results = new HashMap();
+
+    @Override
+    public void onDecision(DefaultEvaluation evaluation) {
+        if (evaluation.getParentPolicy() != null) {
+            results.computeIfAbsent(evaluation.getPermission(), Result::new).policy(evaluation.getParentPolicy()).policy(evaluation.getPolicy()).setStatus(evaluation.getEffect());
+        } else {
+            results.computeIfAbsent(evaluation.getPermission(), Result::new).setStatus(evaluation.getEffect());
+        }
+    }
+
+    @Override
+    public void onComplete() {
+        for (Result result : results.values()) {
+            for (Result.PolicyResult policyResult : result.getResults()) {
+                if (isGranted(policyResult)) {
+                    policyResult.setStatus(Effect.PERMIT);
+                } else {
+                    policyResult.setStatus(Effect.DENY);
+                }
+            }
+
+            if (result.getResults().stream()
+                    .filter(policyResult -> Effect.DENY.equals(policyResult.getStatus())).count() > 0) {
+                result.setStatus(Effect.DENY);
+            } else {
+                result.setStatus(Effect.PERMIT);
+            }
+        }
+
+        onComplete(results.values().stream().collect(Collectors.toList()));
+    }
+
+    protected abstract void onComplete(List<Result> results);
+
+    private boolean isGranted(Result.PolicyResult policyResult) {
+        List<Result.PolicyResult> values = policyResult.getAssociatedPolicies();
+
+        int grantCount = 0;
+        int denyCount = policyResult.getPolicy().getAssociatedPolicies().size();
+
+        for (Result.PolicyResult decision : values) {
+            if (decision.getStatus().equals(Effect.PERMIT)) {
+                grantCount++;
+                denyCount--;
+            }
+        }
+
+        Policy policy = policyResult.getPolicy();
+        DecisionStrategy decisionStrategy = policy.getDecisionStrategy();
+
+        if (decisionStrategy == null) {
+            decisionStrategy = DecisionStrategy.UNANIMOUS;
+        }
+
+        if (DecisionStrategy.AFFIRMATIVE.equals(decisionStrategy) && grantCount > 0) {
+            return true;
+        } else if (DecisionStrategy.UNANIMOUS.equals(decisionStrategy) && denyCount == 0) {
+            return true;
+        } else if (DecisionStrategy.CONSENSUS.equals(decisionStrategy)) {
+            if (grantCount > denyCount) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/DefaultEvaluation.java b/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/DefaultEvaluation.java
new file mode 100644
index 0000000..0bd5b6c
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/DefaultEvaluation.java
@@ -0,0 +1,105 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.policy.evaluation;
+
+import org.keycloak.authorization.Decision;
+import org.keycloak.authorization.Decision.Effect;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.permission.ResourcePermission;
+import org.keycloak.representations.idm.authorization.Logic;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class DefaultEvaluation implements Evaluation {
+
+    private final ResourcePermission permission;
+    private final EvaluationContext executionContext;
+    private final Decision decision;
+    private final Policy policy;
+    private final Policy parentPolicy;
+    private Effect effect;
+
+    public DefaultEvaluation(ResourcePermission permission, EvaluationContext executionContext, Policy parentPolicy, Policy policy, Decision decision) {
+        this.permission = permission;
+        this.executionContext = executionContext;
+        this.parentPolicy = parentPolicy;
+        this.policy = policy;
+        this.decision = decision;
+    }
+
+    /**
+     * Returns the {@link ResourcePermission} to be evaluated.
+     *
+     * @return the permission to be evaluated
+     */
+    public ResourcePermission getPermission() {
+        return this.permission;
+    }
+
+    /**
+     * Returns the {@link org.keycloak.authorization.permission.evaluator.PermissionEvaluator}. Which provides access to the whole evaluation runtime context.
+     *
+     * @return the evaluation context
+     */
+    public EvaluationContext getContext() {
+        return this.executionContext;
+    }
+
+    /**
+     * Grants all the requested permissions to the caller.
+     */
+    public void grant() {
+        if (policy != null && Logic.NEGATIVE.equals(policy.getLogic())) {
+            this.effect = Effect.DENY;
+        } else {
+            this.effect = Effect.PERMIT;
+        }
+
+        this.decision.onDecision(this);
+    }
+
+    public void deny() {
+        if (policy != null && Logic.NEGATIVE.equals(policy.getLogic())) {
+            this.effect = Effect.PERMIT;
+        } else {
+            this.effect = Effect.DENY;
+        }
+
+        this.decision.onDecision(this);
+    }
+
+    public Policy getPolicy() {
+        return this.policy;
+    }
+
+    public Policy getParentPolicy() {
+        return this.parentPolicy;
+    }
+
+    public Effect getEffect() {
+        return effect;
+    }
+
+    void denyIfNoEffect() {
+        if (this.effect == null) {
+            deny();
+        }
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/DefaultPolicyEvaluator.java b/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/DefaultPolicyEvaluator.java
new file mode 100644
index 0000000..724b655
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/DefaultPolicyEvaluator.java
@@ -0,0 +1,190 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.policy.evaluation;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.Decision;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.permission.ResourcePermission;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
+import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class DefaultPolicyEvaluator implements PolicyEvaluator {
+
+    private final AuthorizationProvider authorization;
+    private Map<String, PolicyProviderFactory> policyProviders = new HashMap<>();
+
+    public DefaultPolicyEvaluator(AuthorizationProvider authorization, List<PolicyProviderFactory> policyProviderFactories) {
+        this.authorization = authorization;
+
+        for (PolicyProviderFactory providerFactory : policyProviderFactories) {
+            this.policyProviders.put(providerFactory.getId(), providerFactory);
+        }
+    }
+
+    @Override
+    public void evaluate(ResourcePermission permission, EvaluationContext executionContext, Decision decision) {
+        ResourceServer resourceServer = permission.getResourceServer();
+
+        if (PolicyEnforcementMode.DISABLED.equals(resourceServer.getPolicyEnforcementMode())) {
+            createEvaluation(permission, executionContext, decision, null, null).grant();
+            return;
+        }
+
+        StoreFactory storeFactory = this.authorization.getStoreFactory();
+        PolicyStore policyStore = storeFactory.getPolicyStore();
+        AtomicInteger policiesCount = new AtomicInteger(0);
+        Consumer<Policy> consumer = createDecisionConsumer(permission, executionContext, decision, policiesCount);
+        Resource resource = permission.getResource();
+
+        if (resource != null) {
+            List<? extends Policy> resourcePolicies = policyStore.findByResource(resource.getId());
+
+            if (!resourcePolicies.isEmpty()) {
+                resourcePolicies.forEach(consumer);
+            }
+
+            if (resource.getType() != null) {
+                policyStore.findByResourceType(resource.getType(), resourceServer.getId()).forEach(consumer);
+            }
+
+            if (permission.getScopes().isEmpty() && !resource.getScopes().isEmpty()) {
+                policyStore.findByScopeIds(resource.getScopes().stream().map(Scope::getId).collect(Collectors.toList()), resourceServer.getId()).forEach(consumer);
+            }
+        }
+
+        if (!permission.getScopes().isEmpty()) {
+            policyStore.findByScopeIds(permission.getScopes().stream().map(Scope::getId).collect(Collectors.toList()), resourceServer.getId()).forEach(consumer);
+        }
+
+        if (PolicyEnforcementMode.PERMISSIVE.equals(resourceServer.getPolicyEnforcementMode()) && policiesCount.get() == 0) {
+            createEvaluation(permission, executionContext, decision, null, null).grant();
+        }
+    }
+
+    private  Consumer<Policy> createDecisionConsumer(ResourcePermission permission, EvaluationContext executionContext, Decision decision, AtomicInteger policiesCount) {
+        return (parentPolicy) -> {
+            if (hasRequestedScopes(permission, parentPolicy)) {
+                for (Policy associatedPolicy : parentPolicy.getAssociatedPolicies()) {
+                    PolicyProviderFactory providerFactory = policyProviders.get(associatedPolicy.getType());
+
+                    if (providerFactory == null) {
+                        throw new RuntimeException("Could not find a policy provider for policy type [" + associatedPolicy.getType() + "].");
+                    }
+
+                    PolicyProvider policyProvider = providerFactory.create(associatedPolicy, this.authorization);
+
+                    if (policyProvider == null) {
+                        throw new RuntimeException("Unknown parentPolicy provider for type [" + associatedPolicy.getType() + "].");
+                    }
+
+                    DefaultEvaluation evaluation = createEvaluation(permission, executionContext, decision, parentPolicy, associatedPolicy);
+
+                    policyProvider.evaluate(evaluation);
+                    evaluation.denyIfNoEffect();
+
+                    policiesCount.incrementAndGet();
+                }
+            }
+        };
+    }
+
+    private DefaultEvaluation createEvaluation(ResourcePermission permission, EvaluationContext executionContext, Decision decision, Policy parentPolicy, Policy associatedPolicy) {
+        return new DefaultEvaluation(permission, executionContext, parentPolicy, associatedPolicy, decision);
+    }
+
+    private boolean hasRequestedScopes(final ResourcePermission permission, final Policy policy) {
+        if (permission.getScopes().isEmpty()) {
+            return true;
+        }
+
+        Resource resourcePermission = permission.getResource();
+        Set<Resource> policyResources = policy.getResources();
+
+        if (resourcePermission != null && !policyResources.isEmpty()) {
+            if (!policyResources.stream().filter(resource -> resource.getId().equals(resourcePermission.getId())).findFirst().isPresent()) {
+                return false;
+            }
+        }
+
+        Set<Scope> scopes = new HashSet<>(policy.getScopes());
+
+        if (scopes.isEmpty()) {
+            Set<Resource> resources = new HashSet<>();
+
+            resources.addAll(policyResources);
+
+            for (Resource resource : resources) {
+                scopes.addAll(resource.getScopes());
+            }
+
+            if (!resources.isEmpty() && scopes.isEmpty()) {
+                return false;
+            }
+
+            if (scopes.isEmpty()) {
+                Resource resource = permission.getResource();
+                String type = resource.getType();
+
+                if (type != null) {
+                    List<Resource> resourcesByType = authorization.getStoreFactory().getResourceStore().findByType(type);
+
+                    for (Resource resourceType : resourcesByType) {
+                        if (resourceType.getOwner().equals(resource.getResourceServer().getClientId())) {
+                            resources.add(resourceType);
+                        }
+                    }
+                }
+            }
+
+            for (Resource resource : resources) {
+                scopes.addAll(resource.getScopes());
+            }
+        }
+
+        for (Scope givenScope : scopes) {
+            for (Scope scope : permission.getScopes()) {
+                if (givenScope.getId().equals(scope.getId())) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/Evaluation.java b/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/Evaluation.java
new file mode 100644
index 0000000..f5b0868
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/Evaluation.java
@@ -0,0 +1,54 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.policy.evaluation;
+
+import org.keycloak.authorization.permission.ResourcePermission;
+
+/**
+ * <p>An {@link Evaluation} is mainly used by {@link org.keycloak.authorization.policy.provider.PolicyProvider} in order to evaluate a single
+ * and specific {@link ResourcePermission} against the configured policies.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface Evaluation {
+
+    /**
+     * Returns the {@link ResourcePermission} to be evaluated.
+     *
+     * @return the permission to be evaluated
+     */
+    ResourcePermission getPermission();
+
+    /**
+     * Returns the {@link EvaluationContext}. Which provides access to the whole evaluation runtime context.
+     *
+     * @return the evaluation context
+     */
+    EvaluationContext getContext();
+
+    /**
+     * Grants the requested permission to the caller.
+     */
+    void grant();
+
+    /**
+     * Denies the requested permission.
+     */
+    void deny();
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/EvaluationContext.java b/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/EvaluationContext.java
new file mode 100644
index 0000000..db5ed04
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/EvaluationContext.java
@@ -0,0 +1,45 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.policy.evaluation;
+
+import org.keycloak.authorization.attribute.Attributes;
+import org.keycloak.authorization.identity.Identity;
+
+/**
+ * This interface serves as a bridge between the policy evaluation runtime and the environment in which it is running. When evaluating
+ * policies, this interface can be used to query information from the execution environment/context and enrich decisions.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface EvaluationContext {
+
+    /**
+     * Returns the {@link Identity} that represents an entity (person or non-person) to which the permissions must be granted, or not.
+     *
+     * @return the identity to which the permissions must be granted, or not
+     */
+    Identity getIdentity();
+
+    /**
+     * Returns all attributes within the current execution and runtime environment.
+     *
+     * @return the attributes within the current execution and runtime environment
+     */
+    Attributes getAttributes();
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/package-info.java b/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/package-info.java
new file mode 100644
index 0000000..dcae2ed
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Provides classes related with the evaluation of policies.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+package org.keycloak.authorization.policy.evaluation;
\ No newline at end of file
diff --git a/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/PolicyEvaluator.java b/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/PolicyEvaluator.java
new file mode 100644
index 0000000..c380ba6
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/PolicyEvaluator.java
@@ -0,0 +1,38 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.policy.evaluation;
+
+import org.keycloak.authorization.Decision;
+import org.keycloak.authorization.permission.ResourcePermission;
+
+/**
+ * <p>A {@link PolicyEvaluator} evaluates authorization policies based on a given {@link ResourcePermission}, sending
+ * the results to a {@link Decision} point through the methods defined in that interface.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface PolicyEvaluator {
+
+    /**
+     * Starts the evaluation of the configured authorization policies.
+     *
+     * @param decision a {@link Decision} point to where notifications events will be delivered during the evaluation
+     */
+    void evaluate(ResourcePermission permission, EvaluationContext executionContext, Decision decision);
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/Result.java b/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/Result.java
new file mode 100644
index 0000000..325af3d
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/policy/evaluation/Result.java
@@ -0,0 +1,120 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.policy.evaluation;
+
+import org.keycloak.authorization.Decision.Effect;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.permission.ResourcePermission;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class Result {
+
+    private final ResourcePermission permission;
+    private List<PolicyResult> results = new ArrayList<>();
+    private Effect status;
+
+    public Result(ResourcePermission permission) {
+        this.permission = permission;
+    }
+
+    public ResourcePermission getPermission() {
+        return permission;
+    }
+
+    public List<PolicyResult> getResults() {
+        return results;
+    }
+
+    public PolicyResult policy(Policy policy) {
+        for (PolicyResult result : this.results) {
+            if (result.getPolicy().equals(policy)) {
+                return result;
+            }
+        }
+
+        PolicyResult policyResult = new PolicyResult(policy);
+
+        this.results.add(policyResult);
+
+        return policyResult;
+    }
+
+    public void setStatus(final Effect status) {
+        this.status = status;
+    }
+
+    public Effect getEffect() {
+        return status;
+    }
+
+    public static class PolicyResult {
+
+        private final Policy policy;
+        private List<PolicyResult> associatedPolicies = new ArrayList<>();
+        private Effect status;
+
+        public PolicyResult(Policy policy) {
+            this.policy = policy;
+        }
+
+        public PolicyResult status(Effect status) {
+            this.status = status;
+            return this;
+        }
+
+        public PolicyResult policy(Policy policy) {
+            return getPolicy(policy, this.associatedPolicies);
+        }
+
+        private PolicyResult getPolicy(Policy policy, List<PolicyResult> results) {
+            for (PolicyResult result : results) {
+                if (result.getPolicy().equals(policy)) {
+                    return result;
+                }
+            }
+
+            PolicyResult policyResult = new PolicyResult(policy);
+
+            results.add(policyResult);
+
+            return policyResult;
+        }
+
+        public Policy getPolicy() {
+            return policy;
+        }
+
+        public List<PolicyResult> getAssociatedPolicies() {
+            return associatedPolicies;
+        }
+
+        public Effect getStatus() {
+            return status;
+        }
+
+        public void setStatus(final Effect status) {
+            this.status = status;
+        }
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/policy/provider/package-info.java b/server-spi/src/main/java/org/keycloak/authorization/policy/provider/package-info.java
new file mode 100644
index 0000000..6a66949
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/policy/provider/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Provides classes and a SPI to plug different policy providers.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+package org.keycloak.authorization.policy.provider;
\ No newline at end of file
diff --git a/server-spi/src/main/java/org/keycloak/authorization/policy/provider/PolicyProvider.java b/server-spi/src/main/java/org/keycloak/authorization/policy/provider/PolicyProvider.java
new file mode 100644
index 0000000..2405c3b
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/policy/provider/PolicyProvider.java
@@ -0,0 +1,29 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.policy.provider;
+
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+import org.keycloak.provider.Provider;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface PolicyProvider extends Provider {
+
+    void evaluate(Evaluation evaluation);
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/policy/provider/PolicyProviderAdminService.java b/server-spi/src/main/java/org/keycloak/authorization/policy/provider/PolicyProviderAdminService.java
new file mode 100644
index 0000000..d26208e
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/policy/provider/PolicyProviderAdminService.java
@@ -0,0 +1,33 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.policy.provider;
+
+import org.keycloak.authorization.model.Policy;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface PolicyProviderAdminService {
+
+    void onCreate(Policy policy);
+
+    void onUpdate(Policy policy);
+
+    void onRemove(Policy policy);
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/policy/provider/PolicyProviderFactory.java b/server-spi/src/main/java/org/keycloak/authorization/policy/provider/PolicyProviderFactory.java
new file mode 100644
index 0000000..1beedd9
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/policy/provider/PolicyProviderFactory.java
@@ -0,0 +1,39 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.policy.provider;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.provider.ProviderEvent;
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface PolicyProviderFactory extends ProviderFactory<PolicyProvider> {
+
+    String getName();
+
+    String getGroup();
+
+    PolicyProvider create(Policy policy, AuthorizationProvider authorization);
+
+    PolicyProviderAdminService getAdminResource(ResourceServer resourceServer);
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/policy/provider/PolicySpi.java b/server-spi/src/main/java/org/keycloak/authorization/policy/provider/PolicySpi.java
new file mode 100644
index 0000000..422981d
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/policy/provider/PolicySpi.java
@@ -0,0 +1,48 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.policy.provider;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class PolicySpi implements Spi {
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "policy";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return PolicyProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return PolicyProviderFactory.class;
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/store/AuthorizationStoreFactory.java b/server-spi/src/main/java/org/keycloak/authorization/store/AuthorizationStoreFactory.java
new file mode 100644
index 0000000..dac1b33
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/store/AuthorizationStoreFactory.java
@@ -0,0 +1,63 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.store;
+
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.keycloak.authorization.store.syncronization.ClientApplicationSynchronizer;
+import org.keycloak.authorization.store.syncronization.RealmSynchronizer;
+import org.keycloak.authorization.store.syncronization.Synchronizer;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel.ClientRemovedEvent;
+import org.keycloak.models.RealmModel.RealmRemovedEvent;
+import org.keycloak.provider.ProviderEvent;
+import org.keycloak.provider.ProviderFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface AuthorizationStoreFactory extends ProviderFactory<StoreFactory> {
+
+    @Override
+    default void postInit(KeycloakSessionFactory factory) {
+        registerSynchronizationListeners(factory);
+    }
+
+    default void registerSynchronizationListeners(KeycloakSessionFactory factory) {
+        Map<Class<? extends ProviderEvent>, Synchronizer> synchronizers = new HashMap<>();
+
+        synchronizers.put(ClientRemovedEvent.class, new ClientApplicationSynchronizer());
+        synchronizers.put(RealmRemovedEvent.class, new RealmSynchronizer());
+
+        factory.register(event -> {
+            try {
+                synchronizers.forEach((eventType, synchronizer) -> {
+                    if (eventType.isInstance(event)) {
+                        synchronizer.synchronize(event, factory);
+                    }
+                });
+            } catch (Exception e) {
+                throw new RuntimeException("Error synchronizing authorization data.", e);
+            }
+        });
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/store/package-info.java b/server-spi/src/main/java/org/keycloak/authorization/store/package-info.java
new file mode 100644
index 0000000..d9800da
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/store/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Provides classes and a SPI to plug different metadata storage implementations.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+package org.keycloak.authorization.store;
\ No newline at end of file
diff --git a/server-spi/src/main/java/org/keycloak/authorization/store/PolicyStore.java b/server-spi/src/main/java/org/keycloak/authorization/store/PolicyStore.java
new file mode 100644
index 0000000..f55db99
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/store/PolicyStore.java
@@ -0,0 +1,119 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.store;
+
+
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+
+import java.util.List;
+
+/**
+ * A {@link PolicyStore} is responsible to manage the persistence of {@link Policy} instances.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface PolicyStore {
+
+    /**
+     * Creates a new {@link Policy} instance. The new instance is not necessarily persisted though, which may require
+     * a call to the {#save} method to actually make it persistent.
+     *
+     * @param name           the name of the policy
+     * @param type           the type of the policy
+     * @param resourceServer the resource server to which this policy belongs
+     * @return a new instance of {@link Policy}
+     */
+    Policy create(String name, String type, ResourceServer resourceServer);
+
+    /**
+     * Deletes a policy from the underlying persistence mechanism.
+     *
+     * @param id the id of the policy to delete
+     */
+    void delete(String id);
+
+    /**
+     * Returns a {@link Policy} with the given <code>id</code>
+     *
+     * @param id the identifier of the policy
+     * @return a policy with the given identifier.
+     */
+    Policy findById(String id);
+
+    /**
+     * Returns a {@link Policy} with the given <code>name</code>
+     *
+     * @param name             the name of the policy
+     * @param resourceServerId the resource server id
+     * @return a policy with the given name.
+     */
+    Policy findByName(String name, String resourceServerId);
+
+    /**
+     * Returns a list of {@link Policy} associated with a {@link ResourceServer} with the given <code>resourceServerId</code>.
+     *
+     * @param resourceServerId the identifier of a resource server
+     * @return a list of policies that belong to the given resource server
+     */
+    List<Policy> findByResourceServer(String resourceServerId);
+
+    /**
+     * Returns a list of {@link Policy} associated with a {@link org.keycloak.authorization.core.model.Resource} with the given <code>resourceId</code>.
+     *
+     * @param resourceId the identifier of a resource
+     * @return a list of policies associated with the given resource
+     */
+    List<Policy> findByResource(String resourceId);
+
+    /**
+     * Returns a list of {@link Policy} associated with a {@link org.keycloak.authorization.core.model.Resource} with the given <code>type</code>.
+     *
+     * @param resourceType     the type of a resource
+     * @param resourceServerId the resource server id
+     * @return a list of policies associated with the given resource type
+     */
+    List<Policy> findByResourceType(String resourceType, String resourceServerId);
+
+    /**
+     * Returns a list of {@link Policy} associated with a {@link org.keycloak.authorization.core.model.Scope} with the given <code>scopeIds</code>.
+     *
+     * @param scopeIds the id of the scopes
+     * @param resourceServerId the resource server id
+     * @return a list of policies associated with the given scopes
+     */
+    List<Policy> findByScopeIds(List<String> scopeIds, String resourceServerId);
+
+    /**
+     * Returns a list of {@link Policy} with the given <code>type</code>.
+     *
+     * @param type the type of the policy
+     * @return a list of policies with the given type
+     */
+    List<Policy> findByType(String type);
+
+    /**
+     * Returns a list of {@link Policy} that depends on another policy with the given <code>id</code>.
+     *
+     * @param id the id of the policy to query its dependents
+     * @return a list of policies that depends on the a policy with the given identifier
+     */
+    List<Policy> findDependentPolicies(String id);
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/store/ResourceServerStore.java b/server-spi/src/main/java/org/keycloak/authorization/store/ResourceServerStore.java
new file mode 100644
index 0000000..742f98b
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/store/ResourceServerStore.java
@@ -0,0 +1,63 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.store;
+
+import org.keycloak.authorization.model.ResourceServer;
+
+/**
+ * A {@link ResourceServerStore} is responsible to manage the persistence of {@link ResourceServer} instances.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface ResourceServerStore {
+
+    /**
+     * <p>Creates a {@link ResourceServer} instance backed by this persistent storage implementation.
+     *
+     * @param clientId the client id acting as a resource server
+     *
+     * @return an instance backed by the underlying storage implementation
+     */
+    ResourceServer create(String clientId);
+
+    /**
+     * Removes a {@link ResourceServer} instance, with the given {@code id} from the persistent storage.
+     *
+     * @param id the identifier of an existing resource server instance
+     */
+    void delete(String id);
+
+    /**
+     * Returns a {@link ResourceServer} instance based on its identifier.
+     *
+     * @param id the identifier of an existing resource server instance
+     *
+     * @return the resource server instance with the given identifier or null if no instance was found
+     */
+    ResourceServer findById(String id);
+
+    /**
+     * Returns a {@link ResourceServer} instance based on the identifier of a client application.
+     *
+     * @param id the identifier of an existing client application
+     * 
+     * @return the resource server instance, with the given client id or null if no instance was found
+     */
+    ResourceServer findByClient(String id);
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/store/ResourceStore.java b/server-spi/src/main/java/org/keycloak/authorization/store/ResourceStore.java
new file mode 100644
index 0000000..5b92808
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/store/ResourceStore.java
@@ -0,0 +1,99 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.store;
+
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A {@link ResourceStore} is responsible to manage the persistence of {@link Resource} instances.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface ResourceStore {
+
+    /**
+     * <p>Creates a {@link Resource} instance backed by this persistent storage implementation.
+     *
+     * @param name the name of this resource. It must be unique.
+     * @param resourceServer the resource server to where the given resource belongs to
+     * @param owner the owner of this resource or null if the resource server is the owner
+     * @return an instance backed by the underlying storage implementation
+     */
+    Resource create(String name, ResourceServer resourceServer, String owner);
+
+    /**
+     * Removes a {@link Resource} instance, with the given {@code id} from the persistent storage.
+     *
+     * @param id the identifier of an existing resource instance
+     */
+    void delete(String id);
+
+    /**
+     * Returns a {@link Resource} instance based on its identifier.
+     *
+     * @param id the identifier of an existing resource instance
+     * @return the resource instance with the given identifier or null if no instance was found
+     */
+    Resource findById(String id);
+
+    /**
+     * Finds all {@link Resource} instances with the given {@code ownerId}.
+     *
+     * @param ownerId the identifier of the owner
+     * @return a list with all resource instances owned by the given owner
+     */
+    List<Resource> findByOwner(String ownerId);
+
+    /**
+     * Finds all {@link Resource} instances associated with a given resource server.
+     *
+     * @param resourceServerId the identifier of the resource server
+     * @return a list with all resources associated with the given resource server
+     */
+    List<Resource> findByResourceServer(String resourceServerId);
+
+    /**
+     * Finds all {@link Resource} associated with a given scope.
+     *
+     * @param id one or more scope identifiers
+     * @return a list of resources associated with the given scope(s)
+     */
+    List<Resource> findByScope(String... id);
+
+    /**
+     * Find a {@link Resource} by its name.
+     *
+     * @param name the name of the resource
+     * @param resourceServerId the identifier of the resource server
+     * @return a resource with the given name
+     */
+    Resource findByName(String name, String resourceServerId);
+
+    /**
+     * Finds all {@link Resource} with the given type.
+     *
+     * @param type the type of the resource
+     * @return a list of resources with the given type
+     */
+    List<Resource> findByType(String type);
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/store/ScopeStore.java b/server-spi/src/main/java/org/keycloak/authorization/store/ScopeStore.java
new file mode 100644
index 0000000..501217f
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/store/ScopeStore.java
@@ -0,0 +1,78 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.store;
+
+
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+
+import java.util.List;
+
+/**
+ * A {@link ScopeStore} is responsible to manage the persistence of {@link Scope} instances.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface ScopeStore {
+
+    /**
+     * Creates a new {@link Scope} instance. The new instance is not necessarily persisted though, which may require
+     * a call to the {#save} method to actually make it persistent.
+     *
+     * @param name the name of the scope
+     * @param resourceServer the resource server to which this scope belongs
+     *
+     * @return a new instance of {@link Scope}
+     */
+    Scope create(String name, ResourceServer resourceServer);
+
+    /**
+     * Deletes a scope from the underlying persistence mechanism.
+     *
+     * @param id the id of the scope to delete
+     */
+    void delete(String id);
+
+    /**
+     * Returns a {@link Scope} with the given <code>id</code>
+     *
+     * @param id the identifier of the scope
+     *
+     * @return a scope with the given identifier.
+     */
+    Scope findById(String id);
+
+    /**
+     * Returns a {@link Scope} with the given <code>name</code>
+     *
+     * @param name the name of the scope
+     *
+     * @param resourceServerId
+     * @return a scope with the given name.
+     */
+    Scope findByName(String name, String resourceServerId);
+
+    /**
+     * Returns a list of {@link Scope} associated with a {@link ResourceServer} with the given <code>resourceServerId</code>.
+     *
+     * @param resourceServerId the identifier of a resource server
+     *
+     * @return a list of scopes that belong to the given resource server
+     */
+    List<Scope> findByResourceServer(String id);
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/store/StoreFactory.java b/server-spi/src/main/java/org/keycloak/authorization/store/StoreFactory.java
new file mode 100644
index 0000000..4f50c11
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/store/StoreFactory.java
@@ -0,0 +1,61 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.store;
+
+import org.keycloak.provider.Provider;
+
+/**
+ * <p>A factory for the different types of storages that manage the persistence of the domain model types.
+ *
+ * <p>Implementations of this interface are usually related with the creation of those storage types accordingly with a
+ * specific persistence mechanism such as relational and NoSQL databases, filesystem, etc.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface StoreFactory extends Provider {
+
+    /**
+     * Returns a {@link ResourceStore}.
+     *
+     * @return the resource store
+     */
+    ResourceStore getResourceStore();
+
+    /**
+     * Returns a {@link ResourceServerStore}.
+     *
+     * @return the resource server store
+     */
+    ResourceServerStore getResourceServerStore();
+
+    /**
+     * Returns a {@link ScopeStore}.
+     *
+     * @return the scope store
+     */
+    ScopeStore getScopeStore();
+
+    /**
+     * Returns a {@link PolicyStore}.
+     *
+     * @return the policy store
+     */
+    PolicyStore getPolicyStore();
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/store/StoreFactorySpi.java b/server-spi/src/main/java/org/keycloak/authorization/store/StoreFactorySpi.java
new file mode 100644
index 0000000..53bfb25
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/store/StoreFactorySpi.java
@@ -0,0 +1,48 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.store;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class StoreFactorySpi implements Spi {
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "authorizationPersister";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return StoreFactory.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return AuthorizationStoreFactory.class;
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/store/syncronization/ClientApplicationSynchronizer.java b/server-spi/src/main/java/org/keycloak/authorization/store/syncronization/ClientApplicationSynchronizer.java
new file mode 100644
index 0000000..67683ff
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/store/syncronization/ClientApplicationSynchronizer.java
@@ -0,0 +1,51 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.store.syncronization;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.store.AuthorizationStoreFactory;
+import org.keycloak.authorization.store.ResourceServerStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel.ClientRemovedEvent;
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ClientApplicationSynchronizer implements Synchronizer<ClientRemovedEvent> {
+
+    @Override
+    public void synchronize(ClientRemovedEvent event, KeycloakSessionFactory factory) {
+        ProviderFactory<AuthorizationProvider> providerFactory = factory.getProviderFactory(AuthorizationProvider.class);
+        AuthorizationProvider authorizationProvider = providerFactory.create(event.getKeycloakSession());
+        StoreFactory storeFactory = authorizationProvider.getStoreFactory();
+        ResourceServerStore store = storeFactory.getResourceServerStore();
+        ResourceServer resourceServer = store.findByClient(event.getClient().getId());
+
+        if (resourceServer != null) {
+            String id = resourceServer.getId();
+            storeFactory.getResourceStore().findByResourceServer(id).forEach(resource -> storeFactory.getResourceStore().delete(resource.getId()));
+            storeFactory.getScopeStore().findByResourceServer(id).forEach(scope -> storeFactory.getScopeStore().delete(scope.getId()));
+            storeFactory.getPolicyStore().findByResourceServer(id).forEach(scope -> storeFactory.getPolicyStore().delete(scope.getId()));
+            storeFactory.getResourceServerStore().delete(id);
+        }
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/store/syncronization/RealmSynchronizer.java b/server-spi/src/main/java/org/keycloak/authorization/store/syncronization/RealmSynchronizer.java
new file mode 100644
index 0000000..4f0ef32
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/store/syncronization/RealmSynchronizer.java
@@ -0,0 +1,50 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.store.syncronization;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel.RealmRemovedEvent;
+import org.keycloak.provider.ProviderFactory;
+
+/*
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class RealmSynchronizer implements Synchronizer<RealmRemovedEvent> {
+    @Override
+    public void synchronize(RealmRemovedEvent event, KeycloakSessionFactory factory) {
+        ProviderFactory<AuthorizationProvider> providerFactory = factory.getProviderFactory(AuthorizationProvider.class);
+        AuthorizationProvider authorizationProvider = providerFactory.create(event.getKeycloakSession());
+        StoreFactory storeFactory = authorizationProvider.getStoreFactory();
+
+        event.getRealm().getClients().forEach(clientModel -> {
+            ResourceServer resourceServer = storeFactory.getResourceServerStore().findByClient(clientModel.getClientId());
+
+            if (resourceServer != null) {
+                String id = resourceServer.getId();
+                storeFactory.getResourceStore().findByResourceServer(id).forEach(resource -> storeFactory.getResourceStore().delete(resource.getId()));
+                storeFactory.getScopeStore().findByResourceServer(id).forEach(scope -> storeFactory.getScopeStore().delete(scope.getId()));
+                storeFactory.getPolicyStore().findByResourceServer(id).forEach(scope -> storeFactory.getPolicyStore().delete(scope.getId()));
+                storeFactory.getResourceServerStore().delete(id);
+            }
+        });
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/authorization/store/syncronization/Synchronizer.java b/server-spi/src/main/java/org/keycloak/authorization/store/syncronization/Synchronizer.java
new file mode 100644
index 0000000..eb07947
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/authorization/store/syncronization/Synchronizer.java
@@ -0,0 +1,31 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.store.syncronization;
+
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.provider.ProviderEvent;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface Synchronizer<E extends ProviderEvent> {
+
+    void synchronize(E event, KeycloakSessionFactory factory);
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/component/ComponentFactory.java b/server-spi/src/main/java/org/keycloak/component/ComponentFactory.java
new file mode 100644
index 0000000..b107d5a
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/component/ComponentFactory.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.component;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.provider.ConfiguredProvider;
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderConfigProperty;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.storage.UserStorageProviderModel;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface ComponentFactory<CreatedType, ProviderType extends Provider> extends ProviderFactory<ProviderType>, ConfiguredProvider {
+    CreatedType create(KeycloakSession session, ComponentModel model);
+
+    @Override
+    default ProviderType create(KeycloakSession session) {
+        return null;
+    }
+
+    void validateConfiguration(KeycloakSession session, ComponentModel config) throws ComponentValidationException;
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/component/ComponentModel.java b/server-spi/src/main/java/org/keycloak/component/ComponentModel.java
new file mode 100755
index 0000000..338bc4b
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/component/ComponentModel.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.component;
+
+import org.keycloak.common.util.MultivaluedHashMap;
+
+import java.io.Serializable;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Stored configuration of a User Storage provider instance.
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ * @author <a href="mailto:bburke@redhat.com">Bill Burke</a>
+ */
+public class ComponentModel implements Serializable {
+
+    private String id;
+    private String name;
+    private String providerId;
+    private String providerType;
+    private String parentId;
+    private MultivaluedHashMap<String, String> config = new MultivaluedHashMap<>();
+
+    public ComponentModel() {}
+
+    public ComponentModel(ComponentModel copy) {
+        this.id = copy.id;
+        this.name = copy.name;
+        this.providerId = copy.providerId;
+        this.providerType = copy.providerType;
+        this.config = copy.config;
+    }
+
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public MultivaluedHashMap<String, String> getConfig() {
+        return config;
+    }
+
+    public void setConfig(MultivaluedHashMap<String, String> config) {
+        this.config = config;
+    }
+
+    public String getProviderId() {
+        return providerId;
+    }
+
+    public void setProviderId(String providerId) {
+        this.providerId = providerId;
+    }
+
+    public String getProviderType() {
+        return providerType;
+    }
+
+    public void setProviderType(String providerType) {
+        this.providerType = providerType;
+    }
+
+    public String getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(String parentId) {
+        this.parentId = parentId;
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/component/ComponentValidationException.java b/server-spi/src/main/java/org/keycloak/component/ComponentValidationException.java
new file mode 100644
index 0000000..d1d707c
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/component/ComponentValidationException.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.component;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ComponentValidationException extends RuntimeException {
+    public ComponentValidationException() {
+    }
+
+    public ComponentValidationException(String message) {
+        super(message);
+    }
+
+    public ComponentValidationException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public ComponentValidationException(Throwable cause) {
+        super(cause);
+    }
+
+    public ComponentValidationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/events/admin/AdminEvent.java b/server-spi/src/main/java/org/keycloak/events/admin/AdminEvent.java
index def6a29..24e070a 100644
--- a/server-spi/src/main/java/org/keycloak/events/admin/AdminEvent.java
+++ b/server-spi/src/main/java/org/keycloak/events/admin/AdminEvent.java
@@ -28,6 +28,11 @@ public class AdminEvent {
 
     private AuthDetails authDetails;
 
+    /**
+     * The resource type an AdminEvent was triggered for.
+     */
+    private ResourceType resourceType;
+
     private OperationType operationType;
 
     private String resourcePath;
@@ -133,4 +138,16 @@ public class AdminEvent {
         this.error = error;
     }
 
+    /**
+     * Returns the type of the affected {@link ResourceType} for this {@link AdminEvent}, e.g. {@link ResourceType#USER USER}, {@link ResourceType#GROUP GROUP} etc.
+     *
+     * @return
+     */
+    public ResourceType getResourceType() {
+        return resourceType;
+    }
+
+    public void setResourceType(ResourceType resourceType) {
+        this.resourceType = resourceType;
+    }
 }
diff --git a/server-spi/src/main/java/org/keycloak/events/admin/AdminEventQuery.java b/server-spi/src/main/java/org/keycloak/events/admin/AdminEventQuery.java
index d007171..8035a14 100644
--- a/server-spi/src/main/java/org/keycloak/events/admin/AdminEventQuery.java
+++ b/server-spi/src/main/java/org/keycloak/events/admin/AdminEventQuery.java
@@ -74,6 +74,13 @@ public interface AdminEventQuery {
     AdminEventQuery operation(OperationType... operations);
 
     /**
+     * Search by {@link ResourceType}.
+     * @param resourceTypes
+     * @return <code>this</code> for method chaining
+     */
+    AdminEventQuery resourceType(ResourceType ... resourceTypes);
+
+    /**
      * Search by resource path. Supports wildcards <code>*</code> and <code>**</code>. For example:
      * <ul>
      * <li><b>*&#47;master</b> - matches 'realms/master'</li>
@@ -124,5 +131,4 @@ public interface AdminEventQuery {
      * @return
      */
     List<AdminEvent> getResultList();
-
 }
diff --git a/server-spi/src/main/java/org/keycloak/events/admin/ResourceType.java b/server-spi/src/main/java/org/keycloak/events/admin/ResourceType.java
new file mode 100644
index 0000000..8b9c27c
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/events/admin/ResourceType.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.events.admin;
+
+/**
+ * Represents Keycloak resource types for which {@link AdminEvent AdminEvent's} can be triggered.
+ *
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+public enum ResourceType {
+
+    /**
+     *
+     */
+    REALM
+
+    /**
+     *
+     */
+    , REALM_ROLE
+
+    /**
+     *
+     */
+    , REALM_ROLE_MAPPING
+
+    /**
+     *
+     */
+    , REALM_SCOPE_MAPPING
+
+    /**
+     *
+     */
+    , AUTH_FLOW
+
+    /**
+     *
+     */
+    , AUTH_EXECUTION_FLOW
+
+    /**
+     *
+     */
+    , AUTH_EXECUTION
+
+    /**
+     *
+     */
+    , AUTHENTICATOR_CONFIG
+
+    /**
+     *
+     */
+    , REQUIRED_ACTION
+
+    /**
+     *
+     */
+    , IDENTITY_PROVIDER
+
+    /**
+     *
+     */
+    , IDENTITY_PROVIDER_MAPPER
+
+    /**
+     *
+     */
+    , PROTOCOL_MAPPER
+
+    /**
+     *
+     */
+    , USER
+
+    /**
+     *
+     */
+    , USER_LOGIN_FAILURE
+
+    /**
+     *
+     */
+    , USER_SESSION
+
+    /**
+     *
+     */
+    , USER_FEDERATION_PROVIDER
+
+    /**
+     *
+     */
+    , USER_FEDERATION_MAPPER
+
+    /**
+     *
+     */
+    , GROUP
+
+    /**
+     *
+     */
+    , GROUP_MEMBERSHIP
+
+    /**
+     *
+     */
+    , CLIENT
+
+    /**
+     *
+     */
+    , CLIENT_INITIAL_ACCESS_MODEL
+
+    /**
+     *
+     */
+    , CLIENT_REGISTRATION_TRUSTED_HOST_MODEL
+
+    /**
+     *
+     */
+    , CLIENT_ROLE
+
+    /**
+     *
+     */
+    , CLIENT_ROLE_MAPPING
+
+    /**
+     *
+     */
+    , CLIENT_TEMPLATE
+
+    /**
+     *
+     */
+    , CLIENT_SCOPE_MAPPING
+
+    /**
+     *
+     */
+    , CLUSTER_NODE;
+}
diff --git a/server-spi/src/main/java/org/keycloak/events/Errors.java b/server-spi/src/main/java/org/keycloak/events/Errors.java
index 2d6438f..ea2b887 100755
--- a/server-spi/src/main/java/org/keycloak/events/Errors.java
+++ b/server-spi/src/main/java/org/keycloak/events/Errors.java
@@ -65,9 +65,14 @@ public interface Errors {
     String SSL_REQUIRED = "ssl_required";
 
     String USER_SESSION_NOT_FOUND = "user_session_not_found";
+    String SESSION_EXPIRED = "session_expired";
 
     String EMAIL_SEND_FAILED = "email_send_failed";
     String INVALID_EMAIL = "invalid_email";
     String IDENTITY_PROVIDER_LOGIN_FAILURE = "identity_provider_login_failure";
     String IDENTITY_PROVIDER_ERROR = "identity_provider_error";
+
+    String PASSWORD_CONFIRM_ERROR = "password_confirm_error";
+    String PASSWORD_MISSING = "password_missing";
+    String PASSWORD_REJECTED = "password_rejected";
 }
diff --git a/server-spi/src/main/java/org/keycloak/hash/PasswordHashManager.java b/server-spi/src/main/java/org/keycloak/hash/PasswordHashManager.java
index 8f77d60..9c5afa8 100644
--- a/server-spi/src/main/java/org/keycloak/hash/PasswordHashManager.java
+++ b/server-spi/src/main/java/org/keycloak/hash/PasswordHashManager.java
@@ -18,7 +18,11 @@
 package org.keycloak.hash;
 
 import org.jboss.logging.Logger;
-import org.keycloak.models.*;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.PasswordPolicy;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserCredentialValueModel;
+import org.keycloak.policy.HashAlgorithmPasswordPolicyProviderFactory;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -32,17 +36,12 @@ public class PasswordHashManager {
     }
 
     public static UserCredentialValueModel encode(KeycloakSession session, PasswordPolicy passwordPolicy, String rawPassword) {
-        String algorithm = passwordPolicy.getHashAlgorithm();
-        int iterations = passwordPolicy.getHashIterations();
-        if (iterations < 1) {
-            iterations = 1;
-        }
         PasswordHashProvider provider = session.getProvider(PasswordHashProvider.class, passwordPolicy.getHashAlgorithm());
         if (provider == null) {
-            log.warnv("Could not find hash provider {0} from password policy, using default provider {1}", algorithm, Constants.DEFAULT_HASH_ALGORITHM);
-            provider = session.getProvider(PasswordHashProvider.class, Constants.DEFAULT_HASH_ALGORITHM);
+            log.warnv("Could not find hash provider {0} from password policy, using default provider {1}", passwordPolicy.getHashAlgorithm(), HashAlgorithmPasswordPolicyProviderFactory.DEFAULT_VALUE);
+            provider = session.getProvider(PasswordHashProvider.class, HashAlgorithmPasswordPolicyProviderFactory.DEFAULT_VALUE);
         }
-        return provider.encode(rawPassword, iterations);
+        return provider.encode(rawPassword, passwordPolicy.getHashIterations());
     }
 
     public static boolean verify(KeycloakSession session, RealmModel realm, String password, UserCredentialValueModel credential) {
diff --git a/server-spi/src/main/java/org/keycloak/mappers/UserFederationMapper.java b/server-spi/src/main/java/org/keycloak/mappers/UserFederationMapper.java
index ce9c199..98fa98d 100644
--- a/server-spi/src/main/java/org/keycloak/mappers/UserFederationMapper.java
+++ b/server-spi/src/main/java/org/keycloak/mappers/UserFederationMapper.java
@@ -34,8 +34,8 @@ import org.keycloak.provider.Provider;
 public interface UserFederationMapper extends Provider {
 
     /**
-     * Sync data from federation storage to Keycloak. It's useful just if mapper needs some data preloaded from federation storage (For example
-     * load roles from federation provider and sync them to Keycloak database)
+     * Sync data from federated storage to Keycloak. It's useful just if mapper needs some data preloaded from federated storage (For example
+     * load roles from federated provider and sync them to Keycloak database)
      *
      * Applicable just if sync is supported (see UserFederationMapperFactory.getSyncConfig() )
      *
@@ -48,7 +48,7 @@ public interface UserFederationMapper extends Provider {
     UserFederationSyncResult syncDataFromFederationProviderToKeycloak(UserFederationMapperModel mapperModel, UserFederationProvider federationProvider, KeycloakSession session, RealmModel realm);
 
     /**
-     * Sync data from Keycloak back to federation storage
+     * Sync data from Keycloak back to federated storage
      *
      * @see UserFederationMapperFactory#getSyncConfig()
      * @param mapperModel
diff --git a/server-spi/src/main/java/org/keycloak/mappers/UserFederationMapperFactory.java b/server-spi/src/main/java/org/keycloak/mappers/UserFederationMapperFactory.java
index 661462c..0efcf2e 100644
--- a/server-spi/src/main/java/org/keycloak/mappers/UserFederationMapperFactory.java
+++ b/server-spi/src/main/java/org/keycloak/mappers/UserFederationMapperFactory.java
@@ -32,7 +32,7 @@ import org.keycloak.representations.idm.UserFederationMapperSyncConfigRepresenta
 public interface UserFederationMapperFactory extends ProviderFactory<UserFederationMapper>, ConfiguredProvider {
 
     /**
-     * Refers to providerName (type) of the federation provider, which this mapper can be used for. For example "ldap" or "kerberos"
+     * Refers to providerName (type) of the federated provider, which this mapper can be used for. For example "ldap" or "kerberos"
      *
      * @return providerName
      */
@@ -42,7 +42,7 @@ public interface UserFederationMapperFactory extends ProviderFactory<UserFederat
     String getDisplayType();
 
     /**
-     * Specifies if mapper supports sync data from federation storage to keycloak and viceversa.
+     * Specifies if mapper supports sync data from federated storage to keycloak and viceversa.
      * Also specifies messages to be displayed in admin console UI (For example "Sync roles from LDAP" etc)
      *
      * @return syncConfig representation
diff --git a/server-spi/src/main/java/org/keycloak/migration/MigrationModel.java b/server-spi/src/main/java/org/keycloak/migration/MigrationModel.java
index 6196a29..c2e6dab 100755
--- a/server-spi/src/main/java/org/keycloak/migration/MigrationModel.java
+++ b/server-spi/src/main/java/org/keycloak/migration/MigrationModel.java
@@ -26,7 +26,7 @@ public interface MigrationModel {
     /**
      * Must have the form of major.minor.micro as the version is parsed and numbers are compared
      */
-    String LATEST_VERSION = "1.9.2";
+    String LATEST_VERSION = "2.1.0";
 
     String getStoredVersion();
     void setStoredVersion(String version);
diff --git a/server-spi/src/main/java/org/keycloak/migration/MigrationModelManager.java b/server-spi/src/main/java/org/keycloak/migration/MigrationModelManager.java
index 7a29804..6a2f448 100755
--- a/server-spi/src/main/java/org/keycloak/migration/MigrationModelManager.java
+++ b/server-spi/src/main/java/org/keycloak/migration/MigrationModelManager.java
@@ -26,6 +26,8 @@ import org.keycloak.migration.migrators.MigrateTo1_7_0;
 import org.keycloak.migration.migrators.MigrateTo1_8_0;
 import org.keycloak.migration.migrators.MigrateTo1_9_0;
 import org.keycloak.migration.migrators.MigrateTo1_9_2;
+import org.keycloak.migration.migrators.MigrateTo2_0_0;
+import org.keycloak.migration.migrators.MigrateTo2_1_0;
 import org.keycloak.migration.migrators.MigrationTo1_2_0_CR1;
 import org.keycloak.models.KeycloakSession;
 
@@ -99,6 +101,18 @@ public class MigrationModelManager {
             }
             new MigrateTo1_9_2().migrate(session);
         }
+        if (stored == null || stored.lessThan(MigrateTo2_0_0.VERSION)) {
+            if (stored != null) {
+                logger.debug("Migrating older model to 2.0.0 updates");
+            }
+            new MigrateTo2_0_0().migrate(session);
+        }
+        if (stored == null || stored.lessThan(MigrateTo2_1_0.VERSION)) {
+            if (stored != null) {
+                logger.debug("Migrating older model to 2.1.0 updates");
+            }
+            new MigrateTo2_1_0().migrate(session);
+        }
 
         model.setStoredVersion(MigrationModel.LATEST_VERSION);
     }
diff --git a/server-spi/src/main/java/org/keycloak/migration/migrators/MigrateTo1_3_0.java b/server-spi/src/main/java/org/keycloak/migration/migrators/MigrateTo1_3_0.java
index d83ae84..8d573c7 100755
--- a/server-spi/src/main/java/org/keycloak/migration/migrators/MigrateTo1_3_0.java
+++ b/server-spi/src/main/java/org/keycloak/migration/migrators/MigrateTo1_3_0.java
@@ -56,7 +56,7 @@ public class MigrateTo1_3_0 {
             if (fedProvider.getProviderName().equals(LDAPConstants.LDAP_PROVIDER)) {
                 Map<String, String> config = fedProvider.getConfig();
 
-                // Update config properties for LDAP federation provider
+                // Update config properties for LDAP federated provider
                 if (config.get(LDAPConstants.SEARCH_SCOPE) == null) {
                     config.put(LDAPConstants.SEARCH_SCOPE, String.valueOf(SearchControls.SUBTREE_SCOPE));
                 }
diff --git a/server-spi/src/main/java/org/keycloak/migration/migrators/MigrateTo2_0_0.java b/server-spi/src/main/java/org/keycloak/migration/migrators/MigrateTo2_0_0.java
new file mode 100644
index 0000000..23368f3
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/migration/migrators/MigrateTo2_0_0.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.migration.migrators;
+
+import org.keycloak.migration.ModelVersion;
+import org.keycloak.models.AdminRoles;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
+
+public class MigrateTo2_0_0 {
+
+    public static final ModelVersion VERSION = new ModelVersion("2.0.0");
+
+    public void migrate(KeycloakSession session) {
+        for (RealmModel realm : session.realms().getRealms()) {
+            migrateAuthorizationServices(realm);
+        }
+    }
+
+    private void migrateAuthorizationServices(RealmModel realm) {
+        KeycloakModelUtils.setupAuthorizationServices(realm);
+
+        MigrationUtils.addAdminRole(realm, AdminRoles.VIEW_AUTHORIZATION);
+        MigrationUtils.addAdminRole(realm, AdminRoles.MANAGE_AUTHORIZATION);
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/migration/migrators/MigrateTo2_1_0.java b/server-spi/src/main/java/org/keycloak/migration/migrators/MigrateTo2_1_0.java
new file mode 100644
index 0000000..9e7b931
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/migration/migrators/MigrateTo2_1_0.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.keycloak.migration.migrators;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.migration.ModelVersion;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RequiredActionProviderModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.util.JsonSerialization;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
+ */
+public class MigrateTo2_1_0 {
+    public static final ModelVersion VERSION = new ModelVersion("2.1.0");
+
+    public void migrate(KeycloakSession session) {
+        for (RealmModel realm : session.realms().getRealms()) {
+            migrateDefaultRequiredAction(realm);
+            migrateRolePolicies(realm, session);
+        }
+    }
+    
+    // KEYCLOAK-3244: Required Action "Configure Totp" should be "Configure OTP"
+    private void migrateDefaultRequiredAction(RealmModel realm) {
+        RequiredActionProviderModel otpAction = realm.getRequiredActionProviderByAlias(UserModel.RequiredAction.CONFIGURE_TOTP.name());
+
+        MigrationUtils.updateOTPRequiredAction(otpAction);
+
+        realm.updateRequiredActionProvider(otpAction);
+    }
+
+    // KEYCLOAK-3338: Changes to how role policy config is stored"
+    private void migrateRolePolicies(RealmModel realm, KeycloakSession session) {
+        AuthorizationProvider authorizationProvider = session.getProvider(AuthorizationProvider.class);
+        StoreFactory storeFactory = authorizationProvider.getStoreFactory();
+        PolicyStore policyStore = storeFactory.getPolicyStore();
+        realm.getClients().forEach(clientModel -> {
+            ResourceServer resourceServer = storeFactory.getResourceServerStore().findByClient(clientModel.getId());
+
+            if (resourceServer != null) {
+                policyStore.findByType("role").forEach(policy -> {
+                    Map<String, String> config = policy.getConfig();
+                    String roles = config.get("roles");
+                    List roleConfig;
+
+                    try {
+                        roleConfig = JsonSerialization.readValue(roles, List.class);
+                    } catch (Exception e) {
+                        throw new RuntimeException("Malformed configuration for role policy [" + policy.getName() + "].", e);
+                    }
+
+                    if (!roleConfig.isEmpty() && roleConfig.get(0) instanceof String) {
+                        try {
+                            config.put("roles", JsonSerialization.writeValueAsString(roleConfig.stream().map(new Function<String, Map>() {
+                                @Override
+                                public Map apply(String roleId) {
+                                    Map updated = new HashMap();
+
+                                    updated.put("id", roleId);
+
+                                    return updated;
+                                }
+                            }).collect(Collectors.toList())));
+                            policy.setConfig(config);
+                        } catch (Exception e) {
+                            throw new RuntimeException("Failed to migrate role policy [" + policy.getName() + "].", e);
+                        }
+                    }
+                });
+            }
+        });
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/migration/migrators/MigrationUtils.java b/server-spi/src/main/java/org/keycloak/migration/migrators/MigrationUtils.java
new file mode 100644
index 0000000..08da081
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/migration/migrators/MigrationUtils.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.migration.migrators;
+
+import org.keycloak.Config;
+import org.keycloak.models.*;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class MigrationUtils {
+
+    public static void addAdminRole(RealmModel realm, String roleName) {
+        ClientModel client = realm.getMasterAdminClient();
+        if (client.getRole(roleName) == null) {
+            RoleModel role = client.addRole(roleName);
+            role.setDescription("${role_" + roleName + "}");
+            role.setScopeParamRequired(false);
+
+            client.getRealm().getRole(AdminRoles.ADMIN).addCompositeRole(role);
+        }
+
+        if (!realm.getName().equals(Config.getAdminRealm())) {
+            client = realm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
+            if (client.getRole(roleName) == null) {
+                RoleModel role = client.addRole(roleName);
+                role.setDescription("${role_" + roleName + "}");
+                role.setScopeParamRequired(false);
+
+                client.getRole(AdminRoles.REALM_ADMIN).addCompositeRole(role);
+            }
+        }
+    }
+
+    public static void updateOTPRequiredAction(RequiredActionProviderModel otpAction) {
+        if (otpAction == null) return;
+        if (!otpAction.getProviderId().equals(UserModel.RequiredAction.CONFIGURE_TOTP.name())) return;
+        if (!otpAction.getName().equals("Configure Totp")) return;
+
+        otpAction.setName("Configure OTP");
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/models/AdminRoles.java b/server-spi/src/main/java/org/keycloak/models/AdminRoles.java
index 34cdb36..24455b8 100755
--- a/server-spi/src/main/java/org/keycloak/models/AdminRoles.java
+++ b/server-spi/src/main/java/org/keycloak/models/AdminRoles.java
@@ -37,13 +37,15 @@ public class AdminRoles {
     public static String VIEW_CLIENTS = "view-clients";
     public static String VIEW_EVENTS = "view-events";
     public static String VIEW_IDENTITY_PROVIDERS = "view-identity-providers";
+    public static String VIEW_AUTHORIZATION = "view-authorization";
 
     public static String MANAGE_REALM = "manage-realm";
     public static String MANAGE_USERS = "manage-users";
     public static String MANAGE_IDENTITY_PROVIDERS = "manage-identity-providers";
     public static String MANAGE_CLIENTS = "manage-clients";
     public static String MANAGE_EVENTS = "manage-events";
+    public static String MANAGE_AUTHORIZATION = "manage-authorization";
 
-    public static String[] ALL_REALM_ROLES = {CREATE_CLIENT, VIEW_REALM, VIEW_USERS, VIEW_CLIENTS, VIEW_EVENTS, VIEW_IDENTITY_PROVIDERS, MANAGE_REALM, MANAGE_USERS, MANAGE_CLIENTS, MANAGE_EVENTS, MANAGE_IDENTITY_PROVIDERS};
+    public static String[] ALL_REALM_ROLES = {CREATE_CLIENT, VIEW_REALM, VIEW_USERS, VIEW_CLIENTS, VIEW_EVENTS, VIEW_IDENTITY_PROVIDERS, VIEW_AUTHORIZATION, MANAGE_REALM, MANAGE_USERS, MANAGE_CLIENTS, MANAGE_EVENTS, MANAGE_IDENTITY_PROVIDERS, MANAGE_AUTHORIZATION};
 
 }
diff --git a/server-spi/src/main/java/org/keycloak/models/cache/authorization/CachedStoreFactoryProvider.java b/server-spi/src/main/java/org/keycloak/models/cache/authorization/CachedStoreFactoryProvider.java
new file mode 100644
index 0000000..3be3b78
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/models/cache/authorization/CachedStoreFactoryProvider.java
@@ -0,0 +1,27 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.cache.authorization;
+
+import org.keycloak.authorization.store.StoreFactory;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface CachedStoreFactoryProvider extends StoreFactory {
+}
diff --git a/server-spi/src/main/java/org/keycloak/models/cache/authorization/CachedStoreFactorySpi.java b/server-spi/src/main/java/org/keycloak/models/cache/authorization/CachedStoreFactorySpi.java
new file mode 100644
index 0000000..226949d
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/models/cache/authorization/CachedStoreFactorySpi.java
@@ -0,0 +1,48 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.cache.authorization;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class CachedStoreFactorySpi implements Spi {
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "authz-fached-store-factory";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return CachedStoreFactoryProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return CachedStoreProviderFactory.class;
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/models/cache/authorization/CachedStoreProviderFactory.java b/server-spi/src/main/java/org/keycloak/models/cache/authorization/CachedStoreProviderFactory.java
new file mode 100644
index 0000000..b8563cb
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/models/cache/authorization/CachedStoreProviderFactory.java
@@ -0,0 +1,27 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.cache.authorization;
+
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface CachedStoreProviderFactory extends ProviderFactory<CachedStoreFactoryProvider> {
+}
diff --git a/server-spi/src/main/java/org/keycloak/models/ClientRegistrationTrustedHostModel.java b/server-spi/src/main/java/org/keycloak/models/ClientRegistrationTrustedHostModel.java
new file mode 100644
index 0000000..30b2e6f
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/models/ClientRegistrationTrustedHostModel.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public interface ClientRegistrationTrustedHostModel {
+
+    RealmModel getRealm();
+
+    String getHostName();
+
+    int getCount();
+    void setCount(int count);
+
+    int getRemainingCount();
+    void setRemainingCount(int remainingCount);
+    void decreaseRemainingCount();
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/models/Constants.java b/server-spi/src/main/java/org/keycloak/models/Constants.java
index 460d08f..916565a 100755
--- a/server-spi/src/main/java/org/keycloak/models/Constants.java
+++ b/server-spi/src/main/java/org/keycloak/models/Constants.java
@@ -37,7 +37,9 @@ public interface Constants {
     String[] BROKER_SERVICE_ROLES = {READ_TOKEN_ROLE};
     String OFFLINE_ACCESS_ROLE = OAuth2Constants.OFFLINE_ACCESS;
 
-    String DEFAULT_HASH_ALGORITHM = "pbkdf2";
+    String AUTHZ_UMA_PROTECTION = "uma_protection";
+    String AUTHZ_UMA_AUTHORIZATION = "uma_authorization";
+    String[] AUTHZ_DEFAULT_AUTHORIZATION_ROLES = {AUTHZ_UMA_AUTHORIZATION};
 
     // 15 minutes
     int DEFAULT_ACCESS_TOKEN_LIFESPAN_FOR_IMPLICIT_FLOW_TIMEOUT = 900;
diff --git a/server-spi/src/main/java/org/keycloak/models/dblock/DBLockProvider.java b/server-spi/src/main/java/org/keycloak/models/dblock/DBLockProvider.java
index d9dc131..d7d6053 100644
--- a/server-spi/src/main/java/org/keycloak/models/dblock/DBLockProvider.java
+++ b/server-spi/src/main/java/org/keycloak/models/dblock/DBLockProvider.java
@@ -39,6 +39,13 @@ public interface DBLockProvider extends Provider {
      */
     void releaseLock();
 
+    /**
+     * Check if I have lock
+     *
+     * @return
+     */
+    boolean hasLock();
+
 
     /**
      * @return true if provider supports forced unlock at startup
diff --git a/server-spi/src/main/java/org/keycloak/models/entities/ComponentEntity.java b/server-spi/src/main/java/org/keycloak/models/entities/ComponentEntity.java
new file mode 100755
index 0000000..f873761
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/models/entities/ComponentEntity.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.entities;
+
+import org.keycloak.common.util.MultivaluedHashMap;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ComponentEntity extends AbstractIdentifiableEntity {
+    protected String name;
+    protected String providerType;
+    protected String providerId;
+    protected String parentId;
+    protected Map<String, List<String>> config = new MultivaluedHashMap<>();
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getProviderType() {
+        return providerType;
+    }
+
+    public void setProviderType(String providerType) {
+        this.providerType = providerType;
+    }
+
+    public String getProviderId() {
+        return providerId;
+    }
+
+    public void setProviderId(String providerId) {
+        this.providerId = providerId;
+    }
+
+    public String getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(String parentId) {
+        this.parentId = parentId;
+    }
+
+    public Map<String, List<String>> getConfig() {
+        return config;
+    }
+
+    public void setConfig(Map<String, List<String>> config) {
+        this.config = config;
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/models/entities/RealmEntity.java b/server-spi/src/main/java/org/keycloak/models/entities/RealmEntity.java
index cc3356b..c5a6ecf 100755
--- a/server-spi/src/main/java/org/keycloak/models/entities/RealmEntity.java
+++ b/server-spi/src/main/java/org/keycloak/models/entities/RealmEntity.java
@@ -19,6 +19,7 @@ package org.keycloak.models.entities;
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
@@ -80,13 +81,14 @@ public class RealmEntity extends AbstractIdentifiableEntity {
     private String emailTheme;
 
     // We are using names of defaultRoles (not ids)
-    private List<String> defaultRoles = new ArrayList<String>();
-    private List<String> defaultGroups = new ArrayList<String>();
+    private List<String> defaultRoles = new LinkedList<String>();
+    private List<String> defaultGroups = new LinkedList<String>();
 
-    private List<RequiredCredentialEntity> requiredCredentials = new ArrayList<RequiredCredentialEntity>();
-    private List<UserFederationProviderEntity> userFederationProviders = new ArrayList<UserFederationProviderEntity>();
-    private List<UserFederationMapperEntity> userFederationMappers = new ArrayList<UserFederationMapperEntity>();
-    private List<IdentityProviderEntity> identityProviders = new ArrayList<IdentityProviderEntity>();
+    private List<RequiredCredentialEntity> requiredCredentials = new LinkedList<>();
+    private List<ComponentEntity> componentEntities = new LinkedList<>();
+    private List<UserFederationProviderEntity> userFederationProviders = new LinkedList<UserFederationProviderEntity>();
+    private List<UserFederationMapperEntity> userFederationMappers = new LinkedList<UserFederationMapperEntity>();
+    private List<IdentityProviderEntity> identityProviders = new LinkedList<IdentityProviderEntity>();
 
     private Map<String, String> browserSecurityHeaders = new HashMap<String, String>();
     private Map<String, String> smtpConfig = new HashMap<String, String>();
@@ -682,6 +684,14 @@ public class RealmEntity extends AbstractIdentifiableEntity {
     public void setDefaultGroups(List<String> defaultGroups) {
         this.defaultGroups = defaultGroups;
     }
+
+    public List<ComponentEntity> getComponentEntities() {
+        return componentEntities;
+    }
+
+    public void setComponentEntities(List<ComponentEntity> componentEntities) {
+        this.componentEntities = componentEntities;
+    }
 }
 
 
diff --git a/server-spi/src/main/java/org/keycloak/models/FederatedIdentityModel.java b/server-spi/src/main/java/org/keycloak/models/FederatedIdentityModel.java
index dcda375..e7e4ee6 100755
--- a/server-spi/src/main/java/org/keycloak/models/FederatedIdentityModel.java
+++ b/server-spi/src/main/java/org/keycloak/models/FederatedIdentityModel.java
@@ -57,4 +57,25 @@ public class FederatedIdentityModel {
     public void setToken(String token) {
         this.token = token;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        FederatedIdentityModel that = (FederatedIdentityModel) o;
+
+        if (userId != null ? !userId.equals(that.userId) : that.userId != null) return false;
+        if (!identityProvider.equals(that.identityProvider)) return false;
+        return userName != null ? userName.equals(that.userName) : that.userName == null;
+
+    }
+
+    @Override
+    public int hashCode() {
+        int result = userId != null ? userId.hashCode() : 0;
+        result = 31 * result + identityProvider.hashCode();
+        result = 31 * result + (userName != null ? userName.hashCode() : 0);
+        return result;
+    }
 }
diff --git a/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java b/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java
index a45f475..8b6dcd3 100755
--- a/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java
+++ b/server-spi/src/main/java/org/keycloak/models/KeycloakSession.java
@@ -18,6 +18,9 @@
 package org.keycloak.models;
 
 import org.keycloak.provider.Provider;
+import org.keycloak.scripting.ScriptingProvider;
+import org.keycloak.storage.federated.UserFederatedStorageProvider;
+import org.keycloak.storage.federated.UserFederatedStorageProviderFactory;
 
 import java.util.Set;
 
@@ -29,16 +32,48 @@ public interface KeycloakSession {
 
     KeycloakContext getContext();
 
-    KeycloakTransactionManager getTransaction();
+    KeycloakTransactionManager getTransactionManager();
 
+    /**
+     * Get dedicated provider instance of provider type clazz that was created for this session.  If one hasn't been created yet,
+     * find the factory and allocate by calling ProviderFactory.create(KeycloakSession).  The provider to use is determined
+     * by the "provider" config entry in keycloak-server boot configuration. (keycloak-server.json)
+     *
+     *
+     *
+     * @param clazz
+     * @param <T>
+     * @return
+     */
     <T extends Provider> T getProvider(Class<T> clazz);
 
+    /**
+     * Get dedicated provider instance for a specific provider factory of id of provider type clazz that was created for this session.
+     * If one hasn't been created yet,
+     * find the factory and allocate by calling ProviderFactory.create(KeycloakSession).
+
+     * @param clazz
+     * @param id
+     * @param <T>
+     * @return
+     */
     <T extends Provider> T getProvider(Class<T> clazz, String id);
 
+    /**
+     * Get all provider factories that manage provider instances of class.
+     *
+     * @param clazz
+     * @param <T>
+     * @return
+     */
     <T extends Provider> Set<String> listProviderIds(Class<T> clazz);
 
     <T extends Provider> Set<T> getAllProviders(Class<T> clazz);
 
+    Object getAttribute(String attribute);
+    Object removeAttribute(String attribute);
+    void setAttribute(String name, Object value);
+
     void enlistForClose(Provider provider);
 
     KeycloakSessionFactory getKeycloakSessionFactory();
@@ -66,14 +101,42 @@ public interface KeycloakSession {
     void close();
 
     /**
-     * Possibly both cached and federated view of users depending on configuration.
+     * A cached view of all users in system.
      *
      * @return
      */
     UserFederationManager users();
 
+
     /**
-     *  Keycloak user storage.  Non-federated, but possibly cache (if it is on) view of users.
+     * Un-cached view of all users in system that does NOT include users available from the deprecated UserFederationProvider SPI.
+     *
+     * @return
+     */
+    UserProvider userStorageManager();
+
+    /**
+     *  A cached view of all users in system that does NOT include users available from the deprecated UserFederationProvider SPI.
      */
     UserProvider userStorage();
+
+    /**
+     * Keycloak specific local storage for users.  No cache in front, this api talks directly to database.
+     *
+     * @return
+     */
+    UserProvider userLocalStorage();
+
+    /**
+     * Hybrid storage for UserStorageProviders that can't store a specific piece of keycloak data in their external storage.
+     *
+     * @return
+     */
+    UserFederatedStorageProvider userFederatedStorage();
+
+
+    /**
+     * Keycloak scripting support.
+     */
+    ScriptingProvider scripting();
 }
diff --git a/server-spi/src/main/java/org/keycloak/models/PasswordPolicy.java b/server-spi/src/main/java/org/keycloak/models/PasswordPolicy.java
index 0b22b4e..95dfc53 100755
--- a/server-spi/src/main/java/org/keycloak/models/PasswordPolicy.java
+++ b/server-spi/src/main/java/org/keycloak/models/PasswordPolicy.java
@@ -17,498 +17,101 @@
 
 package org.keycloak.models;
 
-import org.keycloak.hash.PasswordHashManager;
+import org.keycloak.policy.ForceExpiredPasswordPolicyProviderFactory;
+import org.keycloak.policy.HashAlgorithmPasswordPolicyProviderFactory;
+import org.keycloak.policy.HashIterationsPasswordPolicyProviderFactory;
+import org.keycloak.policy.HistoryPasswordPolicyProviderFactory;
+import org.keycloak.policy.PasswordPolicyProvider;
 
 import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
 public class PasswordPolicy implements Serializable {
 
-    public static final String INVALID_PASSWORD_MIN_LENGTH_MESSAGE = "invalidPasswordMinLengthMessage";
-    public static final String INVALID_PASSWORD_MIN_DIGITS_MESSAGE = "invalidPasswordMinDigitsMessage";
-    public static final String INVALID_PASSWORD_MIN_LOWER_CASE_CHARS_MESSAGE = "invalidPasswordMinLowerCaseCharsMessage";
-    public static final String INVALID_PASSWORD_MIN_UPPER_CASE_CHARS_MESSAGE = "invalidPasswordMinUpperCaseCharsMessage";
-    public static final String INVALID_PASSWORD_MIN_SPECIAL_CHARS_MESSAGE = "invalidPasswordMinSpecialCharsMessage";
-    public static final String INVALID_PASSWORD_NOT_USERNAME = "invalidPasswordNotUsernameMessage";
-    public static final String INVALID_PASSWORD_REGEX_PATTERN = "invalidPasswordRegexPatternMessage";
-    public static final String INVALID_PASSWORD_HISTORY = "invalidPasswordHistoryMessage";
-
-    private List<Policy> policies;
     private String policyString;
+    private Map<String, Object> policyConfig;
 
-    public PasswordPolicy(String policyString) {
-        this.policyString = policyString;
-        this.policies = new LinkedList<>();
+    public static PasswordPolicy empty() {
+        return new PasswordPolicy(null, new HashMap<>());
+    }
+
+    public static PasswordPolicy parse(KeycloakSession session, String policyString) {
+        Map<String, Object> policyConfig = new HashMap<>();
 
         if (policyString != null && !policyString.trim().isEmpty()) {
             for (String policy : policyString.split(" and ")) {
                 policy = policy.trim();
 
-                String name;
-                String arg = null;
+                String key;
+                String config = null;
 
                 int i = policy.indexOf('(');
                 if (i == -1) {
-                    name = policy.trim();
+                    key = policy.trim();
                 } else {
-                    name = policy.substring(0, i).trim();
-                    arg = policy.substring(i + 1, policy.length() - 1);
+                    key = policy.substring(0, i).trim();
+                    config = policy.substring(i + 1, policy.length() - 1);
                 }
 
-                if (name.equals(Length.NAME)) {
-                    policies.add(new Length(arg));
-                } else if (name.equals(Digits.NAME)) {
-                    policies.add(new Digits(arg));
-                } else if (name.equals(LowerCase.NAME)) {
-                    policies.add(new LowerCase(arg));
-                } else if (name.equals(UpperCase.NAME)) {
-                    policies.add(new UpperCase(arg));
-                } else if (name.equals(SpecialChars.NAME)) {
-                    policies.add(new SpecialChars(arg));
-                } else if (name.equals(NotUsername.NAME)) {
-                    policies.add(new NotUsername(arg));
-                } else if (name.equals(HashAlgorithm.NAME)) {
-                    policies.add(new HashAlgorithm(arg));
-                } else if (name.equals(HashIterations.NAME)) {
-                    policies.add(new HashIterations(arg));
-                } else if (name.equals(RegexPatterns.NAME)) {
-                    Pattern.compile(arg);
-                    policies.add(new RegexPatterns(arg));
-                } else if (name.equals(PasswordHistory.NAME)) {
-                    policies.add(new PasswordHistory(arg, this));
-                } else if (name.equals(ForceExpiredPasswordChange.NAME)) {
-                    policies.add(new ForceExpiredPasswordChange(arg));
-                } else {
+                PasswordPolicyProvider provider = session.getProvider(PasswordPolicyProvider.class, key);
+                if (provider == null) {
                     throw new IllegalArgumentException("Unsupported policy");
                 }
-            }
-        }
-    }
-
-    public String getHashAlgorithm() {
-        if (policies == null)
-            return Constants.DEFAULT_HASH_ALGORITHM;
-        for (Policy p : policies) {
-            if (p instanceof HashAlgorithm) {
-                return ((HashAlgorithm) p).algorithm;
-            }
-
-        }
-        return Constants.DEFAULT_HASH_ALGORITHM;
-    }
 
-    /**
-     *
-     * @return -1 if no hash iterations setting
-     */
-    public int getHashIterations() {
-        if (policies == null)
-            return -1;
-        for (Policy p : policies) {
-            if (p instanceof HashIterations) {
-                return ((HashIterations) p).iterations;
+                policyConfig.put(key, provider.parseConfig(config));
             }
-
-        }
-        return -1;
-    }
-
-    /**
-     *
-     * @return -1 if no expired passwords setting
-     */
-    public int getExpiredPasswords() {
-        if (policies == null)
-            return -1;
-        for (Policy p : policies) {
-            if (p instanceof PasswordHistory) {
-                return ((PasswordHistory) p).passwordHistoryPolicyValue;
-            }
-
-        }
-        return -1;
-    }
-    
-    /**
-    *
-    * @return -1 if no force expired password change setting
-    */
-   public int getDaysToExpirePassword() {
-       if (policies == null)
-           return -1;
-       for (Policy p : policies) {
-           if (p instanceof ForceExpiredPasswordChange) {
-               return ((ForceExpiredPasswordChange) p).daysToExpirePassword;
-           }
-
-       }
-       return -1;
-   }
-
-    public Error validate(KeycloakSession session, UserModel user, String password) {
-        for (Policy p : policies) {
-            Error error = p.validate(session, user, password);
-            if (error != null) {
-                return error;
-            }
-        }
-        return null;
-    }
-    
-    public Error validate(KeycloakSession session, String user, String password) {
-        for (Policy p : policies) {
-            Error error = p.validate(session, user, password);
-            if (error != null) {
-                return error;
-            }
-        }
-        return null;
-    }
-
-    private static interface Policy extends Serializable {
-        public Error validate(KeycloakSession session, UserModel user, String password);
-        public Error validate(KeycloakSession session, String user, String password);
-    }
-
-    public static class Error {
-        private String message;
-        private Object[] parameters;
-
-        private Error(String message, Object... parameters) {
-            this.message = message;
-            this.parameters = parameters;
-        }
-
-        public String getMessage() {
-            return message;
         }
 
-        public Object[] getParameters() {
-            return parameters;
-        }
-    }
-
-    private static class HashAlgorithm implements Policy {
-        private static final String NAME = "hashAlgorithm";
-        private String algorithm;
-
-        public HashAlgorithm(String arg) {
-            algorithm = stringArg(NAME, Constants.DEFAULT_HASH_ALGORITHM, arg);
-        }
-        
-        @Override
-        public Error validate(KeycloakSession session, String user, String password) {
-            return null;
-        }
-        
-        @Override
-        public Error validate(KeycloakSession session, UserModel user, String password) {
-            return null;
-        }
+        return new PasswordPolicy(policyString, policyConfig);
     }
 
-    private static class HashIterations implements Policy {
-        private static final String NAME = "hashIterations";
-        private int iterations;
-
-        public HashIterations(String arg) {
-            iterations = intArg(NAME, 1, arg);
-        }
-
-        @Override
-        public Error validate(KeycloakSession session, String user, String password) {
-            return null;
-        }
-
-        @Override
-        public Error validate(KeycloakSession session, UserModel user, String password) {
-            return null;
-        }
-    }
-
-    private static class NotUsername implements Policy {
-        private static final String NAME = "notUsername";
-
-        public NotUsername(String arg) {
-        }
-
-        @Override
-        public Error validate(KeycloakSession session, String username, String password) {
-            return username.equals(password) ? new Error(INVALID_PASSWORD_NOT_USERNAME) : null;
-        }
-        
-        @Override
-        public Error validate(KeycloakSession session, UserModel user, String password) {
-            return validate(session, user.getUsername(), password);
-        }
-    }
-
-    private static class Length implements Policy {
-        private static final String NAME = "length";
-        private int min;
-
-        public Length(String arg)
-        {
-            min = intArg(NAME, 8, arg);
-        }
-        
-
-        @Override
-        public Error validate(KeycloakSession session, String username, String password) {
-            return password.length() < min ? new Error(INVALID_PASSWORD_MIN_LENGTH_MESSAGE, min) : null;
-        }
-        
-        @Override
-        public Error validate(KeycloakSession session, UserModel user, String password) {
-            return validate(session, user.getUsername(), password);
-        }
-    }
-
-    private static class Digits implements Policy {
-        private static final String NAME = "digits";
-        private int min;
-
-        public Digits(String arg)
-        {
-            min = intArg(NAME, 1, arg);
-        }
-        
-
-        @Override
-        public Error validate(KeycloakSession session, String username, String password) {
-            int count = 0;
-            for (char c : password.toCharArray()) {
-                if (Character.isDigit(c)) {
-                    count++;
-                }
-            }
-            return count < min ? new Error(INVALID_PASSWORD_MIN_DIGITS_MESSAGE, min) : null;
-        }
-        
-        @Override
-        public Error validate(KeycloakSession session, UserModel user, String password) {
-            return validate(session, user.getUsername(), password);
-        }
+    private PasswordPolicy(String policyString, Map<String, Object> policyConfig) {
+        this.policyString = policyString;
+        this.policyConfig = policyConfig;
     }
 
-    private static class LowerCase implements Policy {
-        private static final String NAME = "lowerCase";
-        private int min;
-
-        public LowerCase(String arg)
-        {
-            min = intArg(NAME, 1, arg);
-        }
-        
-        @Override
-        public Error validate(KeycloakSession session, String username, String password) {
-            int count = 0;
-            for (char c : password.toCharArray()) {
-                if (Character.isLowerCase(c)) {
-                    count++;
-                }
-            }
-            return count < min ? new Error(INVALID_PASSWORD_MIN_LOWER_CASE_CHARS_MESSAGE, min) : null;
-        }
-        
-        @Override
-        public Error validate(KeycloakSession session, UserModel user, String password) {
-            return validate(session, user.getUsername(), password);
-        }
+    public Set<String> getPolicies() {
+        return policyConfig.keySet();
     }
 
-    private static class UpperCase implements Policy {
-        private static final String NAME = "upperCase";
-        private int min;
-
-        public UpperCase(String arg) {
-            min = intArg(NAME, 1, arg);
-        }
-
-        @Override
-        public Error validate(KeycloakSession session, String username, String password) {
-            int count = 0;
-            for (char c : password.toCharArray()) {
-                if (Character.isUpperCase(c)) {
-                    count++;
-                }
-            }
-            return count < min ? new Error(INVALID_PASSWORD_MIN_UPPER_CASE_CHARS_MESSAGE, min) : null;
-        }
-        
-        @Override
-        public Error validate(KeycloakSession session, UserModel user, String password) {
-            return validate(session, user.getUsername(), password);
-        }
+    public <T> T getPolicyConfig(String key) {
+        return (T) policyConfig.get(key);
     }
 
-    private static class SpecialChars implements Policy {
-        private static final String NAME = "specialChars";
-        private int min;
-
-        public SpecialChars(String arg)
-        {
-            min = intArg(NAME, 1, arg);
-        }
-        
-        @Override
-        public Error validate(KeycloakSession session, String username, String password) {
-            int count = 0;
-            for (char c : password.toCharArray()) {
-                if (!Character.isLetterOrDigit(c)) {
-                    count++;
-                }
-            }
-            return count < min ? new Error(INVALID_PASSWORD_MIN_SPECIAL_CHARS_MESSAGE, min) : null;
-        }
-        
-        @Override
-        public Error validate(KeycloakSession session, UserModel user, String password) {
-            return validate(session, user.getUsername(), password);
-        }
-    }
-
-    private static class RegexPatterns implements Policy {
-        private static final String NAME = "regexPattern";
-        private String regexPattern;
-
-        public RegexPatterns(String arg)
-        {
-            regexPattern = arg;
-        }
-
-        @Override
-        public Error validate(KeycloakSession session, String username, String password) {
-            Pattern pattern = Pattern.compile(regexPattern);
-            Matcher matcher = pattern.matcher(password);
-            if (!matcher.matches()) {
-                return new Error(INVALID_PASSWORD_REGEX_PATTERN, (Object) regexPattern);
-            }
-            return null;
-        }
-
-        @Override
-        public Error validate(KeycloakSession session, UserModel user, String password) {
-            return validate(session, user.getUsername(), password);
+    public String getHashAlgorithm() {
+        if (policyConfig.containsKey(HashAlgorithmPasswordPolicyProviderFactory.ID)) {
+            return getPolicyConfig(HashAlgorithmPasswordPolicyProviderFactory.ID);
+        } else {
+            return HashAlgorithmPasswordPolicyProviderFactory.DEFAULT_VALUE;
         }
     }
 
-    private static class PasswordHistory implements Policy {
-        private static final String NAME = "passwordHistory";
-        private final PasswordPolicy passwordPolicy;
-        private int passwordHistoryPolicyValue;
-
-        public PasswordHistory(String arg, PasswordPolicy passwordPolicy)
-        {
-            this.passwordPolicy = passwordPolicy;
-            passwordHistoryPolicyValue = intArg(NAME, 3, arg);
-        }
-        
-        @Override
-        public Error validate(KeycloakSession session, String user, String password) {
-            return null;
-        }
-
-        @Override
-        public Error validate(KeycloakSession session, UserModel user, String password) {
-            if (passwordHistoryPolicyValue != -1) {
-                UserCredentialValueModel cred = getCredentialValueModel(user, UserCredentialModel.PASSWORD);
-                if (cred != null) {
-                    if(PasswordHashManager.verify(session, passwordPolicy, password, cred)) {
-                        return new Error(INVALID_PASSWORD_HISTORY, passwordHistoryPolicyValue);
-                    }
-                }
-
-                List<UserCredentialValueModel> passwordExpiredCredentials = getCredentialValueModels(user, passwordHistoryPolicyValue - 1,
-                        UserCredentialModel.PASSWORD_HISTORY);
-                for (UserCredentialValueModel credential : passwordExpiredCredentials) {
-                    if (PasswordHashManager.verify(session, passwordPolicy, password, credential)) {
-                        return new Error(INVALID_PASSWORD_HISTORY, passwordHistoryPolicyValue);
-                    }
-                }
-            }
-            return null;
-        }
-
-        private UserCredentialValueModel getCredentialValueModel(UserModel user, String credType) {
-            for (UserCredentialValueModel model : user.getCredentialsDirectly()) {
-                if (model.getType().equals(credType)) {
-                    return model;
-                }
-            }
-
-            return null;
-        }
-
-        private List<UserCredentialValueModel> getCredentialValueModels(UserModel user, int expiredPasswordsPolicyValue,
-                String credType) {
-            List<UserCredentialValueModel> credentialModels = new ArrayList<UserCredentialValueModel>();
-            for (UserCredentialValueModel model : user.getCredentialsDirectly()) {
-                if (model.getType().equals(credType)) {
-                    credentialModels.add(model);
-                }
-            }
-
-            Collections.sort(credentialModels, new Comparator<UserCredentialValueModel>() {
-                public int compare(UserCredentialValueModel credFirst, UserCredentialValueModel credSecond) {
-                    if (credFirst.getCreatedDate() > credSecond.getCreatedDate()) {
-                        return -1;
-                    } else if (credFirst.getCreatedDate() < credSecond.getCreatedDate()) {
-                        return 1;
-                    } else {
-                        return 0;
-                    }
-                }
-            });
-
-            if (credentialModels.size() > expiredPasswordsPolicyValue) {
-                return credentialModels.subList(0, expiredPasswordsPolicyValue);
-            }
-            return credentialModels;
+    public int getHashIterations() {
+        if (policyConfig.containsKey(HashIterationsPasswordPolicyProviderFactory.ID)) {
+            return getPolicyConfig(HashIterationsPasswordPolicyProviderFactory.ID);
+        } else {
+            return HashIterationsPasswordPolicyProviderFactory.DEFAULT_VALUE;
         }
     }
-    
-    private static class ForceExpiredPasswordChange implements Policy {
-        private static final String NAME = "forceExpiredPasswordChange";
-        private int daysToExpirePassword;
-
-        public ForceExpiredPasswordChange(String arg) {
-            daysToExpirePassword = intArg(NAME, 365, arg);
-        }
 
-        @Override
-        public Error validate(KeycloakSession session, String username, String password) {
-            return null;
-        }
-
-        @Override
-        public Error validate(KeycloakSession session, UserModel user, String password) {
-            return null;
-        }
-    }
-    
-    private static int intArg(String policy, int defaultValue, String arg) {
-        if (arg == null) {
-            return defaultValue;
+    public int getExpiredPasswords() {
+        if (policyConfig.containsKey(HistoryPasswordPolicyProviderFactory.ID)) {
+            return getPolicyConfig(HistoryPasswordPolicyProviderFactory.ID);
         } else {
-            return Integer.parseInt(arg);
+            return -1;
         }
     }
 
-    private static String stringArg(String policy, String defaultValue, String arg) {
-        if (arg == null) {
-            return defaultValue;
+    public int getDaysToExpirePassword() {
+        if (policyConfig.containsKey(ForceExpiredPasswordPolicyProviderFactory.ID)) {
+            return getPolicyConfig(ForceExpiredPasswordPolicyProviderFactory.ID);
         } else {
-            return arg;
+            return -1;
         }
     }
 
@@ -516,4 +119,5 @@ public class PasswordPolicy implements Serializable {
     public String toString() {
         return policyString;
     }
+
 }
diff --git a/server-spi/src/main/java/org/keycloak/models/RealmModel.java b/server-spi/src/main/java/org/keycloak/models/RealmModel.java
index 1c42e45..04f1476 100755
--- a/server-spi/src/main/java/org/keycloak/models/RealmModel.java
+++ b/server-spi/src/main/java/org/keycloak/models/RealmModel.java
@@ -18,12 +18,17 @@
 package org.keycloak.models;
 
 import org.keycloak.common.enums.SslRequired;
+import org.keycloak.component.ComponentModel;
 import org.keycloak.provider.ProviderEvent;
+import org.keycloak.storage.UserStorageProvider;
+import org.keycloak.storage.UserStorageProviderModel;
 
 import java.security.Key;
 import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -37,10 +42,25 @@ public interface RealmModel extends RoleContainerModel {
         RealmModel getCreatedRealm();
     }
 
+    interface RealmPostCreateEvent extends ProviderEvent {
+        RealmModel getCreatedRealm();
+        KeycloakSession getKeycloakSession();
+    }
+
+    interface RealmRemovedEvent extends ProviderEvent {
+        RealmModel getRealm();
+        KeycloakSession getKeycloakSession();
+    }
+
     interface ClientCreationEvent extends ProviderEvent {
         ClientModel getCreatedClient();
     }
 
+    interface ClientRemovedEvent extends ProviderEvent {
+        ClientModel getClient();
+        KeycloakSession getKeycloakSession();
+    }
+
     interface UserFederationProviderCreationEvent extends ProviderEvent {
         UserFederationProviderModel getCreatedFederationProvider();
         RealmModel getRealm();
@@ -141,6 +161,8 @@ public interface RealmModel extends RoleContainerModel {
 
     void setAccessCodeLifespanLogin(int seconds);
 
+    String getKeyId();
+
     String getPublicKeyPem();
 
     void setPublicKeyPem(String publicKeyPem);
@@ -263,9 +285,30 @@ public interface RealmModel extends RoleContainerModel {
     public IdentityProviderMapperModel getIdentityProviderMapperById(String id);
     public IdentityProviderMapperModel getIdentityProviderMapperByName(String brokerAlias, String name);
 
+
+    ComponentModel addComponentModel(ComponentModel model);
+    void updateComponent(ComponentModel component);
+    void removeComponent(ComponentModel component);
+    void removeComponents(String parentId);
+    List<ComponentModel> getComponents(String parentId, String providerType);
+
+    List<ComponentModel> getComponents(String parentId);
+
+    List<ComponentModel> getComponents();
+    ComponentModel getComponent(String id);
+
+    default
+    List<UserStorageProviderModel> getUserStorageProviders() {
+        List<UserStorageProviderModel> list = new LinkedList<>();
+        for (ComponentModel component : getComponents(getId(), UserStorageProvider.class.getName())) {
+            list.add(new UserStorageProviderModel(component));
+        }
+        Collections.sort(list, UserStorageProviderModel.comparator);
+        return list;
+    }
+
     // Should return list sorted by UserFederationProviderModel.priority
     List<UserFederationProviderModel> getUserFederationProviders();
-
     UserFederationProviderModel addUserFederationProvider(String providerName, Map<String, String> config, int priority, String displayName, int fullSyncPeriod, int changedSyncPeriod, int lastSync);
     void updateUserFederationProvider(UserFederationProviderModel provider);
     void removeUserFederationProvider(UserFederationProviderModel provider);
@@ -322,19 +365,19 @@ public interface RealmModel extends RoleContainerModel {
     Set<String> getEventsListeners();
 
     void setEventsListeners(Set<String> listeners);
-    
+
     Set<String> getEnabledEventTypes();
 
     void setEnabledEventTypes(Set<String> enabledEventTypes);
-    
+
     boolean isAdminEventsEnabled();
 
     void setAdminEventsEnabled(boolean enabled);
-    
+
     boolean isAdminEventsDetailsEnabled();
 
     void setAdminEventsDetailsEnabled(boolean enabled);
-    
+
     ClientModel getMasterAdminClient();
 
     void setMasterAdminClient(ClientModel client);
diff --git a/server-spi/src/main/java/org/keycloak/models/RoleContainerModel.java b/server-spi/src/main/java/org/keycloak/models/RoleContainerModel.java
index 24c60b3..00542eb 100755
--- a/server-spi/src/main/java/org/keycloak/models/RoleContainerModel.java
+++ b/server-spi/src/main/java/org/keycloak/models/RoleContainerModel.java
@@ -17,6 +17,8 @@
 
 package org.keycloak.models;
 
+import org.keycloak.provider.ProviderEvent;
+
 import java.util.List;
 import java.util.Set;
 
@@ -25,6 +27,12 @@ import java.util.Set;
  * @version $Revision: 1 $
  */
 public interface RoleContainerModel {
+
+    interface RoleRemovedEvent extends ProviderEvent {
+        RoleModel getRole();
+        KeycloakSession getKeycloakSession();
+    }
+
     String getId();
 
     RoleModel getRole(String name);
diff --git a/server-spi/src/main/java/org/keycloak/models/ScriptModel.java b/server-spi/src/main/java/org/keycloak/models/ScriptModel.java
new file mode 100644
index 0000000..8d6d5fd
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/models/ScriptModel.java
@@ -0,0 +1,39 @@
+package org.keycloak.models;
+
+/**
+ * Denotes an executable Script with metadata.
+ *
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+public interface ScriptModel {
+
+    /**
+     * Returns the unique id of the script. {@literal null} for ad-hoc created scripts.
+     */
+    String getId();
+
+    /**
+     * Returns the realm id in which the script was defined.
+     */
+    String getRealmId();
+
+    /**
+     * Returns the name of the script.
+     */
+    String getName();
+
+    /**
+     * Returns the MIME-type if the script code, e.g. for Java Script the MIME-type, {@code text/javascript} is used.
+     */
+    String getMimeType();
+
+    /**
+     * Returns the actual source code of the script.
+     */
+    String getCode();
+
+    /**
+     * Returns the description of the script.
+     */
+    String getDescription();
+}
diff --git a/server-spi/src/main/java/org/keycloak/models/UserCredentialValueModel.java b/server-spi/src/main/java/org/keycloak/models/UserCredentialValueModel.java
index 65d0c89..5ef6071 100755
--- a/server-spi/src/main/java/org/keycloak/models/UserCredentialValueModel.java
+++ b/server-spi/src/main/java/org/keycloak/models/UserCredentialValueModel.java
@@ -25,7 +25,7 @@ import java.io.Serializable;
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
 public class UserCredentialValueModel implements Serializable {
-
+    private String id;
     private String type;
     private String value;
     private String device;
@@ -40,6 +40,14 @@ public class UserCredentialValueModel implements Serializable {
     private int period;
 
 
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
     public String getType() {
         return type;
     }
diff --git a/server-spi/src/main/java/org/keycloak/models/UserFederationManager.java b/server-spi/src/main/java/org/keycloak/models/UserFederationManager.java
index ef8d182..cb6867a 100755
--- a/server-spi/src/main/java/org/keycloak/models/UserFederationManager.java
+++ b/server-spi/src/main/java/org/keycloak/models/UserFederationManager.java
@@ -18,7 +18,10 @@
 package org.keycloak.models;
 
 import org.jboss.logging.Logger;
+import org.keycloak.component.ComponentModel;
 import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.policy.PasswordPolicyManagerProvider;
+import org.keycloak.policy.PolicyError;
 import org.keycloak.services.managers.UserManager;
 
 import java.util.ArrayList;
@@ -175,6 +178,38 @@ public class UserFederationManager implements UserProvider {
     }
 
     @Override
+    public void addConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
+        validateUser(realm, user);
+        session.userStorage().addConsent(realm, user, consent);
+
+    }
+
+    @Override
+    public UserConsentModel getConsentByClient(RealmModel realm, UserModel user, String clientInternalId) {
+        validateUser(realm, user);
+        return session.userStorage().getConsentByClient(realm, user, clientInternalId);
+    }
+
+    @Override
+    public List<UserConsentModel> getConsents(RealmModel realm, UserModel user) {
+        validateUser(realm, user);
+        return session.userStorage().getConsents(realm, user);
+    }
+
+    @Override
+    public void updateConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
+        validateUser(realm, user);
+        session.userStorage().updateConsent(realm, user, consent);
+
+    }
+
+    @Override
+    public boolean revokeConsentForClient(RealmModel realm, UserModel user, String clientInternalId) {
+        validateUser(realm, user);
+        return session.userStorage().revokeConsentForClient(realm, user, clientInternalId);
+    }
+
+    @Override
     public UserModel getUserById(String id, RealmModel realm) {
         UserModel user = session.userStorage().getUserById(id, realm);
         if (user != null) {
@@ -265,8 +300,8 @@ public class UserFederationManager implements UserProvider {
     }
 
     @Override
-    public UserModel getUserByServiceAccountClient(ClientModel client) {
-        UserModel user = session.userStorage().getUserByServiceAccountClient(client);
+    public UserModel getServiceAccount(ClientModel client) {
+        UserModel user = session.userStorage().getServiceAccount(client);
         if (user != null) {
             user = validateAndProxyUser(client.getRealm(), user);
         }
@@ -280,6 +315,16 @@ public class UserFederationManager implements UserProvider {
     }
 
     @Override
+    public List<UserModel> getUsers(RealmModel realm) {
+        return getUsers(realm, false);
+    }
+
+    @Override
+    public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) {
+        return getUsers(realm, firstResult, maxResults, false);
+    }
+
+    @Override
     public int getUsersCount(RealmModel realm) {
         return session.userStorage().getUsersCount(realm);
     }
@@ -359,17 +404,17 @@ public class UserFederationManager implements UserProvider {
     }
 
     @Override
-    public List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm) {
-        return searchForUserByAttributes(attributes, realm, 0, Integer.MAX_VALUE - 1);
+    public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm) {
+        return searchForUser(attributes, realm, 0, Integer.MAX_VALUE - 1);
     }
 
     @Override
-    public List<UserModel> searchForUserByAttributes(final Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
+    public List<UserModel> searchForUser(final Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
         federationLoad(realm, attributes);
         return query(new PaginatedQuery() {
             @Override
             public List<UserModel> query(RealmModel realm, int first, int max) {
-                return session.userStorage().searchForUserByAttributes(attributes, realm, first, max);
+                return session.userStorage().searchForUser(attributes, realm, first, max);
             }
         }, realm, firstResult, maxResults);
     }
@@ -445,7 +490,7 @@ public class UserFederationManager implements UserProvider {
     public void updateCredential(RealmModel realm, UserModel user, UserCredentialModel credential) {
         if (credential.getType().equals(UserCredentialModel.PASSWORD)) {
             if (realm.getPasswordPolicy() != null) {
-                PasswordPolicy.Error error = realm.getPasswordPolicy().validate(session, user, credential.getValue());
+                PolicyError error = session.getProvider(PasswordPolicyManagerProvider.class).validate(user, credential.getValue());
                 if (error != null) throw new ModelException(error.getMessage(), error.getParameters());
             }
         }
@@ -555,6 +600,11 @@ public class UserFederationManager implements UserProvider {
     }
 
     @Override
+    public void preRemove(RealmModel realm, ComponentModel component) {
+
+    }
+
+    @Override
     public void close() {
     }
 }
diff --git a/server-spi/src/main/java/org/keycloak/models/UserModel.java b/server-spi/src/main/java/org/keycloak/models/UserModel.java
index 0453977..28c35ab 100755
--- a/server-spi/src/main/java/org/keycloak/models/UserModel.java
+++ b/server-spi/src/main/java/org/keycloak/models/UserModel.java
@@ -17,6 +17,8 @@
 
 package org.keycloak.models;
 
+import org.keycloak.provider.ProviderEvent;
+
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -32,6 +34,11 @@ public interface UserModel extends RoleMapperModel {
     String EMAIL = "email";
     String LOCALE = "locale";
 
+    interface UserRemovedEvent extends ProviderEvent {
+        UserModel getUser();
+        KeycloakSession getKeycloakSession();
+    }
+
     String getId();
 
     String getUsername();
@@ -122,12 +129,6 @@ public interface UserModel extends RoleMapperModel {
     String getServiceAccountClientLink();
     void setServiceAccountClientLink(String clientInternalId);
 
-    void addConsent(UserConsentModel consent);
-    UserConsentModel getConsentByClient(String clientInternalId);
-    List<UserConsentModel> getConsents();
-    void updateConsent(UserConsentModel consent);
-    boolean revokeConsentForClient(String clientInternalId);
-
     public static enum RequiredAction {
         VERIFY_EMAIL, UPDATE_PROFILE, CONFIGURE_TOTP, UPDATE_PASSWORD
     }
diff --git a/server-spi/src/main/java/org/keycloak/models/UserProvider.java b/server-spi/src/main/java/org/keycloak/models/UserProvider.java
index 67c887f..d6ef2cd 100755
--- a/server-spi/src/main/java/org/keycloak/models/UserProvider.java
+++ b/server-spi/src/main/java/org/keycloak/models/UserProvider.java
@@ -17,54 +17,56 @@
 
 package org.keycloak.models;
 
+import org.keycloak.component.ComponentModel;
 import org.keycloak.provider.Provider;
+import org.keycloak.storage.user.UserCredentialValidatorProvider;
+import org.keycloak.storage.user.UserLookupProvider;
+import org.keycloak.storage.user.UserQueryProvider;
+import org.keycloak.storage.user.UserRegistrationProvider;
 
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public interface UserProvider extends Provider {
+public interface UserProvider extends Provider,
+        UserLookupProvider,
+        UserQueryProvider,
+        UserCredentialValidatorProvider,
+        UserRegistrationProvider {
     // Note: The reason there are so many query methods here is for layering a cache on top of an persistent KeycloakSession
 
-    UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions);
-    UserModel addUser(RealmModel realm, String username);
-    boolean removeUser(RealmModel realm, UserModel user);
-
     public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel socialLink);
     public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider);
     void updateFederatedIdentity(RealmModel realm, UserModel federatedUser, FederatedIdentityModel federatedIdentityModel);
+    Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm);
+    FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm);
+    UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm);
 
-    UserModel getUserById(String id, RealmModel realm);
-    UserModel getUserByUsername(String username, RealmModel realm);
-    UserModel getUserByEmail(String email, RealmModel realm);
+    void addConsent(RealmModel realm, UserModel user, UserConsentModel consent);
+    UserConsentModel getConsentByClient(RealmModel realm, UserModel user, String clientInternalId);
+    List<UserConsentModel> getConsents(RealmModel realm, UserModel user);
+    void updateConsent(RealmModel realm, UserModel user, UserConsentModel consent);
+    boolean revokeConsentForClient(RealmModel realm, UserModel user, String clientInternalId);
 
-    List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults);
 
-    UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm);
-    UserModel getUserByServiceAccountClient(ClientModel client);
+    UserModel getServiceAccount(ClientModel client);
     List<UserModel> getUsers(RealmModel realm, boolean includeServiceAccounts);
-
-    // Service account is included for counts
-    int getUsersCount(RealmModel realm);
-    List<UserModel> getGroupMembers(RealmModel realm, GroupModel group);
     List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults, boolean includeServiceAccounts);
-    List<UserModel> searchForUser(String search, RealmModel realm);
-    List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults);
-    List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm);
-    List<UserModel> searchForUserByAttributes(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults);
-
-    // Searching by UserModel.attribute (not property)
-    List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm);
-
-    Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm);
-    FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm);
-
-    void grantToAllUsers(RealmModel realm, RoleModel role);
 
+    /**
+     * only used for local storage
+     *
+     * @param realm
+     * @param id
+     * @param username
+     * @param addDefaultRoles
+     * @param addDefaultRequiredActions
+     * @return
+     */
+    UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions);
     void preRemove(RealmModel realm);
 
     void preRemove(RealmModel realm, UserFederationProviderModel link);
@@ -75,9 +77,12 @@ public interface UserProvider extends Provider {
     void preRemove(RealmModel realm, ClientModel client);
     void preRemove(ProtocolMapperModel protocolMapper);
 
-    boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, List<UserCredentialModel> input);
+
     boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, UserCredentialModel... input);
     CredentialValidationOutput validCredentials(KeycloakSession session, RealmModel realm, UserCredentialModel... input);
 
+
     void close();
+
+    void preRemove(RealmModel realm, ComponentModel component);
 }
diff --git a/server-spi/src/main/java/org/keycloak/models/UserSessionProvider.java b/server-spi/src/main/java/org/keycloak/models/UserSessionProvider.java
index d824584..27ce108 100755
--- a/server-spi/src/main/java/org/keycloak/models/UserSessionProvider.java
+++ b/server-spi/src/main/java/org/keycloak/models/UserSessionProvider.java
@@ -48,9 +48,9 @@ public interface UserSessionProvider extends Provider {
     void removeUserSessions(RealmModel realm);
     void removeClientSession(RealmModel realm, ClientSessionModel clientSession);
 
-    UsernameLoginFailureModel getUserLoginFailure(RealmModel realm, String username);
-    UsernameLoginFailureModel addUserLoginFailure(RealmModel realm, String username);
-    void removeUserLoginFailure(RealmModel realm, String username);
+    UserLoginFailureModel getUserLoginFailure(RealmModel realm, String userId);
+    UserLoginFailureModel addUserLoginFailure(RealmModel realm, String userId);
+    void removeUserLoginFailure(RealmModel realm, String userId);
     void removeAllUserLoginFailures(RealmModel realm);
 
     void onRealmRemoved(RealmModel realm);
@@ -82,6 +82,11 @@ public interface UserSessionProvider extends Provider {
     void removeClientInitialAccessModel(RealmModel realm, String id);
     List<ClientInitialAccessModel> listClientInitialAccess(RealmModel realm);
 
+    ClientRegistrationTrustedHostModel createClientRegistrationTrustedHostModel(RealmModel realm, String hostName, int count);
+    ClientRegistrationTrustedHostModel getClientRegistrationTrustedHostModel(RealmModel realm, String hostName);
+    void removeClientRegistrationTrustedHostModel(RealmModel realm, String hostName);
+    List<ClientRegistrationTrustedHostModel> listClientRegistrationTrustedHosts(RealmModel realm);
+
     void close();
 
 }
diff --git a/server-spi/src/main/java/org/keycloak/models/utils/CredentialValidation.java b/server-spi/src/main/java/org/keycloak/models/utils/CredentialValidation.java
index 074949f..85d52c0 100755
--- a/server-spi/src/main/java/org/keycloak/models/utils/CredentialValidation.java
+++ b/server-spi/src/main/java/org/keycloak/models/utils/CredentialValidation.java
@@ -17,19 +17,18 @@
 
 package org.keycloak.models.utils;
 
+import org.keycloak.common.util.Time;
 import org.keycloak.hash.PasswordHashManager;
 import org.keycloak.jose.jws.JWSInput;
 import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.jose.jws.crypto.RSAProvider;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.OTPPolicy;
-import org.keycloak.models.PasswordPolicy;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserCredentialValueModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.representations.PasswordToken;
-import org.keycloak.common.util.Time;
 
 import java.util.List;
 
@@ -39,16 +38,7 @@ import java.util.List;
  */
 public class CredentialValidation {
 
-    private static int hashIterations(RealmModel realm) {
-        PasswordPolicy policy = realm.getPasswordPolicy();
-        if (policy != null) {
-            return policy.getHashIterations();
-        }
-        return -1;
-
-    }
-
-    /**
+   /**
      * Will update password if hash iteration policy has changed
      *
      * @param realm
@@ -78,8 +68,7 @@ public class CredentialValidation {
         boolean validated = PasswordHashManager.verify(session, realm, unhashedCredValue, credential);
 
         if (validated) {
-            int iterations = hashIterations(realm);
-            if (iterations > -1 && iterations != credential.getHashIterations()) {
+            if (realm.getPasswordPolicy().getHashIterations() != credential.getHashIterations()) {
 
                 UserCredentialValueModel newCred = PasswordHashManager.encode(session, realm, unhashedCredValue);
                 user.updateCredentialDirectly(newCred);
@@ -195,7 +184,7 @@ public class CredentialValidation {
         return true;
     }
 
-    private static boolean validCredential(KeycloakSession session, RealmModel realm, UserModel user, UserCredentialModel credential) {
+    public static boolean validCredential(KeycloakSession session, RealmModel realm, UserModel user, UserCredentialModel credential) {
         if (credential.getType().equals(UserCredentialModel.PASSWORD)) {
             if (!validPassword(session, realm, user, credential.getValue())) {
                 return false;
diff --git a/server-spi/src/main/java/org/keycloak/models/utils/DefaultRequiredActions.java b/server-spi/src/main/java/org/keycloak/models/utils/DefaultRequiredActions.java
index 1292c1c..db38b64 100755
--- a/server-spi/src/main/java/org/keycloak/models/utils/DefaultRequiredActions.java
+++ b/server-spi/src/main/java/org/keycloak/models/utils/DefaultRequiredActions.java
@@ -52,7 +52,7 @@ public class DefaultRequiredActions {
             RequiredActionProviderModel totp = new RequiredActionProviderModel();
             totp.setEnabled(true);
             totp.setAlias(UserModel.RequiredAction.CONFIGURE_TOTP.name());
-            totp.setName("Configure Totp");
+            totp.setName("Configure OTP");
             totp.setProviderId(UserModel.RequiredAction.CONFIGURE_TOTP.name());
             totp.setDefaultAction(false);
             realm.addRequiredActionProvider(totp);
diff --git a/server-spi/src/main/java/org/keycloak/models/utils/DefaultRoles.java b/server-spi/src/main/java/org/keycloak/models/utils/DefaultRoles.java
new file mode 100644
index 0000000..450c4eb
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/models/utils/DefaultRoles.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.models.utils;
+
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class DefaultRoles {
+    public static Set<RoleModel> getDefaultRoles(RealmModel realm) {
+        Set<RoleModel> set = new HashSet<>();
+        for (String r : realm.getDefaultRoles()) {
+            set.add(realm.getRole(r));
+        }
+
+        for (ClientModel application : realm.getClients()) {
+            for (String r : application.getDefaultRoles()) {
+                set.add(application.getRole(r));
+            }
+        }
+        return set;
+
+    }
+    public static void addDefaultRoles(RealmModel realm, UserModel userModel) {
+        for (RoleModel role : getDefaultRoles(realm)) {
+            userModel.grantRole(role);
+        }
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/models/utils/FederatedCredentials.java b/server-spi/src/main/java/org/keycloak/models/utils/FederatedCredentials.java
new file mode 100644
index 0000000..69a823c
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/models/utils/FederatedCredentials.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.models.utils;
+
+import org.keycloak.common.util.Time;
+import org.keycloak.hash.PasswordHashManager;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.OTPPolicy;
+import org.keycloak.models.PasswordPolicy;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserCredentialValueModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.storage.federated.UserFederatedStorageProvider;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class FederatedCredentials {
+    public static void updateCredential(KeycloakSession session, UserFederatedStorageProvider provider, RealmModel realm, UserModel user, UserCredentialModel cred) {
+        if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
+            updatePasswordCredential(session, provider,realm, user, cred);
+        } else if (UserCredentialModel.isOtp(cred.getType())) {
+            updateOtpCredential(session, provider, realm, user, cred);
+        } else {
+            UserCredentialValueModel fedCred = getCredentialByType(provider, realm, user, cred.getType());
+            if (fedCred == null) {
+                fedCred.setCreatedDate(Time.toMillis(Time.currentTime()));
+                fedCred.setType(cred.getType());
+                fedCred.setDevice(cred.getDevice());
+                fedCred.setValue(cred.getValue());
+
+            } else {
+                fedCred.setValue(cred.getValue());
+            }
+            provider.updateCredential(realm, user, fedCred);
+        }
+    }
+
+    public static UserCredentialValueModel getCredentialByType(UserFederatedStorageProvider provider, RealmModel realm, UserModel user, String type) {
+        List<UserCredentialValueModel> creds = provider.getCredentials(realm, user);
+        for (UserCredentialValueModel cred : creds) {
+            if (cred.getType().equals(type)) return cred;
+        }
+        return null;
+    }
+
+    public static LinkedList<UserCredentialValueModel> getCredentialsByType(UserFederatedStorageProvider provider, RealmModel realm, UserModel user, String type) {
+        List<UserCredentialValueModel> creds = provider.getCredentials(realm, user);
+        LinkedList<UserCredentialValueModel> newCreds = new LinkedList<>();
+        for (UserCredentialValueModel cred : creds) {
+            if (cred.getType().equals(type)) newCreds.add(cred);
+        }
+        return newCreds;
+    }
+
+    public static void updatePasswordCredential(KeycloakSession session, UserFederatedStorageProvider provider, RealmModel realm, UserModel user, UserCredentialModel cred) {
+        UserCredentialValueModel fedCred = getCredentialByType(provider, realm, user, cred.getType());
+        if (fedCred == null) {
+            UserCredentialValueModel newCred = PasswordHashManager.encode(session, realm, cred.getValue());
+            newCred.setCreatedDate(Time.toMillis(Time.currentTime()));
+            newCred.setType(cred.getType());
+            newCred.setDevice(cred.getDevice());
+            provider.updateCredential(realm, user, newCred);
+        } else {
+            int expiredPasswordsPolicyValue = -1;
+            PasswordPolicy policy = realm.getPasswordPolicy();
+            if(policy != null) {
+                expiredPasswordsPolicyValue = policy.getExpiredPasswords();
+            }
+
+            if (expiredPasswordsPolicyValue != -1) {
+                fedCred.setType(UserCredentialModel.PASSWORD_HISTORY);
+
+                LinkedList<UserCredentialValueModel> credentialEntities = getCredentialsByType(provider, realm, user, UserCredentialModel.PASSWORD_HISTORY);
+                if (credentialEntities.size() > expiredPasswordsPolicyValue - 1) {
+                    Collections.sort(credentialEntities, new Comparator<UserCredentialValueModel>() {
+                        @Override
+                        public int compare(UserCredentialValueModel o1, UserCredentialValueModel o2) {
+                            if (o1.getCreatedDate().equals(o2.getCreatedDate())) return 0;
+                            return o1.getCreatedDate() < o2.getCreatedDate() ? -1 : 1;
+                        }
+                    });
+                    while (credentialEntities.size() > expiredPasswordsPolicyValue - 1) {
+                        UserCredentialValueModel model = credentialEntities.removeFirst();
+                        provider.removeCredential(realm, user, model);
+                    }
+
+                }
+                provider.updateCredential(realm, user, fedCred);
+                fedCred = PasswordHashManager.encode(session, realm, cred.getValue());
+                fedCred.setCreatedDate(Time.toMillis(Time.currentTime()));
+                fedCred.setType(cred.getType());
+                fedCred.setDevice(cred.getDevice());
+                provider.updateCredential(realm, user, fedCred);
+            } else {
+                // clear password history as it is not required anymore
+                for (UserCredentialValueModel model : getCredentialsByType(provider, realm, user, UserCredentialModel.PASSWORD_HISTORY)) {
+                    provider.removeCredential(realm, user, model);
+                }
+                UserCredentialValueModel newCred = PasswordHashManager.encode(session, realm, cred.getValue());
+                newCred.setCreatedDate(Time.toMillis(Time.currentTime()));
+                newCred.setType(cred.getType());
+                newCred.setDevice(cred.getDevice());
+                newCred.setId(fedCred.getId());
+                provider.updateCredential(realm, user, newCred);
+            }
+
+
+        }
+
+
+    }
+
+    public static  void updateOtpCredential(KeycloakSession session, UserFederatedStorageProvider provider, RealmModel realm, UserModel user, UserCredentialModel cred) {
+        LinkedList<UserCredentialValueModel> credentialEntities = getCredentialsByType(provider, realm, user, UserCredentialModel.PASSWORD_HISTORY);
+
+        if (credentialEntities.isEmpty()) {
+            UserCredentialValueModel fedCred = new UserCredentialValueModel();
+            fedCred.setCreatedDate(Time.toMillis(Time.currentTime()));
+            fedCred.setType(cred.getType());
+            fedCred.setDevice(cred.getDevice());
+            fedCred.setValue(cred.getValue());
+            OTPPolicy otpPolicy = realm.getOTPPolicy();
+            fedCred.setAlgorithm(otpPolicy.getAlgorithm());
+            fedCred.setDigits(otpPolicy.getDigits());
+            fedCred.setCounter(otpPolicy.getInitialCounter());
+            fedCred.setPeriod(otpPolicy.getPeriod());
+            provider.updateCredential(realm, user, fedCred);
+        } else {
+            OTPPolicy policy = realm.getOTPPolicy();
+            if (cred.getDevice() == null) {
+                for (UserCredentialValueModel model : credentialEntities) provider.removeCredential(realm, user, model);
+                UserCredentialValueModel fedCred = new UserCredentialValueModel();
+                fedCred.setCreatedDate(Time.toMillis(Time.currentTime()));
+                fedCred.setType(cred.getType());
+                fedCred.setDevice(cred.getDevice());
+                fedCred.setDigits(policy.getDigits());
+                fedCred.setCounter(policy.getInitialCounter());
+                fedCred.setAlgorithm(policy.getAlgorithm());
+                fedCred.setValue(cred.getValue());
+                fedCred.setPeriod(policy.getPeriod());
+                provider.updateCredential(realm, user, fedCred);
+            } else {
+                UserCredentialValueModel fedCred = new UserCredentialValueModel();
+                for (UserCredentialValueModel model : credentialEntities) {
+                    if (cred.getDevice().equals(model.getDevice())) {
+                        fedCred = model;
+                        break;
+                    }
+                }
+                fedCred.setCreatedDate(Time.toMillis(Time.currentTime()));
+                fedCred.setType(cred.getType());
+                fedCred.setDevice(cred.getDevice());
+                fedCred.setDigits(policy.getDigits());
+                fedCred.setCounter(policy.getInitialCounter());
+                fedCred.setAlgorithm(policy.getAlgorithm());
+                fedCred.setValue(cred.getValue());
+                fedCred.setPeriod(policy.getPeriod());
+                provider.updateCredential(realm, user, fedCred);
+            }
+        }
+    }
+
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/models/utils/FederatedCredentialValidation.java b/server-spi/src/main/java/org/keycloak/models/utils/FederatedCredentialValidation.java
new file mode 100755
index 0000000..54df576
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/models/utils/FederatedCredentialValidation.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.models.utils;
+
+import org.keycloak.common.util.Time;
+import org.keycloak.hash.PasswordHashManager;
+import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.JWSInputException;
+import org.keycloak.jose.jws.crypto.RSAProvider;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.OTPPolicy;
+import org.keycloak.models.PasswordPolicy;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserCredentialValueModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.representations.PasswordToken;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class FederatedCredentialValidation {
+
+    private static int hashIterations(RealmModel realm) {
+        PasswordPolicy policy = realm.getPasswordPolicy();
+        if (policy != null) {
+            return policy.getHashIterations();
+        }
+        return -1;
+
+    }
+
+   /**
+     * Will update password if hash iteration policy has changed
+     *
+     * @param realm
+     * @param user
+     * @param password
+     * @return
+     */
+    public static boolean validPassword(KeycloakSession session, RealmModel realm, UserModel user, String password, UserCredentialValueModel fedCred) {
+        return validateHashedCredential(session, realm, user, password, fedCred);
+
+    }
+
+
+    public static boolean validateHashedCredential(KeycloakSession session, RealmModel realm, UserModel user, String unhashedCredValue, UserCredentialValueModel credential) {
+        if (unhashedCredValue == null || unhashedCredValue.isEmpty()) {
+            return false;
+        }
+
+        boolean validated = PasswordHashManager.verify(session, realm, unhashedCredValue, credential);
+
+        if (validated) {
+            int iterations = hashIterations(realm);
+            if (iterations > -1 && iterations != credential.getHashIterations()) {
+
+                UserCredentialValueModel newCred = PasswordHashManager.encode(session, realm, unhashedCredValue);
+                session.userFederatedStorage().updateCredential(realm, user, newCred);
+            }
+
+        }
+        return validated;
+    }
+
+    public static boolean validPasswordToken(RealmModel realm, UserModel user, String encodedPasswordToken) {
+        try {
+            JWSInput jws = new JWSInput(encodedPasswordToken);
+            if (!RSAProvider.verify(jws, realm.getPublicKey())) {
+                return false;
+            }
+            PasswordToken passwordToken = jws.readJsonContent(PasswordToken.class);
+            if (!passwordToken.getRealm().equals(realm.getName())) {
+                return false;
+            }
+            if (!passwordToken.getUser().equals(user.getId())) {
+                return false;
+            }
+            if (Time.currentTime() - passwordToken.getTimestamp() > realm.getAccessCodeLifespanUserAction()) {
+                return false;
+            }
+            return true;
+        } catch (JWSInputException e) {
+            return false;
+        }
+    }
+
+    public static boolean validHOTP(KeycloakSession session, RealmModel realm, UserModel user, String otp, List<UserCredentialValueModel> fedCreds) {
+        UserCredentialValueModel passwordCred = null;
+        OTPPolicy policy = realm.getOTPPolicy();
+        HmacOTP validator = new HmacOTP(policy.getDigits(), policy.getAlgorithm(), policy.getLookAheadWindow());
+        for (UserCredentialValueModel cred : fedCreds) {
+            if (cred.getType().equals(UserCredentialModel.HOTP)) {
+                int counter = validator.validateHOTP(otp, cred.getValue(), cred.getCounter());
+                if (counter < 0) return false;
+                cred.setCounter(counter);
+                session.userFederatedStorage().updateCredential(realm, user, cred);
+                return true;
+            }
+        }
+        return false;
+
+    }
+
+    public static boolean validTOTP(RealmModel realm, UserModel user, String otp, List<UserCredentialValueModel> fedCreds) {
+        UserCredentialValueModel passwordCred = null;
+        OTPPolicy policy = realm.getOTPPolicy();
+        TimeBasedOTP validator = new TimeBasedOTP(policy.getAlgorithm(), policy.getDigits(), policy.getPeriod(), policy.getLookAheadWindow());
+        for (UserCredentialValueModel cred : fedCreds) {
+            if (validator.validateTOTP(otp, cred.getValue().getBytes())) {
+                return true;
+            }
+        }
+        return false;
+
+    }
+    public static boolean validSecret(RealmModel realm, UserModel user, String secret, UserCredentialValueModel cred) {
+        return cred.getValue().equals(secret);
+
+    }
+
+    public static boolean validCredential(KeycloakSession session, RealmModel realm, UserModel user, UserCredentialModel credential, List<UserCredentialValueModel> fedCreds) {
+        if (credential.getType().equals(UserCredentialModel.PASSWORD)) {
+            if (!validPassword(session, realm, user, credential.getValue(), fedCreds.get(0))) {
+                return false;
+            }
+        } else if (credential.getType().equals(UserCredentialModel.PASSWORD_TOKEN)) {
+            if (!validPasswordToken(realm, user, credential.getValue())) {
+                return false;
+            }
+        } else if (credential.getType().equals(UserCredentialModel.TOTP)) {
+            if (!validTOTP(realm, user, credential.getValue(), fedCreds)) {
+                return false;
+            }
+        } else if (credential.getType().equals(UserCredentialModel.HOTP)) {
+            if (!validHOTP(session, realm, user, credential.getValue(), fedCreds)) {
+                return false;
+            }
+        } else if (credential.getType().equals(UserCredentialModel.SECRET)) {
+            if (!validSecret(realm, user, credential.getValue(), fedCreds.get(0))) {
+                return false;
+            }
+        } else {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java b/server-spi/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java
index e0dc211..bc20d49 100755
--- a/server-spi/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java
+++ b/server-spi/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java
@@ -281,7 +281,7 @@ public final class KeycloakModelUtils {
      */
     public static void runJobInTransaction(KeycloakSessionFactory factory, KeycloakSessionTask task) {
         KeycloakSession session = factory.create();
-        KeycloakTransaction tx = session.getTransaction();
+        KeycloakTransaction tx = session.getTransactionManager();
         try {
             tx.begin();
             task.run(session);
@@ -378,7 +378,6 @@ public final class KeycloakModelUtils {
         return null;
     }
 
-
     public static UserFederationProviderModel findUserFederationProviderById(String fedProviderId, RealmModel realm) {
         for (UserFederationProviderModel fedProvider : realm.getUserFederationProviders()) {
             if (fedProviderId.equals(fedProvider.getId())) {
@@ -642,5 +641,14 @@ public final class KeycloakModelUtils {
         return null;
     }
 
-
+    public static void setupAuthorizationServices(RealmModel realm) {
+        for (String roleName : Constants.AUTHZ_DEFAULT_AUTHORIZATION_ROLES) {
+            if (realm.getRole(roleName) == null) {
+                RoleModel role = realm.addRole(roleName);
+                role.setDescription("${role_" + roleName + "}");
+                role.setScopeParamRequired(false);
+                realm.addDefaultRole(roleName);
+            }
+        }
+    }
 }
diff --git a/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java b/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
index 7f7f7e0..e2d4799 100755
--- a/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
+++ b/server-spi/src/main/java/org/keycloak/models/utils/ModelToRepresentation.java
@@ -17,6 +17,15 @@
 
 package org.keycloak.models.utils;
 
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.authorization.store.ResourceStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.component.ComponentModel;
 import org.keycloak.events.Event;
 import org.keycloak.events.admin.AdminEvent;
 import org.keycloak.events.admin.AuthDetails;
@@ -30,6 +39,7 @@ import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.GroupModel;
 import org.keycloak.models.IdentityProviderMapperModel;
 import org.keycloak.models.IdentityProviderModel;
+import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ModelException;
 import org.keycloak.models.OTPPolicy;
 import org.keycloak.models.ProtocolMapperModel;
@@ -44,6 +54,7 @@ import org.keycloak.models.UserFederationProviderModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 
+import org.keycloak.provider.ProviderConfigProperty;
 import org.keycloak.representations.idm.AdminEventRepresentation;
 import org.keycloak.representations.idm.AuthDetailsRepresentation;
 import org.keycloak.representations.idm.AuthenticationExecutionExportRepresentation;
@@ -51,6 +62,8 @@ import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
 import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.ClientTemplateRepresentation;
+import org.keycloak.representations.idm.ComponentRepresentation;
+import org.keycloak.representations.idm.ConfigPropertyRepresentation;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.representations.idm.EventRepresentation;
 import org.keycloak.representations.idm.FederatedIdentityRepresentation;
@@ -68,8 +81,25 @@ import org.keycloak.representations.idm.UserFederationProviderRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.representations.idm.UserSessionRepresentation;
 import org.keycloak.common.util.Time;
-
-import java.util.*;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+import org.keycloak.util.JsonSerialization;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -195,6 +225,9 @@ public class ModelToRepresentation {
             rep.setAuthDetails(toRepresentation(adminEvent.getAuthDetails()));
         }
         rep.setOperationType(adminEvent.getOperationType().toString());
+        if (adminEvent.getResourceType() != null) {
+            rep.setResourceType(adminEvent.getResourceType().toString());
+        }
         rep.setResourcePath(adminEvent.getResourcePath());
         rep.setRepresentation(adminEvent.getRepresentation());
         rep.setError(adminEvent.getError());
@@ -218,6 +251,8 @@ public class ModelToRepresentation {
         rep.setDescription(role.getDescription());
         rep.setScopeParamRequired(role.isScopeParamRequired());
         rep.setComposite(role.isComposite());
+        rep.setClientRole(role.isClientRole());
+        rep.setContainerId(role.getContainerId());
         return rep;
     }
 
@@ -563,7 +598,7 @@ public class ModelToRepresentation {
         return rep;
     }
 
-    public static UserFederationMapperRepresentation toRepresentation(RealmModel realm, UserFederationMapperModel model) {
+     public static UserFederationMapperRepresentation toRepresentation(RealmModel realm, UserFederationMapperModel model) {
         UserFederationMapperRepresentation rep = new UserFederationMapperRepresentation();
         rep.setId(model.getId());
         rep.setName(model.getName());
@@ -734,4 +769,205 @@ public class ModelToRepresentation {
         return rep;
     }
 
+    public static List<ConfigPropertyRepresentation> toRepresentation(List<ProviderConfigProperty> configProperties) {
+        List<ConfigPropertyRepresentation> propertiesRep = new LinkedList<>();
+        for (ProviderConfigProperty prop : configProperties) {
+            ConfigPropertyRepresentation propRep = new ConfigPropertyRepresentation();
+            propRep.setName(prop.getName());
+            propRep.setLabel(prop.getLabel());
+            propRep.setType(prop.getType());
+            propRep.setDefaultValue(prop.getDefaultValue());
+            propRep.setHelpText(prop.getHelpText());
+            propertiesRep.add(propRep);
+        }
+        return propertiesRep;
+    }
+
+    public static ComponentRepresentation toRepresentation(ComponentModel component) {
+        ComponentRepresentation rep = new ComponentRepresentation();
+        rep.setId(component.getId());
+        rep.setName(component.getName());
+        rep.setProviderId(component.getProviderId());
+        rep.setProviderType(component.getProviderType());
+        rep.setParentId(component.getParentId());
+        rep.setConfig(component.getConfig());
+        return rep;
+    }
+
+    public static ScopeRepresentation toRepresentation(Scope model, AuthorizationProvider authorizationProvider) {
+        ScopeRepresentation scope = new ScopeRepresentation();
+
+        scope.setId(model.getId());
+        scope.setName(model.getName());
+        scope.setIconUri(model.getIconUri());
+
+        StoreFactory storeFactory = authorizationProvider.getStoreFactory();
+
+        scope.setResources(new ArrayList<>());
+
+        storeFactory.getResourceStore().findByScope(model.getId()).forEach(resource -> scope.getResources().add(toRepresentation(resource, resource.getResourceServer(), authorizationProvider)));
+
+        PolicyStore policyStore = storeFactory.getPolicyStore();
+
+        scope.setPolicies(new ArrayList<>());
+
+        policyStore.findByScopeIds(Arrays.asList(model.getId()), model.getResourceServer().getId()).forEach(policyModel -> {
+            PolicyRepresentation policy = new PolicyRepresentation();
+
+            policy.setId(policyModel.getId());
+            policy.setName(policyModel.getName());
+            policy.setType(policyModel.getType());
+
+            if (!scope.getPolicies().contains(policy)) {
+                scope.getPolicies().add(policy);
+            }
+        });
+
+        return scope;
+    }
+
+    public static ResourceServerRepresentation toRepresentation(ResourceServer model, ClientModel client) {
+        ResourceServerRepresentation server = new ResourceServerRepresentation();
+
+        server.setId(model.getId());
+        server.setClientId(model.getClientId());
+        server.setName(client.getClientId());
+        server.setAllowRemoteResourceManagement(model.isAllowRemoteResourceManagement());
+        server.setPolicyEnforcementMode(model.getPolicyEnforcementMode());
+
+        return server;
+    }
+
+    public static PolicyRepresentation toRepresentation(Policy model, AuthorizationProvider authorization) {
+        PolicyRepresentation representation = new PolicyRepresentation();
+
+        representation.setId(model.getId());
+        representation.setName(model.getName());
+        representation.setDescription(model.getDescription());
+        representation.setType(model.getType());
+        representation.setDecisionStrategy(model.getDecisionStrategy());
+        representation.setLogic(model.getLogic());
+        representation.setConfig(new HashMap<>(model.getConfig()));
+
+        List<Policy> policies = authorization.getStoreFactory().getPolicyStore().findDependentPolicies(model.getId());
+
+        representation.setDependentPolicies(policies.stream().map(policy -> {
+            PolicyRepresentation representation1 = new PolicyRepresentation();
+
+            representation1.setId(policy.getId());
+            representation1.setName(policy.getName());
+
+            return representation1;
+        }).collect(Collectors.toList()));
+
+        List<PolicyRepresentation> associatedPolicies = new ArrayList<>();
+
+        List<String> obj = model.getAssociatedPolicies().stream().map(policy -> {
+            PolicyRepresentation representation1 = new PolicyRepresentation();
+
+            representation1.setId(policy.getId());
+            representation1.setName(policy.getName());
+            representation1.setType(policy.getType());
+
+            associatedPolicies.add(representation1);
+
+            return policy.getId();
+        }).collect(Collectors.toList());
+
+        representation.setAssociatedPolicies(associatedPolicies);
+
+        try {
+            representation.getConfig().put("applyPolicies", JsonSerialization.writeValueAsString(obj));
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        return representation;
+    }
+
+    public static ResourceRepresentation toRepresentation(Resource model, ResourceServer resourceServer, AuthorizationProvider authorization) {
+        ResourceRepresentation resource = new ResourceRepresentation();
+
+        resource.setId(model.getId());
+        resource.setType(model.getType());
+        resource.setName(model.getName());
+        resource.setUri(model.getUri());
+        resource.setIconUri(model.getIconUri());
+
+        ResourceOwnerRepresentation owner = new ResourceOwnerRepresentation();
+
+        owner.setId(model.getOwner());
+
+        KeycloakSession keycloakSession = authorization.getKeycloakSession();
+        RealmModel realm = authorization.getRealm();
+
+        if (owner.getId().equals(resourceServer.getClientId())) {
+            ClientModel clientModel = realm.getClientById(resourceServer.getClientId());
+            owner.setName(clientModel.getClientId());
+        } else {
+            UserModel userModel = keycloakSession.users().getUserById(owner.getId(), realm);
+
+            if (userModel == null) {
+                throw new RuntimeException("Could not find the user [" + owner.getId() + "] who owns the Resource [" + resource.getId() + "].");
+            }
+
+            owner.setName(userModel.getUsername());
+        }
+
+        resource.setOwner(owner);
+
+        resource.setScopes(model.getScopes().stream().map(model1 -> {
+            ScopeRepresentation scope = new ScopeRepresentation();
+            scope.setId(model1.getId());
+            scope.setName(model1.getName());
+            String iconUri = model1.getIconUri();
+            if (iconUri != null) {
+                scope.setIconUri(iconUri);
+            }
+            return scope;
+        }).collect(Collectors.toSet()));
+
+        resource.setTypedScopes(new ArrayList<>());
+
+        if (resource.getType() != null) {
+            ResourceStore resourceStore = authorization.getStoreFactory().getResourceStore();
+            for (Resource typed : resourceStore.findByType(resource.getType())) {
+                if (typed.getOwner().equals(resourceServer.getClientId()) && !typed.getId().equals(resource.getId())) {
+                    resource.setTypedScopes(typed.getScopes().stream().map(model1 -> {
+                        ScopeRepresentation scope = new ScopeRepresentation();
+                        scope.setId(model1.getId());
+                        scope.setName(model1.getName());
+                        String iconUri = model1.getIconUri();
+                        if (iconUri != null) {
+                            scope.setIconUri(iconUri);
+                        }
+                        return scope;
+                    }).filter(scopeRepresentation -> !resource.getScopes().contains(scopeRepresentation)).collect(Collectors.toList()));
+                }
+            }
+        }
+
+        resource.setPolicies(new ArrayList<>());
+
+        Set<Policy> policies = new HashSet<>();
+        PolicyStore policyStore = authorization.getStoreFactory().getPolicyStore();
+
+        policies.addAll(policyStore.findByResource(resource.getId()));
+        policies.addAll(policyStore.findByResourceType(resource.getType(), resourceServer.getId()));
+        policies.addAll(policyStore.findByScopeIds(resource.getScopes().stream().map(scope -> scope.getId()).collect(Collectors.toList()), resourceServer.getId()));
+
+        for (Policy policyModel : policies) {
+            PolicyRepresentation policy = new PolicyRepresentation();
+
+            policy.setId(policyModel.getId());
+            policy.setName(policyModel.getName());
+            policy.setType(policyModel.getType());
+
+            if (!resource.getPolicies().contains(policy)) {
+                resource.getPolicies().add(policy);
+            }
+        }
+
+        return resource;
+    }
 }
diff --git a/server-spi/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/server-spi/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index 24e3ac8..f36f010 100755
--- a/server-spi/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/server-spi/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -17,7 +17,21 @@
 
 package org.keycloak.models.utils;
 
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.AuthorizationProviderFactory;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.authorization.store.ResourceServerStore;
+import org.keycloak.authorization.store.ResourceStore;
+import org.keycloak.authorization.store.ScopeStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.component.ComponentModel;
 import org.keycloak.hash.Pbkdf2PasswordHashProvider;
+import org.keycloak.migration.migrators.MigrationUtils;
 import org.keycloak.models.ClientTemplateModel;
 import org.keycloak.models.Constants;
 import org.keycloak.common.util.Base64;
@@ -58,6 +72,8 @@ import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
 import org.keycloak.representations.idm.ClaimRepresentation;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.ClientTemplateRepresentation;
+import org.keycloak.representations.idm.ComponentExportRepresentation;
+import org.keycloak.representations.idm.ComponentRepresentation;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.representations.idm.FederatedIdentityRepresentation;
 import org.keycloak.representations.idm.GroupRepresentation;
@@ -75,18 +91,26 @@ import org.keycloak.representations.idm.UserConsentRepresentation;
 import org.keycloak.representations.idm.UserFederationMapperRepresentation;
 import org.keycloak.representations.idm.UserFederationProviderRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.representations.idm.authorization.PolicyEnforcementMode;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+import org.keycloak.util.JsonSerialization;
 
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 public class RepresentationToModel {
 
@@ -191,7 +215,7 @@ public class RepresentationToModel {
             newRealm.addRequiredCredential(CredentialRepresentation.PASSWORD);
         }
 
-        if (rep.getPasswordPolicy() != null) newRealm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy()));
+        if (rep.getPasswordPolicy() != null) newRealm.setPasswordPolicy(PasswordPolicy.parse(session, rep.getPasswordPolicy()));
         if (rep.getOtpPolicyType() != null) newRealm.setOTPPolicy(toPolicy(rep));
         else newRealm.setOTPPolicy(OTPPolicy.DEFAULT_POLICY);
 
@@ -199,6 +223,9 @@ public class RepresentationToModel {
         if (rep.getRequiredActions() != null) {
             for (RequiredActionProviderRepresentation action : rep.getRequiredActions()) {
                 RequiredActionProviderModel model = toModel(action);
+
+                MigrationUtils.updateOTPRequiredAction(model);
+
                 newRealm.addRequiredActionProvider(model);
             }
         } else {
@@ -264,6 +291,13 @@ public class RepresentationToModel {
             }
         }
 
+        if (rep.getClients() != null) {
+            rep.getClients().forEach(clientRepresentation -> {
+                ClientModel client = newRealm.getClientByClientId(clientRepresentation.getClientId());
+                importAuthorizationSettings(clientRepresentation, client, session);
+            });
+        }
+
         if (rep.getSmtpServer() != null) {
             newRealm.setSmtpConfig(new HashMap(rep.getSmtpServer()));
         }
@@ -274,6 +308,12 @@ public class RepresentationToModel {
             newRealm.setBrowserSecurityHeaders(BrowserSecurityHeaders.defaultHeaders);
         }
 
+        if (rep.getComponents() != null) {
+            MultivaluedHashMap<String, ComponentExportRepresentation> components = rep.getComponents();
+            String parentId = newRealm.getId();
+            importComponents(newRealm, components, parentId);
+        }
+
         List<UserFederationProviderModel> providerModels = null;
         if (rep.getUserFederationProviders() != null) {
             providerModels = convertFederationProviders(rep.getUserFederationProviders());
@@ -335,6 +375,25 @@ public class RepresentationToModel {
         }
     }
 
+    protected static void importComponents(RealmModel newRealm, MultivaluedHashMap<String, ComponentExportRepresentation> components, String parentId) {
+        for (Map.Entry<String, List<ComponentExportRepresentation>> entry : components.entrySet()) {
+            String providerType = entry.getKey();
+            for (ComponentExportRepresentation compRep : entry.getValue()) {
+                ComponentModel component = new ComponentModel();
+                component.setId(compRep.getId());
+                component.setName(compRep.getName());
+                component.setConfig(compRep.getConfig());
+                component.setProviderType(providerType);
+                component.setProviderId(compRep.getProviderId());
+                component.setParentId(parentId);
+                component = newRealm.addComponentModel(component);
+                if (compRep.getSubComponents() != null) {
+                    importComponents(newRealm, compRep.getSubComponents(), component.getId());
+                }
+            }
+        }
+    }
+
     public static void importRoles(RolesRepresentation realmRoles, RealmModel realm) {
         if (realmRoles == null) return;
 
@@ -656,7 +715,7 @@ public class RepresentationToModel {
         return url != null ? url.replace(target, replacement) : null;
     }
 
-    public static void updateRealm(RealmRepresentation rep, RealmModel realm) {
+    public static void updateRealm(RealmRepresentation rep, RealmModel realm, KeycloakSession session) {
         if (rep.getRealm() != null) {
             renameRealm(realm, rep.getRealm());
         }
@@ -704,7 +763,7 @@ public class RepresentationToModel {
         if (rep.isAdminEventsDetailsEnabled() != null) realm.setAdminEventsDetailsEnabled(rep.isAdminEventsDetailsEnabled());
 
 
-        if (rep.getPasswordPolicy() != null) realm.setPasswordPolicy(new PasswordPolicy(rep.getPasswordPolicy()));
+        if (rep.getPasswordPolicy() != null) realm.setPasswordPolicy(PasswordPolicy.parse(session, rep.getPasswordPolicy()));
         if (rep.getOtpPolicyType() != null) realm.setOTPPolicy(toPolicy(rep));
 
         if (rep.getDefaultRoles() != null) {
@@ -984,7 +1043,6 @@ public class RepresentationToModel {
         if (resourceRep.isUseTemplateMappers() != null) client.setUseTemplateMappers(resourceRep.isUseTemplateMappers());
         else client.setUseTemplateMappers(resourceRep.getClientTemplate() != null);
 
-
         return client;
     }
 
@@ -1279,7 +1337,7 @@ public class RepresentationToModel {
         if (userRep.getClientConsents() != null) {
             for (UserConsentRepresentation consentRep : userRep.getClientConsents()) {
                 UserConsentModel consentModel = toModel(newRealm, consentRep);
-                user.addConsent(consentModel);
+                session.userStorage().addConsent(newRealm, user, consentModel);
             }
         }
         if (userRep.getServiceAccountClientId() != null) {
@@ -1594,4 +1652,441 @@ public class RepresentationToModel {
     }
 
 
+    public static ComponentModel toModel(ComponentRepresentation rep) {
+        ComponentModel model = new ComponentModel();
+        model.setParentId(rep.getParentId());
+        model.setProviderType(rep.getProviderType());
+        model.setProviderId(rep.getProviderId());
+        model.setConfig(rep.getConfig());
+        model.setName(rep.getName());
+        return model;
+    }
+
+    public static void importAuthorizationSettings(ClientRepresentation clientRepresentation, ClientModel client, KeycloakSession session) {
+        if (Boolean.TRUE.equals(clientRepresentation.getAuthorizationServicesEnabled())) {
+            AuthorizationProviderFactory authorizationFactory = (AuthorizationProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(AuthorizationProvider.class);
+            AuthorizationProvider authorization = authorizationFactory.create(session, client.getRealm());
+
+            client.setServiceAccountsEnabled(true);
+            client.setBearerOnly(false);
+            client.setPublicClient(false);
+
+            ResourceServerRepresentation rep = clientRepresentation.getAuthorizationSettings();
+
+            if (rep == null) {
+                rep = new ResourceServerRepresentation();
+            }
+
+            rep.setClientId(client.getId());
+
+            toModel(rep, authorization);
+        }
+    }
+
+    public static void toModel(ResourceServerRepresentation rep, AuthorizationProvider authorization) {
+        ResourceServerStore resourceServerStore = authorization.getStoreFactory().getResourceServerStore();
+        ResourceServer resourceServer;
+        ResourceServer existing = resourceServerStore.findByClient(rep.getClientId());
+
+        if (existing == null) {
+            resourceServer = resourceServerStore.create(rep.getClientId());
+            resourceServer.setAllowRemoteResourceManagement(true);
+            resourceServer.setPolicyEnforcementMode(PolicyEnforcementMode.ENFORCING);
+        } else {
+            resourceServer = existing;
+        }
+
+        resourceServer.setPolicyEnforcementMode(rep.getPolicyEnforcementMode());
+        resourceServer.setAllowRemoteResourceManagement(rep.isAllowRemoteResourceManagement());
+
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        ScopeStore scopeStore = storeFactory.getScopeStore();
+
+        rep.getScopes().forEach(scope -> {
+            toModel(scope, resourceServer, authorization);
+        });
+
+        KeycloakSession session = authorization.getKeycloakSession();
+        RealmModel realm = authorization.getRealm();
+
+        rep.getResources().forEach(resourceRepresentation -> {
+            ResourceOwnerRepresentation owner = resourceRepresentation.getOwner();
+
+            if (owner == null) {
+                owner = new ResourceOwnerRepresentation();
+                resourceRepresentation.setOwner(owner);
+            }
+
+            owner.setId(resourceServer.getClientId());
+
+            if (owner.getName() != null) {
+                UserModel user = session.users().getUserByUsername(owner.getName(), realm);
+
+                if (user != null) {
+                    owner.setId(user.getId());
+                }
+            }
+
+            toModel(resourceRepresentation, resourceServer, authorization);
+        });
+
+        rep.getPolicies().forEach(policyRepresentation -> {
+            Map<String, String> config = policyRepresentation.getConfig();
+
+            String roles = config.get("roles");
+
+            if (roles != null && !roles.isEmpty()) {
+                try {
+                    List<Map> rolesMap = JsonSerialization.readValue(roles, List.class);
+                    config.put("roles", JsonSerialization.writeValueAsString(rolesMap.stream().map(roleConfig -> {
+                        String roleName = roleConfig.get("id").toString();
+                        String clientId = null;
+                        int clientIdSeparator = roleName.indexOf("/");
+
+                        if (clientIdSeparator != -1) {
+                            clientId = roleName.substring(0, clientIdSeparator);
+                            roleName = roleName.substring(clientIdSeparator + 1);
+                        }
+
+                        RoleModel role;
+
+                        if (clientId == null) {
+                            role = realm.getRole(roleName);
+                        } else {
+                            role = realm.getClientByClientId(clientId).getRole(roleName);
+                        }
+
+                        // fallback to find any client role with the given name
+                        if (role == null) {
+                            String finalRoleName = roleName;
+                            role = realm.getClients().stream().map(clientModel -> clientModel.getRole(finalRoleName)).filter(roleModel -> roleModel != null)
+                                    .findFirst().orElse(null);
+                        }
+
+                        if (role == null) {
+                            throw new RuntimeException("Error while importing configuration. Role [" + roleName + "] could not be found.");
+                        }
+
+                        roleConfig.put("id", role.getId());
+                        return roleConfig;
+                    }).collect(Collectors.toList())));
+                } catch (Exception e) {
+                    throw new RuntimeException("Error while exporting policy [" + policyRepresentation.getName() + "].", e);
+                }
+            }
+
+            String users = config.get("users");
+
+            if (users != null && !users.isEmpty()) {
+                try {
+                    List<String> usersMap = JsonSerialization.readValue(users, List.class);
+                    config.put("users", JsonSerialization.writeValueAsString(usersMap.stream().map(userName -> session.users().getUserByUsername(userName, realm).getId()).collect(Collectors.toList())));
+                } catch (Exception e) {
+                    throw new RuntimeException("Error while exporting policy [" + policyRepresentation.getName() + "].", e);
+                }
+            }
+
+            String scopes = config.get("scopes");
+
+            if (scopes != null && !scopes.isEmpty()) {
+                try {
+                    List<String> scopesMap = JsonSerialization.readValue(scopes, List.class);
+                    config.put("scopes", JsonSerialization.writeValueAsString(scopesMap.stream().map(scopeName -> {
+                        Scope newScope = scopeStore.findByName(scopeName, resourceServer.getId());
+
+                        if (newScope == null) {
+                            throw new RuntimeException("Scope with name [" + scopeName + "] not defined.");
+                        }
+
+                        return newScope.getId();
+                    }).collect(Collectors.toList())));
+                } catch (Exception e) {
+                    throw new RuntimeException("Error while exporting policy [" + policyRepresentation.getName() + "].", e);
+                }
+            }
+
+            String policyResources = config.get("resources");
+
+            if (policyResources != null && !policyResources.isEmpty()) {
+                ResourceStore resourceStore = storeFactory.getResourceStore();
+                try {
+                    List<String> resources = JsonSerialization.readValue(policyResources, List.class);
+                    config.put("resources", JsonSerialization.writeValueAsString(resources.stream().map(resourceName -> {
+                        return resourceStore.findByName(resourceName, resourceServer.getId()).getId();
+                    }).collect(Collectors.toList())));
+                } catch (Exception e) {
+                    throw new RuntimeException("Error while exporting policy [" + policyRepresentation.getName() + "].", e);
+                }
+            }
+
+            String applyPolicies = config.get("applyPolicies");
+
+            if (applyPolicies != null && !applyPolicies.isEmpty()) {
+                PolicyStore policyStore = storeFactory.getPolicyStore();
+                try {
+                    List<String> policies = JsonSerialization.readValue(applyPolicies, List.class);
+                    config.put("applyPolicies", JsonSerialization.writeValueAsString(policies.stream().map(policyName -> {
+                        Policy policy = policyStore.findByName(policyName, resourceServer.getId());
+
+                        if (policy == null) {
+                            throw new RuntimeException("Policy with name [" + policyName + "] not defined.");
+                        }
+
+                        return policy.getId();
+                    }).collect(Collectors.toList())));
+                } catch (Exception e) {
+                    throw new RuntimeException("Error while exporting policy [" + policyRepresentation.getName() + "].", e);
+                }
+            }
+
+            toModel(policyRepresentation, resourceServer, authorization);
+        });
+    }
+
+    public static Policy toModel(PolicyRepresentation policy, ResourceServer resourceServer, AuthorizationProvider authorization) {
+        PolicyStore policyStore = authorization.getStoreFactory().getPolicyStore();
+        Policy existing;
+
+        if (policy.getId() != null) {
+            existing = policyStore.findById(policy.getId());
+        } else {
+            existing = policyStore.findByName(policy.getName(), resourceServer.getId());
+        }
+
+        if (existing != null) {
+            existing.setName(policy.getName());
+            existing.setDescription(policy.getDescription());
+            existing.setConfig(policy.getConfig());
+            existing.setDecisionStrategy(policy.getDecisionStrategy());
+            existing.setLogic(policy.getLogic());
+
+            updateResources(existing, authorization);
+            updateAssociatedPolicies(existing, resourceServer, authorization);
+            updateScopes(existing, authorization);
+
+            return existing;
+        }
+
+        Policy model = policyStore.create(policy.getName(), policy.getType(), resourceServer);
+
+        model.setDescription(policy.getDescription());
+        model.setDecisionStrategy(policy.getDecisionStrategy());
+        model.setLogic(policy.getLogic());
+        model.setConfig(policy.getConfig());
+
+        updateResources(model, authorization);
+        updateAssociatedPolicies(model, resourceServer, authorization);
+        updateScopes(model, authorization);
+
+        policy.setId(model.getId());
+
+        return model;
+    }
+
+    private static void updateScopes(Policy policy, AuthorizationProvider authorization) {
+        String scopes = policy.getConfig().get("scopes");
+        if (scopes != null) {
+            String[] scopeIds;
+
+            try {
+                scopeIds = JsonSerialization.readValue(scopes, String[].class);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+
+            StoreFactory storeFactory = authorization.getStoreFactory();
+
+            for (String scopeId : scopeIds) {
+                boolean hasScope = false;
+
+                for (Scope scopeModel : new HashSet<Scope>(policy.getScopes())) {
+                    if (scopeModel.getId().equals(scopeId)) {
+                        hasScope = true;
+                    }
+                }
+                if (!hasScope) {
+                    policy.addScope(storeFactory.getScopeStore().findById(scopeId));
+                }
+            }
+
+            for (Scope scopeModel : new HashSet<Scope>(policy.getScopes())) {
+                boolean hasScope = false;
+
+                for (String scopeId : scopeIds) {
+                    if (scopeModel.getId().equals(scopeId)) {
+                        hasScope = true;
+                    }
+                }
+                if (!hasScope) {
+                    policy.removeScope(scopeModel);
+                }
+            }
+        }
+    }
+
+    private static void updateAssociatedPolicies(Policy policy, ResourceServer resourceServer, AuthorizationProvider authorization) {
+        String policies = policy.getConfig().get("applyPolicies");
+
+        if (policies != null) {
+            String[] policyIds;
+
+            try {
+                policyIds = JsonSerialization.readValue(policies, String[].class);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+
+            StoreFactory storeFactory = authorization.getStoreFactory();
+            PolicyStore policyStore = storeFactory.getPolicyStore();
+
+            for (String policyId : policyIds) {
+                boolean hasPolicy = false;
+
+                for (Policy policyModel : new HashSet<Policy>(policy.getAssociatedPolicies())) {
+                    if (policyModel.getId().equals(policyId) || policyModel.getName().equals(policyId)) {
+                        hasPolicy = true;
+                    }
+                }
+
+
+                if (!hasPolicy) {
+                    Policy associatedPolicy = policyStore.findById(policyId);
+
+                    if (associatedPolicy == null) {
+                        associatedPolicy = policyStore.findByName(policyId, resourceServer.getId());
+                    }
+
+                    policy.addAssociatedPolicy(associatedPolicy);
+                }
+            }
+
+            for (Policy policyModel : new HashSet<Policy>(policy.getAssociatedPolicies())) {
+                boolean hasPolicy = false;
+
+                for (String policyId : policyIds) {
+                    if (policyModel.getId().equals(policyId) || policyModel.getName().equals(policyId)) {
+                        hasPolicy = true;
+                    }
+                }
+                if (!hasPolicy) {
+                    policy.removeAssociatedPolicy(policyModel);;
+                }
+            }
+        }
+    }
+
+    private static void updateResources(Policy policy, AuthorizationProvider authorization) {
+        String resources = policy.getConfig().get("resources");
+        if (resources != null) {
+            String[] resourceIds;
+
+            try {
+                resourceIds = JsonSerialization.readValue(resources, String[].class);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+
+            StoreFactory storeFactory = authorization.getStoreFactory();
+
+            for (String resourceId : resourceIds) {
+                boolean hasResource = false;
+                for (Resource resourceModel : new HashSet<Resource>(policy.getResources())) {
+                    if (resourceModel.getId().equals(resourceId)) {
+                        hasResource = true;
+                    }
+                }
+                if (!hasResource && !"".equals(resourceId)) {
+                    policy.addResource(storeFactory.getResourceStore().findById(resourceId));
+                }
+            }
+
+            for (Resource resourceModel : new HashSet<Resource>(policy.getResources())) {
+                boolean hasResource = false;
+
+                for (String resourceId : resourceIds) {
+                    if (resourceModel.getId().equals(resourceId)) {
+                        hasResource = true;
+                    }
+                }
+
+                if (!hasResource) {
+                    policy.removeResource(resourceModel);
+                }
+            }
+        }
+    }
+
+    public static Resource toModel(ResourceRepresentation resource, ResourceServer resourceServer, AuthorizationProvider authorization) {
+        ResourceStore resourceStore = authorization.getStoreFactory().getResourceStore();
+        Resource existing;
+
+        if (resource.getId() != null) {
+            existing = resourceStore.findById(resource.getId());
+        } else {
+            existing = resourceStore.findByName(resource.getName(), resourceServer.getId());
+        }
+
+        if (existing != null) {
+            existing.setName(resource.getName());
+            existing.setType(resource.getType());
+            existing.setUri(resource.getUri());
+            existing.setIconUri(resource.getIconUri());
+
+            existing.updateScopes(resource.getScopes().stream()
+                    .map((ScopeRepresentation scope) -> toModel(scope,  resourceServer, authorization))
+                    .collect(Collectors.toSet()));
+            return existing;
+        }
+
+        ResourceOwnerRepresentation owner = resource.getOwner();
+
+        if (owner == null) {
+            owner = new ResourceOwnerRepresentation();
+            owner.setId(resourceServer.getClientId());
+        }
+
+        if (owner.getId() == null) {
+            throw new RuntimeException("No owner specified for resource [" + resource.getName() + "].");
+        }
+
+        Resource model = resourceStore.create(resource.getName(), resourceServer, owner.getId());
+
+        model.setType(resource.getType());
+        model.setUri(resource.getUri());
+        model.setIconUri(resource.getIconUri());
+
+        Set<ScopeRepresentation> scopes = resource.getScopes();
+
+        if (scopes != null) {
+            model.updateScopes(scopes.stream().map((Function<ScopeRepresentation, Scope>) scope -> toModel(scope, resourceServer, authorization)).collect(Collectors.toSet()));
+        }
+
+        resource.setId(model.getId());
+
+        return model;
+    }
+
+    public static Scope toModel(ScopeRepresentation scope, ResourceServer resourceServer, AuthorizationProvider authorization) {
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        ScopeStore scopeStore = storeFactory.getScopeStore();
+        Scope existing;
+
+        if (scope.getId() != null) {
+            existing = scopeStore.findById(scope.getId());
+        } else {
+            existing = scopeStore.findByName(scope.getName(), resourceServer.getId());
+        }
+
+        if (existing != null) {
+            existing.setName(scope.getName());
+            existing.setIconUri(scope.getIconUri());
+            return existing;
+        }
+
+        Scope model = scopeStore.create(scope.getName(), resourceServer);
+        model.setIconUri(scope.getIconUri());
+        scope.setId(model.getId());
+
+        return model;
+    }
 }
diff --git a/server-spi/src/main/java/org/keycloak/models/utils/UserModelDelegate.java b/server-spi/src/main/java/org/keycloak/models/utils/UserModelDelegate.java
index f2d66e2..9a8e4ab 100755
--- a/server-spi/src/main/java/org/keycloak/models/utils/UserModelDelegate.java
+++ b/server-spi/src/main/java/org/keycloak/models/utils/UserModelDelegate.java
@@ -235,31 +235,6 @@ public class UserModelDelegate implements UserModel {
         delegate.setServiceAccountClientLink(clientInternalId);
     }
 
-    @Override
-    public void addConsent(UserConsentModel consent) {
-        delegate.addConsent(consent);
-    }
-
-    @Override
-    public UserConsentModel getConsentByClient(String clientId) {
-        return delegate.getConsentByClient(clientId);
-    }
-
-    @Override
-    public List<UserConsentModel> getConsents() {
-        return delegate.getConsents();
-    }
-
-    @Override
-    public void updateConsent(UserConsentModel consent) {
-        delegate.updateConsent(consent);
-    }
-
-    @Override
-    public boolean revokeConsentForClient(String clientId) {
-        return delegate.revokeConsentForClient(clientId);
-    }
-
     public UserModel getDelegate() {
         return delegate;
     }
diff --git a/server-spi/src/main/java/org/keycloak/policy/DefaultPasswordPolicyManagerProvider.java b/server-spi/src/main/java/org/keycloak/policy/DefaultPasswordPolicyManagerProvider.java
new file mode 100644
index 0000000..c380f80
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/DefaultPasswordPolicyManagerProvider.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.PasswordPolicy;
+import org.keycloak.models.UserModel;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class DefaultPasswordPolicyManagerProvider implements PasswordPolicyManagerProvider {
+
+    private KeycloakSession session;
+
+    public DefaultPasswordPolicyManagerProvider(KeycloakSession session) {
+        this.session = session;
+    }
+
+    @Override
+    public PolicyError validate(UserModel user, String password) {
+        for (PasswordPolicyProvider p : getProviders(session)) {
+            PolicyError policyError = p.validate(user, password);
+            if (policyError != null) {
+                return policyError;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public PolicyError validate(String user, String password) {
+        for (PasswordPolicyProvider p : getProviders(session)) {
+            PolicyError policyError = p.validate(user, password);
+            if (policyError != null) {
+                return policyError;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public void close() {
+    }
+
+    private List<PasswordPolicyProvider> getProviders(KeycloakSession session) {
+        LinkedList<PasswordPolicyProvider> list = new LinkedList<>();
+        PasswordPolicy policy = session.getContext().getRealm().getPasswordPolicy();
+        for (String id : policy.getPolicies()) {
+            PasswordPolicyProvider provider = session.getProvider(PasswordPolicyProvider.class, id);
+            list.add(provider);
+        }
+        return list;
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/DefaultPasswordPolicyManagerProviderFactory.java b/server-spi/src/main/java/org/keycloak/policy/DefaultPasswordPolicyManagerProviderFactory.java
new file mode 100644
index 0000000..b8aabd4
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/DefaultPasswordPolicyManagerProviderFactory.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class DefaultPasswordPolicyManagerProviderFactory implements PasswordPolicyManagerProviderFactory {
+
+    @Override
+    public PasswordPolicyManagerProvider create(KeycloakSession session) {
+        return new DefaultPasswordPolicyManagerProvider(session);
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public void close() {
+    }
+
+    @Override
+    public String getId() {
+        return "default";
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/DigitsPasswordPolicyProvider.java b/server-spi/src/main/java/org/keycloak/policy/DigitsPasswordPolicyProvider.java
new file mode 100644
index 0000000..d3ca22d
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/DigitsPasswordPolicyProvider.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.models.KeycloakContext;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class DigitsPasswordPolicyProvider implements PasswordPolicyProvider {
+
+    private static final String ERROR_MESSAGE = "invalidPasswordMinDigitsMessage";
+
+    private KeycloakContext context;
+
+    public DigitsPasswordPolicyProvider(KeycloakContext context) {
+        this.context = context;
+    }
+
+    @Override
+    public PolicyError validate(String username, String password) {
+        int min = context.getRealm().getPasswordPolicy().getPolicyConfig(DigitsPasswordPolicyProviderFactory.ID);
+        int count = 0;
+        for (char c : password.toCharArray()) {
+            if (Character.isDigit(c)) {
+                count++;
+            }
+        }
+        return count < min ? new PolicyError(ERROR_MESSAGE, min) : null;
+    }
+
+    @Override
+    public PolicyError validate(UserModel user, String password) {
+        return validate(user.getUsername(), password);
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        return value != null ? Integer.parseInt(value) : 1;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/DigitsPasswordPolicyProviderFactory.java b/server-spi/src/main/java/org/keycloak/policy/DigitsPasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..d7fce9c
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/DigitsPasswordPolicyProviderFactory.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class DigitsPasswordPolicyProviderFactory implements PasswordPolicyProviderFactory {
+
+    static final String ID = "digits";
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return new DigitsPasswordPolicyProvider(session.getContext());
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Digits";
+    }
+
+    @Override
+    public String getConfigType() {
+        return PasswordPolicyProvider.INT_CONFIG_TYPE;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return "1";
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return false;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/ForceExpiredPasswordPolicyProviderFactory.java b/server-spi/src/main/java/org/keycloak/policy/ForceExpiredPasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..ecefffb
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/ForceExpiredPasswordPolicyProviderFactory.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ForceExpiredPasswordPolicyProviderFactory implements PasswordPolicyProviderFactory, PasswordPolicyProvider {
+
+    public static final String ID = "forceExpiredPasswordChange";
+    public static final int DEFAULT_VALUE = 365;
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return this;
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public void close() {
+    }
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+    @Override
+    public PolicyError validate(UserModel user, String password) {
+        return null;
+    }
+
+    @Override
+    public PolicyError validate(String user, String password) {
+        return null;
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Expire Password";
+    }
+
+    @Override
+    public String getConfigType() {
+        return PasswordPolicyProvider.STRING_CONFIG_TYPE;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return String.valueOf(DEFAULT_VALUE);
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return false;
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        return value != null ? Integer.parseInt(value) : DEFAULT_VALUE;
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/HashAlgorithmPasswordPolicyProviderFactory.java b/server-spi/src/main/java/org/keycloak/policy/HashAlgorithmPasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..add3b03
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/HashAlgorithmPasswordPolicyProviderFactory.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class HashAlgorithmPasswordPolicyProviderFactory implements PasswordPolicyProviderFactory, PasswordPolicyProvider {
+
+    public static final String DEFAULT_VALUE = "pbkdf2";
+
+    public static final String ID = "hashAlgorithm";
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return this;
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public void close() {
+    }
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+    @Override
+    public PolicyError validate(UserModel user, String password) {
+        return null;
+    }
+
+    @Override
+    public PolicyError validate(String user, String password) {
+        return null;
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Hashing Algorithm";
+    }
+
+    @Override
+    public String getConfigType() {
+        return PasswordPolicyProvider.STRING_CONFIG_TYPE;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return DEFAULT_VALUE;
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return false;
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        return value != null ? value : DEFAULT_VALUE;
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/HashIterationsPasswordPolicyProviderFactory.java b/server-spi/src/main/java/org/keycloak/policy/HashIterationsPasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..64a77d5
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/HashIterationsPasswordPolicyProviderFactory.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class HashIterationsPasswordPolicyProviderFactory implements PasswordPolicyProvider, PasswordPolicyProviderFactory {
+
+    public static final int DEFAULT_VALUE = 20000;
+
+    public static final String ID = "hashIterations";
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return this;
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+    @Override
+    public PolicyError validate(UserModel user, String password) {
+        return null;
+    }
+
+    @Override
+    public PolicyError validate(String user, String password) {
+        return null;
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        return value != null ? Integer.parseInt(value) : DEFAULT_VALUE;
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Hashing Iterations";
+    }
+
+    @Override
+    public String getConfigType() {
+        return PasswordPolicyProvider.INT_CONFIG_TYPE;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return String.valueOf(DEFAULT_VALUE);
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return false;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/HistoryPasswordPolicyProvider.java b/server-spi/src/main/java/org/keycloak/policy/HistoryPasswordPolicyProvider.java
new file mode 100644
index 0000000..3cfe5fb
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/HistoryPasswordPolicyProvider.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.hash.PasswordHashManager;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.PasswordPolicy;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserCredentialValueModel;
+import org.keycloak.models.UserModel;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class HistoryPasswordPolicyProvider implements PasswordPolicyProvider {
+
+    private static final String ERROR_MESSAGE = "invalidPasswordHistoryMessage";
+
+    private KeycloakSession session;
+
+    public HistoryPasswordPolicyProvider(KeycloakSession session) {
+        this.session = session;
+    }
+
+    @Override
+    public PolicyError validate(String username, String password) {
+        return null;
+    }
+
+    @Override
+    public PolicyError validate(UserModel user, String password) {
+        PasswordPolicy policy = session.getContext().getRealm().getPasswordPolicy();
+        int passwordHistoryPolicyValue = policy.getPolicyConfig(HistoryPasswordPolicyProviderFactory.ID);
+        if (passwordHistoryPolicyValue != -1) {
+            UserCredentialValueModel cred = getCredentialValueModel(user, UserCredentialModel.PASSWORD);
+            if (cred != null) {
+                if(PasswordHashManager.verify(session, policy, password, cred)) {
+                    return new PolicyError(ERROR_MESSAGE, passwordHistoryPolicyValue);
+                }
+            }
+
+            List<UserCredentialValueModel> passwordExpiredCredentials = getCredentialValueModels(user, passwordHistoryPolicyValue - 1,
+                    UserCredentialModel.PASSWORD_HISTORY);
+            for (UserCredentialValueModel credential : passwordExpiredCredentials) {
+                if (PasswordHashManager.verify(session, policy, password, credential)) {
+                    return new PolicyError(ERROR_MESSAGE, passwordHistoryPolicyValue);
+                }
+            }
+        }
+        return null;
+    }
+
+    private UserCredentialValueModel getCredentialValueModel(UserModel user, String credType) {
+        for (UserCredentialValueModel model : user.getCredentialsDirectly()) {
+            if (model.getType().equals(credType)) {
+                return model;
+            }
+        }
+        return null;
+    }
+
+    private List<UserCredentialValueModel> getCredentialValueModels(UserModel user, int expiredPasswordsPolicyValue, String credType) {
+        List<UserCredentialValueModel> credentialModels = new ArrayList<UserCredentialValueModel>();
+        for (UserCredentialValueModel model : user.getCredentialsDirectly()) {
+            if (model.getType().equals(credType)) {
+                credentialModels.add(model);
+            }
+        }
+
+        Collections.sort(credentialModels, new Comparator<UserCredentialValueModel>() {
+            public int compare(UserCredentialValueModel credFirst, UserCredentialValueModel credSecond) {
+                if (credFirst.getCreatedDate() > credSecond.getCreatedDate()) {
+                    return -1;
+                } else if (credFirst.getCreatedDate() < credSecond.getCreatedDate()) {
+                    return 1;
+                } else {
+                    return 0;
+                }
+            }
+        });
+
+        if (credentialModels.size() > expiredPasswordsPolicyValue) {
+            return credentialModels.subList(0, expiredPasswordsPolicyValue);
+        }
+        return credentialModels;
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        return value != null ? Integer.parseInt(value) : HistoryPasswordPolicyProviderFactory.DEFAULT_VALUE;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/HistoryPasswordPolicyProviderFactory.java b/server-spi/src/main/java/org/keycloak/policy/HistoryPasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..c2c180a
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/HistoryPasswordPolicyProviderFactory.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class HistoryPasswordPolicyProviderFactory implements PasswordPolicyProviderFactory {
+
+    public static final String ID = "passwordHistory";
+    public static final Integer DEFAULT_VALUE = 3;
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return new HistoryPasswordPolicyProvider(session);
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Not Recently Used";
+    }
+
+    @Override
+    public String getConfigType() {
+        return PasswordPolicyProvider.INT_CONFIG_TYPE;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return String.valueOf(HistoryPasswordPolicyProviderFactory.DEFAULT_VALUE);
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return false;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/LengthPasswordPolicyProvider.java b/server-spi/src/main/java/org/keycloak/policy/LengthPasswordPolicyProvider.java
new file mode 100644
index 0000000..bdafdc9
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/LengthPasswordPolicyProvider.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.models.KeycloakContext;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class LengthPasswordPolicyProvider implements PasswordPolicyProvider {
+
+    private static final String ERROR_MESSAGE = "invalidPasswordMinLengthMessage";
+
+    private KeycloakContext context;
+
+    public LengthPasswordPolicyProvider(KeycloakContext context) {
+        this.context = context;
+    }
+
+    @Override
+    public PolicyError validate(String username, String password) {
+        int min = context.getRealm().getPasswordPolicy().getPolicyConfig(LengthPasswordPolicyProviderFactory.ID);
+        return password.length() < min ? new PolicyError(ERROR_MESSAGE, min) : null;
+    }
+
+    @Override
+    public PolicyError validate(UserModel user, String password) {
+        return validate(user.getUsername(), password);
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        return value != null ? Integer.parseInt(value) : 8;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/LengthPasswordPolicyProviderFactory.java b/server-spi/src/main/java/org/keycloak/policy/LengthPasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..a60c250
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/LengthPasswordPolicyProviderFactory.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class LengthPasswordPolicyProviderFactory implements PasswordPolicyProviderFactory {
+
+    static final String ID = "length";
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return new LengthPasswordPolicyProvider(session.getContext());
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Minimum Length";
+    }
+
+    @Override
+    public String getConfigType() {
+        return PasswordPolicyProvider.INT_CONFIG_TYPE;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return "8";
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return false;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/LowerCasePasswordPolicyProvider.java b/server-spi/src/main/java/org/keycloak/policy/LowerCasePasswordPolicyProvider.java
new file mode 100644
index 0000000..3312e2d
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/LowerCasePasswordPolicyProvider.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.models.KeycloakContext;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class LowerCasePasswordPolicyProvider implements PasswordPolicyProvider {
+
+    private static final String ERROR_MESSAGE = "invalidPasswordMinLowerCaseCharsMessage";
+
+    private KeycloakContext context;
+
+    public LowerCasePasswordPolicyProvider(KeycloakContext context) {
+        this.context = context;
+    }
+
+    @Override
+    public PolicyError validate(String username, String password) {
+        int min = context.getRealm().getPasswordPolicy().getPolicyConfig(LowerCasePasswordPolicyProviderFactory.ID);
+        int count = 0;
+        for (char c : password.toCharArray()) {
+            if (Character.isLowerCase(c)) {
+                count++;
+            }
+        }
+        return count < min ? new PolicyError(ERROR_MESSAGE, min) : null;
+    }
+
+    @Override
+    public PolicyError validate(UserModel user, String password) {
+        return validate(user.getUsername(), password);
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        return value != null ? Integer.parseInt(value) : 1;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/LowerCasePasswordPolicyProviderFactory.java b/server-spi/src/main/java/org/keycloak/policy/LowerCasePasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..7e96dcf
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/LowerCasePasswordPolicyProviderFactory.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class LowerCasePasswordPolicyProviderFactory implements PasswordPolicyProviderFactory {
+
+    public static final String ID = "lowerCase";
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return new LowerCasePasswordPolicyProvider(session.getContext());
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Lowercase Characters";
+    }
+
+    @Override
+    public String getConfigType() {
+        return PasswordPolicyProvider.INT_CONFIG_TYPE;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return "1";
+    }
+
+    @Override
+    public void close() {
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return false;
+    }
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/NotUsernamePasswordPolicyProvider.java b/server-spi/src/main/java/org/keycloak/policy/NotUsernamePasswordPolicyProvider.java
new file mode 100644
index 0000000..54634e6
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/NotUsernamePasswordPolicyProvider.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.models.KeycloakContext;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class NotUsernamePasswordPolicyProvider implements PasswordPolicyProvider {
+
+    private static final String ERROR_MESSAGE = "invalidPasswordNotUsernameMessage";
+
+    private KeycloakContext context;
+
+    public NotUsernamePasswordPolicyProvider(KeycloakContext context) {
+        this.context = context;
+    }
+
+    @Override
+    public PolicyError validate(String username, String password) {
+        if (username == null) {
+            return null;
+        }
+        return username.equals(password) ? new PolicyError(ERROR_MESSAGE) : null;
+    }
+
+    @Override
+    public PolicyError validate(UserModel user, String password) {
+        return validate(user.getUsername(), password);
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        return null;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/NotUsernamePasswordPolicyProviderFactory.java b/server-spi/src/main/java/org/keycloak/policy/NotUsernamePasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..30ebbff
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/NotUsernamePasswordPolicyProviderFactory.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class NotUsernamePasswordPolicyProviderFactory implements PasswordPolicyProviderFactory {
+
+    static final String ID = "notUsername";
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return new NotUsernamePasswordPolicyProvider(session.getContext());
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Not Username";
+    }
+
+    @Override
+    public String getConfigType() {
+        return null;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return null;
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return false;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/PasswordPolicyManagerProvider.java b/server-spi/src/main/java/org/keycloak/policy/PasswordPolicyManagerProvider.java
new file mode 100644
index 0000000..3039c95
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/PasswordPolicyManagerProvider.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.models.UserModel;
+import org.keycloak.provider.Provider;
+
+/**
+ * @author <a href="mailto:roelof.naude@epiuse.com">Roelof Naude</a>
+ */
+public interface PasswordPolicyManagerProvider extends Provider {
+
+    PolicyError validate(UserModel user, String password);
+    PolicyError validate(String user, String password);
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/PasswordPolicyManagerProviderFactory.java b/server-spi/src/main/java/org/keycloak/policy/PasswordPolicyManagerProviderFactory.java
new file mode 100644
index 0000000..f68701e
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/PasswordPolicyManagerProviderFactory.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * @author <a href="mailto:roelof.naude@epiuse.com">Roelof Naude</a>
+ */
+public interface PasswordPolicyManagerProviderFactory extends ProviderFactory<PasswordPolicyManagerProvider> {
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/PasswordPolicyManagerSpi.java b/server-spi/src/main/java/org/keycloak/policy/PasswordPolicyManagerSpi.java
new file mode 100644
index 0000000..266cf1f
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/PasswordPolicyManagerSpi.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class PasswordPolicyManagerSpi implements Spi {
+
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "password-policy-manager";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return PasswordPolicyManagerProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return PasswordPolicyManagerProviderFactory.class;
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/PasswordPolicyProvider.java b/server-spi/src/main/java/org/keycloak/policy/PasswordPolicyProvider.java
new file mode 100644
index 0000000..96b1803
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/PasswordPolicyProvider.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.models.UserModel;
+import org.keycloak.provider.Provider;
+
+/**
+ * @author <a href="mailto:roelof.naude@epiuse.com">Roelof Naude</a>
+ */
+public interface PasswordPolicyProvider extends Provider {
+
+    String STRING_CONFIG_TYPE = "String";
+    String INT_CONFIG_TYPE = "int";
+
+    PolicyError validate(UserModel user, String password);
+    PolicyError validate(String user, String password);
+    Object parseConfig(String value);
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/PasswordPolicyProviderFactory.java b/server-spi/src/main/java/org/keycloak/policy/PasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..44714e3
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/PasswordPolicyProviderFactory.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * @author <a href="mailto:roelof.naude@epiuse.com">Roelof Naude</a>
+ */
+public interface PasswordPolicyProviderFactory extends ProviderFactory<PasswordPolicyProvider> {
+
+    String getDisplayName();
+    String getConfigType();
+    String getDefaultConfigValue();
+    boolean isMultiplSupported();
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/PasswordPolicySpi.java b/server-spi/src/main/java/org/keycloak/policy/PasswordPolicySpi.java
new file mode 100644
index 0000000..97ad19a
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/PasswordPolicySpi.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:roelof.naude@epiuse.com">Roelof Naude</a>
+ */
+public class PasswordPolicySpi implements Spi {
+
+    @Override
+    public boolean isInternal() {
+        return false;
+    }
+
+    @Override
+    public String getName() {
+        return "password-policy";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return PasswordPolicyProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return PasswordPolicyProviderFactory.class;
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/PolicyError.java b/server-spi/src/main/java/org/keycloak/policy/PolicyError.java
new file mode 100644
index 0000000..d3a84f0
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/PolicyError.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public final class PolicyError {
+    private String message;
+    private Object[] parameters;
+
+    public PolicyError(String message, Object... parameters) {
+        this.message = message;
+        this.parameters = parameters;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public Object[] getParameters() {
+        return parameters;
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/RegexPatternsPasswordPolicyProvider.java b/server-spi/src/main/java/org/keycloak/policy/RegexPatternsPasswordPolicyProvider.java
new file mode 100644
index 0000000..7d4dbcc
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/RegexPatternsPasswordPolicyProvider.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.models.KeycloakContext;
+import org.keycloak.models.UserModel;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class RegexPatternsPasswordPolicyProvider implements PasswordPolicyProvider {
+
+    private static final String ERROR_MESSAGE = "invalidPasswordRegexPatternMessage";
+
+    private KeycloakContext context;
+
+    public RegexPatternsPasswordPolicyProvider(KeycloakContext context) {
+        this.context = context;
+    }
+
+    @Override
+    public PolicyError validate(String username, String password) {
+        Pattern pattern = context.getRealm().getPasswordPolicy().getPolicyConfig(RegexPatternsPasswordPolicyProviderFactory.ID);
+        Matcher matcher = pattern.matcher(password);
+        if (!matcher.matches()) {
+            return new PolicyError(ERROR_MESSAGE, pattern.pattern());
+        }
+        return null;
+    }
+
+    @Override
+    public PolicyError validate(UserModel user, String password) {
+        return validate(user.getUsername(), password);
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        if (value == null) {
+            throw new IllegalArgumentException("Config required");
+        }
+        return Pattern.compile(value);
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/RegexPatternsPasswordPolicyProviderFactory.java b/server-spi/src/main/java/org/keycloak/policy/RegexPatternsPasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..c0ce732
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/RegexPatternsPasswordPolicyProviderFactory.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class RegexPatternsPasswordPolicyProviderFactory implements PasswordPolicyProviderFactory {
+
+    static final String ID = "regexPattern";
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return new RegexPatternsPasswordPolicyProvider(session.getContext());
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Regular Expression";
+    }
+
+    @Override
+    public String getConfigType() {
+        return PasswordPolicyProvider.STRING_CONFIG_TYPE;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return "";
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return true;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/SpecialCharsPasswordPolicyProvider.java b/server-spi/src/main/java/org/keycloak/policy/SpecialCharsPasswordPolicyProvider.java
new file mode 100644
index 0000000..694d81e
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/SpecialCharsPasswordPolicyProvider.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.models.KeycloakContext;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class SpecialCharsPasswordPolicyProvider implements PasswordPolicyProvider {
+
+    private static final String ERROR_MESSAGE = "invalidPasswordMinSpecialCharsMessage";
+
+    private KeycloakContext context;
+
+    public SpecialCharsPasswordPolicyProvider(KeycloakContext context) {
+        this.context = context;
+    }
+
+    @Override
+    public PolicyError validate(String username, String password) {
+        int min = context.getRealm().getPasswordPolicy().getPolicyConfig(SpecialCharsPasswordPolicyProviderFactory.ID);
+        int count = 0;
+        for (char c : password.toCharArray()) {
+            if (!Character.isLetterOrDigit(c)) {
+                count++;
+            }
+        }
+        return count < min ? new PolicyError(ERROR_MESSAGE, min) : null;
+    }
+
+    @Override
+    public PolicyError validate(UserModel user, String password) {
+        return validate(user.getUsername(), password);
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        return value != null ? Integer.parseInt(value) : 1;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/SpecialCharsPasswordPolicyProviderFactory.java b/server-spi/src/main/java/org/keycloak/policy/SpecialCharsPasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..908cbee
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/SpecialCharsPasswordPolicyProviderFactory.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class SpecialCharsPasswordPolicyProviderFactory implements PasswordPolicyProviderFactory {
+
+    public static final String ID = "specialChars";
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return new SpecialCharsPasswordPolicyProvider(session.getContext());
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public void close() {
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Special Characters";
+    }
+
+    @Override
+    public String getConfigType() {
+        return PasswordPolicyProvider.INT_CONFIG_TYPE;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return "1";
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return false;
+    }
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/UpperCasePasswordPolicyProvider.java b/server-spi/src/main/java/org/keycloak/policy/UpperCasePasswordPolicyProvider.java
new file mode 100644
index 0000000..d8a570b
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/UpperCasePasswordPolicyProvider.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.models.KeycloakContext;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class UpperCasePasswordPolicyProvider implements PasswordPolicyProvider {
+
+    private static final String ERROR_MESSAGE = "invalidPasswordMinUpperCaseCharsMessage";
+
+    private KeycloakContext context;
+
+    public UpperCasePasswordPolicyProvider(KeycloakContext context) {
+        this.context = context;
+    }
+
+    @Override
+    public PolicyError validate(String username, String password) {
+        int min = context.getRealm().getPasswordPolicy().getPolicyConfig(UpperCasePasswordPolicyProviderFactory.ID);
+        int count = 0;
+        for (char c : password.toCharArray()) {
+            if (Character.isUpperCase(c)) {
+                count++;
+            }
+        }
+        return count < min ? new PolicyError(ERROR_MESSAGE, min) : null;
+    }
+
+    @Override
+    public PolicyError validate(UserModel user, String password) {
+        return validate(user.getUsername(), password);
+    }
+
+    @Override
+    public Object parseConfig(String value) {
+        return value != null ? Integer.parseInt(value) : 1;
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/policy/UpperCasePasswordPolicyProviderFactory.java b/server-spi/src/main/java/org/keycloak/policy/UpperCasePasswordPolicyProviderFactory.java
new file mode 100644
index 0000000..8dce247
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/policy/UpperCasePasswordPolicyProviderFactory.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.policy;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class UpperCasePasswordPolicyProviderFactory implements PasswordPolicyProviderFactory {
+
+    public static final String ID = "upperCase";
+
+    @Override
+    public PasswordPolicyProvider create(KeycloakSession session) {
+        return new UpperCasePasswordPolicyProvider(session.getContext());
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public void close() {
+    }
+
+    @Override
+    public String getDisplayName() {
+        return "Uppercase Characters";
+    }
+
+    @Override
+    public String getConfigType() {
+        return PasswordPolicyProvider.INT_CONFIG_TYPE;
+    }
+
+    @Override
+    public String getDefaultConfigValue() {
+        return "1";
+    }
+
+    @Override
+    public boolean isMultiplSupported() {
+        return false;
+    }
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/protocol/LoginProtocol.java b/server-spi/src/main/java/org/keycloak/protocol/LoginProtocol.java
index 6cc1be4..086a8ed 100755
--- a/server-spi/src/main/java/org/keycloak/protocol/LoginProtocol.java
+++ b/server-spi/src/main/java/org/keycloak/protocol/LoginProtocol.java
@@ -74,4 +74,11 @@ public interface LoginProtocol extends Provider {
     Response frontchannelLogout(UserSessionModel userSession, ClientSessionModel clientSession);
     Response finishLogout(UserSessionModel userSession);
 
+    /**
+     * @param userSession
+     * @param clientSession
+     * @return true if SSO cookie authentication can't be used. User will need to "actively" reauthenticate
+     */
+    boolean requireReauthentication(UserSessionModel userSession, ClientSessionModel clientSession);
+
 }
diff --git a/server-spi/src/main/java/org/keycloak/protocol/oidc/TokenIntrospectionProvider.java b/server-spi/src/main/java/org/keycloak/protocol/oidc/TokenIntrospectionProvider.java
new file mode 100644
index 0000000..e30f5da
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/protocol/oidc/TokenIntrospectionProvider.java
@@ -0,0 +1,38 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.protocol.oidc;
+
+import org.keycloak.provider.Provider;
+
+import javax.ws.rs.core.Response;
+
+/**
+ * Provides introspection for a determined OAuth2 token type.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface TokenIntrospectionProvider extends Provider {
+
+    /**
+     * Introspect the <code>token</code>.
+     *
+     * @param token the token to introspect.
+     * @return the response with the information about the token
+     */
+    Response introspect(String token);
+}
diff --git a/server-spi/src/main/java/org/keycloak/protocol/oidc/TokenIntrospectionProviderFactory.java b/server-spi/src/main/java/org/keycloak/protocol/oidc/TokenIntrospectionProviderFactory.java
new file mode 100644
index 0000000..48b7556
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/protocol/oidc/TokenIntrospectionProviderFactory.java
@@ -0,0 +1,28 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.protocol.oidc;
+
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * A factory that creates {@link TokenIntrospectionProvider} instances.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface TokenIntrospectionProviderFactory extends ProviderFactory<TokenIntrospectionProvider> {
+}
diff --git a/server-spi/src/main/java/org/keycloak/protocol/oidc/TokenIntrospectionSpi.java b/server-spi/src/main/java/org/keycloak/protocol/oidc/TokenIntrospectionSpi.java
new file mode 100644
index 0000000..4eb6d39
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/protocol/oidc/TokenIntrospectionSpi.java
@@ -0,0 +1,49 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.protocol.oidc;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * <p>A {@link Spi} to support additional tokens types to the OAuth2 Token Introspection Endpoint.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class TokenIntrospectionSpi implements Spi {
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "oauth2-token-introspection";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return TokenIntrospectionProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return TokenIntrospectionProviderFactory.class;
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/provider/ProviderConfigProperty.java b/server-spi/src/main/java/org/keycloak/provider/ProviderConfigProperty.java
index 4392a9c..5ddfb4c 100755
--- a/server-spi/src/main/java/org/keycloak/provider/ProviderConfigProperty.java
+++ b/server-spi/src/main/java/org/keycloak/provider/ProviderConfigProperty.java
@@ -24,6 +24,7 @@ package org.keycloak.provider;
 public class ProviderConfigProperty {
     public static final String BOOLEAN_TYPE="boolean";
     public static final String STRING_TYPE="String";
+    public static final String SCRIPT_TYPE="Script";
     public static final String ROLE_TYPE="Role";
     public static final String LIST_TYPE="List";
     public static final String CLIENT_LIST_TYPE="ClientList";
@@ -35,6 +36,17 @@ public class ProviderConfigProperty {
     protected String type;
     protected Object defaultValue;
 
+    public ProviderConfigProperty() {
+    }
+
+    public ProviderConfigProperty(String name, String label, String helpText, String type, Object defaultValue) {
+        this.name = name;
+        this.label = label;
+        this.helpText = helpText;
+        this.type = type;
+        this.defaultValue = defaultValue;
+    }
+
     public String getName() {
         return name;
     }
diff --git a/server-spi/src/main/java/org/keycloak/provider/ProviderLoader.java b/server-spi/src/main/java/org/keycloak/provider/ProviderLoader.java
index 76c2950..2d7a07a 100644
--- a/server-spi/src/main/java/org/keycloak/provider/ProviderLoader.java
+++ b/server-spi/src/main/java/org/keycloak/provider/ProviderLoader.java
@@ -24,6 +24,19 @@ import java.util.List;
  */
 public interface ProviderLoader {
 
+    /**
+     * Load the SPI definitions themselves.
+     *
+     * @return a list of Spi definition objects
+     */
+    List<Spi> loadSpis();
+
+    /**
+     * Load all provider factories of a specific SPI.
+     *
+     * @param spi the Spi definition
+     * @return a list of provider factories
+     */
     List<ProviderFactory> load(Spi spi);
 
 }
diff --git a/server-spi/src/main/java/org/keycloak/scripting/InvocableScript.java b/server-spi/src/main/java/org/keycloak/scripting/InvocableScript.java
new file mode 100644
index 0000000..342652f
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/scripting/InvocableScript.java
@@ -0,0 +1,64 @@
+package org.keycloak.scripting;
+
+import org.keycloak.models.ScriptModel;
+
+import javax.script.Invocable;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+
+/**
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+public class InvocableScript implements Invocable {
+
+    /**
+     * Holds the script metadata as well as the actual script.
+     */
+    private final ScriptModel script;
+
+    /**
+     * Holds the {@link ScriptEngine} instance initialized with the script code.
+     */
+    private final ScriptEngine scriptEngine;
+
+    public InvocableScript(ScriptModel script, ScriptEngine scriptEngine) {
+        this.script = script;
+        this.scriptEngine =  scriptEngine;
+    }
+
+    @Override
+    public Object invokeMethod(Object thiz, String name, Object... args) throws ScriptException, NoSuchMethodException {
+        return getInvocableEngine().invokeMethod(thiz, name, args);
+    }
+
+    @Override
+    public Object invokeFunction(String name, Object... args) throws ScriptException, NoSuchMethodException {
+        return getInvocableEngine().invokeFunction(name, args);
+    }
+
+    @Override
+    public <T> T getInterface(Class<T> clazz) {
+        return getInvocableEngine().getInterface(clazz);
+    }
+
+    @Override
+    public <T> T getInterface(Object thiz, Class<T> clazz) {
+        return getInvocableEngine().getInterface(thiz, clazz);
+    }
+
+    private Invocable getInvocableEngine() {
+        return (Invocable) scriptEngine;
+    }
+
+    /**
+     * Returns {@literal true} iif the {@link ScriptEngine} has a function with the given {@code functionName}.
+     * @param functionName
+     * @return
+     */
+    public boolean hasFunction(String functionName){
+
+        Object candidate = scriptEngine.getContext().getAttribute(functionName);
+
+        return candidate != null;
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/scripting/Script.java b/server-spi/src/main/java/org/keycloak/scripting/Script.java
new file mode 100644
index 0000000..2e81372
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/scripting/Script.java
@@ -0,0 +1,97 @@
+package org.keycloak.scripting;
+
+import org.keycloak.models.ScriptModel;
+
+/**
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+public class Script implements ScriptModel {
+
+    private String id;
+
+    private String realmId;
+
+    private String name;
+
+    private String mimeType;
+
+    private String code;
+
+    private String description;
+
+    public Script(String id, String realmId, String name, String mimeType, String code, String description) {
+
+        this.id = id;
+        this.realmId = realmId;
+        this.name = name;
+        this.mimeType = mimeType;
+        this.code = code;
+        this.description = description;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    @Override
+    public String getRealmId() {
+        return realmId;
+    }
+
+    public void setRealmId(String realmId) {
+        this.realmId = realmId;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String getMimeType() {
+        return mimeType;
+    }
+
+    public void setMimeType(String mimeType) {
+        this.mimeType = mimeType;
+    }
+
+    @Override
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    @Override
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    @Override
+    public String toString() {
+        return "Script{" +
+                "id='" + id + '\'' +
+                ", realmId='" + realmId + '\'' +
+                ", name='" + name + '\'' +
+                ", type='" + mimeType + '\'' +
+                ", code='" + code + '\'' +
+                ", description='" + description + '\'' +
+                '}';
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/scripting/ScriptBindingsConfigurer.java b/server-spi/src/main/java/org/keycloak/scripting/ScriptBindingsConfigurer.java
new file mode 100644
index 0000000..9d55195
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/scripting/ScriptBindingsConfigurer.java
@@ -0,0 +1,25 @@
+package org.keycloak.scripting;
+
+import javax.script.Bindings;
+
+/**
+ * Callback interface for customization of {@link Bindings} for a {@link javax.script.ScriptEngine}.
+ *
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+@FunctionalInterface
+public interface ScriptBindingsConfigurer {
+
+    /**
+     * A default {@link ScriptBindingsConfigurer} leaves the Bindings empty.
+     */
+    ScriptBindingsConfigurer EMPTY = new ScriptBindingsConfigurer() {
+
+        @Override
+        public void configureBindings(Bindings bindings) {
+            //NOOP
+        }
+    };
+
+    void configureBindings(Bindings bindings);
+}
\ No newline at end of file
diff --git a/server-spi/src/main/java/org/keycloak/scripting/ScriptExecutionException.java b/server-spi/src/main/java/org/keycloak/scripting/ScriptExecutionException.java
new file mode 100644
index 0000000..e912ca9
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/scripting/ScriptExecutionException.java
@@ -0,0 +1,17 @@
+package org.keycloak.scripting;
+
+import org.keycloak.models.ScriptModel;
+
+import javax.script.ScriptException;
+
+/**
+ * Augments a {@link ScriptException} and adds additional metadata.
+ *
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+public class ScriptExecutionException extends RuntimeException {
+
+    public ScriptExecutionException(ScriptModel script, ScriptException se) {
+        super("Error executing script '" + script.getName() + "'", se);
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/scripting/ScriptingProvider.java b/server-spi/src/main/java/org/keycloak/scripting/ScriptingProvider.java
new file mode 100644
index 0000000..163120b
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/scripting/ScriptingProvider.java
@@ -0,0 +1,32 @@
+package org.keycloak.scripting;
+
+import org.keycloak.models.ScriptModel;
+import org.keycloak.provider.Provider;
+
+import javax.script.ScriptEngine;
+
+/**
+ * A {@link Provider} than provides Scripting capabilities.
+ *
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+public interface ScriptingProvider extends Provider {
+
+    /**
+     * Returns an {@link InvocableScript} based on the given {@link ScriptModel}.
+     * <p>The {@code InvocableScript} wraps a dedicated {@link ScriptEngine} that was populated with the provided {@link ScriptBindingsConfigurer}</p>
+     *
+     * @param script             the script to wrap
+     * @param bindingsConfigurer populates the {@link javax.script.Bindings}
+     * @return
+     */
+    InvocableScript prepareScript(ScriptModel script, ScriptBindingsConfigurer bindingsConfigurer);
+
+    /**
+     * Returns an {@link InvocableScript} based on the given {@link ScriptModel} with an {@link ScriptBindingsConfigurer#EMPTY} {@code ScriptBindingsConfigurer}.
+     * @see #prepareScript(ScriptModel, ScriptBindingsConfigurer)
+     * @param script
+     * @return
+     */
+    InvocableScript prepareScript(ScriptModel script);
+}
diff --git a/server-spi/src/main/java/org/keycloak/scripting/ScriptingProviderFactory.java b/server-spi/src/main/java/org/keycloak/scripting/ScriptingProviderFactory.java
new file mode 100644
index 0000000..826c6cc
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/scripting/ScriptingProviderFactory.java
@@ -0,0 +1,9 @@
+package org.keycloak.scripting;
+
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+public interface ScriptingProviderFactory extends ProviderFactory<ScriptingProvider> {
+}
diff --git a/server-spi/src/main/java/org/keycloak/scripting/ScriptingSpi.java b/server-spi/src/main/java/org/keycloak/scripting/ScriptingSpi.java
new file mode 100644
index 0000000..1fa39d8
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/scripting/ScriptingSpi.java
@@ -0,0 +1,31 @@
+package org.keycloak.scripting;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+public class ScriptingSpi implements Spi {
+
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "scripting";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return ScriptingProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return ScriptingProviderFactory.class;
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/services/managers/BruteForceProtector.java b/server-spi/src/main/java/org/keycloak/services/managers/BruteForceProtector.java
index 33ba774..e884b02 100755
--- a/server-spi/src/main/java/org/keycloak/services/managers/BruteForceProtector.java
+++ b/server-spi/src/main/java/org/keycloak/services/managers/BruteForceProtector.java
@@ -20,6 +20,7 @@ package org.keycloak.services.managers;
 import org.keycloak.common.ClientConnection;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
 import org.keycloak.provider.Provider;
 
 /**
@@ -27,7 +28,7 @@ import org.keycloak.provider.Provider;
  * @version $Revision: 1 $
  */
 public interface BruteForceProtector extends Provider {
-    void failedLogin(RealmModel realm, String username, ClientConnection clientConnection);
+    void failedLogin(RealmModel realm, UserModel user, ClientConnection clientConnection);
 
-    boolean isTemporarilyDisabled(KeycloakSession session, RealmModel realm, String username);
+    boolean isTemporarilyDisabled(KeycloakSession session, RealmModel realm, UserModel user);
 }
diff --git a/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapter.java b/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapter.java
new file mode 100644
index 0000000..6a4e7d2
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapter.java
@@ -0,0 +1,420 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.adapter;
+
+import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.component.ComponentModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleContainerModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserCredentialValueModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.DefaultRoles;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.storage.StorageId;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * This abstract class provides implementations for everything but getUsername().  getId() returns a default value
+ * of "f:" + providerId + ":" + getUsername().  isEnabled() returns true.  getRoleMappings() will return default roles.
+ * getGroups() will return default groups.
+ *
+ * All other read methods return null, an empty collection, or false depending
+ * on the type.  All update methods throw a ReadOnlyException.
+ *
+ * Provider implementors should override the methods for attributes, properties, and mappings they support.
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public abstract class AbstractUserAdapter implements UserModel {
+    public static class ReadOnlyException extends RuntimeException {
+        public ReadOnlyException(String message) {
+            super(message);
+        }
+    }
+    protected KeycloakSession session;
+    protected RealmModel realm;
+    protected ComponentModel storageProviderModel;
+
+    public AbstractUserAdapter(KeycloakSession session, RealmModel realm, ComponentModel storageProviderModel) {
+        this.session = session;
+        this.realm = realm;
+        this.storageProviderModel = storageProviderModel;
+    }
+
+    @Override
+    public Set<String> getRequiredActions() {
+        return Collections.EMPTY_SET;
+    }
+
+    @Override
+    public void addRequiredAction(String action) {
+        throw new ReadOnlyException("user is read only for this update");
+
+    }
+
+    @Override
+    public void removeRequiredAction(String action) {
+        throw new ReadOnlyException("user is read only for this update");
+
+    }
+
+    @Override
+    public void addRequiredAction(RequiredAction action) {
+        throw new ReadOnlyException("user is read only for this update");
+
+    }
+
+    @Override
+    public void removeRequiredAction(RequiredAction action) {
+        throw new ReadOnlyException("user is read only for this update");
+    }
+
+    /**
+     * Get group membership mappings that are managed by this storage provider
+     *
+     * @return
+     */
+    protected Set<GroupModel> getGroupsInternal() {
+        return Collections.EMPTY_SET;
+    }
+
+    /**
+     * Should the realm's default groups be appended to getGroups() call?
+     * If your storage provider is not managing group mappings then it is recommended that
+     * this method return true
+     *
+     * @return
+     */
+    protected boolean appendDefaultGroups() {
+        return true;
+    }
+
+    @Override
+    public Set<GroupModel> getGroups() {
+        Set<GroupModel> set = new HashSet<>();
+        if (appendDefaultGroups()) set.addAll(realm.getDefaultGroups());
+        set.addAll(getGroupsInternal());
+        return set;
+    }
+
+    @Override
+    public void joinGroup(GroupModel group) {
+        throw new ReadOnlyException("user is read only for this update");
+
+    }
+
+    @Override
+    public void leaveGroup(GroupModel group) {
+        throw new ReadOnlyException("user is read only for this update");
+
+    }
+
+    @Override
+    public boolean isMemberOf(GroupModel group) {
+        Set<GroupModel> roles = getGroups();
+        return KeycloakModelUtils.isMember(roles, group);
+    }
+
+    @Override
+    public Set<RoleModel> getRealmRoleMappings() {
+        Set<RoleModel> roleMappings = getRoleMappings();
+
+        Set<RoleModel> realmRoles = new HashSet<RoleModel>();
+        for (RoleModel role : roleMappings) {
+            RoleContainerModel container = role.getContainer();
+            if (container instanceof RealmModel) {
+                realmRoles.add(role);
+            }
+        }
+        return realmRoles;
+    }
+
+    @Override
+    public Set<RoleModel> getClientRoleMappings(ClientModel app) {
+        Set<RoleModel> roleMappings = getRoleMappings();
+
+        Set<RoleModel> roles = new HashSet<RoleModel>();
+        for (RoleModel role : roleMappings) {
+            RoleContainerModel container = role.getContainer();
+            if (container instanceof ClientModel) {
+                ClientModel appModel = (ClientModel) container;
+                if (appModel.getId().equals(app.getId())) {
+                    roles.add(role);
+                }
+            }
+        }
+        return roles;
+    }
+
+    @Override
+    public boolean hasRole(RoleModel role) {
+        Set<RoleModel> roles = getRoleMappings();
+        return KeycloakModelUtils.hasRole(roles, role);
+    }
+
+    @Override
+    public void grantRole(RoleModel role) {
+        throw new ReadOnlyException("user is read only for this update");
+
+    }
+
+    /**
+     * Should the realm's default roles be appended to getRoleMappings() call?
+     * If your storage provider is not managing all role mappings then it is recommended that
+     * this method return true
+     *
+     * @return
+     */
+    protected boolean appendDefaultRolesToRoleMappings() {
+        return true;
+    }
+
+    protected Set<RoleModel> getRoleMappingsInternal() {
+        return Collections.EMPTY_SET;
+    }
+
+    @Override
+    public Set<RoleModel> getRoleMappings() {
+        Set<RoleModel> set = new HashSet<>();
+        if (appendDefaultRolesToRoleMappings()) set.addAll(DefaultRoles.getDefaultRoles(realm));
+        set.addAll(getRoleMappingsInternal());
+        return set;
+    }
+
+
+    @Override
+    public void deleteRoleMapping(RoleModel role) {
+        throw new ReadOnlyException("user is read only for this update");
+
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return true;
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        throw new ReadOnlyException("user is read only for this update");
+    }
+
+    @Override
+    public boolean isOtpEnabled() {
+        return false;
+    }
+
+    @Override
+    public void setOtpEnabled(boolean totp) {
+        throw new ReadOnlyException("user is read only for this update");
+
+    }
+
+    /**
+     * This method should not be overriden
+     *
+     * @return
+     */
+    @Override
+    public String getFederationLink() {
+        return null;
+    }
+
+    /**
+     * This method should not be overriden
+     *
+     * @return
+     */
+    @Override
+    public void setFederationLink(String link) {
+        throw new ReadOnlyException("user is read only for this update");
+
+    }
+
+    /**
+     * This method should not be overriden
+     *
+     * @return
+     */
+    @Override
+    public String getServiceAccountClientLink() {
+        return null;
+    }
+
+    /**
+     * This method should not be overriden
+     *
+     * @return
+     */
+    @Override
+    public void setServiceAccountClientLink(String clientInternalId) {
+        throw new ReadOnlyException("user is read only for this update");
+
+    }
+
+    protected StorageId storageId;
+
+    /**
+     * Defaults to 'f:' + storageProvider.getId() + ':' + getUsername()
+     *
+     * @return
+     */
+    @Override
+    public String getId() {
+        if (storageId == null) {
+            storageId = new StorageId(storageProviderModel.getId(), getUsername());
+        }
+        return storageId.getId();
+    }
+
+    @Override
+    public void setUsername(String username) {
+        throw new ReadOnlyException("user is read only for this update");
+    }
+
+    protected long created = System.currentTimeMillis();
+
+    @Override
+    public Long getCreatedTimestamp() {
+        return created;
+    }
+
+    @Override
+    public void setCreatedTimestamp(Long timestamp) {
+        throw new ReadOnlyException("user is read only for this update");
+
+    }
+
+    @Override
+    public void setSingleAttribute(String name, String value) {
+        throw new ReadOnlyException("user is read only for this update");
+
+    }
+
+    @Override
+    public void removeAttribute(String name) {
+        throw new ReadOnlyException("user is read only for this update");
+
+    }
+
+    @Override
+    public void setAttribute(String name, List<String> values) {
+        throw new ReadOnlyException("user is read only for this update");
+
+    }
+
+    @Override
+    public String getFirstAttribute(String name) {
+        return null;
+    }
+
+    @Override
+    public Map<String, List<String>> getAttributes() {
+        return new MultivaluedHashMap<>();
+    }
+
+    @Override
+    public List<String> getAttribute(String name) {
+        return null;
+    }
+
+    @Override
+    public String getFirstName() {
+        return null;
+    }
+
+    @Override
+    public void setFirstName(String firstName) {
+        throw new ReadOnlyException("user is read only for this update");
+
+    }
+
+    @Override
+    public String getLastName() {
+        return null;
+    }
+
+    @Override
+    public void setLastName(String lastName) {
+        throw new ReadOnlyException("user is read only for this update");
+
+    }
+
+    @Override
+    public String getEmail() {
+        return null;
+    }
+
+    @Override
+    public void setEmail(String email) {
+        throw new ReadOnlyException("user is read only for this update");
+
+    }
+
+    @Override
+    public boolean isEmailVerified() {
+        return false;
+    }
+
+    @Override
+    public void setEmailVerified(boolean verified) {
+        throw new ReadOnlyException("user is read only for this update");
+
+    }
+
+    @Override
+    public void updateCredential(UserCredentialModel cred) {
+        throw new ReadOnlyException("user is read only for this update");
+
+    }
+
+    @Override
+    public List<UserCredentialValueModel> getCredentialsDirectly() {
+        return Collections.EMPTY_LIST;
+    }
+
+    @Override
+    public void updateCredentialDirectly(UserCredentialValueModel cred) {
+        throw new ReadOnlyException("user is read only for this update");
+
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || !(o instanceof UserModel)) return false;
+
+        UserModel that = (UserModel) o;
+        return that.getId().equals(getId());
+    }
+
+    @Override
+    public int hashCode() {
+        return getId().hashCode();
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapterFederatedStorage.java b/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapterFederatedStorage.java
new file mode 100644
index 0000000..bfe0b95
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/adapter/AbstractUserAdapterFederatedStorage.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.adapter;
+
+import org.keycloak.component.ComponentModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleContainerModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserCredentialValueModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.DefaultRoles;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.storage.StorageId;
+import org.keycloak.storage.federated.UserFederatedStorageProvider;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Assumes everything is managed by federated storage except for username.  getId() returns a default value
+ * of "f:" + providerId + ":" + getUsername().  UserModel properties like enabled, firstName, lastName, email, etc. are all
+ * stored as attributes in federated storage.
+ *
+ * isEnabled() defaults to true if the ENABLED_ATTRIBUTE isn't set in federated
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public abstract class AbstractUserAdapterFederatedStorage implements UserModel {
+    public static String FIRST_NAME_ATTRIBUTE = "FIRST_NAME";
+    public static String LAST_NAME_ATTRIBUTE = "LAST_NAME";
+    public static String EMAIL_ATTRIBUTE = "EMAIL";
+    public static String EMAIL_VERIFIED_ATTRIBUTE = "EMAIL_VERIFIED";
+    public static String CREATED_TIMESTAMP_ATTRIBUTE = "CREATED_TIMESTAMP";
+    public static String ENABLED_ATTRIBUTE = "ENABLED";
+    public static String OTP_ENABLED_ATTRIBUTE = "OTP_ENABLED";
+
+
+    protected KeycloakSession session;
+    protected RealmModel realm;
+    protected ComponentModel storageProviderModel;
+
+    public AbstractUserAdapterFederatedStorage(KeycloakSession session, RealmModel realm, ComponentModel storageProviderModel) {
+        this.session = session;
+        this.realm = realm;
+        this.storageProviderModel = storageProviderModel;
+    }
+
+    public UserFederatedStorageProvider getFederatedStorage() {
+        return session.userFederatedStorage();
+    }
+
+    @Override
+    public Set<String> getRequiredActions() {
+        return getFederatedStorage().getRequiredActions(realm, this);
+    }
+
+    @Override
+    public void addRequiredAction(String action) {
+        getFederatedStorage().addRequiredAction(realm, this, action);
+
+    }
+
+    @Override
+    public void removeRequiredAction(String action) {
+        getFederatedStorage().removeRequiredAction(realm, this, action);
+
+    }
+
+    @Override
+    public void addRequiredAction(RequiredAction action) {
+        getFederatedStorage().addRequiredAction(realm, this, action.name());
+
+    }
+
+    @Override
+    public void removeRequiredAction(RequiredAction action) {
+        getFederatedStorage().removeRequiredAction(realm, this, action.name());
+    }
+
+    /**
+     * Get group membership mappings that are managed by this storage provider
+     *
+     * @return
+     */
+    protected Set<GroupModel> getGroupsInternal() {
+        return Collections.EMPTY_SET;
+    }
+
+    /**
+     * Should the realm's default groups be appended to getGroups() call?
+     * If your storage provider is not managing group mappings then it is recommended that
+     * this method return true
+     *
+     * @return
+     */
+    protected boolean appendDefaultGroups() {
+        return true;
+    }
+
+    @Override
+    public Set<GroupModel> getGroups() {
+        Set<GroupModel> set = new HashSet<>();
+        set.addAll(getFederatedStorage().getGroups(realm, this));
+        if (appendDefaultGroups()) set.addAll(realm.getDefaultGroups());
+        set.addAll(getGroupsInternal());
+        return set;
+    }
+
+    @Override
+    public void joinGroup(GroupModel group) {
+        getFederatedStorage().joinGroup(realm, this, group);
+
+    }
+
+    @Override
+    public void leaveGroup(GroupModel group) {
+        getFederatedStorage().leaveGroup(realm, this, group);
+
+    }
+
+    @Override
+    public boolean isMemberOf(GroupModel group) {
+        Set<GroupModel> roles = getGroups();
+        return KeycloakModelUtils.isMember(roles, group);
+    }
+
+    @Override
+    public Set<RoleModel> getRealmRoleMappings() {
+        Set<RoleModel> roleMappings = getRoleMappings();
+
+        Set<RoleModel> realmRoles = new HashSet<RoleModel>();
+        for (RoleModel role : roleMappings) {
+            RoleContainerModel container = role.getContainer();
+            if (container instanceof RealmModel) {
+                realmRoles.add(role);
+            }
+        }
+        return realmRoles;
+    }
+
+    @Override
+    public Set<RoleModel> getClientRoleMappings(ClientModel app) {
+        Set<RoleModel> roleMappings = getRoleMappings();
+
+        Set<RoleModel> roles = new HashSet<RoleModel>();
+        for (RoleModel role : roleMappings) {
+            RoleContainerModel container = role.getContainer();
+            if (container instanceof ClientModel) {
+                ClientModel appModel = (ClientModel) container;
+                if (appModel.getId().equals(app.getId())) {
+                    roles.add(role);
+                }
+            }
+        }
+        return roles;
+    }
+
+    @Override
+    public boolean hasRole(RoleModel role) {
+        Set<RoleModel> roles = getRoleMappings();
+        return KeycloakModelUtils.hasRole(roles, role);
+    }
+
+    @Override
+    public void grantRole(RoleModel role) {
+        getFederatedStorage().grantRole(realm, this, role);
+
+    }
+
+    /**
+     * Should the realm's default roles be appended to getRoleMappings() call?
+     * If your storage provider is not managing all role mappings then it is recommended that
+     * this method return true
+     *
+     * @return
+     */
+    protected boolean appendDefaultRolesToRoleMappings() {
+        return true;
+    }
+
+    protected Set<RoleModel> getRoleMappingsInternal() {
+        return Collections.EMPTY_SET;
+    }
+
+    @Override
+    public Set<RoleModel> getRoleMappings() {
+        Set<RoleModel> set = new HashSet<>();
+        set.addAll(getFederatedRoleMappings());
+        if (appendDefaultRolesToRoleMappings()) set.addAll(DefaultRoles.getDefaultRoles(realm));
+        set.addAll(getRoleMappingsInternal());
+        return set;
+    }
+
+    protected Set<RoleModel> getFederatedRoleMappings() {
+        return getFederatedStorage().getRoleMappings(realm, this);
+    }
+
+    @Override
+    public void deleteRoleMapping(RoleModel role) {
+        getFederatedStorage().deleteRoleMapping(realm, this, role);
+
+    }
+
+    @Override
+    public boolean isEnabled() {
+        String val = getFirstAttribute(ENABLED_ATTRIBUTE);
+        if (val == null) return true;
+        else return Boolean.valueOf(val);
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+       setSingleAttribute(ENABLED_ATTRIBUTE, Boolean.toString(enabled));
+    }
+
+    @Override
+    public boolean isOtpEnabled() {
+        String val = getFirstAttribute(OTP_ENABLED_ATTRIBUTE);
+        if (val == null) return false;
+        else return Boolean.valueOf(val);
+    }
+
+    @Override
+    public void setOtpEnabled(boolean totp) {
+        setSingleAttribute(OTP_ENABLED_ATTRIBUTE, Boolean.toString(totp));
+
+    }
+
+    /**
+     * This method should not be overriden
+     *
+     * @return
+     */
+    @Override
+    public String getFederationLink() {
+        return null;
+    }
+
+    /**
+     * This method should not be overriden
+     *
+     * @return
+     */
+    @Override
+    public void setFederationLink(String link) {
+
+    }
+
+    /**
+     * This method should not be overriden
+     *
+     * @return
+     */
+    @Override
+    public String getServiceAccountClientLink() {
+        return null;
+    }
+
+    /**
+     * This method should not be overriden
+     *
+     * @return
+     */
+    @Override
+    public void setServiceAccountClientLink(String clientInternalId) {
+
+    }
+
+    protected StorageId storageId;
+
+    /**
+     * Defaults to 'f:' + storageProvider.getId() + ':' + getUsername()
+     *
+     * @return
+     */
+    @Override
+    public String getId() {
+        if (storageId == null) {
+            storageId = new StorageId(storageProviderModel.getId(), getUsername());
+        }
+        return storageId.getId();
+    }
+
+    @Override
+    public Long getCreatedTimestamp() {
+        String val = getFirstAttribute(CREATED_TIMESTAMP_ATTRIBUTE);
+        if (val == null) return null;
+        else return Long.valueOf(val);
+    }
+
+    @Override
+    public void setCreatedTimestamp(Long timestamp) {
+        if (timestamp == null) {
+            setSingleAttribute(CREATED_TIMESTAMP_ATTRIBUTE, null);
+        } else {
+            setSingleAttribute(CREATED_TIMESTAMP_ATTRIBUTE, Long.toString(timestamp));
+        }
+
+    }
+
+    @Override
+    public void setSingleAttribute(String name, String value) {
+        getFederatedStorage().setSingleAttribute(realm, this, name, value);
+
+    }
+
+    @Override
+    public void removeAttribute(String name) {
+        getFederatedStorage().removeAttribute(realm, this, name);
+
+    }
+
+    @Override
+    public void setAttribute(String name, List<String> values) {
+        getFederatedStorage().setAttribute(realm, this, name, values);
+
+    }
+
+    @Override
+    public String getFirstAttribute(String name) {
+        return getFederatedStorage().getAttributes(realm, this).getFirst(name);
+    }
+
+    @Override
+    public Map<String, List<String>> getAttributes() {
+        return getFederatedStorage().getAttributes(realm, this);
+    }
+
+    @Override
+    public List<String> getAttribute(String name) {
+        return getFederatedStorage().getAttributes(realm, this).get(name);
+    }
+
+    @Override
+    public String getFirstName() {
+        return getFirstAttribute(FIRST_NAME_ATTRIBUTE);
+    }
+
+    @Override
+    public void setFirstName(String firstName) {
+        setSingleAttribute(FIRST_NAME_ATTRIBUTE, firstName);
+
+    }
+
+    @Override
+    public String getLastName() {
+        return getFirstAttribute(LAST_NAME_ATTRIBUTE);
+    }
+
+    @Override
+    public void setLastName(String lastName) {
+        setSingleAttribute(LAST_NAME_ATTRIBUTE, lastName);
+
+    }
+
+    @Override
+    public String getEmail() {
+        return getFirstAttribute(EMAIL_ATTRIBUTE);
+    }
+
+    @Override
+    public void setEmail(String email) {
+        setSingleAttribute(EMAIL_ATTRIBUTE, email);
+
+    }
+
+    @Override
+    public boolean isEmailVerified() {
+        String val = getFirstAttribute(EMAIL_VERIFIED_ATTRIBUTE);
+        if (val == null) return false;
+        else return Boolean.valueOf(val);
+    }
+
+    @Override
+    public void setEmailVerified(boolean verified) {
+        setSingleAttribute(EMAIL_VERIFIED_ATTRIBUTE, Boolean.toString(verified));
+
+    }
+
+    @Override
+    public void updateCredential(UserCredentialModel cred) {
+        getFederatedStorage().updateCredential(realm, this, cred);
+
+    }
+
+    @Override
+    public List<UserCredentialValueModel> getCredentialsDirectly() {
+        return getFederatedStorage().getCredentials(realm, this);
+    }
+
+    @Override
+    public void updateCredentialDirectly(UserCredentialValueModel cred) {
+        getFederatedStorage().updateCredential(realm, this, cred);
+
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || !(o instanceof UserModel)) return false;
+
+        UserModel that = (UserModel) o;
+        return that.getId().equals(getId());
+    }
+
+    @Override
+    public int hashCode() {
+        return getId().hashCode();
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/changeset/UserData.java b/server-spi/src/main/java/org/keycloak/storage/changeset/UserData.java
new file mode 100755
index 0000000..4b2813a
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/changeset/UserData.java
@@ -0,0 +1,387 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.storage.changeset;
+
+import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.models.UserCredentialValueModel;
+import org.keycloak.models.entities.AbstractIdentifiableEntity;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class UserData {
+
+    private String id;
+    private boolean idChanged;
+    private String username;
+    private boolean usernameChanged;
+    private Long createdTimestamp;
+    private boolean createdTimestampChanged;
+    private String firstName;
+    private boolean firstNameChanged;
+    private String lastName;
+    private boolean lastNameChanged;
+    private String email;
+    private boolean emailChanged;
+    private boolean emailVerified;
+    private boolean emailVerifiedChanged;
+    private boolean totp;
+    private boolean totpChanged;
+    private boolean enabled;
+    private boolean enabledChanged;
+
+    private Set<String> roleIds = new HashSet<>();
+    private boolean rolesChanged;
+    private Set<String> groupIds = new HashSet<>();
+    private boolean groupsChanged;
+
+    private MultivaluedHashMap<String, String> attributes = new MultivaluedHashMap<>();
+    private boolean attributesChanged;
+    private Set<String> requiredActions = new HashSet<>();
+    private boolean requiredActionsChanged;
+    private List<UserCredentialValueModel> credentials = new LinkedList<>();
+    private boolean credentialsChanged;
+
+    public void rememberState() {
+        original = new UserData();
+        original.id = id;
+        original.username = username;
+        original.createdTimestamp = createdTimestamp;
+        original.firstName = firstName;
+        original.lastName = lastName;
+        original.email = email;
+        original.emailVerified = emailVerified;
+        original.totp = totp;
+        original.enabled = enabled;
+        original.attributes.putAll(attributes);
+        original.requiredActions.addAll(requiredActions);
+        original.credentials.addAll(credentials);
+    }
+
+    private UserData original = null;
+
+    public void clearChangeFlags() {
+        original = null;
+        idChanged = false;
+        usernameChanged = false;
+        createdTimestampChanged = false;
+        firstNameChanged = false;
+        lastNameChanged = false;
+        emailChanged = false;
+        emailVerifiedChanged = false;
+        totpChanged = false;
+        enabledChanged = false;
+        rolesChanged = false;
+        groupsChanged = false;
+        attributesChanged = false;
+        requiredActionsChanged = false;
+        credentialsChanged = false;
+    }
+
+    public boolean isChanged() {
+        return !idChanged
+        && !usernameChanged
+        && !createdTimestampChanged
+        && !firstNameChanged
+        && !lastNameChanged
+        && !emailChanged
+        && !emailVerifiedChanged
+        && !totpChanged
+        && !enabledChanged
+        && !rolesChanged
+        && !groupsChanged
+        && !attributesChanged
+        && !requiredActionsChanged
+        && !credentialsChanged;
+    }
+
+    public boolean isIdChanged() {
+        return idChanged;
+    }
+
+    public boolean isUsernameChanged() {
+        return usernameChanged;
+    }
+
+    public boolean isCreatedTimestampChanged() {
+        return createdTimestampChanged;
+    }
+
+    public boolean isFirstNameChanged() {
+        return firstNameChanged;
+    }
+
+    public boolean isLastNameChanged() {
+        return lastNameChanged;
+    }
+
+    public boolean isEmailChanged() {
+        return emailChanged;
+    }
+
+    public boolean isEmailVerifiedChanged() {
+        return emailVerifiedChanged;
+    }
+
+    public boolean isTotpChanged() {
+        return totpChanged;
+    }
+
+    public boolean isEnabledChanged() {
+        return enabledChanged;
+    }
+
+    public boolean isRolesChanged() {
+        return rolesChanged;
+    }
+
+    public boolean isGroupsChanged() {
+        return groupsChanged;
+    }
+
+    public boolean isAttributesChanged() {
+        return attributesChanged;
+    }
+
+    public boolean isRequiredActionsChanged() {
+        return requiredActionsChanged;
+    }
+
+    public boolean isCredentialsChanged() {
+        return credentialsChanged;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+        idChanged = true;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+        usernameChanged = true;
+    }
+    
+    public Long getCreatedTimestamp() {
+        return createdTimestamp;
+    }
+
+    public void setCreatedTimestamp(Long timestamp) {
+        this.createdTimestamp = timestamp;
+        createdTimestampChanged = true;
+    }
+
+
+    public String getFirstName() {
+        return firstName;
+    }
+
+    public void setFirstName(String firstName) {
+        this.firstName = firstName;
+        firstNameChanged = true;
+    }
+
+    public String getLastName() {
+        return lastName;
+    }
+
+    public void setLastName(String lastName) {
+        this.lastName = lastName;
+        lastNameChanged = true;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+        emailChanged = true;
+    }
+
+    public boolean isEmailVerified() {
+        return emailVerified;
+    }
+
+    public void setEmailVerified(boolean emailVerified) {
+        this.emailVerified = emailVerified;
+        emailVerifiedChanged = true;
+    }
+
+    public boolean isTotp() {
+        return totp;
+    }
+
+    public void setTotp(boolean totp) {
+        this.totp = totp;
+        totpChanged = true;
+    }
+
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+        enabledChanged = true;
+    }
+
+    public Set<String> getRoleMappings() {
+        return Collections.unmodifiableSet(roleIds);
+    }
+
+    public void grantRole(String roleId) {
+        if (roleIds.contains(roleId)) return;
+        roleIds.add(roleId);
+        rolesChanged = true;
+    }
+
+    public void deleteRoleMapping(String roleId) {
+        if (!roleIds.contains(roleId)) return;
+        roleIds.remove(roleId);
+        rolesChanged = true;
+    }
+
+    public MultivaluedHashMap<String, String> getAttributes() {
+        return attributes;
+    }
+
+    public void setSingleAttribute(String name, String value) {
+        attributes.putSingle(name, value);
+        attributesChanged = true;
+
+    }
+    public void setAttribute(String name, List<String> values) {
+        attributes.put(name, values);
+        attributesChanged = true;
+    }
+    public void removeAttribute(String name) {
+        attributes.remove(name);
+        attributesChanged = true;
+    }
+
+
+
+    public Set<String> getRequiredActions() {
+        return Collections.unmodifiableSet(requiredActions);
+    }
+    public void addRequiredAction(String action) {
+        if (requiredActions.contains(action)) return;
+        requiredActions.add(action);
+        requiredActionsChanged = true;
+    }
+    public void removeRequiredAction(String action) {
+        if (!requiredActions.contains(action)) return;
+        requiredActions.remove(action);
+        requiredActionsChanged = true;
+    }
+
+    public List<UserCredentialValueModel> getCredentials() {
+        return Collections.unmodifiableList(credentials);
+    }
+
+    public void removeCredentialType(String type) {
+        Iterator<UserCredentialValueModel> it = credentials.iterator();
+        while (it.hasNext()) {
+            if (it.next().getType().equals(type)) {
+                it.remove();
+                credentialsChanged = true;
+            }
+        }
+
+    }
+
+    public void removeCredentialDevice(String type, String device) {
+        Iterator<UserCredentialValueModel> it = credentials.iterator();
+        while (it.hasNext()) {
+            UserCredentialValueModel next = it.next();
+            if (next.getType().equals(type) && next.getDevice().equals(device)) {
+                it.remove();
+                credentialsChanged = true;
+            }
+        }
+
+    }
+
+    public void setCredential(UserCredentialValueModel cred) {
+        removeCredentialType(cred.getType());
+        addCredential(cred);
+    }
+    public void addCredential(UserCredentialValueModel cred) {
+        credentials.add(cred);
+        credentialsChanged = true;
+    }
+
+    public Set<String> getGroupIds() {
+        return Collections.unmodifiableSet(groupIds);
+    }
+
+    public void joinGroup(String groupId) {
+        if (groupIds.contains(groupId)) return;
+        groupIds.add(groupId);
+        groupsChanged = true;
+    }
+
+    public void leaveGroup(String groupId) {
+        if (!groupIds.contains(groupId)) return;
+        groupIds.remove(groupId);
+        groupsChanged = true;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) return true;
+
+        if (this.id == null) return false;
+
+        if (o == null || getClass() != o.getClass()) return false;
+
+        AbstractIdentifiableEntity that = (AbstractIdentifiableEntity) o;
+
+        if (!getId().equals(that.getId())) return false;
+
+        return true;
+
+    }
+
+    @Override
+    public int hashCode() {
+        return id!=null ? id.hashCode() : super.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s [ id=%s ]", getClass().getSimpleName(), getId());
+    }
+
+}
+
diff --git a/server-spi/src/main/java/org/keycloak/storage/changeset/UserDataAdapter.java b/server-spi/src/main/java/org/keycloak/storage/changeset/UserDataAdapter.java
new file mode 100644
index 0000000..6ec78f2
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/changeset/UserDataAdapter.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.changeset;
+
+import org.keycloak.common.util.Time;
+import org.keycloak.hash.PasswordHashManager;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.OTPPolicy;
+import org.keycloak.models.PasswordPolicy;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleContainerModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserCredentialValueModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ *
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class UserDataAdapter implements UserModel {
+    protected UserData userData;
+    protected RealmModel realm;
+    protected KeycloakSession session;
+    protected Set<String> managedCredentialTypes;
+    protected List<UserCredentialModel> updatedManagedCredentials = new LinkedList<>();
+
+    public UserDataAdapter(KeycloakSession session, RealmModel realm, UserData userData) {
+        this.session = session;
+        this.realm = realm;
+        this.userData = userData;
+        this.userData.rememberState();
+    }
+
+    @Override
+    public String getId() {
+        return userData.getId();
+    }
+
+    @Override
+    public String getUsername() {
+        return userData.getUsername();
+    }
+
+    @Override
+    public void setUsername(String username) {
+        userData.setUsername(username);
+
+    }
+
+    @Override
+    public Long getCreatedTimestamp() {
+        return userData.getCreatedTimestamp();
+    }
+
+    @Override
+    public void setCreatedTimestamp(Long timestamp) {
+        userData.setCreatedTimestamp(timestamp);
+
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return userData.isEnabled();
+    }
+
+    @Override
+    public boolean isOtpEnabled() {
+        return userData.isTotp();
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        userData.setEnabled(enabled);
+
+    }
+
+    @Override
+    public void setSingleAttribute(String name, String value) {
+        userData.setSingleAttribute(name, value);
+
+    }
+
+    @Override
+    public void setAttribute(String name, List<String> values) {
+        userData.setAttribute(name, values);
+
+    }
+
+    @Override
+    public void removeAttribute(String name) {
+        userData.removeAttribute(name);
+
+    }
+
+    @Override
+    public String getFirstAttribute(String name) {
+        return userData.getAttributes().getFirst(name);
+    }
+
+    @Override
+    public List<String> getAttribute(String name) {
+        return userData.getAttributes().get(name);
+    }
+
+    @Override
+    public Map<String, List<String>> getAttributes() {
+        return userData.getAttributes();
+    }
+
+    @Override
+    public Set<String> getRequiredActions() {
+        return userData.getRequiredActions();
+    }
+
+    @Override
+    public void addRequiredAction(String action) {
+        userData.addRequiredAction(action);
+
+    }
+
+    @Override
+    public void removeRequiredAction(String action) {
+        userData.removeRequiredAction(action);
+
+    }
+
+    @Override
+    public void addRequiredAction(RequiredAction action) {
+        userData.addRequiredAction(action.name());
+
+    }
+
+    @Override
+    public void removeRequiredAction(RequiredAction action) {
+        userData.removeRequiredAction(action.name());
+
+    }
+
+    @Override
+    public String getFirstName() {
+        return userData.getFirstName();
+    }
+
+    @Override
+    public void setFirstName(String firstName) {
+        userData.setFirstName(firstName);
+
+    }
+
+    @Override
+    public String getLastName() {
+        return userData.getLastName();
+    }
+
+    @Override
+    public void setLastName(String lastName) {
+        userData.setLastName(lastName);
+
+    }
+
+    @Override
+    public String getEmail() {
+        return userData.getEmail();
+    }
+
+    @Override
+    public void setEmail(String email) {
+        userData.setEmail(email);
+
+    }
+
+    @Override
+    public boolean isEmailVerified() {
+        return userData.isEmailVerified();
+    }
+
+    @Override
+    public void setEmailVerified(boolean verified) {
+        userData.setEmailVerified(verified);
+
+    }
+
+    @Override
+    public void setOtpEnabled(boolean totp) {
+        userData.setTotp(totp);
+
+    }
+
+    @Override
+    public void updateCredential(UserCredentialModel cred) {
+
+    }
+
+    @Override
+    public List<UserCredentialValueModel> getCredentialsDirectly() {
+        return null;
+    }
+
+    @Override
+    public void updateCredentialDirectly(UserCredentialValueModel cred) {
+
+    }
+
+    @Override
+    public Set<GroupModel> getGroups() {
+        Set<String> groups = userData.getGroupIds();
+        Set<GroupModel> set = new HashSet<>();
+        for (String id : groups) {
+            GroupModel group = realm.getGroupById(id);
+            if (group != null) set.add(group);
+        }
+        return set;
+    }
+
+    @Override
+    public void joinGroup(GroupModel group) {
+        userData.joinGroup(group.getId());
+
+    }
+
+    @Override
+    public void leaveGroup(GroupModel group) {
+        userData.leaveGroup(group.getId());
+
+    }
+
+    @Override
+    public boolean isMemberOf(GroupModel group) {
+        Set<GroupModel> roles = getGroups();
+        return KeycloakModelUtils.isMember(roles, group);
+    }
+
+    @Override
+    public String getFederationLink() {
+        return null;
+    }
+
+    @Override
+    public void setFederationLink(String link) {
+
+    }
+
+    @Override
+    public String getServiceAccountClientLink() {
+        return null;
+    }
+
+    @Override
+    public void setServiceAccountClientLink(String clientInternalId) {
+
+    }
+
+    @Override
+    public Set<RoleModel> getRealmRoleMappings() {
+        Set<RoleModel> roleMappings = getRoleMappings();
+
+        Set<RoleModel> realmRoles = new HashSet<RoleModel>();
+        for (RoleModel role : roleMappings) {
+            RoleContainerModel container = role.getContainer();
+            if (container instanceof RealmModel) {
+                realmRoles.add(role);
+            }
+        }
+        return realmRoles;
+    }
+
+    @Override
+    public Set<RoleModel> getClientRoleMappings(ClientModel app) {
+        Set<RoleModel> roleMappings = getRoleMappings();
+
+        Set<RoleModel> roles = new HashSet<RoleModel>();
+        for (RoleModel role : roleMappings) {
+            RoleContainerModel container = role.getContainer();
+            if (container instanceof ClientModel) {
+                ClientModel appModel = (ClientModel)container;
+                if (appModel.getId().equals(app.getId())) {
+                    roles.add(role);
+                }
+            }
+        }
+        return roles;
+    }
+
+    @Override
+    public boolean hasRole(RoleModel role) {
+        Set<RoleModel> roles = getRoleMappings();
+        return KeycloakModelUtils.hasRole(roles, role);
+    }
+
+    @Override
+    public void grantRole(RoleModel role) {
+        userData.grantRole(role.getId());
+
+    }
+
+    @Override
+    public Set<RoleModel> getRoleMappings() {
+        Set<String> roles = userData.getRoleMappings();
+        Set<RoleModel> set = new HashSet<>();
+        for (String id : roles) {
+            RoleModel role = realm.getRoleById(id);
+            if (role != null) set.add(role);
+        }
+        return set;
+    }
+
+    @Override
+    public void deleteRoleMapping(RoleModel role) {
+        userData.deleteRoleMapping(role.getId());
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/federated/UserAttributeFederatedStorage.java b/server-spi/src/main/java/org/keycloak/storage/federated/UserAttributeFederatedStorage.java
new file mode 100644
index 0000000..08755da
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/federated/UserAttributeFederatedStorage.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.federated;
+
+import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface UserAttributeFederatedStorage {
+    void setSingleAttribute(RealmModel realm, UserModel user, String name, String value);
+    void setAttribute(RealmModel realm, UserModel user, String name, List<String> values);
+    void removeAttribute(RealmModel realm, UserModel user, String name);
+    MultivaluedHashMap<String, String> getAttributes(RealmModel realm, UserModel user);
+    List<String> getUsersByUserAttribute(RealmModel realm, String name, String value);
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/federated/UserBrokerLinkFederatedStorage.java b/server-spi/src/main/java/org/keycloak/storage/federated/UserBrokerLinkFederatedStorage.java
new file mode 100644
index 0000000..6fcbabf
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/federated/UserBrokerLinkFederatedStorage.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.federated;
+
+import org.keycloak.models.FederatedIdentityModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface UserBrokerLinkFederatedStorage {
+    String getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm);
+    public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel socialLink);
+    public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider);
+    void updateFederatedIdentity(RealmModel realm, UserModel federatedUser, FederatedIdentityModel federatedIdentityModel);
+    Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm);
+    FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm);
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/federated/UserConsentFederatedStorage.java b/server-spi/src/main/java/org/keycloak/storage/federated/UserConsentFederatedStorage.java
new file mode 100644
index 0000000..7a14b14
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/federated/UserConsentFederatedStorage.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.federated;
+
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserConsentModel;
+import org.keycloak.models.UserModel;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface UserConsentFederatedStorage {
+    void addConsent(RealmModel realm, UserModel user, UserConsentModel consent);
+    UserConsentModel getConsentByClient(RealmModel realm, UserModel user, String clientInternalId);
+    List<UserConsentModel> getConsents(RealmModel realm, UserModel user);
+    void updateConsent(RealmModel realm, UserModel user, UserConsentModel consent);
+    boolean revokeConsentForClient(RealmModel realm, UserModel user, String clientInternalId);
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/federated/UserCredentialsFederatedStorage.java b/server-spi/src/main/java/org/keycloak/storage/federated/UserCredentialsFederatedStorage.java
new file mode 100644
index 0000000..7239182
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/federated/UserCredentialsFederatedStorage.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.federated;
+
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserCredentialValueModel;
+import org.keycloak.models.UserModel;
+
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface UserCredentialsFederatedStorage {
+    void updateCredential(RealmModel realm, UserModel user, UserCredentialModel cred);
+    void updateCredential(RealmModel realm, UserModel user, UserCredentialValueModel cred);
+    void removeCredential(RealmModel realm, UserModel user, UserCredentialValueModel cred);
+    List<UserCredentialValueModel> getCredentials(RealmModel realm, UserModel user);
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/federated/UserFederatedStorageProvider.java b/server-spi/src/main/java/org/keycloak/storage/federated/UserFederatedStorageProvider.java
new file mode 100755
index 0000000..b604991
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/federated/UserFederatedStorageProvider.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.storage.federated;
+
+import org.keycloak.component.ComponentModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserFederationProviderModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.provider.Provider;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface UserFederatedStorageProvider extends Provider,
+        UserAttributeFederatedStorage,
+        UserBrokerLinkFederatedStorage,
+        UserConsentFederatedStorage,
+        UserCredentialsFederatedStorage,
+        UserGroupMembershipFederatedStorage,
+        UserRequiredActionsFederatedStorage,
+        UserRoleMappingsFederatedStorage {
+
+    void preRemove(RealmModel realm);
+
+    void preRemove(RealmModel realm, UserFederationProviderModel link);
+
+    void preRemove(RealmModel realm, GroupModel group);
+
+    void preRemove(RealmModel realm, RoleModel role);
+
+    void preRemove(RealmModel realm, ClientModel client);
+
+    void preRemove(ProtocolMapperModel protocolMapper);
+
+    void preRemove(RealmModel realm, UserModel user);
+
+    void preRemove(RealmModel realm, ComponentModel model);
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/federated/UserFederatedStorageProviderFactory.java b/server-spi/src/main/java/org/keycloak/storage/federated/UserFederatedStorageProviderFactory.java
new file mode 100644
index 0000000..667542c
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/federated/UserFederatedStorageProviderFactory.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.federated;
+
+import org.keycloak.provider.ProviderFactory;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface UserFederatedStorageProviderFactory extends ProviderFactory<UserFederatedStorageProvider> {
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/federated/UserFederatedStorageProviderSpi.java b/server-spi/src/main/java/org/keycloak/storage/federated/UserFederatedStorageProviderSpi.java
new file mode 100755
index 0000000..21b1ad0
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/federated/UserFederatedStorageProviderSpi.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.storage.federated;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class UserFederatedStorageProviderSpi implements Spi {
+
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "userFederatedStorage";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return UserFederatedStorageProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return UserFederatedStorageProviderFactory.class;
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/federated/UserGroupMembershipFederatedStorage.java b/server-spi/src/main/java/org/keycloak/storage/federated/UserGroupMembershipFederatedStorage.java
new file mode 100644
index 0000000..dad2399
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/federated/UserGroupMembershipFederatedStorage.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.federated;
+
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface UserGroupMembershipFederatedStorage {
+    Set<GroupModel> getGroups(RealmModel realm, UserModel user);
+    void joinGroup(RealmModel realm,UserModel user, GroupModel group);
+    void leaveGroup(RealmModel realm,UserModel user, GroupModel group);
+    List<String> getMembership(RealmModel realm, GroupModel group, int firstResult, int max);
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/federated/UserRequiredActionsFederatedStorage.java b/server-spi/src/main/java/org/keycloak/storage/federated/UserRequiredActionsFederatedStorage.java
new file mode 100644
index 0000000..1e14f78
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/federated/UserRequiredActionsFederatedStorage.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.federated;
+
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface UserRequiredActionsFederatedStorage {
+    Set<String> getRequiredActions(RealmModel realm, UserModel user);
+    void addRequiredAction(RealmModel realm,UserModel user, String action);
+    void removeRequiredAction(RealmModel realm,UserModel user, String action);
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/federated/UserRoleMappingsFederatedStorage.java b/server-spi/src/main/java/org/keycloak/storage/federated/UserRoleMappingsFederatedStorage.java
new file mode 100644
index 0000000..f63d9ec
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/federated/UserRoleMappingsFederatedStorage.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.federated;
+
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface UserRoleMappingsFederatedStorage {
+
+    void grantRole(RealmModel realm,UserModel user, RoleModel role);
+
+    Set<RoleModel> getRoleMappings(RealmModel realm,UserModel user);
+
+    void deleteRoleMapping(RealmModel realm, UserModel user, RoleModel role);
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/StorageId.java b/server-spi/src/main/java/org/keycloak/storage/StorageId.java
new file mode 100644
index 0000000..ab44e47
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/StorageId.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage;
+
+import org.keycloak.component.ComponentModel;
+import org.keycloak.models.UserModel;
+
+import java.io.Serializable;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class StorageId implements Serializable {
+    private String id;
+    private String providerId;
+    private String externalId;
+
+
+    public StorageId(String id) {
+        this.id = id;
+        if (!id.startsWith("f:")) {
+            externalId = id;
+            return;
+        }
+        int providerIndex = id.indexOf(':', 2);
+        providerId = id.substring(2, providerIndex);
+        externalId = id.substring(providerIndex + 1);
+
+    }
+
+    public StorageId(String providerId, String externalId) {
+        this.id = "f:" + providerId + ":" + externalId;
+        this.providerId = providerId;
+        this.externalId = externalId;
+    }
+
+    /**
+     * generate the id string that should be returned by UserModel.getId()
+     *
+     * @param model
+     * @param externalId id used to resolve user in external storage
+     * @return
+     */
+    public static String keycloakId(ComponentModel model, String externalId) {
+        return new StorageId(model.getId(), externalId).getId();
+    }
+
+    public static String externalId(String keycloakId) {
+        return new StorageId(keycloakId).getExternalId();
+    }
+
+
+
+    public static String resolveProviderId(UserModel user) {
+        return new StorageId(user.getId()).getProviderId();
+    }
+    public static boolean isLocalStorage(UserModel user) {
+        return new StorageId(user.getId()).getProviderId() == null;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public String getProviderId() {
+        return providerId;
+    }
+
+    public String getExternalId() {
+        return externalId;
+    }
+
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/user/UserCredentialAuthenticationProvider.java b/server-spi/src/main/java/org/keycloak/storage/user/UserCredentialAuthenticationProvider.java
new file mode 100644
index 0000000..948ef47
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/user/UserCredentialAuthenticationProvider.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.user;
+
+import org.keycloak.models.CredentialValidationOutput;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserCredentialModel;
+
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface UserCredentialAuthenticationProvider {
+    Set<String> getSupportedCredentialAuthenticationTypes();
+    CredentialValidationOutput validCredential(KeycloakSession session, RealmModel realm, UserCredentialModel input);
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/user/UserCredentialValidatorProvider.java b/server-spi/src/main/java/org/keycloak/storage/user/UserCredentialValidatorProvider.java
new file mode 100644
index 0000000..4c3d897
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/user/UserCredentialValidatorProvider.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.user;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserModel;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface UserCredentialValidatorProvider {
+    boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, List<UserCredentialModel> input);
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/user/UserLookupProvider.java b/server-spi/src/main/java/org/keycloak/storage/user/UserLookupProvider.java
new file mode 100644
index 0000000..0399862
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/user/UserLookupProvider.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.user;
+
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface UserLookupProvider {
+    UserModel getUserById(String id, RealmModel realm);
+
+    UserModel getUserByUsername(String username, RealmModel realm);
+
+    UserModel getUserByEmail(String email, RealmModel realm);
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/user/UserQueryProvider.java b/server-spi/src/main/java/org/keycloak/storage/user/UserQueryProvider.java
new file mode 100644
index 0000000..877b09f
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/user/UserQueryProvider.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.user;
+
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface UserQueryProvider {
+
+    int getUsersCount(RealmModel realm);
+
+    List<UserModel> getUsers(RealmModel realm);
+    List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults);
+
+    /**
+     * Search for users with username, email or first + last name that is like search string.
+     *
+     * If possible, implementations should treat the parameter values as partial match patterns i.e. in RDMBS terms use LIKE.
+     *
+     * This method is used by the admin console search box
+     *
+     * @param search
+     * @param realm
+     * @return
+     */
+    List<UserModel> searchForUser(String search, RealmModel realm);
+
+    /**
+     * Search for users with username, email or first + last name that is like search string.
+     *
+     * If possible, implementations should treat the parameter values as partial match patterns i.e. in RDMBS terms use LIKE.
+     *
+     * This method is used by the admin console search box
+     *
+     * @param search
+     * @param realm
+     * @param firstResult
+     * @param maxResults
+     * @return
+     */
+    List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults);
+
+    /**
+     * Search for user by parameter.  Valid parameters are:
+     * "first" - first name
+     * "last" - last name
+     * "email" - email
+     * "username" - username
+     *
+     * If possible, implementations should treat the parameter values as partial match patterns i.e. in RDMBS terms use LIKE.
+     *
+     * This method is used by the REST API when querying users.
+     *
+     *
+     * @param params
+     * @param realm
+     * @return
+     */
+    List<UserModel> searchForUser(Map<String, String> params, RealmModel realm);
+
+    /**
+     * Search for user by parameter.  Valid parameters are:
+     * "first" - first name
+     * "last" - last name
+     * "email" - email
+     * "username" - username
+     *
+     * If possible, implementations should treat the parameter values as patterns i.e. in RDMBS terms use LIKE.
+     * This method is used by the REST API when querying users.
+     *
+     *
+     * @param params
+     * @param realm
+     * @param firstResult
+     * @param maxResults
+     * @return
+     */
+    List<UserModel> searchForUser(Map<String, String> params, RealmModel realm, int firstResult, int maxResults);
+
+    List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults);
+    List<UserModel> getGroupMembers(RealmModel realm, GroupModel group);
+
+
+    // Searching by UserModel.attribute (not property)
+    List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm);
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/user/UserRegistrationProvider.java b/server-spi/src/main/java/org/keycloak/storage/user/UserRegistrationProvider.java
new file mode 100644
index 0000000..7697042
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/user/UserRegistrationProvider.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage.user;
+
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface UserRegistrationProvider {
+
+    UserModel addUser(RealmModel realm, String username);
+
+    boolean removeUser(RealmModel realm, UserModel user);
+
+    void grantToAllUsers(RealmModel realm, RoleModel role);
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/UserStorageManager.java b/server-spi/src/main/java/org/keycloak/storage/UserStorageManager.java
new file mode 100755
index 0000000..1a1fca5
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/UserStorageManager.java
@@ -0,0 +1,612 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.storage;
+
+import org.jboss.logging.Logger;
+import org.keycloak.common.util.reflections.Types;
+import org.keycloak.component.ComponentModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.CredentialValidationOutput;
+import org.keycloak.models.FederatedIdentityModel;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ModelException;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserConsentModel;
+import org.keycloak.storage.user.UserCredentialAuthenticationProvider;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.storage.user.UserCredentialValidatorProvider;
+import org.keycloak.models.UserCredentialValueModel;
+import org.keycloak.models.UserFederationProviderModel;
+import org.keycloak.storage.user.UserLookupProvider;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserProvider;
+import org.keycloak.storage.user.UserQueryProvider;
+import org.keycloak.storage.user.UserRegistrationProvider;
+import org.keycloak.models.utils.CredentialValidation;
+import org.keycloak.storage.federated.UserFederatedStorageProvider;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class UserStorageManager implements UserProvider {
+
+    private static final Logger logger = Logger.getLogger(UserStorageManager.class);
+
+    protected KeycloakSession session;
+
+    public UserStorageManager(KeycloakSession session) {
+        this.session = session;
+    }
+
+    protected UserProvider localStorage() {
+        return session.userLocalStorage();
+    }
+
+    protected List<UserStorageProviderModel> getStorageProviders(RealmModel realm) {
+        return realm.getUserStorageProviders();
+    }
+
+    protected <T> T getFirstStorageProvider(RealmModel realm, Class<T> type) {
+        for (UserStorageProviderModel model : getStorageProviders(realm)) {
+            UserStorageProviderFactory factory = (UserStorageProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, model.getProviderId());
+
+            if (Types.supports(type, factory, UserStorageProviderFactory.class)) {
+                return type.cast(getStorageProviderInstance(model, factory));
+            }
+        }
+        return null;
+    }
+
+    private UserStorageProvider getStorageProviderInstance(UserStorageProviderModel model, UserStorageProviderFactory factory) {
+        UserStorageProvider instance = (UserStorageProvider)session.getAttribute(model.getId());
+        if (instance != null) return instance;
+        instance = factory.create(session, model);
+        session.enlistForClose(instance);
+        session.setAttribute(model.getId(), instance);
+        return instance;
+    }
+
+
+    protected <T> List<T> getStorageProviders(RealmModel realm, Class<T> type) {
+        List<T> list = new LinkedList<>();
+        for (UserStorageProviderModel model : getStorageProviders(realm)) {
+            UserStorageProviderFactory factory = (UserStorageProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, model.getProviderId());
+            if (Types.supports(type, factory, UserStorageProviderFactory.class)) {
+                list.add(type.cast(getStorageProviderInstance(model, factory)));
+            }
+
+
+        }
+        return list;
+    }
+
+
+    @Override
+    public UserModel addUser(RealmModel realm, String id, String username, boolean addDefaultRoles, boolean addDefaultRequiredActions) {
+        return localStorage().addUser(realm, id, username.toLowerCase(), addDefaultRoles, addDefaultRequiredActions);
+    }
+
+    @Override
+    public UserModel addUser(RealmModel realm, String username) {
+        UserRegistrationProvider registry = getFirstStorageProvider(realm, UserRegistrationProvider.class);
+        if (registry != null) {
+            return registry.addUser(realm, username);
+        }
+        return localStorage().addUser(realm, username.toLowerCase());
+    }
+
+    public UserStorageProvider getStorageProvider(RealmModel realm, String componentId) {
+        ComponentModel model = realm.getComponent(componentId);
+        if (model == null) return null;
+        UserStorageProviderFactory factory = (UserStorageProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(UserStorageProvider.class, model.getProviderId());
+        if (factory == null) {
+            throw new ModelException("Could not find UserStorageProviderFactory for: " + model.getProviderId());
+        }
+        return getStorageProviderInstance(new UserStorageProviderModel(model), factory);
+    }
+
+    @Override
+    public boolean removeUser(RealmModel realm, UserModel user) {
+        getFederatedStorage().preRemove(realm, user);
+        StorageId storageId = new StorageId(user.getId());
+        if (storageId.getProviderId() == null) {
+            return localStorage().removeUser(realm, user);
+        }
+        UserRegistrationProvider registry = (UserRegistrationProvider)getStorageProvider(realm, storageId.getProviderId());
+        if (registry == null) {
+            throw new ModelException("Could not resolve StorageProvider: " + storageId.getProviderId());
+        }
+        return registry.removeUser(realm, user);
+
+    }
+
+    public UserFederatedStorageProvider getFederatedStorage() {
+        return session.userFederatedStorage();
+    }
+
+    @Override
+    public void addFederatedIdentity(RealmModel realm, UserModel user, FederatedIdentityModel socialLink) {
+        if (StorageId.isLocalStorage(user)) {
+            localStorage().addFederatedIdentity(realm, user, socialLink);
+        } else {
+            getFederatedStorage().addFederatedIdentity(realm, user, socialLink);
+        }
+    }
+
+    public void updateFederatedIdentity(RealmModel realm, UserModel federatedUser, FederatedIdentityModel federatedIdentityModel) {
+        if (StorageId.isLocalStorage(federatedUser)) {
+            localStorage().updateFederatedIdentity(realm, federatedUser, federatedIdentityModel);
+
+        } else {
+            getFederatedStorage().updateFederatedIdentity(realm, federatedUser, federatedIdentityModel);
+        }
+    }
+
+    @Override
+    public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider) {
+        if (StorageId.isLocalStorage(user)) {
+            return localStorage().removeFederatedIdentity(realm, user, socialProvider);
+        } else {
+            return getFederatedStorage().removeFederatedIdentity(realm, user, socialProvider);
+        }
+    }
+
+    @Override
+    public void addConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
+        if (StorageId.isLocalStorage(user)) {
+            localStorage().addConsent(realm, user, consent);
+        } else {
+            getFederatedStorage().addConsent(realm, user, consent);
+        }
+
+    }
+
+    @Override
+    public UserConsentModel getConsentByClient(RealmModel realm, UserModel user, String clientInternalId) {
+        if (StorageId.isLocalStorage(user)) {
+            return localStorage().getConsentByClient(realm, user, clientInternalId);
+        } else {
+            return getFederatedStorage().getConsentByClient(realm, user, clientInternalId);
+        }
+    }
+
+    @Override
+    public List<UserConsentModel> getConsents(RealmModel realm, UserModel user) {
+        if (StorageId.isLocalStorage(user)) {
+            return localStorage().getConsents(realm, user);
+
+        } else {
+            return getFederatedStorage().getConsents(realm, user);
+        }
+    }
+
+    @Override
+    public void updateConsent(RealmModel realm, UserModel user, UserConsentModel consent) {
+        if (StorageId.isLocalStorage(user)) {
+            localStorage().updateConsent(realm, user, consent);
+        } else {
+            getFederatedStorage().updateConsent(realm, user, consent);
+        }
+
+    }
+
+    @Override
+    public boolean revokeConsentForClient(RealmModel realm, UserModel user, String clientInternalId) {
+        if (StorageId.isLocalStorage(user)) {
+            return localStorage().revokeConsentForClient(realm, user, clientInternalId);
+        } else {
+            return getFederatedStorage().revokeConsentForClient(realm, user, clientInternalId);
+        }
+    }
+
+    @Override
+    public UserModel getUserById(String id, RealmModel realm) {
+        StorageId storageId = new StorageId(id);
+        if (storageId.getProviderId() == null) {
+            return localStorage().getUserById(id, realm);
+        }
+        UserLookupProvider provider = (UserLookupProvider)getStorageProvider(realm, storageId.getProviderId());
+        return provider.getUserById(id, realm);
+    }
+
+    @Override
+    public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) {
+        return getGroupMembers(realm, group, -1, -1);
+    }
+
+    @Override
+    public UserModel getUserByUsername(String username, RealmModel realm) {
+        UserModel user = localStorage().getUserByUsername(username, realm);
+        if (user != null) return user;
+        for (UserLookupProvider provider : getStorageProviders(realm, UserLookupProvider.class)) {
+            user = provider.getUserByUsername(username, realm);
+            if (user != null) return user;
+        }
+        return null;
+    }
+
+    @Override
+    public UserModel getUserByEmail(String email, RealmModel realm) {
+        UserModel user = localStorage().getUserByEmail(email, realm);
+        if (user != null) return user;
+        for (UserLookupProvider provider : getStorageProviders(realm, UserLookupProvider.class)) {
+            user = provider.getUserByEmail(email, realm);
+            if (user != null) return user;
+        }
+        return null;
+    }
+
+    @Override
+    public UserModel getUserByFederatedIdentity(FederatedIdentityModel socialLink, RealmModel realm) {
+        UserModel user = localStorage().getUserByFederatedIdentity(socialLink, realm);
+        if (user != null) {
+            return user;
+        }
+        String id = getFederatedStorage().getUserByFederatedIdentity(socialLink, realm);
+        if (id != null) return getUserById(id, realm);
+        return null;
+    }
+
+    @Override
+    public UserModel getServiceAccount(ClientModel client) {
+        return localStorage().getServiceAccount(client);
+    }
+
+    @Override
+    public List<UserModel> getUsers(RealmModel realm, boolean includeServiceAccounts) {
+        return getUsers(realm, 0, Integer.MAX_VALUE - 1, includeServiceAccounts);
+
+    }
+
+    @Override
+    public List<UserModel> getUsers(RealmModel realm) {
+        return getUsers(realm, false);
+    }
+
+    @Override
+    public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) {
+        return getUsers(realm, firstResult, maxResults, false);
+    }
+
+    @Override
+    public int getUsersCount(RealmModel realm) {
+        int size = localStorage().getUsersCount(realm);
+        for (UserQueryProvider provider : getStorageProviders(realm, UserQueryProvider.class)) {
+            size += provider.getUsersCount(realm);
+        }
+        return size;
+    }
+
+    @FunctionalInterface
+    interface PaginatedQuery {
+        List<UserModel> query(Object provider, int first, int max);
+    }
+
+    protected List<UserModel> query(PaginatedQuery pagedQuery, RealmModel realm, int firstResult, int maxResults) {
+        if (maxResults == 0) return Collections.EMPTY_LIST;
+
+
+
+        List<UserQueryProvider> storageProviders = getStorageProviders(realm, UserQueryProvider.class);
+        // we can skip rest of method if there are no storage providers
+        if (storageProviders.isEmpty()) {
+            return pagedQuery.query(localStorage(), firstResult, maxResults);
+        }
+        LinkedList<Object> providers = new LinkedList<>();
+        List<UserModel> results = new LinkedList<UserModel>();
+        providers.add(localStorage());
+        providers.addAll(storageProviders);
+        providers.add(getFederatedStorage());
+
+        int leftToRead = maxResults;
+        int leftToFirstResult = firstResult;
+
+        Iterator<Object> it = providers.iterator();
+        while (it.hasNext() && leftToRead != 0) {
+            Object provider = it.next();
+            boolean exhausted = false;
+            int index = 0;
+            if (leftToFirstResult > 0) {
+                do {
+                    int toRead = Math.min(50, leftToFirstResult);
+                    List<UserModel> tmp = pagedQuery.query(provider, index, toRead);
+                    leftToFirstResult -= tmp.size();
+                    index += tmp.size();
+                    if (tmp.size() < toRead) {
+                        exhausted = true;
+                        break;
+                    }
+                } while (leftToFirstResult > 0);
+            }
+            if (exhausted) continue;
+            List<UserModel> tmp = pagedQuery.query(provider, index, leftToRead);
+            results.addAll(tmp);
+            if (leftToRead > 0) leftToRead -= tmp.size();
+        }
+
+        return results;
+    }
+
+    @Override
+    public List<UserModel> getUsers(final RealmModel realm, int firstResult, int maxResults, final boolean includeServiceAccounts) {
+        return query((provider, first, max) -> {
+            if (provider instanceof UserProvider) { // it is local storage
+                return ((UserProvider) provider).getUsers(realm, first, max, includeServiceAccounts);
+            } else if (provider instanceof UserQueryProvider) {
+                return ((UserQueryProvider)provider).getUsers(realm, first, max);
+
+            }
+            return Collections.EMPTY_LIST;
+        }
+        , realm, firstResult, maxResults);
+    }
+
+    @Override
+    public List<UserModel> searchForUser(String search, RealmModel realm) {
+        return searchForUser(search, realm, 0, Integer.MAX_VALUE - 1);
+    }
+
+    @Override
+    public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) {
+        return query((provider, first, max) -> {
+            if (provider instanceof UserQueryProvider) {
+                return ((UserQueryProvider)provider).searchForUser(search, realm, first, max);
+
+            }
+            return Collections.EMPTY_LIST;
+        }, realm, firstResult, maxResults);
+    }
+
+    @Override
+    public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm) {
+        return searchForUser(attributes, realm, 0, Integer.MAX_VALUE - 1);
+    }
+
+    @Override
+    public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
+        return query((provider, first, max) -> {
+            if (provider instanceof UserQueryProvider) {
+                return ((UserQueryProvider)provider).searchForUser(attributes, realm, first, max);
+
+            }
+            return Collections.EMPTY_LIST;
+        }
+        , realm, firstResult, maxResults);
+    }
+
+    @Override
+    public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) {
+        List<UserModel> results = query((provider, first, max) -> {
+            if (provider instanceof UserQueryProvider) {
+                return ((UserQueryProvider)provider).searchForUserByUserAttribute(attrName, attrValue, realm);
+
+            } else if (provider instanceof UserFederatedStorageProvider) {
+                List<String> ids = ((UserFederatedStorageProvider)provider).getUsersByUserAttribute(realm, attrName, attrValue);
+                List<UserModel> rs = new LinkedList<>();
+                for (String id : ids) {
+                    UserModel user = getUserById(id, realm);
+                    if (user != null) rs.add(user);
+                }
+                return rs;
+
+            }
+            return Collections.EMPTY_LIST;
+        }, realm,0, Integer.MAX_VALUE - 1);
+        return results;
+    }
+
+    @Override
+    public Set<FederatedIdentityModel> getFederatedIdentities(UserModel user, RealmModel realm) {
+        if (user == null) throw new IllegalStateException("Federated user no longer valid");
+        Set<FederatedIdentityModel> set = new HashSet<>();
+        if (StorageId.isLocalStorage(user)) {
+            set.addAll(localStorage().getFederatedIdentities(user, realm));
+        }
+        set.addAll(getFederatedStorage().getFederatedIdentities(user, realm));
+        return set;
+    }
+
+    @Override
+    public FederatedIdentityModel getFederatedIdentity(UserModel user, String socialProvider, RealmModel realm) {
+        if (user == null) throw new IllegalStateException("Federated user no longer valid");
+        if (StorageId.isLocalStorage(user)) {
+            FederatedIdentityModel model = localStorage().getFederatedIdentity(user, socialProvider, realm);
+            if (model != null) return model;
+        }
+        return getFederatedStorage().getFederatedIdentity(user, socialProvider, realm);
+    }
+
+    @Override
+    public void grantToAllUsers(RealmModel realm, RoleModel role) {
+        // not federation-aware for now
+        List<UserRegistrationProvider> storageProviders = getStorageProviders(realm, UserRegistrationProvider.class);
+        LinkedList<UserRegistrationProvider> providers = new LinkedList<>();
+        providers.add(localStorage());
+        providers.addAll(storageProviders);
+        for (UserRegistrationProvider provider : providers) {
+            provider.grantToAllUsers(realm, role);
+        }
+    }
+
+    @Override
+    public List<UserModel> getGroupMembers(final RealmModel realm, final GroupModel group, int firstResult, int maxResults) {
+        List<UserModel> results = query((provider, first, max) -> {
+            if (provider instanceof UserQueryProvider) {
+                return ((UserQueryProvider)provider).getGroupMembers(realm, group, first, max);
+
+            } else if (provider instanceof UserFederatedStorageProvider) {
+                List<String> ids = ((UserFederatedStorageProvider)provider).getMembership(realm, group, first, max);
+                List<UserModel> rs = new LinkedList<UserModel>();
+                for (String id : ids) {
+                    UserModel user = getUserById(id, realm);
+                    if (user != null) rs.add(user);
+                }
+                return rs;
+
+            }
+            return Collections.EMPTY_LIST;
+        }, realm, firstResult, maxResults);
+        return results;
+    }
+
+
+    @Override
+    public void preRemove(RealmModel realm) {
+        localStorage().preRemove(realm);
+        getFederatedStorage().preRemove(realm);
+        for (UserStorageProvider provider : getStorageProviders(realm, UserStorageProvider.class)) {
+            provider.preRemove(realm);
+        }
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, UserFederationProviderModel model) {
+        getFederatedStorage().preRemove(realm, model);
+        localStorage().preRemove(realm, model);
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, GroupModel group) {
+        localStorage().preRemove(realm, group);
+        getFederatedStorage().preRemove(realm, group);
+        for (UserStorageProvider provider : getStorageProviders(realm, UserStorageProvider.class)) {
+            provider.preRemove(realm, group);
+        }
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, RoleModel role) {
+        localStorage().preRemove(realm, role);
+        getFederatedStorage().preRemove(realm, role);
+        for (UserStorageProvider provider : getStorageProviders(realm, UserStorageProvider.class)) {
+            provider.preRemove(realm, role);
+        }
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, ClientModel client) {
+        localStorage().preRemove(realm, client);
+        getFederatedStorage().preRemove(realm, client);
+
+    }
+
+    @Override
+    public void preRemove(ProtocolMapperModel protocolMapper) {
+        localStorage().preRemove(protocolMapper);
+        getFederatedStorage().preRemove(protocolMapper);
+    }
+
+    @Override
+    public boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, List<UserCredentialModel> input) {
+        if (StorageId.isLocalStorage(user)) {
+            return localStorage().validCredentials(session, realm, user, input);
+        }
+        // make sure we hit the cache here!
+        List<UserCredentialValueModel> userCreds = user.getCredentialsDirectly();
+
+        LinkedList<UserCredentialModel> toValidate = new LinkedList<>();
+        toValidate.addAll(input);
+        Iterator<UserCredentialModel> it = toValidate.iterator();
+        boolean failedStoredCredential = false;
+        // we allow for multiple credentials of same type, i.e. multiple OTP devices
+        while (it.hasNext()) {
+            UserCredentialModel cred = it.next();
+            boolean credValidated = false;
+            for (UserCredentialValueModel userCred : userCreds) {
+                if (!userCred.getType().equals(cred.getType())) continue;
+                if (CredentialValidation.validCredential(session, realm, user, cred)) {
+                    credValidated = true;
+                    break;
+                } else {
+                    failedStoredCredential = true;
+                }
+            }
+            if (credValidated) {
+                it.remove();
+            } else if (failedStoredCredential) {
+                return false;
+            }
+        }
+
+        if (toValidate.isEmpty()) return true;
+
+        UserStorageProvider provider = getStorageProvider(realm, StorageId.resolveProviderId(user));
+        if (!(provider instanceof UserCredentialValidatorProvider)) {
+            return false;
+        }
+        return ((UserCredentialValidatorProvider)provider).validCredentials(session, realm, user, toValidate);
+    }
+
+    @Override
+    public boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, UserCredentialModel... input) {
+        return validCredentials(session, realm, user, Arrays.asList(input));
+    }
+
+    @Override
+    public CredentialValidationOutput validCredentials(KeycloakSession session, RealmModel realm, UserCredentialModel... input) {
+        List<UserCredentialAuthenticationProvider> providers = getStorageProviders(realm, UserCredentialAuthenticationProvider.class);
+        if (providers.isEmpty()) return CredentialValidationOutput.failed();
+
+        CredentialValidationOutput result = null;
+        for (UserCredentialModel cred : input) {
+            UserCredentialAuthenticationProvider providerSupportingCreds = null;
+
+            // Find first provider, which supports required credential type
+            for (UserCredentialAuthenticationProvider provider : providers) {
+                if (provider.getSupportedCredentialAuthenticationTypes().contains(cred.getType())) {
+                    providerSupportingCreds = provider;
+                    break;
+                }
+            }
+
+            if (providerSupportingCreds == null) {
+                logger.warn("Don't have provider supporting credentials of type " + cred.getType());
+                return CredentialValidationOutput.failed();
+            }
+
+            logger.debug("Found provider [" + providerSupportingCreds + "] supporting credentials of type " + cred.getType());
+            CredentialValidationOutput currentResult = providerSupportingCreds.validCredential(session, realm, cred);
+            result = (result == null) ? currentResult : result.merge(currentResult);
+        }
+
+        // For now, validCredentials(realm, input) is not supported for local userProviders
+        return (result != null) ? result : CredentialValidationOutput.failed();
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, ComponentModel component) {
+
+    }
+
+    @Override
+    public void close() {
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/UserStorageProvider.java b/server-spi/src/main/java/org/keycloak/storage/UserStorageProvider.java
new file mode 100644
index 0000000..dbb4b3c
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/UserStorageProvider.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.storage;
+
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.provider.Provider;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface UserStorageProvider extends Provider {
+    void preRemove(RealmModel realm);
+    void preRemove(RealmModel realm, GroupModel group);
+    void preRemove(RealmModel realm, RoleModel role);
+}
+
diff --git a/server-spi/src/main/java/org/keycloak/storage/UserStorageProviderFactory.java b/server-spi/src/main/java/org/keycloak/storage/UserStorageProviderFactory.java
new file mode 100755
index 0000000..5102355
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/UserStorageProviderFactory.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.storage;
+
+import org.keycloak.Config;
+import org.keycloak.component.ComponentFactory;
+import org.keycloak.component.ComponentModel;
+import org.keycloak.component.ComponentValidationException;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.provider.ProviderConfigProperty;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface UserStorageProviderFactory<T extends UserStorageProvider> extends ComponentFactory<T, UserStorageProvider> {
+
+
+    /**
+     * called per Keycloak transaction.
+     *
+     * @param session
+     * @param model
+     * @return
+     */
+    T create(KeycloakSession session, ComponentModel model);
+
+    /**
+     * This is the name of the provider and will be showed in the admin console as an option.
+     *
+     * @return
+     */
+    @Override
+    String getId();
+
+    @Override
+    default void init(Config.Scope config) {
+
+    }
+
+    @Override
+    default void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    @Override
+    default void close() {
+
+    }
+
+    @Override
+    default String getHelpText() {
+        return "";
+    }
+
+    @Override
+    default List<ProviderConfigProperty> getConfigProperties() {
+        return Collections.EMPTY_LIST;
+    }
+
+    @Override
+    default void validateConfiguration(KeycloakSession session, ComponentModel config) throws ComponentValidationException {
+
+    }
+
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/UserStorageProviderModel.java b/server-spi/src/main/java/org/keycloak/storage/UserStorageProviderModel.java
new file mode 100755
index 0000000..351107f
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/UserStorageProviderModel.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.storage;
+
+import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.component.ComponentModel;
+import org.keycloak.models.RealmModel;
+
+import java.io.Serializable;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Stored configuration of a User Storage provider instance.
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ * @author <a href="mailto:bburke@redhat.com">Bill Burke</a>
+ */
+public class UserStorageProviderModel extends ComponentModel {
+
+    public static Comparator<UserStorageProviderModel> comparator = new Comparator<UserStorageProviderModel>() {
+        @Override
+        public int compare(UserStorageProviderModel o1, UserStorageProviderModel o2) {
+            return o1.getPriority() - o2.getPriority();
+        }
+    };
+
+    public UserStorageProviderModel() {
+        setProviderType(UserStorageProvider.class.getName());
+    }
+
+    public UserStorageProviderModel(ComponentModel copy) {
+        super(copy);
+    }
+
+    public int getPriority() {
+        String priority = getConfig().getFirst("priority");
+        if (priority == null) return 0;
+        return Integer.valueOf(priority);
+
+    }
+
+    public void setPriority(int priority) {
+        getConfig().putSingle("priority", Integer.toString(priority));
+    }
+}
diff --git a/server-spi/src/main/java/org/keycloak/storage/UserStorageProviderSpi.java b/server-spi/src/main/java/org/keycloak/storage/UserStorageProviderSpi.java
new file mode 100755
index 0000000..4027ea3
--- /dev/null
+++ b/server-spi/src/main/java/org/keycloak/storage/UserStorageProviderSpi.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.storage;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class UserStorageProviderSpi implements Spi {
+
+    @Override
+    public boolean isInternal() {
+        return false;
+    }
+
+    @Override
+    public String getName() {
+        return "storage";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return UserStorageProvider.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return UserStorageProviderFactory.class;
+    }
+
+}
diff --git a/server-spi/src/main/resources/META-INF/services/org.keycloak.policy.PasswordPolicyManagerProviderFactory b/server-spi/src/main/resources/META-INF/services/org.keycloak.policy.PasswordPolicyManagerProviderFactory
new file mode 100644
index 0000000..128272d
--- /dev/null
+++ b/server-spi/src/main/resources/META-INF/services/org.keycloak.policy.PasswordPolicyManagerProviderFactory
@@ -0,0 +1,18 @@
+#
+# Copyright 2016 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.keycloak.policy.DefaultPasswordPolicyManagerProviderFactory
\ No newline at end of file
diff --git a/server-spi/src/main/resources/META-INF/services/org.keycloak.policy.PasswordPolicyProviderFactory b/server-spi/src/main/resources/META-INF/services/org.keycloak.policy.PasswordPolicyProviderFactory
new file mode 100644
index 0000000..a436fe9
--- /dev/null
+++ b/server-spi/src/main/resources/META-INF/services/org.keycloak.policy.PasswordPolicyProviderFactory
@@ -0,0 +1,28 @@
+#
+# Copyright 2016 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.keycloak.policy.DigitsPasswordPolicyProviderFactory
+org.keycloak.policy.ForceExpiredPasswordPolicyProviderFactory
+org.keycloak.policy.HashAlgorithmPasswordPolicyProviderFactory
+org.keycloak.policy.HashIterationsPasswordPolicyProviderFactory
+org.keycloak.policy.HistoryPasswordPolicyProviderFactory
+org.keycloak.policy.LengthPasswordPolicyProviderFactory
+org.keycloak.policy.LowerCasePasswordPolicyProviderFactory
+org.keycloak.policy.NotUsernamePasswordPolicyProviderFactory
+org.keycloak.policy.RegexPatternsPasswordPolicyProviderFactory
+org.keycloak.policy.SpecialCharsPasswordPolicyProviderFactory
+org.keycloak.policy.UpperCasePasswordPolicyProviderFactory
diff --git a/server-spi/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/server-spi/src/main/resources/META-INF/services/org.keycloak.provider.Spi
index 657faaf..d2431d8 100755
--- a/server-spi/src/main/resources/META-INF/services/org.keycloak.provider.Spi
+++ b/server-spi/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -16,6 +16,8 @@
 #
 
 org.keycloak.models.UserFederationSpi
+org.keycloak.storage.UserStorageProviderSpi
+org.keycloak.storage.federated.UserFederatedStorageProviderSpi
 org.keycloak.mappers.UserFederationMapperSpi
 org.keycloak.models.RealmSpi
 org.keycloak.models.UserSessionSpi
@@ -29,6 +31,7 @@ org.keycloak.events.EventStoreSpi
 org.keycloak.exportimport.ExportSpi
 org.keycloak.exportimport.ImportSpi
 org.keycloak.timer.TimerSpi
+org.keycloak.scripting.ScriptingSpi
 org.keycloak.services.managers.BruteForceProtectorSpi
 org.keycloak.services.resource.RealmResourceSPI
 org.keycloak.protocol.ClientInstallationSpi
@@ -52,5 +55,10 @@ org.keycloak.authentication.RequiredActionSpi
 org.keycloak.authentication.FormAuthenticatorSpi
 org.keycloak.authentication.FormActionSpi
 org.keycloak.cluster.ClusterSpi
-
-
+org.keycloak.authorization.policy.provider.PolicySpi
+org.keycloak.authorization.store.StoreFactorySpi
+org.keycloak.authorization.AuthorizationSpi
+org.keycloak.models.cache.authorization.CachedStoreFactorySpi
+org.keycloak.protocol.oidc.TokenIntrospectionSpi
+org.keycloak.policy.PasswordPolicySpi
+org.keycloak.policy.PasswordPolicyManagerSpi
\ No newline at end of file

services/pom.xml 8(+7 -1)

diff --git a/services/pom.xml b/services/pom.xml
index 41ca54d..a8a009d 100755
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
@@ -32,6 +32,8 @@
 
     <properties>
         <version.swagger.doclet>1.0.5</version.swagger.doclet>
+        <maven.compiler.target>1.8</maven.compiler.target>
+        <maven.compiler.source>1.8</maven.compiler.source>
     </properties>
 
     <dependencies>
@@ -108,6 +110,10 @@
             <artifactId>jboss-jaxrs-api_2.0_spec</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.jboss.spec.javax.transaction</groupId>
+            <artifactId>jboss-transaction-api_1.2_spec</artifactId>
+        </dependency>
+        <dependency>
             <groupId>org.jboss.resteasy</groupId>
             <artifactId>resteasy-multipart-provider</artifactId>
         </dependency>
diff --git a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
index 68c0620..cd921bb 100755
--- a/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
+++ b/services/src/main/java/org/keycloak/authentication/AuthenticationProcessor.java
@@ -37,6 +37,7 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
 import org.keycloak.models.utils.FormMessage;
+import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.protocol.LoginProtocol;
 import org.keycloak.protocol.LoginProtocol.Error;
 import org.keycloak.protocol.oidc.TokenManager;
@@ -543,8 +544,10 @@ public class AuthenticationProcessor {
             if (username == null) {
 
             } else {
-                getBruteForceProtector().failedLogin(realm, username, connection);
-
+                UserModel user = KeycloakModelUtils.findUserByNameOrEmail(session, realm, username);
+                if (user != null) {
+                    getBruteForceProtector().failedLogin(realm, user, connection);
+                }
             }
         }
     }
@@ -851,7 +854,7 @@ public class AuthenticationProcessor {
         if (authenticatedUser == null) return;
         if (!authenticatedUser.isEnabled()) throw new AuthenticationFlowException(AuthenticationFlowError.USER_DISABLED);
         if (realm.isBruteForceProtected()) {
-            if (getBruteForceProtector().isTemporarilyDisabled(session, realm, authenticatedUser.getUsername())) {
+            if (getBruteForceProtector().isTemporarilyDisabled(session, realm, authenticatedUser)) {
                 throw new AuthenticationFlowException(AuthenticationFlowError.USER_TEMPORARILY_DISABLED);
             }
         }
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/AbstractUsernameFormAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/AbstractUsernameFormAuthenticator.java
index 137e370..ad4bb0b 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/browser/AbstractUsernameFormAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/AbstractUsernameFormAuthenticator.java
@@ -100,7 +100,7 @@ public abstract class AbstractUsernameFormAuthenticator extends AbstractFormAuth
             return false;
         }
         if (context.getRealm().isBruteForceProtected()) {
-            if (context.getProtector().isTemporarilyDisabled(context.getSession(), context.getRealm(), user.getUsername())) {
+            if (context.getProtector().isTemporarilyDisabled(context.getSession(), context.getRealm(), user)) {
                 context.getEvent().user(user);
                 context.getEvent().error(Errors.USER_TEMPORARILY_DISABLED);
                 Response challengeResponse = temporarilyDisabledUser(context);
@@ -119,6 +119,10 @@ public abstract class AbstractUsernameFormAuthenticator extends AbstractFormAuth
             context.failureChallenge(AuthenticationFlowError.INVALID_USER, challengeResponse);
             return false;
         }
+
+        // remove leading and trailing whitespace
+        username = username.trim();
+
         context.getEvent().detail(Details.USERNAME, username);
         context.getClientSession().setNote(AbstractUsernameFormAuthenticator.ATTEMPTED_USERNAME, username);
 
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/CookieAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/CookieAuthenticator.java
index 7a94ea0..6c961e1 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/browser/CookieAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/CookieAuthenticator.java
@@ -19,10 +19,17 @@ package org.keycloak.authentication.authenticators.browser;
 
 import org.keycloak.authentication.AuthenticationFlowContext;
 import org.keycloak.authentication.Authenticator;
+import org.keycloak.common.util.Time;
+import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.protocol.LoginProtocol;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.services.ServicesLogger;
 import org.keycloak.services.managers.AuthenticationManager;
+import org.keycloak.util.TokenUtil;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -42,9 +49,19 @@ public class CookieAuthenticator implements Authenticator {
         if (authResult == null) {
             context.attempted();
         } else {
-            context.setUser(authResult.getUser());
-            context.attachUserSession(authResult.getSession());
-            context.success();
+            ClientSessionModel clientSession = context.getClientSession();
+            LoginProtocol protocol = context.getSession().getProvider(LoginProtocol.class, clientSession.getAuthMethod());
+
+            // Cookie re-authentication is skipped if re-authentication is required
+            if (protocol.requireReauthentication(authResult.getSession(), clientSession)) {
+                context.attempted();
+            } else {
+                clientSession.setNote(AuthenticationManager.SSO_AUTH, "true");
+
+                context.setUser(authResult.getUser());
+                context.attachUserSession(authResult.getSession());
+                context.success();
+            }
         }
 
     }
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/ScriptBasedAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/ScriptBasedAuthenticator.java
new file mode 100644
index 0000000..895f035
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/ScriptBasedAuthenticator.java
@@ -0,0 +1,115 @@
+package org.keycloak.authentication.authenticators.browser;
+
+import org.jboss.logging.Logger;
+import org.keycloak.authentication.AuthenticationFlowContext;
+import org.keycloak.authentication.Authenticator;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.scripting.InvocableScript;
+import org.keycloak.scripting.Script;
+import org.keycloak.scripting.ScriptBindingsConfigurer;
+import org.keycloak.scripting.ScriptingProvider;
+
+import javax.script.Bindings;
+import javax.script.ScriptException;
+import java.util.Map;
+
+/**
+ * An {@link Authenticator} that can execute a configured script during authentication flow.
+ * <p>scripts must provide </p>
+ *
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+public class ScriptBasedAuthenticator implements Authenticator {
+
+    private static final Logger LOGGER = Logger.getLogger(ScriptBasedAuthenticator.class);
+
+    static final String SCRIPT_CODE = "scriptCode";
+    static final String SCRIPT_NAME = "scriptName";
+    static final String SCRIPT_DESCRIPTION = "scriptDescription";
+
+    static final String ACTION = "action";
+    static final String AUTHENTICATE = "authenticate";
+    static final String TEXT_JAVASCRIPT = "text/javascript";
+
+    @Override
+    public void authenticate(AuthenticationFlowContext context) {
+        tryInvoke(AUTHENTICATE, context);
+    }
+
+    @Override
+    public void action(AuthenticationFlowContext context) {
+        tryInvoke(ACTION, context);
+    }
+
+    private void tryInvoke(String functionName, AuthenticationFlowContext context) {
+
+        InvocableScript script = getInvocableScript(context);
+
+        if (!script.hasFunction(functionName)) {
+            return;
+        }
+
+        try {
+            //should context be wrapped in a readonly wrapper?
+            script.invokeFunction(functionName, context);
+        } catch (ScriptException | NoSuchMethodException e) {
+            LOGGER.error(e);
+        }
+    }
+
+    private InvocableScript getInvocableScript(final AuthenticationFlowContext context) {
+
+        final Script script = createAdhocScriptFromContext(context);
+
+        ScriptBindingsConfigurer bindingsConfigurer = new ScriptBindingsConfigurer() {
+
+            @Override
+            public void configureBindings(Bindings bindings) {
+
+                bindings.put("script", script);
+                bindings.put("LOG", LOGGER);
+            }
+        };
+
+        ScriptingProvider scripting = context.getSession().scripting();
+
+        //how to deal with long running scripts -> timeout?
+
+        return scripting.prepareScript(script, bindingsConfigurer);
+    }
+
+    private Script createAdhocScriptFromContext(AuthenticationFlowContext context) {
+
+        Map<String, String> config = context.getAuthenticatorConfig().getConfig();
+
+        String scriptName = config.get(SCRIPT_NAME);
+        String scriptCode = config.get(SCRIPT_CODE);
+        String scriptDescription = config.get(SCRIPT_DESCRIPTION);
+
+        RealmModel realm = context.getRealm();
+
+        return new Script(null /* scriptId */, realm.getId(), scriptName, TEXT_JAVASCRIPT, scriptCode, scriptDescription);
+    }
+
+    @Override
+    public boolean requiresUser() {
+        return false;
+    }
+
+    @Override
+    public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) {
+        return false;
+    }
+
+    @Override
+    public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) {
+        //NOOP
+    }
+
+    @Override
+    public void close() {
+        //NOOP
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/browser/ScriptBasedAuthenticatorFactory.java b/services/src/main/java/org/keycloak/authentication/authenticators/browser/ScriptBasedAuthenticatorFactory.java
new file mode 100644
index 0000000..b25af8f
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/browser/ScriptBasedAuthenticatorFactory.java
@@ -0,0 +1,123 @@
+package org.keycloak.authentication.authenticators.browser;
+
+import org.keycloak.Config;
+import org.keycloak.authentication.Authenticator;
+import org.keycloak.authentication.AuthenticatorFactory;
+import org.keycloak.models.AuthenticationExecutionModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.provider.ProviderConfigProperty;
+
+import java.util.List;
+
+import static java.util.Arrays.asList;
+import static org.keycloak.authentication.authenticators.browser.ScriptBasedAuthenticator.SCRIPT_CODE;
+import static org.keycloak.authentication.authenticators.browser.ScriptBasedAuthenticator.SCRIPT_DESCRIPTION;
+import static org.keycloak.authentication.authenticators.browser.ScriptBasedAuthenticator.SCRIPT_NAME;
+import static org.keycloak.provider.ProviderConfigProperty.SCRIPT_TYPE;
+import static org.keycloak.provider.ProviderConfigProperty.STRING_TYPE;
+
+/**
+ * An {@link AuthenticatorFactory} for {@link ScriptBasedAuthenticator}s.
+ *
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+public class ScriptBasedAuthenticatorFactory implements AuthenticatorFactory {
+
+    static final String PROVIDER_ID = "auth-script-based";
+
+    static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = {
+            AuthenticationExecutionModel.Requirement.REQUIRED,
+            AuthenticationExecutionModel.Requirement.OPTIONAL,
+            AuthenticationExecutionModel.Requirement.DISABLED};
+
+    static final ScriptBasedAuthenticator SINGLETON = new ScriptBasedAuthenticator();
+
+    @Override
+    public Authenticator create(KeycloakSession session) {
+
+        /*
+         would be great to have the actual authenticatorId here in order to initialize the authenticator in the ctor with
+         the appropriate config from session.getContext().getRealm().getAuthenticatorConfigById(authenticatorId);
+
+         This would help to avoid potentially re-evaluating the provide script multiple times per authenticator execution.
+        */
+        return SINGLETON;
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+        //NOOP
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+        //NOOP
+    }
+
+    @Override
+    public void close() {
+        //NOOP
+    }
+
+    @Override
+    public String getId() {
+        return PROVIDER_ID;
+    }
+
+    @Override
+    public String getReferenceCategory() {
+        return "script";
+    }
+
+    @Override
+    public boolean isConfigurable() {
+        return true;
+    }
+
+    @Override
+    public boolean isUserSetupAllowed() {
+        return false;
+    }
+
+    @Override
+    public AuthenticationExecutionModel.Requirement[] getRequirementChoices() {
+        return REQUIREMENT_CHOICES;
+    }
+
+    @Override
+    public String getDisplayType() {
+        return "Script-based Authentication";
+    }
+
+    @Override
+    public String getHelpText() {
+        return "Script based authentication.";
+    }
+
+    @Override
+    public List<ProviderConfigProperty> getConfigProperties() {
+
+        ProviderConfigProperty name = new ProviderConfigProperty();
+        name.setType(STRING_TYPE);
+        name.setName(SCRIPT_NAME);
+        name.setLabel("Script Name");
+        name.setHelpText("The name of the script used to authenticate.");
+
+        ProviderConfigProperty description = new ProviderConfigProperty();
+        description.setType(STRING_TYPE);
+        description.setName(SCRIPT_DESCRIPTION);
+        description.setLabel("Script Description");
+        description.setHelpText("The description of the script used to authenticate.");
+
+        ProviderConfigProperty script = new ProviderConfigProperty();
+        script.setType(SCRIPT_TYPE);
+        script.setName(SCRIPT_CODE);
+        script.setLabel("Script Source");
+        script.setDefaultValue("//enter your script here");
+        script.setHelpText("The script used to authenticate. Scripts must at least define a function with the name 'authenticate' that accepts a context (AuthenticationFlowContext) parameter." +
+                "This authenticator exposes the following additional variables: 'script', 'LOG'");
+
+        return asList(name, description, script);
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/client/ClientAuthUtil.java b/services/src/main/java/org/keycloak/authentication/authenticators/client/ClientAuthUtil.java
index 0d7d911..94cefa3 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/client/ClientAuthUtil.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/client/ClientAuthUtil.java
@@ -17,13 +17,10 @@
 
 package org.keycloak.authentication.authenticators.client;
 
-import java.util.HashMap;
-import java.util.Map;
-
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
-import org.keycloak.OAuth2Constants;
+import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -32,12 +29,8 @@ public class ClientAuthUtil {
 
 
     public static Response errorResponse(int status, String error, String errorDescription) {
-        Map<String, String> e = new HashMap<String, String>();
-        e.put(OAuth2Constants.ERROR, error);
-        if (errorDescription != null) {
-            e.put(OAuth2Constants.ERROR_DESCRIPTION, errorDescription);
-        }
-        return Response.status(status).entity(e).type(MediaType.APPLICATION_JSON_TYPE).build();
+        OAuth2ErrorRepresentation errorRep = new OAuth2ErrorRepresentation(error, errorDescription);
+        return Response.status(status).entity(errorRep).type(MediaType.APPLICATION_JSON_TYPE).build();
     }
 
 }
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/client/ClientIdAndSecretAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/client/ClientIdAndSecretAuthenticator.java
index c92ed06..4516de4 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/client/ClientIdAndSecretAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/client/ClientIdAndSecretAuthenticator.java
@@ -19,9 +19,12 @@ package org.keycloak.authentication.authenticators.client;
 
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
@@ -33,6 +36,7 @@ import org.keycloak.authentication.AuthenticationFlowError;
 import org.keycloak.authentication.ClientAuthenticationFlowContext;
 import org.keycloak.models.AuthenticationExecutionModel;
 import org.keycloak.models.ClientModel;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.provider.ProviderConfigProperty;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.services.ServicesLogger;
@@ -86,7 +90,7 @@ public class ClientIdAndSecretAuthenticator extends AbstractClientAuthenticator 
 
         if (formData != null && client_id == null) {
             client_id = formData.getFirst(OAuth2Constants.CLIENT_ID);
-            clientSecret = formData.getFirst("client_secret");
+            clientSecret = formData.getFirst(OAuth2Constants.CLIENT_SECRET);
         }
 
         if (client_id == null) {
@@ -179,4 +183,16 @@ public class ClientIdAndSecretAuthenticator extends AbstractClientAuthenticator 
     public String getId() {
         return PROVIDER_ID;
     }
+
+    @Override
+    public Set<String> getProtocolAuthenticatorMethods(String loginProtocol) {
+        if (loginProtocol.equals(OIDCLoginProtocol.LOGIN_PROTOCOL)) {
+            Set<String> results = new LinkedHashSet<>();
+            results.add(OIDCLoginProtocol.CLIENT_SECRET_BASIC);
+            results.add(OIDCLoginProtocol.CLIENT_SECRET_POST);
+            return results;
+        } else {
+            return Collections.emptySet();
+        }
+    }
 }
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/client/JWTClientAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/client/JWTClientAuthenticator.java
index f97dce0..5139e3a 100644
--- a/services/src/main/java/org/keycloak/authentication/authenticators/client/JWTClientAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/client/JWTClientAuthenticator.java
@@ -22,9 +22,11 @@ import java.security.cert.X509Certificate;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
@@ -32,16 +34,20 @@ import javax.ws.rs.core.Response;
 import org.keycloak.OAuth2Constants;
 import org.keycloak.authentication.AuthenticationFlowError;
 import org.keycloak.authentication.ClientAuthenticationFlowContext;
+import org.keycloak.common.util.Time;
 import org.keycloak.jose.jws.JWSInput;
 import org.keycloak.jose.jws.crypto.RSAProvider;
 import org.keycloak.models.AuthenticationExecutionModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.provider.ProviderConfigProperty;
 import org.keycloak.representations.JsonWebToken;
+import org.keycloak.representations.idm.CertificateRepresentation;
 import org.keycloak.services.ServicesLogger;
 import org.keycloak.services.Urls;
+import org.keycloak.services.util.CertificateInfoHelper;
 
 /**
  * Client authentication based on JWT signed by client private key .
@@ -57,6 +63,7 @@ public class JWTClientAuthenticator extends AbstractClientAuthenticator {
     protected static ServicesLogger logger = ServicesLogger.ROOT_LOGGER;
 
     public static final String PROVIDER_ID = "client-jwt";
+    public static final String ATTR_PREFIX = "jwt.credential";
     public static final String CERTIFICATE_ATTR = "jwt.credential.certificate";
 
     public static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = {
@@ -115,15 +122,12 @@ public class JWTClientAuthenticator extends AbstractClientAuthenticator {
             }
 
             // Get client key and validate signature
-            String encodedCertificate = client.getAttribute(CERTIFICATE_ATTR);
-            if (encodedCertificate == null) {
-                Response challengeResponse = ClientAuthUtil.errorResponse(Response.Status.BAD_REQUEST.getStatusCode(), "unauthorized_client", "Client '" + clientId + "' doesn't have certificate configured");
-                context.failure(AuthenticationFlowError.CLIENT_CREDENTIALS_SETUP_REQUIRED, challengeResponse);
+            PublicKey clientPublicKey = getSignatureValidationKey(client, context);
+            if (clientPublicKey == null) {
+                // Error response already set to context
                 return;
             }
 
-            X509Certificate clientCert = KeycloakModelUtils.getCertificate(encodedCertificate);
-            PublicKey clientPublicKey = clientCert.getPublicKey();
             boolean signatureValid;
             try {
                 signatureValid = RSAProvider.verify(jws, clientPublicKey);
@@ -145,6 +149,11 @@ public class JWTClientAuthenticator extends AbstractClientAuthenticator {
                 throw new RuntimeException("Token is not active");
             }
 
+            // KEYCLOAK-2986
+            if (token.getExpiration() == 0 && token.getIssuedAt() + 10 < Time.currentTime()) {
+                throw new RuntimeException("Token is not active");
+            }
+
             context.success();
         } catch (Exception e) {
             logger.errorValidatingAssertion(e);
@@ -153,6 +162,33 @@ public class JWTClientAuthenticator extends AbstractClientAuthenticator {
         }
     }
 
+    protected PublicKey getSignatureValidationKey(ClientModel client, ClientAuthenticationFlowContext context) {
+        CertificateRepresentation certInfo = CertificateInfoHelper.getCertificateFromClient(client, ATTR_PREFIX);
+
+        String encodedCertificate = certInfo.getCertificate();
+        String encodedPublicKey = certInfo.getPublicKey();
+
+        if (encodedCertificate == null && encodedPublicKey == null) {
+            Response challengeResponse = ClientAuthUtil.errorResponse(Response.Status.BAD_REQUEST.getStatusCode(), "unauthorized_client", "Client '" + client.getClientId() + "' doesn't have certificate or publicKey configured");
+            context.failure(AuthenticationFlowError.CLIENT_CREDENTIALS_SETUP_REQUIRED, challengeResponse);
+            return null;
+        }
+
+        if (encodedCertificate != null && encodedPublicKey != null) {
+            Response challengeResponse = ClientAuthUtil.errorResponse(Response.Status.BAD_REQUEST.getStatusCode(), "unauthorized_client", "Client '" + client.getClientId() + "' has both publicKey and certificate configured");
+            context.failure(AuthenticationFlowError.CLIENT_CREDENTIALS_SETUP_REQUIRED, challengeResponse);
+            return null;
+        }
+
+        // TODO: Caching of publicKeys / certificates, so it doesn't need to be always computed from pem. For performance reasons...
+        if (encodedCertificate != null) {
+            X509Certificate clientCert = KeycloakModelUtils.getCertificate(encodedCertificate);
+            return clientCert.getPublicKey();
+        } else {
+            return KeycloakModelUtils.getPublicKey(encodedPublicKey);
+        }
+    }
+
     @Override
     public String getDisplayType() {
         return "Signed Jwt";
@@ -203,4 +239,15 @@ public class JWTClientAuthenticator extends AbstractClientAuthenticator {
     public String getId() {
         return PROVIDER_ID;
     }
+
+    @Override
+    public Set<String> getProtocolAuthenticatorMethods(String loginProtocol) {
+        if (loginProtocol.equals(OIDCLoginProtocol.LOGIN_PROTOCOL)) {
+            Set<String> results = new HashSet<>();
+            results.add(OIDCLoginProtocol.PRIVATE_KEY_JWT);
+            return results;
+        } else {
+            return Collections.emptySet();
+        }
+    }
 }
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/AbstractDirectGrantAuthenticator.java b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/AbstractDirectGrantAuthenticator.java
index 8de4230..88d0e15 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/AbstractDirectGrantAuthenticator.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/AbstractDirectGrantAuthenticator.java
@@ -24,6 +24,7 @@ import org.keycloak.authentication.Authenticator;
 import org.keycloak.authentication.AuthenticatorFactory;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
 
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
@@ -36,12 +37,8 @@ import java.util.Map;
  */
 public abstract class AbstractDirectGrantAuthenticator implements Authenticator, AuthenticatorFactory {
     public Response errorResponse(int status, String error, String errorDescription) {
-        Map<String, String> e = new HashMap<String, String>();
-        e.put(OAuth2Constants.ERROR, error);
-        if (errorDescription != null) {
-            e.put(OAuth2Constants.ERROR_DESCRIPTION, errorDescription);
-        }
-        return Response.status(status).entity(e).type(MediaType.APPLICATION_JSON_TYPE).build();
+        OAuth2ErrorRepresentation errorRep = new OAuth2ErrorRepresentation(error, errorDescription);
+        return Response.status(status).entity(errorRep).type(MediaType.APPLICATION_JSON_TYPE).build();
     }
 
     @Override
diff --git a/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateUsername.java b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateUsername.java
index 26aeaeb..de48a3c 100755
--- a/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateUsername.java
+++ b/services/src/main/java/org/keycloak/authentication/authenticators/directgrant/ValidateUsername.java
@@ -84,7 +84,7 @@ public class ValidateUsername extends AbstractDirectGrantAuthenticator {
             return;
         }
         if (context.getRealm().isBruteForceProtected()) {
-            if (context.getProtector().isTemporarilyDisabled(context.getSession(), context.getRealm(), user.getUsername())) {
+            if (context.getProtector().isTemporarilyDisabled(context.getSession(), context.getRealm(), user)) {
                 context.getEvent().user(user);
                 context.getEvent().error(Errors.USER_TEMPORARILY_DISABLED);
                 Response challengeResponse = errorResponse(Response.Status.BAD_REQUEST.getStatusCode(), "invalid_grant", "Account temporarily disabled");
diff --git a/services/src/main/java/org/keycloak/authentication/forms/RegistrationPassword.java b/services/src/main/java/org/keycloak/authentication/forms/RegistrationPassword.java
index 7f2b0c8..a42a073 100755
--- a/services/src/main/java/org/keycloak/authentication/forms/RegistrationPassword.java
+++ b/services/src/main/java/org/keycloak/authentication/forms/RegistrationPassword.java
@@ -33,6 +33,8 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserCredentialModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.utils.FormMessage;
+import org.keycloak.policy.PasswordPolicyManagerProvider;
+import org.keycloak.policy.PolicyError;
 import org.keycloak.provider.ProviderConfigProperty;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.services.messages.Messages;
@@ -70,7 +72,7 @@ public class RegistrationPassword implements FormAction, FormActionFactory {
             errors.add(new FormMessage(RegistrationPage.FIELD_PASSWORD_CONFIRM, Messages.INVALID_PASSWORD_CONFIRM));
         }
         if (formData.getFirst(RegistrationPage.FIELD_PASSWORD) != null) {
-            PasswordPolicy.Error err = context.getRealm().getPasswordPolicy().validate(context.getSession(), context.getRealm().isRegistrationEmailAsUsername() ? formData.getFirst(RegistrationPage.FIELD_EMAIL) : formData.getFirst(RegistrationPage.FIELD_USERNAME), formData.getFirst(RegistrationPage.FIELD_PASSWORD));
+            PolicyError err = context.getSession().getProvider(PasswordPolicyManagerProvider.class).validate(context.getRealm().isRegistrationEmailAsUsername() ? formData.getFirst(RegistrationPage.FIELD_EMAIL) : formData.getFirst(RegistrationPage.FIELD_USERNAME), formData.getFirst(RegistrationPage.FIELD_PASSWORD));
             if (err != null)
                 errors.add(new FormMessage(RegistrationPage.FIELD_PASSWORD, err.getMessage(), err.getParameters()));
         }
diff --git a/services/src/main/java/org/keycloak/authentication/requiredactions/UpdatePassword.java b/services/src/main/java/org/keycloak/authentication/requiredactions/UpdatePassword.java
index 47c9d5b..7918815 100755
--- a/services/src/main/java/org/keycloak/authentication/requiredactions/UpdatePassword.java
+++ b/services/src/main/java/org/keycloak/authentication/requiredactions/UpdatePassword.java
@@ -21,6 +21,8 @@ import org.keycloak.Config;
 import org.keycloak.authentication.RequiredActionContext;
 import org.keycloak.authentication.RequiredActionFactory;
 import org.keycloak.authentication.RequiredActionProvider;
+import org.keycloak.events.Details;
+import org.keycloak.events.Errors;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.events.EventType;
 import org.keycloak.models.KeycloakSession;
@@ -84,17 +86,23 @@ public class UpdatePassword implements RequiredActionProvider, RequiredActionFac
         String passwordNew = formData.getFirst("password-new");
         String passwordConfirm = formData.getFirst("password-confirm");
 
+        EventBuilder errorEvent = event.clone().event(EventType.UPDATE_PASSWORD_ERROR)
+                .client(context.getClientSession().getClient())
+                .user(context.getClientSession().getUserSession().getUser());
+
         if (Validation.isBlank(passwordNew)) {
             Response challenge = context.form()
                     .setError(Messages.MISSING_PASSWORD)
                     .createResponse(UserModel.RequiredAction.UPDATE_PASSWORD);
             context.challenge(challenge);
+            errorEvent.error(Errors.PASSWORD_MISSING);
             return;
         } else if (!passwordNew.equals(passwordConfirm)) {
             Response challenge = context.form()
                     .setError(Messages.NOTMATCH_PASSWORD)
                     .createResponse(UserModel.RequiredAction.UPDATE_PASSWORD);
             context.challenge(challenge);
+            errorEvent.error(Errors.PASSWORD_CONFIRM_ERROR);
             return;
         }
 
@@ -102,12 +110,14 @@ public class UpdatePassword implements RequiredActionProvider, RequiredActionFac
             context.getSession().users().updateCredential(context.getRealm(), context.getUser(), UserCredentialModel.password(passwordNew));
             context.success();
         } catch (ModelException me) {
+            errorEvent.detail(Details.REASON, me.getMessage()).error(Errors.PASSWORD_REJECTED);
             Response challenge = context.form()
                     .setError(me.getMessage(), me.getParameters())
                     .createResponse(UserModel.RequiredAction.UPDATE_PASSWORD);
             context.challenge(challenge);
             return;
         } catch (Exception ape) {
+            errorEvent.detail(Details.REASON, ape.getMessage()).error(Errors.PASSWORD_REJECTED);
             Response challenge = context.form()
                     .setError(ape.getMessage())
                     .createResponse(UserModel.RequiredAction.UPDATE_PASSWORD);
diff --git a/services/src/main/java/org/keycloak/authentication/requiredactions/UpdateTotp.java b/services/src/main/java/org/keycloak/authentication/requiredactions/UpdateTotp.java
index a9c3e7c..9ba9922 100644
--- a/services/src/main/java/org/keycloak/authentication/requiredactions/UpdateTotp.java
+++ b/services/src/main/java/org/keycloak/authentication/requiredactions/UpdateTotp.java
@@ -113,7 +113,7 @@ public class UpdateTotp implements RequiredActionProvider, RequiredActionFactory
 
     @Override
     public String getDisplayText() {
-        return "Configure Totp";
+        return "Configure OTP";
     }
 
 
diff --git a/services/src/main/java/org/keycloak/authorization/admin/AuthorizationService.java b/services/src/main/java/org/keycloak/authorization/admin/AuthorizationService.java
new file mode 100644
index 0000000..a4ff868
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/admin/AuthorizationService.java
@@ -0,0 +1,77 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.admin;
+
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.services.resources.admin.RealmAuth;
+
+import javax.ws.rs.Path;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AuthorizationService {
+
+    private final RealmAuth auth;
+    private final ClientModel client;
+    private final KeycloakSession session;
+    private final ResourceServer resourceServer;
+    private final AuthorizationProvider authorization;
+
+    public AuthorizationService(KeycloakSession session, ClientModel client, RealmAuth auth) {
+        this.session = session;
+        this.client = client;
+        this.authorization = session.getProvider(AuthorizationProvider.class);
+        this.resourceServer = this.authorization.getStoreFactory().getResourceServerStore().findByClient(this.client.getId());
+        this.auth = auth;
+
+        if (auth != null) {
+            this.auth.init(RealmAuth.Resource.AUTHORIZATION);
+        }
+    }
+
+    @Path("/resource-server")
+    public ResourceServerService resourceServer() {
+        ResourceServerService resource = new ResourceServerService(this.authorization, this.resourceServer, this.client, this.auth);
+
+        ResteasyProviderFactory.getInstance().injectProperties(resource);
+
+        return resource;
+    }
+
+    public void enable() {
+        if (!isEnabled()) {
+            resourceServer().create();
+        }
+    }
+
+    public void disable() {
+        if (isEnabled()) {
+            resourceServer().delete();
+        }
+    }
+
+    public boolean isEnabled() {
+        return this.resourceServer != null;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java b/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java
new file mode 100644
index 0000000..4af34ad
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyEvaluationService.java
@@ -0,0 +1,259 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.admin;
+
+import org.jboss.resteasy.spi.HttpRequest;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.admin.representation.PolicyEvaluationRequest;
+import org.keycloak.authorization.admin.representation.PolicyEvaluationResponse;
+import org.keycloak.authorization.attribute.Attributes;
+import org.keycloak.authorization.common.KeycloakEvaluationContext;
+import org.keycloak.authorization.common.KeycloakIdentity;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.permission.ResourcePermission;
+import org.keycloak.authorization.policy.evaluation.DecisionResultCollector;
+import org.keycloak.authorization.policy.evaluation.EvaluationContext;
+import org.keycloak.authorization.policy.evaluation.Result;
+import org.keycloak.authorization.store.ScopeStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.authorization.util.Permissions;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.protocol.ProtocolMapper;
+import org.keycloak.protocol.oidc.mappers.OIDCAccessTokenMapper;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.services.Urls;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Produces;
+import javax.ws.rs.container.AsyncResponse;
+import javax.ws.rs.container.Suspended;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static java.util.Arrays.asList;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class PolicyEvaluationService {
+
+    private final AuthorizationProvider authorization;
+    @Context
+    private HttpRequest httpRequest;
+
+    private final ResourceServer resourceServer;
+
+    PolicyEvaluationService(ResourceServer resourceServer, AuthorizationProvider authorization) {
+        this.resourceServer = resourceServer;
+        this.authorization = authorization;
+    }
+
+    @POST
+    @Consumes("application/json")
+    @Produces("application/json")
+    public void evaluate(PolicyEvaluationRequest evaluationRequest, @Suspended AsyncResponse asyncResponse) {
+        KeycloakIdentity identity = createIdentity(evaluationRequest);
+        EvaluationContext evaluationContext = createEvaluationContext(evaluationRequest, identity);
+        authorization.evaluators().from(createPermissions(evaluationRequest, evaluationContext, authorization), evaluationContext).evaluate(createDecisionCollector(authorization, identity, asyncResponse));
+    }
+
+    private DecisionResultCollector createDecisionCollector(AuthorizationProvider authorization, KeycloakIdentity identity, AsyncResponse asyncResponse) {
+        return new DecisionResultCollector() {
+            @Override
+            protected void onComplete(List<Result> results) {
+                try {
+                    asyncResponse.resume(Response.ok(PolicyEvaluationResponse.build(results, resourceServer,  authorization, identity)).build());
+                } catch (Throwable cause) {
+                    asyncResponse.resume(cause);
+                }
+            }
+
+            @Override
+            public void onError(Throwable cause) {
+                asyncResponse.resume(cause);
+            }
+        };
+    }
+
+    private EvaluationContext createEvaluationContext(PolicyEvaluationRequest representation, KeycloakIdentity identity) {
+        return new KeycloakEvaluationContext(identity, this.authorization.getKeycloakSession()) {
+            @Override
+            public Attributes getAttributes() {
+                Map<String, Collection<String>> attributes = new HashMap<>(super.getAttributes().toMap());
+                Map<String, String> givenAttributes = representation.getContext().get("attributes");
+
+                if (givenAttributes != null) {
+                    givenAttributes.forEach((key, entryValue) -> {
+                        if (entryValue != null) {
+                            List<String> values = new ArrayList();
+
+                            for (String value : entryValue.split(",")) {
+                                values.add(value);
+                            }
+
+                            attributes.put(key, values);
+                        }
+                    });
+                }
+
+                return Attributes.from(attributes);
+            }
+        };
+    }
+
+    private List<ResourcePermission> createPermissions(PolicyEvaluationRequest representation, EvaluationContext evaluationContext, AuthorizationProvider authorization) {
+        List<PolicyEvaluationRequest.Resource> resources = representation.getResources();
+        return resources.stream().flatMap((Function<PolicyEvaluationRequest.Resource, Stream<ResourcePermission>>) resource -> {
+            Set<String> givenScopes = resource.getScopes();
+
+            if (givenScopes == null) {
+                givenScopes = new HashSet();
+            }
+
+            StoreFactory storeFactory = authorization.getStoreFactory();
+
+            if (resource.getId() != null) {
+                Resource resourceModel = storeFactory.getResourceStore().findById(resource.getId());
+                return Permissions.createResourcePermissions(resourceModel, givenScopes, authorization).stream();
+            } else if (resource.getType() != null) {
+                Set<String> finalGivenScopes = givenScopes;
+                return storeFactory.getResourceStore().findByType(resource.getType()).stream().flatMap(resource1 -> Permissions.createResourcePermissions(resource1, finalGivenScopes, authorization).stream());
+            } else {
+                ScopeStore scopeStore = storeFactory.getScopeStore();
+                List<Scope> scopes = givenScopes.stream().map(scopeName -> scopeStore.findByName(scopeName, this.resourceServer.getId())).collect(Collectors.toList());
+                List<ResourcePermission> collect = scopes.stream().map(scope -> new ResourcePermission(null, asList(scope), resourceServer)).collect(Collectors.toList());
+
+                if (scopes.isEmpty()) {
+                    scopes = scopeStore.findByResourceServer(resourceServer.getId());
+                }
+
+                for (Scope scope : scopes) {
+                    collect.addAll(storeFactory.getResourceStore().findByScope(scope.getId()).stream().map(resource12 -> new ResourcePermission(resource12, asList(scope), resourceServer)).collect(Collectors.toList()));
+                }
+
+                return collect.stream();
+            }
+        }).collect(Collectors.toList());
+    }
+
+    private KeycloakIdentity createIdentity(PolicyEvaluationRequest representation) {
+        KeycloakSession keycloakSession = this.authorization.getKeycloakSession();
+        RealmModel realm = keycloakSession.getContext().getRealm();
+        AccessToken accessToken = new AccessToken();
+
+        accessToken.subject(representation.getUserId());
+        accessToken.issuedFor(representation.getClientId());
+        accessToken.audience(representation.getClientId());
+        accessToken.issuer(Urls.realmIssuer(keycloakSession.getContext().getUri().getBaseUri(), realm.getName()));
+        accessToken.setRealmAccess(new AccessToken.Access());
+
+        AccessToken.Access realmAccess = accessToken.getRealmAccess();
+        Map<String, Object> claims = accessToken.getOtherClaims();
+        Map<String, String> givenAttributes = representation.getContext().get("attributes");
+
+        if (givenAttributes != null) {
+            givenAttributes.forEach((key, value) -> claims.put(key, asList(value)));
+        }
+
+        String subject = accessToken.getSubject();
+
+        if (subject != null) {
+            UserModel userModel = keycloakSession.users().getUserById(subject, realm);
+
+            if (userModel != null) {
+                userModel.getAttributes().forEach(claims::put);
+
+                userModel.getRoleMappings().stream().map(RoleModel::getName).forEach(roleName -> realmAccess.addRole(roleName));
+
+                String clientId = representation.getClientId();
+
+                if (clientId == null) {
+                    clientId = resourceServer.getClientId();
+                }
+
+                if (clientId != null) {
+                    ClientModel clientModel = realm.getClientById(clientId);
+                    ClientSessionModel clientSession = null;
+                    UserSessionModel userSession = null;
+                    try {
+                        clientSession = keycloakSession.sessions().createClientSession(realm, clientModel);
+                        userSession = keycloakSession.sessions().createUserSession(realm, userModel, userModel.getUsername(), "127.0.0.1", "passwd", false, null, null);
+
+                        UserSessionModel finalUserSession = userSession;
+                        ClientSessionModel finalClientSession = clientSession;
+
+                        for (ProtocolMapperModel mapping : clientModel.getProtocolMappers()) {
+                            KeycloakSessionFactory sessionFactory = keycloakSession.getKeycloakSessionFactory();
+                            ProtocolMapper mapper = (ProtocolMapper)sessionFactory.getProviderFactory(ProtocolMapper.class, mapping.getProtocolMapper());
+
+                            if (mapper != null && (mapper instanceof OIDCAccessTokenMapper)) {
+                                accessToken = ((OIDCAccessTokenMapper)mapper).transformAccessToken(accessToken, mapping, keycloakSession, finalUserSession, finalClientSession);
+                            }
+                        }
+                    } finally {
+                        if (clientSession != null) {
+                            keycloakSession.sessions().removeClientSession(realm, clientSession);
+                        }
+
+                        if (userSession != null) {
+                            keycloakSession.sessions().removeUserSession(realm, userSession);
+                        }
+                    }
+
+                    AccessToken.Access clientAccess = accessToken.addAccess(clientModel.getClientId());
+                    clientAccess.roles(new HashSet<>());
+
+                    userModel.getClientRoleMappings(clientModel).stream().map(RoleModel::getName).forEach(roleName -> clientAccess.addRole(roleName));
+
+                    ClientModel resourceServerClient = realm.getClientById(resourceServer.getClientId());
+                    AccessToken.Access resourceServerAccess = accessToken.addAccess(resourceServerClient.getClientId());
+                    resourceServerAccess.roles(new HashSet<>());
+
+                    userModel.getClientRoleMappings(resourceServerClient).stream().map(RoleModel::getName).forEach(roleName -> resourceServerAccess.addRole(roleName));
+                }
+            }
+        }
+
+        if (representation.getRoleIds() != null) {
+            representation.getRoleIds().forEach(roleName -> realmAccess.addRole(roleName));
+        }
+
+        return new KeycloakIdentity(accessToken, keycloakSession);
+    }
+}
\ No newline at end of file
diff --git a/services/src/main/java/org/keycloak/authorization/admin/PolicyService.java b/services/src/main/java/org/keycloak/authorization/admin/PolicyService.java
new file mode 100644
index 0000000..d7e6dee
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/admin/PolicyService.java
@@ -0,0 +1,247 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.admin;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
+import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
+import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.representations.idm.authorization.PolicyProviderRepresentation;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.services.resources.admin.RealmAuth;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import java.util.stream.Collectors;
+
+import static org.keycloak.models.utils.ModelToRepresentation.toRepresentation;
+import static org.keycloak.models.utils.RepresentationToModel.toModel;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class PolicyService {
+
+    private final ResourceServer resourceServer;
+    private final AuthorizationProvider authorization;
+    private final RealmAuth auth;
+
+    public PolicyService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) {
+        this.resourceServer = resourceServer;
+        this.authorization = authorization;
+        this.auth = auth;
+    }
+
+    @POST
+    @Consumes("application/json")
+    @Produces("application/json")
+    @NoCache
+    public Response create(PolicyRepresentation representation) {
+        this.auth.requireManage();
+        Policy policy = toModel(representation, this.resourceServer, authorization);
+        PolicyProviderAdminService resource = getPolicyProviderAdminResource(policy.getType(), authorization);
+
+        if (resource != null) {
+            try {
+                resource.onCreate(policy);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        representation.setId(policy.getId());
+
+        return Response.status(Status.CREATED).entity(representation).build();
+    }
+
+    @Path("{id}")
+    @PUT
+    @Consumes("application/json")
+    @Produces("application/json")
+    @NoCache
+    public Response update(@PathParam("id") String id, PolicyRepresentation representation) {
+        this.auth.requireManage();
+        representation.setId(id);
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        Policy policy = storeFactory.getPolicyStore().findById(representation.getId());
+
+        if (policy == null) {
+            return Response.status(Status.NOT_FOUND).build();
+        }
+
+        policy = toModel(representation, resourceServer, authorization);
+
+        PolicyProviderAdminService resource = getPolicyProviderAdminResource(policy.getType(), authorization);
+
+        if (resource != null) {
+            try {
+                resource.onUpdate(policy);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        return Response.status(Status.CREATED).build();
+    }
+
+    @Path("{id}")
+    @DELETE
+    public Response delete(@PathParam("id") String id) {
+        this.auth.requireManage();
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        PolicyStore policyStore = storeFactory.getPolicyStore();
+        Policy policy = policyStore.findById(id);
+
+        if (policy == null) {
+            return Response.status(Status.NOT_FOUND).build();
+        }
+
+        PolicyProviderAdminService resource = getPolicyProviderAdminResource(policy.getType(), authorization);
+
+        if (resource != null) {
+            try {
+                resource.onRemove(policy);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        policyStore.findDependentPolicies(id).forEach(dependentPolicy -> {
+            if (dependentPolicy.getAssociatedPolicies().size() == 1) {
+                policyStore.delete(dependentPolicy.getId());
+            } else {
+                dependentPolicy.removeAssociatedPolicy(policy);
+            }
+        });
+
+        policyStore.delete(policy.getId());
+
+        return Response.noContent().build();
+    }
+
+    @Path("{id}")
+    @GET
+    @Produces("application/json")
+    @NoCache
+    public Response findById(@PathParam("id") String id) {
+        this.auth.requireView();
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        Policy model = storeFactory.getPolicyStore().findById(id);
+
+        if (model == null) {
+            return Response.status(Status.NOT_FOUND).build();
+        }
+
+        return Response.ok(toRepresentation(model, authorization)).build();
+    }
+
+    @Path("/search")
+    @GET
+    @Produces("application/json")
+    @NoCache
+    public Response find(@QueryParam("name") String name) {
+        this.auth.requireView();
+        StoreFactory storeFactory = authorization.getStoreFactory();
+
+        if (name == null) {
+            return Response.status(Status.BAD_REQUEST).build();
+        }
+
+        Policy model = storeFactory.getPolicyStore().findByName(name, this.resourceServer.getId());
+
+        if (model == null) {
+            return Response.status(Status.OK).build();
+        }
+
+        return Response.ok(toRepresentation(model, authorization)).build();
+    }
+
+    @GET
+    @Produces("application/json")
+    @NoCache
+    public Response findAll() {
+        this.auth.requireView();
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        return Response.ok(
+                storeFactory.getPolicyStore().findByResourceServer(resourceServer.getId()).stream()
+                        .map(policy -> toRepresentation(policy, authorization))
+                        .collect(Collectors.toList()))
+                .build();
+    }
+
+    @Path("providers")
+    @GET
+    @Produces("application/json")
+    @NoCache
+    public Response findPolicyProviders() {
+        this.auth.requireView();
+        return Response.ok(
+                authorization.getProviderFactories().stream()
+                        .map(provider -> {
+                            PolicyProviderRepresentation representation = new PolicyProviderRepresentation();
+
+                            representation.setName(provider.getName());
+                            representation.setGroup(provider.getGroup());
+                            representation.setType(provider.getId());
+
+                            return representation;
+                        })
+                        .collect(Collectors.toList()))
+                .build();
+    }
+
+    @Path("evaluate")
+    public PolicyEvaluationService getPolicyEvaluateResource() {
+        this.auth.requireView();
+        PolicyEvaluationService resource = new PolicyEvaluationService(this.resourceServer, this.authorization);
+
+        ResteasyProviderFactory.getInstance().injectProperties(resource);
+
+        return resource;
+    }
+
+    @Path("{policyType}")
+    public Object getPolicyTypeResource(@PathParam("policyType") String policyType) {
+        this.auth.requireView();
+        return getPolicyProviderAdminResource(policyType, this.authorization);
+    }
+
+    private PolicyProviderAdminService getPolicyProviderAdminResource(String policyType, AuthorizationProvider authorization) {
+        PolicyProviderFactory providerFactory = authorization.getProviderFactory(policyType);
+
+        if (providerFactory != null) {
+            return providerFactory.getAdminResource(this.resourceServer);
+        }
+
+        return null;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/admin/representation/PolicyEvaluationRequest.java b/services/src/main/java/org/keycloak/authorization/admin/representation/PolicyEvaluationRequest.java
new file mode 100644
index 0000000..17edef9
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/admin/representation/PolicyEvaluationRequest.java
@@ -0,0 +1,123 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.admin.representation;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class PolicyEvaluationRequest {
+
+    private Map<String, Map<String, String>> context;
+    private List<Resource> resources;
+    private String clientId;
+    private String userId;
+    private List<String> roleIds;
+    private boolean entitlements;
+
+    public Map<String, Map<String, String>> getContext() {
+        return this.context;
+    }
+
+    public void setContext(Map<String, Map<String, String>> context) {
+        this.context = context;
+    }
+
+    public List<Resource> getResources() {
+        return this.resources;
+    }
+
+    public void setResources(List<Resource> resources) {
+        this.resources = resources;
+    }
+
+    public String getClientId() {
+        return this.clientId;
+    }
+
+    public void setClientId(final String clientId) {
+        this.clientId = clientId;
+    }
+
+    public String getUserId() {
+        return this.userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public List<String> getRoleIds() {
+        return this.roleIds;
+    }
+
+    public void setRoleIds(List<String> roleIds) {
+        this.roleIds = roleIds;
+    }
+
+    public boolean isEntitlements() {
+        return entitlements;
+    }
+
+    public void setEntitlements(boolean entitlements) {
+        this.entitlements = entitlements;
+    }
+
+    public static class Resource {
+        private String id;
+        private String name;
+        private String type;
+        private Set<String> scopes;
+
+        public String getId() {
+            return this.id;
+        }
+
+        public void setId(String id) {
+            this.id = id;
+        }
+
+        public String getName() {
+            return this.name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public String getType() {
+            return type;
+        }
+
+        public void setType(final String type) {
+            this.type = type;
+        }
+
+        public Set<String> getScopes() {
+            return scopes;
+        }
+
+        public void setScopes(final Set<String> scopes) {
+            this.scopes = scopes;
+        }
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/admin/representation/PolicyEvaluationResponse.java b/services/src/main/java/org/keycloak/authorization/admin/representation/PolicyEvaluationResponse.java
new file mode 100644
index 0000000..d320a64
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/admin/representation/PolicyEvaluationResponse.java
@@ -0,0 +1,307 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.admin.representation;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.Decision.Effect;
+import org.keycloak.authorization.common.KeycloakIdentity;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.policy.evaluation.Result;
+import org.keycloak.authorization.policy.evaluation.Result.PolicyResult;
+import org.keycloak.authorization.util.Permissions;
+import org.keycloak.models.utils.ModelToRepresentation;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class PolicyEvaluationResponse {
+
+    private List<EvaluationResultRepresentation> results;
+    private boolean entitlements;
+    private Effect status;
+    private AccessToken rpt;
+
+    private PolicyEvaluationResponse() {
+
+    }
+
+    public static PolicyEvaluationResponse build(List<Result> results, ResourceServer resourceServer, AuthorizationProvider authorization, KeycloakIdentity identity) {
+        PolicyEvaluationResponse response = new PolicyEvaluationResponse();
+        List<EvaluationResultRepresentation> resultsRep = new ArrayList<>();
+        AccessToken accessToken = identity.getAccessToken();
+        AccessToken.Authorization authorizationData = new AccessToken.Authorization();
+
+        authorizationData.setPermissions(Permissions.allPermits(results, authorization));
+        accessToken.setAuthorization(authorizationData);
+
+        response.rpt = accessToken;
+
+        if (results.stream().anyMatch(evaluationResult -> evaluationResult.getEffect().equals(Effect.DENY))) {
+            response.status = Effect.DENY;
+        } else {
+            response.status = Effect.PERMIT;
+        }
+
+        for (Result result : results) {
+            EvaluationResultRepresentation rep = new EvaluationResultRepresentation();
+
+            rep.setStatus(result.getEffect());
+            resultsRep.add(rep);
+
+            if (result.getPermission().getResource() != null) {
+                rep.setResource(ModelToRepresentation.toRepresentation(result.getPermission().getResource(), resourceServer, authorization));
+            } else {
+                ResourceRepresentation resource = new ResourceRepresentation();
+
+                resource.setName("Any Resource with Scopes " + result.getPermission().getScopes().stream().map(Scope::getName).collect(Collectors.toList()));
+
+                rep.setResource(resource);
+            }
+
+            rep.setScopes(result.getPermission().getScopes().stream().map(scope -> ModelToRepresentation.toRepresentation(scope, authorization)).collect(Collectors.toList()));
+
+            List<PolicyResultRepresentation> policies = new ArrayList<>();
+
+            for (PolicyResult policy : result.getResults()) {
+                policies.add(toRepresentation(policy, authorization));
+            }
+
+            rep.setPolicies(policies);
+        }
+
+        resultsRep.sort((o1, o2) -> o1.getResource().getName().compareTo(o2.getResource().getName()));
+
+        Map<String, EvaluationResultRepresentation> groupedResults = new HashMap<>();
+
+        resultsRep.forEach(evaluationResultRepresentation -> {
+            EvaluationResultRepresentation result = groupedResults.get(evaluationResultRepresentation.getResource().getId());
+            ResourceRepresentation resource = evaluationResultRepresentation.getResource();
+
+            if (result == null) {
+                groupedResults.put(resource.getId(), evaluationResultRepresentation);
+                result = evaluationResultRepresentation;
+            }
+
+            if (result.getStatus().equals(Effect.PERMIT) || (evaluationResultRepresentation.getStatus().equals(Effect.PERMIT) && result.getStatus().equals(Effect.DENY))) {
+                result.setStatus(Effect.PERMIT);
+            }
+
+            List<ScopeRepresentation> scopes = result.getScopes();
+
+            if (scopes == null) {
+                scopes = new ArrayList<>();
+                result.setScopes(scopes);
+            }
+
+            List<ScopeRepresentation> currentScopes = evaluationResultRepresentation.getScopes();
+
+            if (currentScopes != null) {
+                for (ScopeRepresentation scope : currentScopes) {
+                    if (!scopes.contains(scope)) {
+                        scopes.add(scope);
+                    }
+                    if (evaluationResultRepresentation.getStatus().equals(Effect.PERMIT)) {
+                        result.getAllowedScopes().add(scope);
+                    }
+                }
+            }
+
+            if (resource.getId() != null) {
+                if (!scopes.isEmpty()) {
+                    result.getResource().setName(evaluationResultRepresentation.getResource().getName() + " with scopes " + scopes.stream().flatMap((Function<ScopeRepresentation, Stream<?>>) scopeRepresentation -> Arrays.asList(scopeRepresentation.getName()).stream()).collect(Collectors.toList()));
+                } else {
+                    result.getResource().setName(evaluationResultRepresentation.getResource().getName());
+                }
+            } else {
+                result.getResource().setName("Any Resource with Scopes " + scopes.stream().flatMap((Function<ScopeRepresentation, Stream<?>>) scopeRepresentation -> Arrays.asList(scopeRepresentation.getName()).stream()).collect(Collectors.toList()));
+            }
+
+            List<PolicyResultRepresentation> policies = result.getPolicies();
+
+            for (PolicyResultRepresentation policy : new ArrayList<>(evaluationResultRepresentation.getPolicies())) {
+                if (!policies.contains(policy)) {
+                    policies.add(policy);
+                } else {
+                    policy = policies.get(policies.indexOf(policy));
+                }
+
+                if (policy.getStatus().equals(Effect.DENY)) {
+                    Policy policyModel = authorization.getStoreFactory().getPolicyStore().findById(policy.getPolicy().getId());
+                    for (ScopeRepresentation scope : policyModel.getScopes().stream().map(scopeModel -> ModelToRepresentation.toRepresentation(scopeModel, authorization)).collect(Collectors.toList())) {
+                        if (!policy.getScopes().contains(scope)) {
+                            policy.getScopes().add(scope);
+                        }
+                    }
+                    for (ScopeRepresentation scope : currentScopes) {
+                        if (!policy.getScopes().contains(scope)) {
+                            policy.getScopes().add(scope);
+                        }
+                    }
+                }
+            }
+        });
+
+        response.results = groupedResults.values().stream().collect(Collectors.toList());
+
+        return response;
+    }
+
+    private static PolicyResultRepresentation toRepresentation(PolicyResult policy, AuthorizationProvider authorization) {
+        PolicyResultRepresentation policyResultRep = new PolicyResultRepresentation();
+
+        policyResultRep.setPolicy(ModelToRepresentation.toRepresentation(policy.getPolicy(), authorization));
+        policyResultRep.setStatus(policy.getStatus());
+        policyResultRep.setAssociatedPolicies(policy.getAssociatedPolicies().stream().map(result -> toRepresentation(result, authorization)).collect(Collectors.toList()));
+
+        return policyResultRep;
+    }
+
+    public List<EvaluationResultRepresentation> getResults() {
+        return results;
+    }
+
+    public Effect getStatus() {
+        return status;
+    }
+
+    public boolean isEntitlements() {
+        return entitlements;
+    }
+
+    public AccessToken getRpt() {
+        return rpt;
+    }
+
+    public static class EvaluationResultRepresentation {
+
+        private ResourceRepresentation resource;
+        private List<ScopeRepresentation> scopes;
+        private List<PolicyResultRepresentation> policies;
+        private Effect status;
+        private List<ScopeRepresentation> allowedScopes = new ArrayList<>();
+
+        public void setResource(final ResourceRepresentation resource) {
+            this.resource = resource;
+        }
+
+        public ResourceRepresentation getResource() {
+            return resource;
+        }
+
+        public void setScopes(List<ScopeRepresentation> scopes) {
+            this.scopes = scopes;
+        }
+
+        public List<ScopeRepresentation> getScopes() {
+            return scopes;
+        }
+
+        public void setPolicies(final List<PolicyResultRepresentation> policies) {
+            this.policies = policies;
+        }
+
+        public List<PolicyResultRepresentation> getPolicies() {
+            return policies;
+        }
+
+        public void setStatus(final Effect status) {
+            this.status = status;
+        }
+
+        public Effect getStatus() {
+            return status;
+        }
+
+        public void setAllowedScopes(List<ScopeRepresentation> allowedScopes) {
+            this.allowedScopes = allowedScopes;
+        }
+
+        public List<ScopeRepresentation> getAllowedScopes() {
+            return allowedScopes;
+        }
+    }
+
+    public static class PolicyResultRepresentation {
+
+        private PolicyRepresentation policy;
+        private Effect status;
+        private List<PolicyResultRepresentation> associatedPolicies;
+        private List<ScopeRepresentation> scopes = new ArrayList<>();
+
+        public PolicyRepresentation getPolicy() {
+            return policy;
+        }
+
+        public void setPolicy(final PolicyRepresentation policy) {
+            this.policy = policy;
+        }
+
+        public Effect getStatus() {
+            return status;
+        }
+
+        public void setStatus(final Effect status) {
+            this.status = status;
+        }
+
+        public List<PolicyResultRepresentation> getAssociatedPolicies() {
+            return associatedPolicies;
+        }
+
+        public void setAssociatedPolicies(final List<PolicyResultRepresentation> associatedPolicies) {
+            this.associatedPolicies = associatedPolicies;
+        }
+
+        @Override
+        public int hashCode() {
+            return this.policy.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            final PolicyResultRepresentation policy = (PolicyResultRepresentation) o;
+            return this.policy.equals(policy.getPolicy());
+        }
+
+        public void setScopes(List<ScopeRepresentation> scopes) {
+            this.scopes = scopes;
+        }
+
+        public List<ScopeRepresentation> getScopes() {
+            return scopes;
+        }
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/admin/ResourceServerService.java b/services/src/main/java/org/keycloak/authorization/admin/ResourceServerService.java
new file mode 100644
index 0000000..d02b827
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/admin/ResourceServerService.java
@@ -0,0 +1,231 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.admin;
+
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.authorization.store.ResourceStore;
+import org.keycloak.authorization.store.ScopeStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.exportimport.util.ExportUtils;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.utils.RepresentationToModel;
+import org.keycloak.representations.idm.authorization.DecisionStrategy;
+import org.keycloak.representations.idm.authorization.Logic;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
+import org.keycloak.services.resources.admin.RealmAuth;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.io.IOException;
+import java.util.HashMap;
+
+import static org.keycloak.models.utils.ModelToRepresentation.toRepresentation;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ResourceServerService {
+
+    private final AuthorizationProvider authorization;
+    private final RealmAuth auth;
+    private final KeycloakSession session;
+    private ResourceServer resourceServer;
+    private final ClientModel client;
+
+    public ResourceServerService(AuthorizationProvider authorization, ResourceServer resourceServer, ClientModel client, RealmAuth auth) {
+        this.authorization = authorization;
+        this.session = authorization.getKeycloakSession();
+        this.client = client;
+        this.resourceServer = resourceServer;
+        this.auth = auth;
+    }
+
+    public void create() {
+        this.auth.requireManage();
+        this.resourceServer = this.authorization.getStoreFactory().getResourceServerStore().create(this.client.getId());
+        createDefaultRoles();
+        createDefaultPermission(createDefaultResource(), createDefaultPolicy());
+    }
+
+    @PUT
+    @Consumes("application/json")
+    @Produces("application/json")
+    public Response update(ResourceServerRepresentation server) {
+        this.auth.requireManage();
+        this.resourceServer.setAllowRemoteResourceManagement(server.isAllowRemoteResourceManagement());
+        this.resourceServer.setPolicyEnforcementMode(server.getPolicyEnforcementMode());
+
+        return Response.noContent().build();
+    }
+
+    public void delete() {
+        this.auth.requireManage();
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        ResourceStore resourceStore = storeFactory.getResourceStore();
+        String id = resourceServer.getId();
+
+        resourceStore.findByResourceServer(id).forEach(resource -> resourceStore.delete(resource.getId()));
+
+        ScopeStore scopeStore = storeFactory.getScopeStore();
+
+        scopeStore.findByResourceServer(id).forEach(scope -> scopeStore.delete(scope.getId()));
+
+        PolicyStore policyStore = storeFactory.getPolicyStore();
+
+        policyStore.findByResourceServer(id).forEach(scope -> policyStore.delete(scope.getId()));
+
+        storeFactory.getResourceServerStore().delete(id);
+    }
+
+    @GET
+    @Produces("application/json")
+    public Response findById() {
+        this.auth.requireView();
+        return Response.ok(toRepresentation(this.resourceServer, this.client)).build();
+    }
+
+    @Path("/settings")
+    @GET
+    @Produces("application/json")
+    public Response exportSettings() {
+        this.auth.requireManage();
+        return Response.ok(ExportUtils.exportAuthorizationSettings(session, client)).build();
+    }
+
+    @Path("/import")
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response importSettings(@Context final UriInfo uriInfo, ResourceServerRepresentation rep) throws IOException {
+        this.auth.requireManage();
+
+        rep.setClientId(client.getId());
+
+        RepresentationToModel.toModel(rep, authorization);
+
+        return Response.noContent().build();
+    }
+
+    @Path("/resource")
+    public ResourceSetService getResourceSetResource() {
+        ResourceSetService resource = new ResourceSetService(this.resourceServer, this.authorization, this.auth);
+
+        ResteasyProviderFactory.getInstance().injectProperties(resource);
+
+        return resource;
+    }
+
+    @Path("/scope")
+    public ScopeService getScopeResource() {
+        ScopeService resource = new ScopeService(this.resourceServer, this.authorization, this.auth);
+
+        ResteasyProviderFactory.getInstance().injectProperties(resource);
+
+        return resource;
+    }
+
+    @Path("/policy")
+    public PolicyService getPolicyResource() {
+        PolicyService resource = new PolicyService(this.resourceServer, this.authorization, this.auth);
+
+        ResteasyProviderFactory.getInstance().injectProperties(resource);
+
+        return resource;
+    }
+
+    private void createDefaultPermission(ResourceRepresentation resource, PolicyRepresentation policy) {
+        PolicyRepresentation defaultPermission = new PolicyRepresentation();
+
+        defaultPermission.setName("Default Permission");
+        defaultPermission.setType("resource");
+        defaultPermission.setDescription("A permission that applies to the default resource type");
+        defaultPermission.setDecisionStrategy(DecisionStrategy.UNANIMOUS);
+        defaultPermission.setLogic(Logic.POSITIVE);
+
+        HashMap<String, String> defaultPermissionConfig = new HashMap<>();
+
+        defaultPermissionConfig.put("default", "true");
+        defaultPermissionConfig.put("defaultResourceType", resource.getType());
+        defaultPermissionConfig.put("applyPolicies", "[\"" + policy.getName() + "\"]");
+
+        defaultPermission.setConfig(defaultPermissionConfig);
+
+        getPolicyResource().create(defaultPermission);
+    }
+
+    private PolicyRepresentation createDefaultPolicy() {
+        PolicyRepresentation defaultPolicy = new PolicyRepresentation();
+
+        defaultPolicy.setName("Default Policy");
+        defaultPolicy.setDescription("A policy that grants access only for users within this realm");
+        defaultPolicy.setType("js");
+        defaultPolicy.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE);
+        defaultPolicy.setLogic(Logic.POSITIVE);
+
+        HashMap<String, String> defaultPolicyConfig = new HashMap<>();
+
+        defaultPolicyConfig.put("code", "// by default, grants any permission associated with this policy\n$evaluation.grant();\n");
+
+        defaultPolicy.setConfig(defaultPolicyConfig);
+
+        getPolicyResource().create(defaultPolicy);
+
+        return defaultPolicy;
+    }
+
+    private ResourceRepresentation createDefaultResource() {
+        ResourceRepresentation defaultResource = new ResourceRepresentation();
+
+        defaultResource.setName("Default Resource");
+        defaultResource.setUri("/*");
+        defaultResource.setType("urn:" + this.client.getClientId() + ":resources:default");
+
+        getResourceSetResource().create(defaultResource);
+        return defaultResource;
+    }
+
+    private void createDefaultRoles() {
+        RoleModel umaProtectionRole = client.getRole(Constants.AUTHZ_UMA_PROTECTION);
+
+        if (umaProtectionRole == null) {
+            umaProtectionRole = client.addRole(Constants.AUTHZ_UMA_PROTECTION);
+        }
+
+        UserModel serviceAccount = this.session.users().getServiceAccount(client);
+
+        if (!serviceAccount.hasRole(umaProtectionRole)) {
+            serviceAccount.grantRole(umaProtectionRole);
+        }
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java b/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java
new file mode 100644
index 0000000..c628a82
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/admin/ResourceSetService.java
@@ -0,0 +1,195 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.admin;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.authorization.store.ResourceStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.services.ErrorResponse;
+import org.keycloak.services.resources.admin.RealmAuth;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.keycloak.models.utils.ModelToRepresentation.toRepresentation;
+import static org.keycloak.models.utils.RepresentationToModel.toModel;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ResourceSetService {
+
+    private final AuthorizationProvider authorization;
+    private final RealmAuth auth;
+    private ResourceServer resourceServer;
+
+    public ResourceSetService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) {
+        this.resourceServer = resourceServer;
+        this.authorization = authorization;
+        this.auth = auth;
+    }
+
+    @POST
+    @Consumes("application/json")
+    @Produces("application/json")
+    public Response create(ResourceRepresentation resource) {
+        requireManage();
+        StoreFactory storeFactory = this.authorization.getStoreFactory();
+        Resource existingResource = storeFactory.getResourceStore().findByName(resource.getName(), this.resourceServer.getId());
+
+        if (existingResource != null && existingResource.getResourceServer().getId().equals(this.resourceServer.getId())
+                && existingResource.getOwner().equals(resource.getOwner())) {
+            return ErrorResponse.exists("Resource with name [" + resource.getName() + "] already exists.");
+        }
+
+        Resource model = toModel(resource, this.resourceServer, authorization);
+
+        ResourceRepresentation representation = new ResourceRepresentation();
+
+        representation.setId(model.getId());
+
+        return Response.status(Status.CREATED).entity(representation).build();
+    }
+
+    @Path("{id}")
+    @PUT
+    @Consumes("application/json")
+    @Produces("application/json")
+    public Response update(@PathParam("id") String id, ResourceRepresentation resource) {
+        requireManage();
+        resource.setId(id);
+        StoreFactory storeFactory = this.authorization.getStoreFactory();
+        ResourceStore resourceStore = storeFactory.getResourceStore();
+        Resource model = resourceStore.findById(resource.getId());
+
+        if (model == null) {
+            return Response.status(Status.NOT_FOUND).build();
+        }
+
+        toModel(resource, resourceServer, authorization);
+
+        return Response.noContent().build();
+    }
+
+    @Path("{id}")
+    @DELETE
+    public Response delete(@PathParam("id") String id) {
+        requireManage();
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        Resource resource = storeFactory.getResourceStore().findById(id);
+
+        if (resource == null) {
+            return Response.status(Status.NOT_FOUND).build();
+        }
+
+        PolicyStore policyStore = storeFactory.getPolicyStore();
+        List<Policy> policies = policyStore.findByResource(id);
+
+        for (Policy policyModel : policies) {
+            if (policyModel.getResources().size() == 1) {
+                policyStore.delete(policyModel.getId());
+            } else {
+                policyModel.addResource(resource);
+            }
+        }
+
+        storeFactory.getResourceStore().delete(id);
+
+        return Response.noContent().build();
+    }
+
+    @Path("{id}")
+    @GET
+    @NoCache
+    @Produces("application/json")
+    public Response findById(@PathParam("id") String id) {
+        requireView();
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        Resource model = storeFactory.getResourceStore().findById(id);
+
+        if (model == null) {
+            return Response.status(Status.NOT_FOUND).build();
+        }
+
+        return Response.ok(toRepresentation(model, this.resourceServer, authorization)).build();
+    }
+
+    @Path("/search")
+    @GET
+    @Produces("application/json")
+    @NoCache
+    public Response find(@QueryParam("name") String name) {
+        this.auth.requireView();
+        StoreFactory storeFactory = authorization.getStoreFactory();
+
+        if (name == null) {
+            return Response.status(Status.BAD_REQUEST).build();
+        }
+
+        Resource model = storeFactory.getResourceStore().findByName(name, this.resourceServer.getId());
+
+        if (model == null) {
+            return Response.status(Status.OK).build();
+        }
+
+        return Response.ok(toRepresentation(model, this.resourceServer, authorization)).build();
+    }
+
+    @GET
+    @NoCache
+    @Produces("application/json")
+    public Response findAll() {
+        requireView();
+        StoreFactory storeFactory = authorization.getStoreFactory();
+
+        return Response.ok(
+                storeFactory.getResourceStore().findByResourceServer(this.resourceServer.getId()).stream()
+                        .map(resource -> toRepresentation(resource, this.resourceServer, authorization))
+                        .collect(Collectors.toList()))
+                .build();
+    }
+
+    private void requireView() {
+        if (this.auth != null) {
+            this.auth.requireView();
+        }
+    }
+
+    private void requireManage() {
+        if (this.auth != null) {
+            this.auth.requireManage();
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/src/main/java/org/keycloak/authorization/admin/ScopeService.java b/services/src/main/java/org/keycloak/authorization/admin/ScopeService.java
new file mode 100644
index 0000000..df0e6da
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/admin/ScopeService.java
@@ -0,0 +1,169 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.admin;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+import org.keycloak.services.ErrorResponse;
+import org.keycloak.services.resources.admin.RealmAuth;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.keycloak.models.utils.ModelToRepresentation.toRepresentation;
+import static org.keycloak.models.utils.RepresentationToModel.toModel;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ScopeService {
+
+    private final AuthorizationProvider authorization;
+    private final RealmAuth auth;
+    private ResourceServer resourceServer;
+
+    public ScopeService(ResourceServer resourceServer, AuthorizationProvider authorization, RealmAuth auth) {
+        this.resourceServer = resourceServer;
+        this.authorization = authorization;
+        this.auth = auth;
+    }
+
+    @POST
+    @Consumes("application/json")
+    @Produces("application/json")
+    public Response create(ScopeRepresentation scope) {
+        this.auth.requireManage();
+        Scope model = toModel(scope, this.resourceServer, authorization);
+
+        scope.setId(model.getId());
+
+        return Response.status(Status.CREATED).entity(scope).build();
+    }
+
+    @Path("{id}")
+    @PUT
+    @Consumes("application/json")
+    @Produces("application/json")
+    public Response update(@PathParam("id") String id, ScopeRepresentation scope) {
+        this.auth.requireManage();
+        scope.setId(id);
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        Scope model = storeFactory.getScopeStore().findById(scope.getId());
+
+        if (model == null) {
+            return Response.status(Status.NOT_FOUND).build();
+        }
+
+        toModel(scope, resourceServer, authorization);
+
+        return Response.noContent().build();
+    }
+
+    @Path("{id}")
+    @DELETE
+    public Response delete(@PathParam("id") String id) {
+        this.auth.requireManage();
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        List<Resource> resources = storeFactory.getResourceStore().findByScope(id);
+
+        if (!resources.isEmpty()) {
+            return ErrorResponse.exists("Scopes can not be removed while associated with resources.");
+        }
+
+        Scope scope = storeFactory.getScopeStore().findById(id);
+        PolicyStore policyStore = storeFactory.getPolicyStore();
+        List<Policy> policies = policyStore.findByScopeIds(Arrays.asList(scope.getId()), resourceServer.getId());
+
+        for (Policy policyModel : policies) {
+            if (policyModel.getScopes().size() == 1) {
+                policyStore.delete(policyModel.getId());
+            } else {
+                policyModel.removeScope(scope);
+            }
+        }
+
+        storeFactory.getScopeStore().delete(id);
+
+        return Response.noContent().build();
+    }
+
+    @Path("{id}")
+    @GET
+    @Produces("application/json")
+    public Response findById(@PathParam("id") String id) {
+        this.auth.requireView();
+        Scope model = this.authorization.getStoreFactory().getScopeStore().findById(id);
+
+        if (model == null) {
+            return Response.status(Status.NOT_FOUND).build();
+        }
+
+        return Response.ok(toRepresentation(model, this.authorization)).build();
+    }
+
+    @Path("/search")
+    @GET
+    @Produces("application/json")
+    @NoCache
+    public Response find(@QueryParam("name") String name) {
+        this.auth.requireView();
+        StoreFactory storeFactory = authorization.getStoreFactory();
+
+        if (name == null) {
+            return Response.status(Status.BAD_REQUEST).build();
+        }
+
+        Scope model = storeFactory.getScopeStore().findByName(name, this.resourceServer.getId());
+
+        if (model == null) {
+            return Response.status(Status.OK).build();
+        }
+
+        return Response.ok(toRepresentation(model, authorization)).build();
+    }
+
+    @GET
+    @Produces("application/json")
+    public Response findAll() {
+        this.auth.requireView();
+        return Response.ok(
+                this.authorization.getStoreFactory().getScopeStore().findByResourceServer(this.resourceServer.getId()).stream()
+                        .map(scope -> toRepresentation(scope, this.authorization))
+                        .collect(Collectors.toList()))
+                .build();
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
new file mode 100644
index 0000000..4e7c2a9
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.authorization;
+
+import org.jboss.resteasy.spi.HttpRequest;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.OAuthErrorException;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.authorization.representation.AuthorizationRequest;
+import org.keycloak.authorization.authorization.representation.AuthorizationResponse;
+import org.keycloak.authorization.common.KeycloakEvaluationContext;
+import org.keycloak.authorization.common.KeycloakIdentity;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.permission.ResourcePermission;
+import org.keycloak.authorization.policy.evaluation.DecisionResultCollector;
+import org.keycloak.authorization.policy.evaluation.Result;
+import org.keycloak.authorization.protection.permission.PermissionTicket;
+import org.keycloak.authorization.store.ResourceStore;
+import org.keycloak.authorization.store.ScopeStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.authorization.util.Permissions;
+import org.keycloak.authorization.util.Tokens;
+import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.JWSInputException;
+import org.keycloak.models.RealmModel;
+import org.keycloak.protocol.oidc.TokenManager;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.idm.authorization.Permission;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+import org.keycloak.services.ErrorResponseException;
+import org.keycloak.services.resources.Cors;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.POST;
+import javax.ws.rs.Produces;
+import javax.ws.rs.container.AsyncResponse;
+import javax.ws.rs.container.Suspended;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AuthorizationTokenService {
+
+    private final AuthorizationProvider authorization;
+
+    @Context
+    private HttpRequest httpRequest;
+
+    public AuthorizationTokenService(AuthorizationProvider authorization) {
+        this.authorization = authorization;
+    }
+
+    @OPTIONS
+    public Response authorizepPreFlight() {
+        return Cors.add(this.httpRequest, Response.ok()).auth().preflight().build();
+    }
+
+    @POST
+    @Consumes("application/json")
+    @Produces("application/json")
+    public void authorize(AuthorizationRequest authorizationRequest, @Suspended AsyncResponse asyncResponse) {
+        KeycloakEvaluationContext evaluationContext = new KeycloakEvaluationContext(this.authorization.getKeycloakSession());
+        KeycloakIdentity identity = (KeycloakIdentity) evaluationContext.getIdentity();
+
+        if (!identity.hasRole("uma_authorization")) {
+            throw new ErrorResponseException(OAuthErrorException.INVALID_SCOPE, "Requires uma_authorization scope.", Status.FORBIDDEN);
+        }
+
+        if (authorizationRequest == null) {
+            throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Invalid authorization request.", Status.BAD_REQUEST);
+        }
+
+        PermissionTicket ticket = verifyPermissionTicket(authorizationRequest);
+
+        authorization.evaluators().from(createPermissions(ticket, authorizationRequest, authorization), evaluationContext).evaluate(new DecisionResultCollector() {
+            @Override
+            public void onComplete(List<Result> results) {
+                List<Permission> entitlements = Permissions.allPermits(results, authorization);
+
+                if (entitlements.isEmpty()) {
+                    HashMap<Object, Object> error = new HashMap<>();
+
+                    error.put(OAuth2Constants.ERROR, "not_authorized");
+
+                    asyncResponse.resume(Cors.add(httpRequest, Response.status(Status.FORBIDDEN)
+                            .entity(error))
+                            .allowedOrigins(identity.getAccessToken())
+                            .exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build());
+                } else {
+                    AuthorizationResponse response = new AuthorizationResponse(createRequestingPartyToken(entitlements, identity.getAccessToken()));
+                    asyncResponse.resume(Cors.add(httpRequest, Response.status(Status.CREATED).entity(response)).allowedOrigins(identity.getAccessToken())
+                            .allowedMethods("POST")
+                            .exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build());
+                }
+            }
+
+            @Override
+            public void onError(Throwable cause) {
+                asyncResponse.resume(cause);
+            }
+        });
+    }
+
+    private List<ResourcePermission> createPermissions(PermissionTicket ticket, AuthorizationRequest request, AuthorizationProvider authorization) {
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        Map<String, Set<String>> permissionsToEvaluate = new HashMap<>();
+
+        ticket.getResources().forEach(requestedResource -> {
+            Resource resource;
+
+            if (requestedResource.getId() != null) {
+                resource = storeFactory.getResourceStore().findById(requestedResource.getId());
+            } else {
+                resource = storeFactory.getResourceStore().findByName(requestedResource.getName(), ticket.getResourceServerId());
+            }
+
+            if (resource == null && (requestedResource.getScopes() == null || requestedResource.getScopes().isEmpty())) {
+                throw new ErrorResponseException("invalid_resource", "Resource with id [" + requestedResource.getId() + "] or name [" + requestedResource.getName() + "] does not exist.", Status.FORBIDDEN);
+            }
+
+            Set<ScopeRepresentation> requestedScopes = requestedResource.getScopes();
+            Set<String> collect = requestedScopes.stream().map(ScopeRepresentation::getName).collect(Collectors.toSet());
+
+            if (resource != null) {
+                permissionsToEvaluate.put(resource.getId(), collect);
+            } else {
+                ResourceStore resourceStore = authorization.getStoreFactory().getResourceStore();
+                ScopeStore scopeStore = authorization.getStoreFactory().getScopeStore();
+                List<Resource> resources = new ArrayList<Resource>();
+
+                resources.addAll(resourceStore.findByScope(requestedScopes.stream().map(scopeRepresentation -> {
+                    Scope scope = scopeStore.findByName(scopeRepresentation.getName(), ticket.getResourceServerId());
+
+                    if (scope == null) {
+                        return null;
+                    }
+
+                    return scope.getId();
+                }).filter(s -> s != null).collect(Collectors.toList()).toArray(new String[requestedScopes.size()])));
+
+                for (Resource resource1 : resources) {
+                    permissionsToEvaluate.put(resource1.getId(), collect);
+                }
+
+                permissionsToEvaluate.put("$KC_SCOPE_PERMISSION", collect);
+            }
+        });
+
+        String rpt = request.getRpt();
+
+        if (rpt != null && !"".equals(rpt)) {
+            if (!Tokens.verifySignature(rpt, getRealm().getPublicKey())) {
+                throw new ErrorResponseException("invalid_rpt", "RPT signature is invalid", Status.FORBIDDEN);
+            }
+
+            AccessToken requestingPartyToken;
+
+            try {
+                requestingPartyToken = new JWSInput(rpt).readJsonContent(AccessToken.class);
+            } catch (JWSInputException e) {
+                throw new ErrorResponseException("invalid_rpt", "Invalid RPT", Status.FORBIDDEN);
+            }
+
+            if (requestingPartyToken.isActive()) {
+                AccessToken.Authorization authorizationData = requestingPartyToken.getAuthorization();
+
+                if (authorizationData != null) {
+                    List<Permission> permissions = authorizationData.getPermissions();
+
+                    if (permissions != null) {
+                        permissions.forEach(permission -> {
+                            Resource resourcePermission = storeFactory.getResourceStore().findById(permission.getResourceSetId());
+
+                            if (resourcePermission != null) {
+                                Set<String> scopes = permissionsToEvaluate.get(resourcePermission.getId());
+
+                                if (scopes == null) {
+                                    scopes = new HashSet<>();
+                                    permissionsToEvaluate.put(resourcePermission.getId(), scopes);
+                                }
+
+                                Set<String> scopePermission = permission.getScopes();
+
+                                if (scopePermission != null) {
+                                    scopes.addAll(scopePermission);
+                                }
+                            }
+                        });
+                    }
+                }
+            }
+        }
+
+        ResourceServer resourceServer = authorization.getStoreFactory().getResourceServerStore().findById(ticket.getResourceServerId());
+
+        return permissionsToEvaluate.entrySet().stream()
+                .flatMap((Function<Entry<String, Set<String>>, Stream<ResourcePermission>>) entry -> {
+                    String key = entry.getKey();
+
+                    if ("$KC_SCOPE_PERMISSION".equals(key)) {
+                        ScopeStore scopeStore = authorization.getStoreFactory().getScopeStore();
+                        List<Scope> scopes = entry.getValue().stream().map(scopeName -> {
+                            Scope byName = scopeStore.findByName(scopeName, resourceServer.getId());
+                            return byName;
+                        }).collect(Collectors.toList());
+                        return Arrays.asList(new ResourcePermission(null, scopes, resourceServer)).stream();
+                    } else {
+                        Resource entryResource = storeFactory.getResourceStore().findById(key);
+                        return Permissions.createResourcePermissions(entryResource, entry.getValue(), authorization).stream();
+                    }
+                }).collect(Collectors.toList());
+    }
+
+    private RealmModel getRealm() {
+        return this.authorization.getKeycloakSession().getContext().getRealm();
+    }
+
+    private String createRequestingPartyToken(List<Permission> permissions, AccessToken accessToken) {
+        AccessToken.Authorization authorization = new AccessToken.Authorization();
+
+        authorization.setPermissions(permissions);
+        accessToken.setAuthorization(authorization);
+
+        return new TokenManager().encodeToken(getRealm(), accessToken);
+    }
+
+    private PermissionTicket verifyPermissionTicket(AuthorizationRequest request) {
+        String ticketString = request.getTicket();
+
+        if (ticketString == null || !Tokens.verifySignature(ticketString, getRealm().getPublicKey())) {
+            throw new ErrorResponseException("invalid_ticket", "Ticket verification failed", Status.FORBIDDEN);
+        }
+
+        try {
+            PermissionTicket ticket = new JWSInput(ticketString).readJsonContent(PermissionTicket.class);
+
+            if (!ticket.isActive()) {
+                throw new ErrorResponseException("invalid_ticket", "Invalid permission ticket.", Status.FORBIDDEN);
+            }
+
+            return ticket;
+        } catch (JWSInputException e) {
+            throw new ErrorResponseException("invalid_ticket", "Could not parse permission ticket.", Status.FORBIDDEN);
+        }
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/authorization/representation/AuthorizationRequest.java b/services/src/main/java/org/keycloak/authorization/authorization/representation/AuthorizationRequest.java
new file mode 100644
index 0000000..d4f0f24
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/authorization/representation/AuthorizationRequest.java
@@ -0,0 +1,49 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.authorization.representation;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AuthorizationRequest {
+
+    private String ticket;
+    private String rpt;
+
+    public AuthorizationRequest(String ticket, String rpt) {
+        this.ticket = ticket;
+        this.rpt = rpt;
+    }
+
+    public AuthorizationRequest(String ticket) {
+        this(ticket, null);
+    }
+
+    public AuthorizationRequest() {
+        this(null, null);
+    }
+
+    public String getTicket() {
+        return this.ticket;
+    }
+
+    public String getRpt() {
+        return this.rpt;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/authorization/representation/AuthorizationResponse.java b/services/src/main/java/org/keycloak/authorization/authorization/representation/AuthorizationResponse.java
new file mode 100644
index 0000000..cd0a521
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/authorization/representation/AuthorizationResponse.java
@@ -0,0 +1,43 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.authorization.representation;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AuthorizationResponse {
+
+    private String rpt;
+
+    public AuthorizationResponse(String rpt) {
+        this.rpt = rpt;
+    }
+
+    public AuthorizationResponse() {
+        this(null);
+    }
+
+    public String getRpt() {
+        return this.rpt;
+    }
+
+    public void setRpt(final String rpt) {
+        this.rpt = rpt;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/AuthorizationService.java b/services/src/main/java/org/keycloak/authorization/AuthorizationService.java
new file mode 100644
index 0000000..f519b40
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/AuthorizationService.java
@@ -0,0 +1,65 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization;
+
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.keycloak.authorization.authorization.AuthorizationTokenService;
+import org.keycloak.authorization.entitlement.EntitlementService;
+import org.keycloak.authorization.protection.ProtectionService;
+
+import javax.ws.rs.Path;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AuthorizationService {
+
+    private final AuthorizationProvider authorization;
+
+    public AuthorizationService(AuthorizationProvider authorization) {
+        this.authorization = authorization;
+    }
+
+    @Path("/entitlement")
+    public Object getEntitlementService() {
+        EntitlementService service = new EntitlementService(this.authorization);
+
+        ResteasyProviderFactory.getInstance().injectProperties(service);
+
+        return service;
+    }
+
+    @Path("/protection")
+    public Object getProtectionService() {
+        ProtectionService service = new ProtectionService(this.authorization);
+
+        ResteasyProviderFactory.getInstance().injectProperties(service);
+
+        return service;
+    }
+
+    @Path("/authorize")
+    public Object authorize() {
+        AuthorizationTokenService resource = new AuthorizationTokenService(this.authorization);
+
+        ResteasyProviderFactory.getInstance().injectProperties(resource);
+
+        return resource;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/common/KeycloakEvaluationContext.java b/services/src/main/java/org/keycloak/authorization/common/KeycloakEvaluationContext.java
new file mode 100644
index 0000000..fc929ec
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/common/KeycloakEvaluationContext.java
@@ -0,0 +1,80 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.common;
+
+import org.keycloak.authorization.attribute.Attributes;
+import org.keycloak.authorization.identity.Identity;
+import org.keycloak.authorization.policy.evaluation.EvaluationContext;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.representations.AccessToken;
+
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class KeycloakEvaluationContext implements EvaluationContext {
+
+    private final KeycloakIdentity identity;
+    private final KeycloakSession keycloakSession;
+
+    public KeycloakEvaluationContext(KeycloakSession keycloakSession) {
+        this(new KeycloakIdentity(keycloakSession), keycloakSession);
+    }
+
+    public KeycloakEvaluationContext(KeycloakIdentity identity, KeycloakSession keycloakSession) {
+        this.identity = identity;
+        this.keycloakSession = keycloakSession;
+    }
+
+    @Override
+    public Identity getIdentity() {
+        return this.identity;
+    }
+
+    @Override
+    public Attributes getAttributes() {
+        HashMap<String, Collection<String>> attributes = new HashMap<>();
+
+        attributes.put("kc.time.date_time", Arrays.asList(new SimpleDateFormat("MM/dd/yyyy hh:mm:ss").format(new Date())));
+        attributes.put("kc.client.network.ip_address", Arrays.asList(this.keycloakSession.getContext().getConnection().getRemoteAddr()));
+        attributes.put("kc.client.network.host", Arrays.asList(this.keycloakSession.getContext().getConnection().getRemoteHost()));
+
+        AccessToken accessToken = this.identity.getAccessToken();
+
+        if (accessToken != null) {
+            attributes.put("kc.client.id", Arrays.asList(accessToken.getIssuedFor()));
+        }
+
+        List<String> userAgents = this.keycloakSession.getContext().getRequestHeaders().getRequestHeader("User-Agent");
+
+        if (userAgents != null) {
+            attributes.put("kc.client.user_agent", userAgents);
+        }
+
+        attributes.put("kc.realm.name", Arrays.asList(this.keycloakSession.getContext().getRealm().getName()));
+
+        return Attributes.from(attributes);
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java b/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java
new file mode 100644
index 0000000..c40c38a
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java
@@ -0,0 +1,155 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.common;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.keycloak.authorization.attribute.Attributes;
+import org.keycloak.authorization.identity.Identity;
+import org.keycloak.authorization.util.Tokens;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.saml.common.util.StringUtil;
+import org.keycloak.services.ErrorResponseException;
+import org.keycloak.util.JsonSerialization;
+
+import javax.ws.rs.core.Response.Status;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class KeycloakIdentity implements Identity {
+
+    private final AccessToken accessToken;
+    private final RealmModel realm;
+    private final KeycloakSession keycloakSession;
+    private final Attributes attributes;
+
+    public KeycloakIdentity(KeycloakSession keycloakSession) {
+        this(Tokens.getAccessToken(keycloakSession), keycloakSession);
+    }
+
+    public KeycloakIdentity(AccessToken accessToken, KeycloakSession keycloakSession) {
+        if (accessToken == null) {
+            throw new ErrorResponseException("invalid_bearer_token", "Could not obtain bearer access_token from request.", Status.FORBIDDEN);
+        }
+        if (keycloakSession == null) {
+            throw new ErrorResponseException("no_keycloak_session", "No keycloak session", Status.FORBIDDEN);
+        }
+        this.accessToken = accessToken;
+        this.keycloakSession = keycloakSession;
+        this.realm = keycloakSession.getContext().getRealm();
+
+        Map<String, Collection<String>> attributes = new HashMap<>();
+
+        try {
+            ObjectNode objectNode = JsonSerialization.createObjectNode(this.accessToken);
+            Iterator<String> iterator = objectNode.fieldNames();
+
+            while (iterator.hasNext()) {
+                String fieldName = iterator.next();
+                JsonNode fieldValue = objectNode.get(fieldName);
+                List<String> values = new ArrayList<>();
+
+                if (fieldValue.isArray()) {
+                    Iterator<JsonNode> valueIterator = fieldValue.iterator();
+
+                    while (valueIterator.hasNext()) {
+                        values.add(valueIterator.next().asText());
+                    }
+                } else {
+                    String value = fieldValue.asText();
+
+                    if (StringUtil.isNullOrEmpty(value)) {
+                        continue;
+                    }
+
+                    values.add(value);
+                }
+
+                if (!values.isEmpty()) {
+                    attributes.put(fieldName, values);
+                }
+            }
+
+            AccessToken.Access realmAccess = accessToken.getRealmAccess();
+
+            if (realmAccess != null) {
+                attributes.put("kc.realm.roles", realmAccess.getRoles());
+            }
+
+            Map<String, AccessToken.Access> resourceAccess = accessToken.getResourceAccess();
+
+            if (resourceAccess != null) {
+                resourceAccess.forEach((clientId, access) -> attributes.put("kc.client." + clientId + ".roles", access.getRoles()));
+            }
+        } catch (Exception e) {
+            throw new RuntimeException("Error while reading attributes from security token.", e);
+        }
+
+        this.attributes = Attributes.from(attributes);
+    }
+
+    @Override
+    public String getId() {
+        if (isResourceServer()) {
+            ClientSessionModel clientSession = this.keycloakSession.sessions().getClientSession(this.accessToken.getClientSession());
+            return clientSession.getClient().getId();
+        }
+
+        return this.accessToken.getSubject();
+    }
+
+    @Override
+    public Attributes getAttributes() {
+        return this.attributes;
+    }
+
+    public AccessToken getAccessToken() {
+        return this.accessToken;
+    }
+
+    private  boolean isResourceServer() {
+        UserModel clientUser = null;
+
+        if (this.accessToken.getClientSession() != null) {
+            ClientSessionModel clientSession = this.keycloakSession.sessions().getClientSession(this.accessToken.getClientSession());
+            clientUser = this.keycloakSession.users().getServiceAccount(clientSession.getClient());
+        } else if (this.accessToken.getIssuedFor() != null) {
+            ClientModel clientModel = this.keycloakSession.realms().getClientById(this.accessToken.getIssuedFor(), this.realm);
+            clientUser = this.keycloakSession.users().getServiceAccount(clientModel);
+        }
+
+
+        if (clientUser == null) {
+            return false;
+        }
+
+        return this.accessToken.getSubject().equals(clientUser.getId());
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/config/Configuration.java b/services/src/main/java/org/keycloak/authorization/config/Configuration.java
new file mode 100644
index 0000000..6669edc
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/config/Configuration.java
@@ -0,0 +1,269 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.config;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.keycloak.protocol.oidc.OIDCWellKnownProvider.DEFAULT_GRANT_TYPES_SUPPORTED;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class Configuration {
+
+    private static final String UMA_VERSION = "1.0";
+    private static final List<String> DEFAULT_TOKEN_PROFILES = Arrays.asList("bearer");
+
+    public static final Configuration fromDefault(String authzServerUri,
+                                                  String realm,
+                                                  URI authorizationEndpoint,
+                                                  URI tokenEndpoint, String publicKeyPem) {
+        Configuration configuration = new Configuration();
+
+        if (authzServerUri.endsWith("/")) {
+            authzServerUri = authzServerUri.substring(0, authzServerUri.lastIndexOf("/"));
+        }
+
+        configuration.setVersion(UMA_VERSION);
+        configuration.setIssuer(URI.create(authzServerUri));
+        configuration.setPatProfiles(DEFAULT_TOKEN_PROFILES);
+        configuration.setAatProfiles(DEFAULT_TOKEN_PROFILES);
+        configuration.setRptProfiles(DEFAULT_TOKEN_PROFILES);
+        configuration.setPatGrantTypes(DEFAULT_GRANT_TYPES_SUPPORTED);
+        configuration.setAatGrantTypes(DEFAULT_GRANT_TYPES_SUPPORTED);
+        configuration.setTokenEndpoint(tokenEndpoint);
+        configuration.setAuthorizationEndpoint(authorizationEndpoint);
+        configuration.setResourceSetRegistrationEndpoint(URI.create(authzServerUri + "/authz/protection/resource_set"));
+        configuration.setPermissionRegistrationEndpoint(URI.create(authzServerUri + "/authz/protection/permission"));
+        configuration.setRptEndpoint(URI.create(authzServerUri + "/authz/authorize"));
+        configuration.setRealmPublicKey(publicKeyPem);
+        configuration.setServerUrl(URI.create(authzServerUri));
+        configuration.setRealm(realm);
+
+        return configuration;
+    }
+
+    private String realmPublicKey;
+    private String version;
+    private URI issuer;
+
+    @JsonProperty("pat_profiles_supported")
+    private List<String> patProfiles;
+
+    @JsonProperty("pat_grant_types_supported")
+    private List<String> patGrantTypes;
+
+    @JsonProperty("aat_profiles_supported")
+    private List<String> aatProfiles;
+
+    @JsonProperty("aat_grant_types_supported")
+    private List<String> aatGrantTypes;
+
+    @JsonProperty("rpt_profiles_supported")
+    private List<String> rptProfiles;
+
+    @JsonProperty("claim_token_profiles_supported")
+    private List<String> claimTokenProfiles;
+
+    @JsonProperty("dynamic_client_endpoint")
+    private URI dynamicClientEndpoint;
+
+    @JsonProperty("token_endpoint")
+    private URI tokenEndpoint;
+
+    @JsonProperty("authorization_endpoint")
+    private URI authorizationEndpoint;
+
+    @JsonProperty("requesting_party_claims_endpoint")
+    private URI requestingPartyClaimsEndpoint;
+
+    @JsonProperty("resource_set_registration_endpoint")
+    private URI resourceSetRegistrationEndpoint;
+
+    @JsonProperty("introspection_endpoint")
+    private URI introspectionEndpoint;
+
+    @JsonProperty("permission_registration_endpoint")
+    private URI permissionRegistrationEndpoint;
+
+    @JsonProperty("rpt_endpoint")
+    private URI rptEndpoint;
+
+    /**
+     * Non-standard, Keycloak specific configuration options
+     */
+    private String realm;
+
+    private URI serverUrl;
+
+    public String getVersion() {
+        return this.version;
+    }
+
+    void setVersion(final String version) {
+        this.version = version;
+    }
+
+    public URI getIssuer() {
+        return this.issuer;
+    }
+
+    void setIssuer(final URI issuer) {
+        this.issuer = issuer;
+    }
+
+    public List<String> getPatProfiles() {
+        return this.patProfiles;
+    }
+
+    void setPatProfiles(final List<String> patProfiles) {
+        this.patProfiles = patProfiles;
+    }
+
+    public List<String> getPatGrantTypes() {
+        return this.patGrantTypes;
+    }
+
+    void setPatGrantTypes(final List<String> patGrantTypes) {
+        this.patGrantTypes = patGrantTypes;
+    }
+
+    public List<String> getAatProfiles() {
+        return this.aatProfiles;
+    }
+
+    void setAatProfiles(final List<String> aatProfiles) {
+        this.aatProfiles = aatProfiles;
+    }
+
+    public List<String> getAatGrantTypes() {
+        return this.aatGrantTypes;
+    }
+
+    void setAatGrantTypes(final List<String> aatGrantTypes) {
+        this.aatGrantTypes = aatGrantTypes;
+    }
+
+    public List<String> getRptProfiles() {
+        return this.rptProfiles;
+    }
+
+    void setRptProfiles(final List<String> rptProfiles) {
+        this.rptProfiles = rptProfiles;
+    }
+
+    public List<String> getClaimTokenProfiles() {
+        return this.claimTokenProfiles;
+    }
+
+    void setClaimTokenProfiles(final List<String> claimTokenProfiles) {
+        this.claimTokenProfiles = claimTokenProfiles;
+    }
+
+    public URI getDynamicClientEndpoint() {
+        return this.dynamicClientEndpoint;
+    }
+
+    void setDynamicClientEndpoint(final URI dynamicClientEndpoint) {
+        this.dynamicClientEndpoint = dynamicClientEndpoint;
+    }
+
+    public URI getTokenEndpoint() {
+        return this.tokenEndpoint;
+    }
+
+    void setTokenEndpoint(final URI tokenEndpoint) {
+        this.tokenEndpoint = tokenEndpoint;
+    }
+
+    public URI getAuthorizationEndpoint() {
+        return this.authorizationEndpoint;
+    }
+
+    void setAuthorizationEndpoint(final URI authorizationEndpoint) {
+        this.authorizationEndpoint = authorizationEndpoint;
+    }
+
+    public URI getRequestingPartyClaimsEndpoint() {
+        return this.requestingPartyClaimsEndpoint;
+    }
+
+    void setRequestingPartyClaimsEndpoint(final URI requestingPartyClaimsEndpoint) {
+        this.requestingPartyClaimsEndpoint = requestingPartyClaimsEndpoint;
+    }
+
+    public URI getResourceSetRegistrationEndpoint() {
+        return this.resourceSetRegistrationEndpoint;
+    }
+
+    void setResourceSetRegistrationEndpoint(final URI resourceSetRegistrationEndpoint) {
+        this.resourceSetRegistrationEndpoint = resourceSetRegistrationEndpoint;
+    }
+
+    public URI getIntrospectionEndpoint() {
+        return this.introspectionEndpoint;
+    }
+
+    void setIntrospectionEndpoint(final URI introspectionEndpoint) {
+        this.introspectionEndpoint = introspectionEndpoint;
+    }
+
+    public URI getPermissionRegistrationEndpoint() {
+        return this.permissionRegistrationEndpoint;
+    }
+
+    void setPermissionRegistrationEndpoint(final URI permissionRegistrationEndpoint) {
+        this.permissionRegistrationEndpoint = permissionRegistrationEndpoint;
+    }
+
+    public URI getRptEndpoint() {
+        return this.rptEndpoint;
+    }
+
+    void setRptEndpoint(final URI rptEndpoint) {
+        this.rptEndpoint = rptEndpoint;
+    }
+
+    public String getRealm() {
+        return this.realm;
+    }
+
+    public void setRealm(final String realm) {
+        this.realm = realm;
+    }
+
+    public URI getServerUrl() {
+        return this.serverUrl;
+    }
+
+    public void setServerUrl(URI serverUrl) {
+        this.serverUrl = serverUrl;
+    }
+
+    public void setRealmPublicKey(String realmPublicKey) {
+        this.realmPublicKey = realmPublicKey;
+    }
+
+    public String getRealmPublicKey() {
+        return realmPublicKey;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/config/UmaWellKnownProvider.java b/services/src/main/java/org/keycloak/authorization/config/UmaWellKnownProvider.java
new file mode 100644
index 0000000..07e5908
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/config/UmaWellKnownProvider.java
@@ -0,0 +1,56 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.authorization.config;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
+import org.keycloak.services.resources.RealmsResource;
+import org.keycloak.wellknown.WellKnownProvider;
+
+import javax.ws.rs.core.UriInfo;
+import java.net.URI;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class UmaWellKnownProvider implements WellKnownProvider {
+
+    private final KeycloakSession session;
+
+    public UmaWellKnownProvider(KeycloakSession session) {
+        this.session = session;
+    }
+
+    @Override
+    public Object getConfig() {
+        RealmModel realm = this.session.getContext().getRealm();
+        UriInfo uriInfo = this.session.getContext().getUri();
+
+        return Configuration.fromDefault(RealmsResource.realmBaseUrl(uriInfo).build(realm.getName()).toString(), realm.getName(),
+                URI.create(RealmsResource.protocolUrl(uriInfo).path(OIDCLoginProtocolService.class, "auth").build(realm.getName(), OIDCLoginProtocol.LOGIN_PROTOCOL).toString()),
+                URI.create(RealmsResource.protocolUrl(uriInfo).path(OIDCLoginProtocolService.class, "token").build(realm.getName(), OIDCLoginProtocol.LOGIN_PROTOCOL).toString()),
+                realm.getPublicKeyPem());
+    }
+
+    @Override
+    public void close() {
+
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/config/UmaWellKnownProviderFactory.java b/services/src/main/java/org/keycloak/authorization/config/UmaWellKnownProviderFactory.java
new file mode 100644
index 0000000..7776720
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/config/UmaWellKnownProviderFactory.java
@@ -0,0 +1,54 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.authorization.config;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.wellknown.WellKnownProvider;
+import org.keycloak.wellknown.WellKnownProviderFactory;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class UmaWellKnownProviderFactory implements WellKnownProviderFactory {
+    @Override
+    public WellKnownProvider create(KeycloakSession session) {
+        return new UmaWellKnownProvider(session);
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "uma-configuration";
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/DefaultAuthorizationProviderFactory.java b/services/src/main/java/org/keycloak/authorization/DefaultAuthorizationProviderFactory.java
new file mode 100644
index 0000000..6146594
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/DefaultAuthorizationProviderFactory.java
@@ -0,0 +1,79 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization;
+
+import org.keycloak.Config;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.cache.authorization.CachedStoreFactoryProvider;
+
+import java.util.concurrent.Executor;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class DefaultAuthorizationProviderFactory implements AuthorizationProviderFactory {
+
+    private Executor scheduler;
+
+    @Override
+    public AuthorizationProvider create(KeycloakSession session) {
+        return create(session, session.getContext().getRealm());
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+        //TODO: user-defined configuration
+//        Executor executor = Executors.newWorkStealingPool();
+//        this.scheduler = command -> {
+//            Map<Class<?>, Object> contextDataMap = ResteasyProviderFactory.getContextDataMap();
+//            executor.execute(() -> {
+//                ResteasyProviderFactory.pushContextDataMap(contextDataMap);
+//                command.run();
+//            });
+//        };
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "authorization";
+    }
+
+    @Override
+    public AuthorizationProvider create(KeycloakSession session, RealmModel realm) {
+        StoreFactory storeFactory = session.getProvider(CachedStoreFactoryProvider.class);
+
+        if (storeFactory == null) {
+            storeFactory = session.getProvider(StoreFactory.class);
+        }
+
+        return new AuthorizationProvider(session, realm, storeFactory);
+    }
+}
\ No newline at end of file
diff --git a/services/src/main/java/org/keycloak/authorization/entitlement/EntitlementService.java b/services/src/main/java/org/keycloak/authorization/entitlement/EntitlementService.java
new file mode 100644
index 0000000..e281063
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/entitlement/EntitlementService.java
@@ -0,0 +1,314 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.entitlement;
+
+import org.jboss.resteasy.spi.HttpRequest;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.OAuthErrorException;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.common.KeycloakEvaluationContext;
+import org.keycloak.authorization.common.KeycloakIdentity;
+import org.keycloak.authorization.entitlement.representation.EntitlementRequest;
+import org.keycloak.authorization.entitlement.representation.EntitlementResponse;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.permission.ResourcePermission;
+import org.keycloak.authorization.policy.evaluation.DecisionResultCollector;
+import org.keycloak.authorization.policy.evaluation.Result;
+import org.keycloak.authorization.store.ResourceStore;
+import org.keycloak.authorization.store.ScopeStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.authorization.util.Permissions;
+import org.keycloak.authorization.util.Tokens;
+import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.JWSInputException;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakContext;
+import org.keycloak.models.RealmModel;
+import org.keycloak.protocol.oidc.TokenManager;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.idm.authorization.Permission;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+import org.keycloak.services.ErrorResponseException;
+import org.keycloak.services.resources.Cors;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.OPTIONS;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.container.AsyncResponse;
+import javax.ws.rs.container.Suspended;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class EntitlementService {
+
+    private final AuthorizationProvider authorization;
+
+    @Context
+    private HttpRequest request;
+
+    public EntitlementService(AuthorizationProvider authorization) {
+        this.authorization = authorization;
+    }
+
+    @Path("{resource_server_id}")
+    @OPTIONS
+    public Response authorizePreFlight(@PathParam("resource_server_id") String resourceServerId) {
+        return Cors.add(this.request, Response.ok()).auth().preflight().build();
+    }
+
+    @Path("{resource_server_id}")
+    @GET()
+    @Produces("application/json")
+    @Consumes("application/json")
+    public void getAll(@PathParam("resource_server_id") String resourceServerId, @Suspended AsyncResponse asyncResponse) {
+        KeycloakIdentity identity = new KeycloakIdentity(this.authorization.getKeycloakSession());
+
+        if (resourceServerId == null) {
+            throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Requires resource_server_id request parameter.", Status.BAD_REQUEST);
+        }
+
+        RealmModel realm = this.authorization.getKeycloakSession().getContext().getRealm();
+        ClientModel client = realm.getClientByClientId(resourceServerId);
+
+        if (client == null) {
+            throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Identifier is not associated with any client and resource server.", Status.BAD_REQUEST);
+        }
+
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        ResourceServer resourceServer = storeFactory.getResourceServerStore().findByClient(client.getId());
+
+        authorization.evaluators().from(Permissions.all(resourceServer, identity, authorization), new KeycloakEvaluationContext(this.authorization.getKeycloakSession())).evaluate(new DecisionResultCollector() {
+
+            @Override
+            public void onError(Throwable cause) {
+                asyncResponse.resume(cause);
+            }
+
+            @Override
+            protected void onComplete(List<Result> results) {
+                List<Permission> entitlements = Permissions.allPermits(results, authorization);
+
+                if (entitlements.isEmpty()) {
+                    HashMap<Object, Object> error = new HashMap<>();
+
+                    error.put(OAuth2Constants.ERROR, "not_authorized");
+
+                    asyncResponse.resume(Cors.add(request, Response.status(Status.FORBIDDEN)
+                            .entity(error))
+                            .allowedOrigins(identity.getAccessToken())
+                            .exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build());
+                } else {
+                    asyncResponse.resume(Cors.add(request, Response.ok().entity(new EntitlementResponse(createRequestingPartyToken(entitlements)))).allowedOrigins(identity.getAccessToken()).allowedMethods("GET").exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build());
+                }
+            }
+        });
+    }
+
+    @Path("{resource_server_id}")
+    @POST
+    @Consumes("application/json")
+    @Produces("application/json")
+    public void get(@PathParam("resource_server_id") String resourceServerId, EntitlementRequest entitlementRequest, @Suspended AsyncResponse asyncResponse) {
+        KeycloakIdentity identity = new KeycloakIdentity(this.authorization.getKeycloakSession());
+
+        if (entitlementRequest == null) {
+            throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Invalid entitlement request.", Status.BAD_REQUEST);
+        }
+
+        if (resourceServerId == null) {
+            throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Invalid resource_server_id.", Status.BAD_REQUEST);
+        }
+
+        RealmModel realm = this.authorization.getKeycloakSession().getContext().getRealm();
+
+        ClientModel client = realm.getClientByClientId(resourceServerId);
+
+        if (client == null) {
+            throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Identifier is not associated with any resource server.", Status.BAD_REQUEST);
+        }
+
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        ResourceServer resourceServer = storeFactory.getResourceServerStore().findByClient(client.getId());
+
+        authorization.evaluators().from(createPermissions(entitlementRequest, resourceServer, authorization), new KeycloakEvaluationContext(this.authorization.getKeycloakSession())).evaluate(new DecisionResultCollector() {
+
+            @Override
+            public void onError(Throwable cause) {
+                asyncResponse.resume(cause);
+            }
+
+            @Override
+            protected void onComplete(List<Result> results) {
+                List<Permission> entitlements = Permissions.allPermits(results, authorization);
+
+                if (entitlements.isEmpty()) {
+                    HashMap<Object, Object> error = new HashMap<>();
+
+                    error.put(OAuth2Constants.ERROR, "not_authorized");
+
+                    asyncResponse.resume(Cors.add(request, Response.status(Status.FORBIDDEN)
+                            .entity(error))
+                            .allowedOrigins(identity.getAccessToken())
+                            .exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build());
+                } else {
+                    asyncResponse.resume(Cors.add(request, Response.ok().entity(new EntitlementResponse(createRequestingPartyToken(entitlements)))).allowedOrigins(identity.getAccessToken()).allowedMethods("GET").exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build());
+                }
+            }
+        });
+    }
+
+    private String createRequestingPartyToken(List<Permission> permissions) {
+        AccessToken accessToken = Tokens.getAccessToken(this.authorization.getKeycloakSession());
+        RealmModel realm = this.authorization.getKeycloakSession().getContext().getRealm();
+        AccessToken.Authorization authorization = new AccessToken.Authorization();
+
+        authorization.setPermissions(permissions);
+        accessToken.setAuthorization(authorization);
+
+        return new TokenManager().encodeToken(realm, accessToken);
+    }
+
+    private List<ResourcePermission> createPermissions(EntitlementRequest entitlementRequest, ResourceServer resourceServer, AuthorizationProvider authorization) {
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        Map<String, Set<String>> permissionsToEvaluate = new HashMap<>();
+
+        entitlementRequest.getPermissions().forEach(requestedResource -> {
+            Resource resource;
+
+            if (requestedResource.getResourceSetId() != null) {
+                resource = storeFactory.getResourceStore().findById(requestedResource.getResourceSetId());
+            } else {
+                resource = storeFactory.getResourceStore().findByName(requestedResource.getResourceSetName(), resourceServer.getId());
+            }
+
+            if (resource == null && (requestedResource.getScopes() == null || requestedResource.getScopes().isEmpty())) {
+                throw new ErrorResponseException("invalid_resource", "Resource with id [" + requestedResource.getResourceSetId() + "] or name [" + requestedResource.getResourceSetName() + "] does not exist.", Status.FORBIDDEN);
+            }
+
+            Set<ScopeRepresentation> requestedScopes = requestedResource.getScopes().stream().map(ScopeRepresentation::new).collect(Collectors.toSet());
+            Set<String> collect = requestedScopes.stream().map(ScopeRepresentation::getName).collect(Collectors.toSet());
+
+            if (resource != null) {
+                permissionsToEvaluate.put(resource.getId(), collect);
+            } else {
+                ResourceStore resourceStore = authorization.getStoreFactory().getResourceStore();
+                ScopeStore scopeStore = authorization.getStoreFactory().getScopeStore();
+                List<Resource> resources = new ArrayList<Resource>();
+
+                resources.addAll(resourceStore.findByScope(requestedScopes.stream().map(scopeRepresentation -> {
+                    Scope scope = scopeStore.findByName(scopeRepresentation.getName(), resourceServer.getId());
+
+                    if (scope == null) {
+                        return null;
+                    }
+
+                    return scope.getId();
+                }).filter(s -> s != null).collect(Collectors.toList()).toArray(new String[requestedScopes.size()])));
+
+                for (Resource resource1 : resources) {
+                    permissionsToEvaluate.put(resource1.getId(), collect);
+                }
+
+                permissionsToEvaluate.put("$KC_SCOPE_PERMISSION", collect);
+            }
+        });
+
+        String rpt = entitlementRequest.getRpt();
+
+        if (rpt != null && !"".equals(rpt)) {
+            KeycloakContext context = authorization.getKeycloakSession().getContext();
+            if (!Tokens.verifySignature(rpt, context.getRealm().getPublicKey())) {
+                throw new ErrorResponseException("invalid_rpt", "RPT signature is invalid", Status.FORBIDDEN);
+            }
+
+            AccessToken requestingPartyToken;
+
+            try {
+                requestingPartyToken = new JWSInput(rpt).readJsonContent(AccessToken.class);
+            } catch (JWSInputException e) {
+                throw new ErrorResponseException("invalid_rpt", "Invalid RPT", Status.FORBIDDEN);
+            }
+
+            if (requestingPartyToken.isActive()) {
+                AccessToken.Authorization authorizationData = requestingPartyToken.getAuthorization();
+
+                if (authorizationData != null) {
+                    List<Permission> permissions = authorizationData.getPermissions();
+
+                    if (permissions != null) {
+                        permissions.forEach(permission -> {
+                            Resource resourcePermission = storeFactory.getResourceStore().findById(permission.getResourceSetId());
+
+                            if (resourcePermission != null) {
+                                Set<String> scopes = permissionsToEvaluate.get(resourcePermission.getId());
+
+                                if (scopes == null) {
+                                    scopes = new HashSet<>();
+                                    permissionsToEvaluate.put(resourcePermission.getId(), scopes);
+                                }
+
+                                Set<String> scopePermission = permission.getScopes();
+
+                                if (scopePermission != null) {
+                                    scopes.addAll(scopePermission);
+                                }
+                            }
+                        });
+                    }
+                }
+            }
+        }
+
+        return permissionsToEvaluate.entrySet().stream()
+                .flatMap((Function<Map.Entry<String, Set<String>>, Stream<ResourcePermission>>) entry -> {
+                    String key = entry.getKey();
+
+                    if ("$KC_SCOPE_PERMISSION".equals(key)) {
+                        ScopeStore scopeStore = authorization.getStoreFactory().getScopeStore();
+                        List<Scope> scopes = entry.getValue().stream().map(scopeName -> {
+                            Scope byName = scopeStore.findByName(scopeName, resourceServer.getId());
+                            return byName;
+                        }).collect(Collectors.toList());
+                        return Arrays.asList(new ResourcePermission(null, scopes, resourceServer)).stream();
+                    } else {
+                        Resource entryResource = storeFactory.getResourceStore().findById(key);
+                        return Permissions.createResourcePermissions(entryResource, entry.getValue(), authorization).stream();
+                    }
+                }).collect(Collectors.toList());
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/entitlement/representation/EntitlementRequest.java b/services/src/main/java/org/keycloak/authorization/entitlement/representation/EntitlementRequest.java
new file mode 100644
index 0000000..3afcc31
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/entitlement/representation/EntitlementRequest.java
@@ -0,0 +1,25 @@
+package org.keycloak.authorization.entitlement.representation;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.keycloak.authorization.protection.permission.representation.PermissionRequest;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class EntitlementRequest {
+
+    private String rpt;
+
+    private List<PermissionRequest> permissions = new ArrayList<>();
+
+    public List<PermissionRequest> getPermissions() {
+        return permissions;
+    }
+
+    public String getRpt() {
+        return rpt;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/entitlement/representation/EntitlementResponse.java b/services/src/main/java/org/keycloak/authorization/entitlement/representation/EntitlementResponse.java
new file mode 100644
index 0000000..8e883cd
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/entitlement/representation/EntitlementResponse.java
@@ -0,0 +1,42 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.entitlement.representation;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class EntitlementResponse {
+
+    private String rpt;
+
+    public EntitlementResponse(String rpt) {
+        this.rpt = rpt;
+    }
+
+    public EntitlementResponse() {
+        this(null);
+    }
+
+    public String getRpt() {
+        return this.rpt;
+    }
+
+    public void setRpt(final String rpt) {
+        this.rpt = rpt;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/ErrorCode.java b/services/src/main/java/org/keycloak/authorization/ErrorCode.java
new file mode 100644
index 0000000..63ac38a
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/ErrorCode.java
@@ -0,0 +1,28 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public interface ErrorCode {
+
+    String INVALID_CLIENT_ID = "invalid_client_id";
+
+}
diff --git a/services/src/main/java/org/keycloak/authorization/protection/introspect/RPTIntrospectionProvider.java b/services/src/main/java/org/keycloak/authorization/protection/introspect/RPTIntrospectionProvider.java
new file mode 100644
index 0000000..a31e834
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/protection/introspect/RPTIntrospectionProvider.java
@@ -0,0 +1,86 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.authorization.protection.introspect;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.jboss.logging.Logger;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.protocol.oidc.AccessTokenIntrospectionProvider;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.AccessToken.Authorization;
+import org.keycloak.util.JsonSerialization;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ * Introspects token accordingly with UMA Bearer Token Profile.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class RPTIntrospectionProvider extends AccessTokenIntrospectionProvider {
+
+    protected static final Logger LOGGER = Logger.getLogger(RPTIntrospectionProvider.class);
+
+    public RPTIntrospectionProvider(KeycloakSession session) {
+        super(session);
+    }
+
+    @Override
+    public Response introspect(String token) {
+        LOGGER.debug("Introspecting requesting party token");
+        try {
+            AccessToken requestingPartyToken = toAccessToken(token);
+            boolean active = isActive(requestingPartyToken);
+            ObjectNode tokenMetadata;
+
+            if (active) {
+                LOGGER.debug("Token is active");
+                AccessToken introspect = new AccessToken();
+                introspect.type(requestingPartyToken.getType());
+                introspect.expiration(requestingPartyToken.getExpiration());
+                introspect.issuedAt(requestingPartyToken.getIssuedAt());
+                introspect.audience(requestingPartyToken.getAudience());
+                introspect.notBefore(requestingPartyToken.getNotBefore());
+                introspect.setRealmAccess(null);
+                introspect.setResourceAccess(null);
+                tokenMetadata = JsonSerialization.createObjectNode(introspect);
+                tokenMetadata.putPOJO("permissions", requestingPartyToken.getAuthorization().getPermissions());
+            } else {
+                LOGGER.debug("Token is not active");
+                tokenMetadata = JsonSerialization.createObjectNode();
+            }
+
+            tokenMetadata.put("active", active);
+
+            return Response.ok(JsonSerialization.writeValueAsBytes(tokenMetadata)).type(MediaType.APPLICATION_JSON_TYPE).build();
+        } catch (Exception e) {
+            throw new RuntimeException("Error creating token introspection response.", e);
+        }
+    }
+
+    private boolean isActive(AccessToken requestingPartyToken) {
+        Authorization authorization = requestingPartyToken.getAuthorization();
+        return requestingPartyToken.isActive() && authorization != null && authorization.getPermissions() != null && !authorization.getPermissions().isEmpty();
+    }
+
+    @Override
+    public void close() {
+
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/protection/introspect/RPTIntrospectionProviderFactory.java b/services/src/main/java/org/keycloak/authorization/protection/introspect/RPTIntrospectionProviderFactory.java
new file mode 100644
index 0000000..1c4d894
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/protection/introspect/RPTIntrospectionProviderFactory.java
@@ -0,0 +1,54 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.authorization.protection.introspect;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.protocol.oidc.TokenIntrospectionProvider;
+import org.keycloak.protocol.oidc.TokenIntrospectionProviderFactory;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class RPTIntrospectionProviderFactory implements TokenIntrospectionProviderFactory {
+    @Override
+    public TokenIntrospectionProvider create(KeycloakSession session) {
+        return new RPTIntrospectionProvider(session);
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "requesting_party_token";
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/protection/permission/AbstractPermissionService.java b/services/src/main/java/org/keycloak/authorization/protection/permission/AbstractPermissionService.java
new file mode 100644
index 0000000..eb215f9
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/protection/permission/AbstractPermissionService.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.protection.permission;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.common.KeycloakIdentity;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.protection.permission.representation.PermissionRequest;
+import org.keycloak.authorization.protection.permission.representation.PermissionResponse;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.jose.jws.JWSBuilder;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+import org.keycloak.services.ErrorResponseException;
+
+import javax.ws.rs.core.Response;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AbstractPermissionService {
+
+    private final AuthorizationProvider authorization;
+    private final KeycloakIdentity identity;
+    private final ResourceServer resourceServer;
+
+    public AbstractPermissionService(KeycloakIdentity identity, ResourceServer resourceServer, AuthorizationProvider authorization) {
+        this.identity = identity;
+        this.resourceServer = resourceServer;
+        this.authorization = authorization;
+    }
+
+    public Response create(List<PermissionRequest> request) {
+        if (request == null) {
+            throw new ErrorResponseException("invalid_permission_request", "Invalid permission request.", Response.Status.BAD_REQUEST);
+        }
+
+        List<ResourceRepresentation> resource = verifyRequestedResource(request);
+
+        return Response.status(Response.Status.CREATED).entity(new PermissionResponse(createPermissionTicket(resource))).build();
+    }
+
+    private List<ResourceRepresentation> verifyRequestedResource(List<PermissionRequest> request) {
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        return request.stream().map(request1 -> {
+            String resourceSetId = request1.getResourceSetId();
+            String resourceSetName = request1.getResourceSetName();
+            boolean resourceNotProvider = resourceSetId == null && resourceSetName == null;
+
+            if (resourceNotProvider) {
+                if ((request1.getScopes() == null || request1.getScopes().isEmpty())) {
+                    throw new ErrorResponseException("invalid_resource_set_id", "Resource id or name not provided.", Response.Status.BAD_REQUEST);
+                }
+            }
+
+            Resource resource = null;
+
+            if (!resourceNotProvider) {
+                if (resourceSetId != null) {
+                    resource = storeFactory.getResourceStore().findById(resourceSetId);
+                } else {
+                    resource = storeFactory.getResourceStore().findByName(resourceSetName, this.resourceServer.getId());
+                }
+
+                if (resource == null) {
+                    if (resourceSetId != null) {
+                        throw new ErrorResponseException("nonexistent_resource_set_id", "Resource set with id[" + resourceSetId + "] does not exists in this server.", Response.Status.BAD_REQUEST);
+                    } else {
+                        throw new ErrorResponseException("nonexistent_resource_set_name", "Resource set with name[" + resourceSetName + "] does not exists in this server.", Response.Status.BAD_REQUEST);
+                    }
+                }
+            }
+
+            Set<ScopeRepresentation> scopes = verifyRequestedScopes(request1, resource);
+
+            if (resource != null) {
+                if (scopes.isEmpty() && !request1.getScopes().isEmpty()) {
+                    return new ResourceRepresentation(null, request1.getScopes().stream().map(ScopeRepresentation::new).collect(Collectors.toSet()));
+                }
+                return new ResourceRepresentation(resource.getName(), scopes);
+            }
+
+            return new ResourceRepresentation(null, scopes);
+        }).collect(Collectors.toList());
+    }
+
+    private Set<ScopeRepresentation> verifyRequestedScopes(PermissionRequest request, Resource resource) {
+        return request.getScopes().stream().map(scopeName -> {
+            if (resource != null) {
+                for (Scope scope : resource.getScopes()) {
+                    if (scope.getName().equals(scopeName)) {
+                        return new ScopeRepresentation(scopeName);
+                    }
+                }
+
+                for (Resource baseResource : authorization.getStoreFactory().getResourceStore().findByType(resource.getType())) {
+                    if (baseResource.getOwner().equals(resource.getResourceServer().getClientId())) {
+                        for (Scope baseScope : baseResource.getScopes()) {
+                            if (baseScope.getName().equals(scopeName)) {
+                                return new ScopeRepresentation(scopeName);
+                            }
+                        }
+                    }
+                }
+
+                return null;
+            } else {
+                return new ScopeRepresentation(scopeName);
+            }
+        }).filter(scopeRepresentation -> scopeRepresentation != null).collect(Collectors.toSet());
+    }
+
+    private String createPermissionTicket(List<ResourceRepresentation> resources) {
+        return new JWSBuilder().jsonContent(new PermissionTicket(resources, this.resourceServer.getId(), this.identity.getAccessToken()))
+                .rsa256(this.authorization.getKeycloakSession().getContext().getRealm().getPrivateKey());
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/protection/permission/PermissionService.java b/services/src/main/java/org/keycloak/authorization/protection/permission/PermissionService.java
new file mode 100644
index 0000000..4f2181f
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/protection/permission/PermissionService.java
@@ -0,0 +1,47 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.protection.permission;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.common.KeycloakIdentity;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.protection.permission.representation.PermissionRequest;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+import java.util.Arrays;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class PermissionService extends AbstractPermissionService {
+
+    public PermissionService(KeycloakIdentity identity, ResourceServer resourceServer, AuthorizationProvider authorization) {
+        super(identity, resourceServer, authorization);
+    }
+
+    @POST
+    @Consumes("application/json")
+    @Produces("application/json")
+    public Response create(PermissionRequest request) {
+        return create(Arrays.asList(request));
+    }
+
+}
\ No newline at end of file
diff --git a/services/src/main/java/org/keycloak/authorization/protection/permission/PermissionsService.java b/services/src/main/java/org/keycloak/authorization/protection/permission/PermissionsService.java
new file mode 100644
index 0000000..eea2108
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/protection/permission/PermissionsService.java
@@ -0,0 +1,46 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.protection.permission;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.common.KeycloakIdentity;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.protection.permission.representation.PermissionRequest;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class PermissionsService extends AbstractPermissionService {
+
+    public PermissionsService(KeycloakIdentity identity, ResourceServer resourceServer, AuthorizationProvider authorization) {
+        super(identity, resourceServer, authorization);
+    }
+
+    @POST
+    @Consumes("application/json")
+    @Produces("application/json")
+    public Response create(List<PermissionRequest> request) {
+        return super.create(request);
+    }
+}
\ No newline at end of file
diff --git a/services/src/main/java/org/keycloak/authorization/protection/permission/PermissionTicket.java b/services/src/main/java/org/keycloak/authorization/protection/permission/PermissionTicket.java
new file mode 100644
index 0000000..8726ce6
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/protection/permission/PermissionTicket.java
@@ -0,0 +1,58 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.protection.permission;
+
+import org.keycloak.TokenIdGenerator;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.JsonWebToken;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class PermissionTicket extends JsonWebToken {
+
+    private final List<ResourceRepresentation> resources = new ArrayList<>();
+    private final String resourceServerId;
+
+    public PermissionTicket() {
+        this.resourceServerId = null;
+    }
+
+    public PermissionTicket(List<ResourceRepresentation> resources, String resourceServerId, AccessToken accessToken) {
+        id(TokenIdGenerator.generateId());
+        subject(accessToken.getSubject());
+        expiration(accessToken.getExpiration());
+        notBefore(accessToken.getNotBefore());
+        issuedAt(accessToken.getIssuedAt());
+        issuedFor(accessToken.getIssuedFor());
+        this.resources.addAll(resources);
+        this.resourceServerId = resourceServerId;
+    }
+
+    public List<ResourceRepresentation> getResources() {
+        return this.resources;
+    }
+
+    public String getResourceServerId() {
+        return this.resourceServerId;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/protection/permission/representation/PermissionRequest.java b/services/src/main/java/org/keycloak/authorization/protection/permission/representation/PermissionRequest.java
new file mode 100644
index 0000000..31d6d55
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/protection/permission/representation/PermissionRequest.java
@@ -0,0 +1,67 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.protection.permission.representation;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class PermissionRequest {
+
+    @JsonProperty("resource_set_id")
+    private final String resourceSetId;
+
+    @JsonProperty("resource_set_name")
+    private final String resourceSetName;
+
+    private final Set<String> scopes;
+
+    public PermissionRequest(String resourceSetId, String... scopes) {
+        this.resourceSetId = resourceSetId;
+
+        if (scopes != null) {
+            this.scopes = new HashSet(Arrays.asList(scopes));
+        } else {
+            this.scopes = new HashSet<>();
+        }
+
+        this.resourceSetName = null;
+    }
+
+    public PermissionRequest() {
+        this(null, null);
+    }
+
+    public String getResourceSetId() {
+        return this.resourceSetId;
+    }
+
+    public String getResourceSetName() {
+        return resourceSetName;
+    }
+
+    public Set<String> getScopes() {
+        return this.scopes;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/protection/permission/representation/PermissionResponse.java b/services/src/main/java/org/keycloak/authorization/protection/permission/representation/PermissionResponse.java
new file mode 100644
index 0000000..24efefa
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/protection/permission/representation/PermissionResponse.java
@@ -0,0 +1,39 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.protection.permission.representation;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class PermissionResponse {
+
+    private final String ticket;
+
+    public PermissionResponse(String ticket) {
+        this.ticket = ticket;
+    }
+
+    public PermissionResponse() {
+        this(null);
+    }
+
+    public String getTicket() {
+        return this.ticket;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/protection/ProtectionService.java b/services/src/main/java/org/keycloak/authorization/protection/ProtectionService.java
new file mode 100644
index 0000000..45fb6fe
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/protection/ProtectionService.java
@@ -0,0 +1,116 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.protection;
+
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.keycloak.OAuthErrorException;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.admin.ResourceSetService;
+import org.keycloak.authorization.common.KeycloakIdentity;
+import org.keycloak.authorization.identity.Identity;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.protection.permission.PermissionService;
+import org.keycloak.authorization.protection.permission.PermissionsService;
+import org.keycloak.authorization.protection.resource.ResourceService;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.services.ErrorResponseException;
+
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response.Status;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ProtectionService {
+
+    private final AuthorizationProvider authorization;
+
+    public ProtectionService(AuthorizationProvider authorization) {
+        this.authorization = authorization;
+    }
+
+    @Path("/resource_set")
+    public Object resource() {
+        KeycloakIdentity identity = createIdentity();
+        ResourceServer resourceServer = getResourceServer(identity);
+        ResourceSetService resourceManager = new ResourceSetService(resourceServer, this.authorization, null);
+
+        ResteasyProviderFactory.getInstance().injectProperties(resourceManager);
+
+        ResourceService resource = new ResourceService(resourceServer, identity, resourceManager, this.authorization);
+
+        ResteasyProviderFactory.getInstance().injectProperties(resource);
+
+        return resource;
+    }
+
+    @Path("/permission")
+    public Object permission() {
+        KeycloakIdentity identity = createIdentity();
+
+        PermissionService resource = new PermissionService(identity, getResourceServer(identity), this.authorization);
+
+        ResteasyProviderFactory.getInstance().injectProperties(resource);
+
+        return resource;
+    }
+
+    @Path("/permissions")
+    public Object permissions() {
+        KeycloakIdentity identity = createIdentity();
+
+        PermissionsService resource = new PermissionsService(identity, getResourceServer(identity), this.authorization);
+
+        ResteasyProviderFactory.getInstance().injectProperties(resource);
+
+        return resource;
+    }
+
+    private KeycloakIdentity createIdentity() {
+        KeycloakIdentity identity = new KeycloakIdentity(this.authorization.getKeycloakSession());
+        ResourceServer resourceServer = getResourceServer(identity);
+        KeycloakSession keycloakSession = authorization.getKeycloakSession();
+        RealmModel realm = keycloakSession.getContext().getRealm();
+        ClientModel client = realm.getClientById(resourceServer.getClientId());
+
+        if (!identity.hasClientRole(client.getClientId(), "uma_protection")) {
+            throw new ErrorResponseException(OAuthErrorException.INVALID_SCOPE, "Requires uma_protection scope.", Status.FORBIDDEN);
+        }
+
+        return identity;
+    }
+
+    private ResourceServer getResourceServer(Identity identity) {
+        RealmModel realm = this.authorization.getKeycloakSession().getContext().getRealm();
+        ClientModel clientApplication = realm.getClientById(identity.getId());
+
+        if (clientApplication == null) {
+            throw new ErrorResponseException("invalid_clientId", "Client application with id [" + identity.getId() + "] does not exist in realm [" + realm.getName() + "]", Status.BAD_REQUEST);
+        }
+
+        ResourceServer resourceServer = this.authorization.getStoreFactory().getResourceServerStore().findByClient(identity.getId());
+
+        if (resourceServer == null) {
+            throw new ErrorResponseException("invalid_clientId", "Client application [" + clientApplication.getClientId() + "] is not registered as resource server.", Status.FORBIDDEN);
+        }
+
+        return resourceServer;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/protection/resource/RegistrationResponse.java b/services/src/main/java/org/keycloak/authorization/protection/resource/RegistrationResponse.java
new file mode 100644
index 0000000..4f82242
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/protection/resource/RegistrationResponse.java
@@ -0,0 +1,50 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.protection.resource;
+
+import com.fasterxml.jackson.annotation.JsonUnwrapped;
+import org.keycloak.authorization.protection.resource.representation.UmaResourceRepresentation;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class RegistrationResponse {
+
+    private final UmaResourceRepresentation resourceDescription;
+
+    public RegistrationResponse(UmaResourceRepresentation resourceDescription) {
+        this.resourceDescription = resourceDescription;
+    }
+
+    public RegistrationResponse() {
+        this(null);
+    }
+
+    @JsonUnwrapped
+    public UmaResourceRepresentation getResourceDescription() {
+        return this.resourceDescription;
+    }
+
+    public String getId() {
+        if (this.resourceDescription != null) {
+            return this.resourceDescription.getId();
+        }
+
+        return null;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/protection/resource/representation/RegistrationResponse.java b/services/src/main/java/org/keycloak/authorization/protection/resource/representation/RegistrationResponse.java
new file mode 100644
index 0000000..6922d51
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/protection/resource/representation/RegistrationResponse.java
@@ -0,0 +1,50 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.protection.resource.representation;
+
+import com.fasterxml.jackson.annotation.JsonUnwrapped;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class RegistrationResponse {
+
+    private final UmaResourceRepresentation resourceDescription;
+
+    public RegistrationResponse(UmaResourceRepresentation resourceDescription) {
+        this.resourceDescription = resourceDescription;
+    }
+
+    public RegistrationResponse() {
+        this(null);
+    }
+
+    @JsonUnwrapped
+    public UmaResourceRepresentation getResourceDescription() {
+        return this.resourceDescription;
+    }
+
+    public String getId() {
+        if (this.resourceDescription != null) {
+            return this.resourceDescription.getId();
+        }
+
+        return null;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/protection/resource/representation/UmaResourceRepresentation.java b/services/src/main/java/org/keycloak/authorization/protection/resource/representation/UmaResourceRepresentation.java
new file mode 100644
index 0000000..0e9bafa
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/protection/resource/representation/UmaResourceRepresentation.java
@@ -0,0 +1,150 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.protection.resource.representation;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.net.URI;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * <p>One or more resources that the resource server manages as a set of protected resources.
+ *
+ * <p>For more details, <a href="https://docs.kantarainitiative.org/uma/draft-oauth-resource-reg.html#rfc.section.2.2">OAuth-resource-reg</a>.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class UmaResourceRepresentation {
+
+    @JsonProperty("_id")
+    private String id;
+
+    private String name;
+    private String uri;
+    private String type;
+    private Set<UmaScopeRepresentation> scopes;
+
+    @JsonProperty("icon_uri")
+    private String iconUri;
+    private String owner;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param name a human-readable string describing a set of one or more resources
+     * @param uri a {@link URI} that provides the network location for the resource set being registered
+     * @param type a string uniquely identifying the semantics of the resource set
+     * @param scopes the available scopes for this resource set
+     * @param iconUri a {@link URI} for a graphic icon representing the resource set
+     */
+    public UmaResourceRepresentation(String name, Set<UmaScopeRepresentation> scopes, String uri, String type, String iconUri) {
+        this.name = name;
+        this.scopes = scopes;
+        this.uri = uri;
+        this.type = type;
+        this.iconUri = iconUri;
+    }
+
+    /**
+     * Creates a new instance.
+     *
+     * @param name a human-readable string describing a set of one or more resources
+     * @param uri a {@link URI} that provides the network location for the resource set being registered
+     * @param type a string uniquely identifying the semantics of the resource set
+     * @param scopes the available scopes for this resource set
+     */
+    public UmaResourceRepresentation(String name, Set<UmaScopeRepresentation> scopes, String uri, String type) {
+        this(name, scopes, uri, type, null);
+    }
+
+    /**
+     * Creates a new instance.
+     *
+     * @param name a human-readable string describing a set of one or more resources
+     * @param serverUri a {@link URI} that identifies this resource server
+     * @param scopes the available scopes for this resource set
+     */
+    public UmaResourceRepresentation(String name, Set<UmaScopeRepresentation> scopes) {
+        this(name, scopes, null, null, null);
+    }
+
+    /**
+     * Creates a new instance.
+     *
+     */
+    public UmaResourceRepresentation() {
+        this(null, null, null, null, null);
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getId() {
+        return this.id;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public String getUri() {
+        return this.uri;
+    }
+
+    public String getType() {
+        return this.type;
+    }
+
+    public Set<UmaScopeRepresentation> getScopes() {
+        return Collections.unmodifiableSet(this.scopes);
+    }
+
+    public String getIconUri() {
+        return this.iconUri;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setUri(String uri) {
+        this.uri = uri;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public void setScopes(Set<UmaScopeRepresentation> scopes) {
+        this.scopes = scopes;
+    }
+
+    public void setIconUri(String iconUri) {
+        this.iconUri = iconUri;
+    }
+
+    public String getOwner() {
+        return owner;
+    }
+
+    public void setOwner(String owner) {
+        this.owner = owner;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/protection/resource/representation/UmaScopeRepresentation.java b/services/src/main/java/org/keycloak/authorization/protection/resource/representation/UmaScopeRepresentation.java
new file mode 100644
index 0000000..4a184d9
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/protection/resource/representation/UmaScopeRepresentation.java
@@ -0,0 +1,98 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.protection.resource.representation;
+
+import java.net.URI;
+import java.util.Objects;
+
+/**
+ * <p>A bounded extent of access that is possible to perform on a resource set. In authorization policy terminology,
+ * a scope is one of the potentially many "verbs" that can logically apply to a resource set ("object").
+ *
+ * <p>For more details, <a href="https://docs.kantarainitiative.org/uma/draft-oauth-resource-reg.html#rfc.section.2.1">OAuth-resource-reg</a>.
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class UmaScopeRepresentation {
+
+    private String id;
+    private String name;
+    private String iconUri;
+
+    /**
+     * Creates an instance.
+     *
+     * @param name the a human-readable string describing some scope (extent) of access
+     * @param iconUri a {@link URI} for a graphic icon representing the scope
+     */
+    public UmaScopeRepresentation(String name, String iconUri) {
+        this.name = name;
+        this.iconUri = iconUri;
+    }
+
+    /**
+     * Creates an instance.
+     *
+     * @param name the a human-readable string describing some scope (extent) of access
+     */
+    public UmaScopeRepresentation(String name) {
+        this(name, null);
+    }
+
+    /**
+     * Creates an instance.
+     */
+    public UmaScopeRepresentation() {
+        this(null, null);
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public String getIconUri() {
+        return this.iconUri;
+    }
+
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        UmaScopeRepresentation scope = (UmaScopeRepresentation) o;
+        return Objects.equals(getName(), scope.getName());
+    }
+
+    public int hashCode() {
+        return Objects.hash(getName());
+    }
+
+    public String getId() {
+        return this.id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setIconUri(String iconUri) {
+        this.iconUri = iconUri;
+    }
+}
\ No newline at end of file
diff --git a/services/src/main/java/org/keycloak/authorization/protection/resource/ResourceService.java b/services/src/main/java/org/keycloak/authorization/protection/resource/ResourceService.java
new file mode 100644
index 0000000..168d62b
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/protection/resource/ResourceService.java
@@ -0,0 +1,228 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.authorization.protection.resource;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.admin.ResourceSetService;
+import org.keycloak.authorization.identity.Identity;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.protection.resource.representation.UmaResourceRepresentation;
+import org.keycloak.authorization.protection.resource.representation.UmaScopeRepresentation;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.models.utils.ModelToRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceOwnerRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+import org.keycloak.services.ErrorResponseException;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ResourceService {
+
+    private final ResourceServer resourceServer;
+    private final ResourceSetService resourceManager;
+    private final Identity identity;
+    private final AuthorizationProvider authorization;
+
+    public ResourceService(ResourceServer resourceServer, Identity identity, ResourceSetService resourceManager, AuthorizationProvider authorization) {
+        this.identity = identity;
+        this.resourceServer = resourceServer;
+        this.resourceManager = resourceManager;
+        this.authorization = authorization;
+    }
+
+    @POST
+    @Consumes("application/json")
+    @Produces("application/json")
+    public Response create(UmaResourceRepresentation umaResource) {
+        checkResourceServerSettings();
+        ResourceRepresentation resource = toResourceRepresentation(umaResource);
+        Response response = this.resourceManager.create(resource);
+
+        if (response.getEntity() instanceof ResourceRepresentation) {
+            return Response.status(Status.CREATED).entity(toUmaRepresentation((ResourceRepresentation) response.getEntity())).build();
+        }
+
+        return response;
+    }
+
+    @Path("/{id}")
+    @DELETE
+    public Response delete(@PathParam("id") String id) {
+        checkResourceServerSettings();
+        return this.resourceManager.delete(id);
+    }
+
+    @Path("/{id}")
+    @GET
+    @Produces("application/json")
+    public RegistrationResponse findById(@PathParam("id") String id) {
+        Response response = this.resourceManager.findById(id);
+        UmaResourceRepresentation resource = toUmaRepresentation((ResourceRepresentation) response.getEntity());
+
+        if (resource == null) {
+            throw new ErrorResponseException("not_found", "Resource with id [" + id + "] not found.", Status.NOT_FOUND);
+        }
+
+        return new RegistrationResponse(resource);
+    }
+
+    @GET
+    @Produces("application/json")
+    public Set<String> find(@QueryParam("filter") String filter) {
+        if (filter == null) {
+            return findAll();
+        } else {
+            return findByFilter(filter);
+        }
+    }
+
+    private Set<String> findAll() {
+        Response response = this.resourceManager.findAll();
+        List<ResourceRepresentation> resources = (List<ResourceRepresentation>) response.getEntity();
+        return resources.stream().map(ResourceRepresentation::getId).collect(Collectors.toSet());
+    }
+
+    private Set<String> findByFilter(String filter) {
+        Set<ResourceRepresentation> resources = new HashSet<>();
+        StoreFactory storeFactory = authorization.getStoreFactory();
+
+        if (filter != null) {
+            for (String currentFilter : filter.split("&")) {
+                String[] parts = currentFilter.split("=");
+                String filterType = parts[0];
+                final String filterValue;
+
+                if (parts.length > 1) {
+                    filterValue = parts[1];
+                } else {
+                    filterValue = null;
+                }
+
+
+                if ("name".equals(filterType)) {
+                    resources.addAll(storeFactory.getResourceStore().findByResourceServer(this.resourceServer.getId()).stream().filter(description -> filterValue == null || filterValue.equals(description.getName())).collect(Collectors.toSet()).stream()
+                            .map(resource -> ModelToRepresentation.toRepresentation(resource, this.resourceServer, authorization))
+                            .collect(Collectors.toList()));
+                } else if ("type".equals(filterType)) {
+                    resources.addAll(storeFactory.getResourceStore().findByResourceServer(this.resourceServer.getId()).stream().filter(description -> filterValue == null || filterValue.equals(description.getType())).collect(Collectors.toSet()).stream()
+                            .map(resource -> ModelToRepresentation.toRepresentation(resource, this.resourceServer, authorization))
+                            .collect(Collectors.toList()));
+                } else if ("uri".equals(filterType)) {
+                    resources.addAll(storeFactory.getResourceStore().findByResourceServer(this.resourceServer.getId()).stream().filter(description -> filterValue == null || filterValue.equals(description.getUri())).collect(Collectors.toSet()).stream()
+                            .map(resource -> ModelToRepresentation.toRepresentation(resource, this.resourceServer, authorization))
+                            .collect(Collectors.toList()));
+                } else if ("owner".equals(filterType)) {
+                    resources.addAll(storeFactory.getResourceStore().findByResourceServer(this.resourceServer.getId()).stream().filter(description -> filterValue == null || filterValue.equals(description.getOwner())).collect(Collectors.toSet()).stream()
+                            .map(resource -> ModelToRepresentation.toRepresentation(resource, this.resourceServer, authorization))
+                            .collect(Collectors.toList()));
+                }
+            }
+        } else {
+            resources = storeFactory.getResourceStore().findByOwner(identity.getId()).stream()
+                    .map(resource -> ModelToRepresentation.toRepresentation(resource, this.resourceServer, authorization))
+                    .collect(Collectors.toSet());
+        }
+
+        return resources.stream()
+                .map(ResourceRepresentation::getId)
+                .collect(Collectors.toSet());
+    }
+
+    private ResourceRepresentation toResourceRepresentation(UmaResourceRepresentation umaResource) {
+        ResourceRepresentation resource = new ResourceRepresentation();
+
+        resource.setId(umaResource.getId());
+        resource.setIconUri(umaResource.getIconUri());
+        resource.setName(umaResource.getName());
+        resource.setUri(umaResource.getUri());
+        resource.setType(umaResource.getType());
+
+        ResourceOwnerRepresentation owner = new ResourceOwnerRepresentation();
+        String ownerId = umaResource.getOwner();
+
+        if (ownerId == null) {
+            ownerId = this.identity.getId();
+        }
+
+        owner.setId(ownerId);
+        resource.setOwner(owner);
+
+        resource.setScopes(umaResource.getScopes().stream().map(representation -> {
+            ScopeRepresentation scopeRepresentation = new ScopeRepresentation();
+
+            scopeRepresentation.setId(representation.getId());
+            scopeRepresentation.setName(representation.getName());
+            scopeRepresentation.setIconUri(representation.getIconUri());
+
+            return scopeRepresentation;
+        }).collect(Collectors.toSet()));
+
+        return resource;
+    }
+
+    private UmaResourceRepresentation toUmaRepresentation(ResourceRepresentation representation) {
+        if (representation == null) {
+            return null;
+        }
+
+        UmaResourceRepresentation resource = new UmaResourceRepresentation();
+
+        resource.setId(representation.getId());
+        resource.setIconUri(representation.getIconUri());
+        resource.setName(representation.getName());
+        resource.setUri(representation.getUri());
+        resource.setType(representation.getType());
+
+        if (representation.getOwner() != null) {
+            resource.setOwner(representation.getOwner().getId());
+        }
+
+        resource.setScopes(representation.getScopes().stream().map(scopeRepresentation -> {
+            UmaScopeRepresentation umaScopeRep = new UmaScopeRepresentation();
+            umaScopeRep.setId(scopeRepresentation.getId());
+            umaScopeRep.setName(scopeRepresentation.getName());
+            umaScopeRep.setIconUri(scopeRepresentation.getIconUri());
+            return umaScopeRep;
+        }).collect(Collectors.toSet()));
+
+        return resource;
+    }
+
+    private void checkResourceServerSettings() {
+        if (!this.resourceServer.isAllowRemoteResourceManagement()) {
+            throw new ErrorResponseException("not_supported", "Remote management is disabled.", Status.BAD_REQUEST);
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/src/main/java/org/keycloak/authorization/util/Permissions.java b/services/src/main/java/org/keycloak/authorization/util/Permissions.java
new file mode 100644
index 0000000..116ddd6
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/util/Permissions.java
@@ -0,0 +1,172 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.util;
+
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.Decision.Effect;
+import org.keycloak.authorization.identity.Identity;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.authorization.permission.ResourcePermission;
+import org.keycloak.authorization.policy.evaluation.Result;
+import org.keycloak.authorization.store.ResourceStore;
+import org.keycloak.authorization.store.ScopeStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.representations.idm.authorization.Permission;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public final class Permissions {
+
+    /**
+     * Returns a list of permissions for all resources and scopes that belong to the given <code>resourceServer</code> and
+     * <code>identity</code>.
+     *
+     * TODO: review once we support caches
+     *
+     * @param resourceServer
+     * @param identity
+     * @param authorization
+     * @return
+     */
+    public static List<ResourcePermission> all(ResourceServer resourceServer, Identity identity, AuthorizationProvider authorization) {
+        List<ResourcePermission> permissions = new ArrayList<>();
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        ResourceStore resourceStore = storeFactory.getResourceStore();
+
+        resourceStore.findByOwner(resourceServer.getClientId()).stream().forEach(resource -> permissions.addAll(createResourcePermissions(resource, resource.getScopes().stream().map(Scope::getName).collect(Collectors.toSet()), authorization)));
+        resourceStore.findByOwner(identity.getId()).stream().forEach(resource -> permissions.addAll(createResourcePermissions(resource, resource.getScopes().stream().map(Scope::getName).collect(Collectors.toSet()), authorization)));
+
+        return permissions;
+    }
+
+    public static List<ResourcePermission> createResourcePermissions(Resource resource, Set<String> requestedScopes, AuthorizationProvider authorization) {
+        List<ResourcePermission> permissions = new ArrayList<>();
+        String type = resource.getType();
+        ResourceServer resourceServer = resource.getResourceServer();
+        List<Scope> scopes;
+
+        if (requestedScopes.isEmpty()) {
+            scopes = resource.getScopes();
+            // check if there is a typed resource whose scopes are inherited by the resource being requested. In this case, we assume that parent resource
+            // is owned by the resource server itself
+            if (type != null && !resource.getOwner().equals(resourceServer.getClientId())) {
+                StoreFactory storeFactory = authorization.getStoreFactory();
+                ResourceStore resourceStore = storeFactory.getResourceStore();
+                resourceStore.findByType(type).forEach(resource1 -> {
+                    if (resource1.getOwner().equals(resourceServer.getClientId())) {
+                        for (Scope typeScope : resource1.getScopes()) {
+                            if (!scopes.contains(typeScope)) {
+                                scopes.add(typeScope);
+                            }
+                        }
+                    }
+                });
+            }
+        } else {
+            ScopeStore scopeStore = authorization.getStoreFactory().getScopeStore();
+            scopes = requestedScopes.stream().map(scopeName -> {
+                Scope byName = scopeStore.findByName(scopeName, resource.getResourceServer().getId());
+                return byName;
+            }).collect(Collectors.toList());
+        }
+
+        if (scopes.isEmpty()) {
+            permissions.add(new ResourcePermission(resource, Collections.emptyList(), resource.getResourceServer()));
+        } else {
+            for (Scope scope : scopes) {
+                permissions.add(new ResourcePermission(resource, Arrays.asList(scope), resource.getResourceServer()));
+            }
+        }
+
+        return permissions;
+    }
+
+    public static List<Permission> allPermits(List<Result> evaluation, AuthorizationProvider authorizationProvider) {
+        Map<String, Permission> permissions = new HashMap<>();
+
+        for (Result evaluationResult : evaluation) {
+            ResourcePermission permission = evaluationResult.getPermission();
+            Set<String> scopes = permission.getScopes().stream().map(Scope::getName).collect(Collectors.toSet());
+
+            if (evaluationResult.getEffect().equals(Effect.DENY)) {
+                continue;
+            }
+
+            List<Resource> resources = new ArrayList<>();
+            Resource resource = permission.getResource();
+
+            if (resource != null) {
+                resources.add(resource);
+            } else {
+                List<Scope> permissionScopes = permission.getScopes();
+
+                if (!permissionScopes.isEmpty()) {
+                    ResourceStore resourceStore = authorizationProvider.getStoreFactory().getResourceStore();
+                    resources.addAll(resourceStore.findByScope(permissionScopes.stream().map(Scope::getId).collect(Collectors.toList()).toArray(new String[permissionScopes.size()])));
+                }
+            }
+
+            if (!resources.isEmpty()) {
+                for (Resource allowedResource : resources) {
+                    String resourceId = allowedResource.getId();
+                    String resourceName = allowedResource.getName();
+                    Permission evalPermission = permissions.get(allowedResource.getId());
+
+                    if (evalPermission == null) {
+                        evalPermission = new Permission(resourceId, resourceName, scopes);
+                        permissions.put(resourceId, evalPermission);
+                    }
+
+                    if (scopes != null && !scopes.isEmpty()) {
+                        Set<String> finalScopes = evalPermission.getScopes();
+
+                        if (finalScopes == null) {
+                            finalScopes = new HashSet();
+                            evalPermission.setScopes(finalScopes);
+                        }
+
+                        for (String scopeName : scopes) {
+                            if (!finalScopes.contains(scopeName)) {
+                                finalScopes.add(scopeName);
+                            }
+                        }
+                    }
+                }
+            } else {
+                Permission scopePermission = new Permission(null, null, scopes);
+                permissions.put(scopePermission.toString(), scopePermission);
+            }
+        }
+
+        return permissions.values().stream().collect(Collectors.toList());
+    }
+}
diff --git a/services/src/main/java/org/keycloak/authorization/util/Tokens.java b/services/src/main/java/org/keycloak/authorization/util/Tokens.java
new file mode 100644
index 0000000..0deeef5
--- /dev/null
+++ b/services/src/main/java/org/keycloak/authorization/util/Tokens.java
@@ -0,0 +1,65 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.authorization.util;
+
+import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.crypto.RSAProvider;
+import org.keycloak.models.KeycloakContext;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.services.ErrorResponseException;
+import org.keycloak.services.managers.AppAuthManager;
+import org.keycloak.services.managers.AuthenticationManager.AuthResult;
+
+import javax.ws.rs.core.Response.Status;
+import java.security.PublicKey;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class Tokens {
+
+    public static AccessToken getAccessToken(KeycloakSession keycloakSession) {
+        AppAuthManager authManager = new AppAuthManager();
+        KeycloakContext context = keycloakSession.getContext();
+        AuthResult authResult = authManager.authenticateBearerToken(keycloakSession, context.getRealm(), context.getUri(), context.getConnection(), context.getRequestHeaders());
+
+        if (authResult != null) {
+            return authResult.getToken();
+        }
+
+        return null;
+    }
+
+    public static String getAccessTokenAsString(KeycloakSession keycloakSession) {
+        AppAuthManager authManager = new AppAuthManager();
+
+        return authManager.extractAuthorizationHeaderToken(keycloakSession.getContext().getRequestHeaders());
+    }
+
+    public static boolean verifySignature(String token, PublicKey publicKey) {
+        try {
+            JWSInput jws = new JWSInput(token);
+
+            return RSAProvider.verify(jws, publicKey);
+        } catch (Exception e) {
+            throw new ErrorResponseException("invalid_signature", "Unexpected error while validating signature.", Status.INTERNAL_SERVER_ERROR);
+        }
+    }
+}
diff --git a/services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProviderFactory.java b/services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProviderFactory.java
index a268ebd..82c2cdd 100755
--- a/services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProviderFactory.java
+++ b/services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProviderFactory.java
@@ -16,14 +16,14 @@
  */
 package org.keycloak.broker.oidc;
 
-import org.keycloak.broker.provider.util.SimpleHttp;
 import org.keycloak.broker.provider.AbstractIdentityProviderFactory;
 import org.keycloak.jose.jwk.JWK;
-import org.keycloak.jose.jwk.JWKParser;
 import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.utils.KeycloakModelUtils;
-import org.keycloak.protocol.oidc.representations.JSONWebKeySet;
+import org.keycloak.jose.jwk.JSONWebKeySet;
 import org.keycloak.protocol.oidc.representations.OIDCConfigurationRepresentation;
+import org.keycloak.protocol.oidc.utils.JWKSUtils;
+import org.keycloak.services.ServicesLogger;
 import org.keycloak.util.JsonSerialization;
 
 import java.io.IOException;
@@ -36,6 +36,8 @@ import java.util.Map;
  */
 public class OIDCIdentityProviderFactory extends AbstractIdentityProviderFactory<OIDCIdentityProvider> {
 
+    private static final ServicesLogger logger = ServicesLogger.ROOT_LOGGER;
+
     public static final String PROVIDER_ID = "oidc";
 
     @Override
@@ -59,7 +61,7 @@ public class OIDCIdentityProviderFactory extends AbstractIdentityProviderFactory
     }
 
     protected static Map<String, String> parseOIDCConfig(InputStream inputStream) {
-        OIDCConfigurationRepresentation rep = null;
+        OIDCConfigurationRepresentation rep;
         try {
             rep = JsonSerialization.readValue(inputStream, OIDCConfigurationRepresentation.class);
         } catch (IOException e) {
@@ -72,31 +74,24 @@ public class OIDCIdentityProviderFactory extends AbstractIdentityProviderFactory
         config.setTokenUrl(rep.getTokenEndpoint());
         config.setUserInfoUrl(rep.getUserinfoEndpoint());
         if (rep.getJwksUri() != null) {
-            String uri = rep.getJwksUri();
-            String keySetString = null;
-            try {
-                keySetString = SimpleHttp.doGet(uri).asString();
-                JSONWebKeySet keySet = JsonSerialization.readValue(keySetString, JSONWebKeySet.class);
-                for (JWK jwk : keySet.getKeys()) {
-                    JWKParser parse = JWKParser.create(jwk);
-                    if (parse.getJwk().getPublicKeyUse().equals(JWK.SIG_USE) && keyTypeSupported(jwk.getKeyType())) {
-                        PublicKey key = parse.toPublicKey();
-                        config.setPublicKeySignatureVerifier(KeycloakModelUtils.getPemFromKey(key));
-                        config.setValidateSignature(true);
-                        break;
-                    }
-
-                }
-            } catch (IOException e) {
-                throw new RuntimeException("Failed to query JWKSet from: " + uri, e);
-            }
-
+            sendJwksRequest(rep, config);
         }
         return config.getConfig();
     }
 
-    protected static boolean keyTypeSupported(String type) {
-        return type != null && type.equals("RSA");
+    protected static void sendJwksRequest(OIDCConfigurationRepresentation rep, OIDCIdentityProviderConfig config) {
+        try {
+            JSONWebKeySet keySet = JWKSUtils.sendJwksRequest(rep.getJwksUri());
+            PublicKey key = JWKSUtils.getKeyForUse(keySet, JWK.Use.SIG);
+            if (key == null) {
+                logger.supportedJwkNotFound(JWK.Use.SIG.asString());
+            } else {
+                config.setPublicKeySignatureVerifier(KeycloakModelUtils.getPemFromKey(key));
+                config.setValidateSignature(true);
+            }
+        } catch (IOException e) {
+            throw new RuntimeException("Failed to query JWKSet from: " + rep.getJwksUri(), e);
+        }
     }
 
 }
diff --git a/services/src/main/java/org/keycloak/email/DefaultEmailSenderProvider.java b/services/src/main/java/org/keycloak/email/DefaultEmailSenderProvider.java
index a2469ec..c19d1e8 100644
--- a/services/src/main/java/org/keycloak/email/DefaultEmailSenderProvider.java
+++ b/services/src/main/java/org/keycloak/email/DefaultEmailSenderProvider.java
@@ -24,7 +24,6 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.services.ServicesLogger;
 
-import javax.mail.Message;
 import javax.mail.MessagingException;
 import javax.mail.Multipart;
 import javax.mail.Session;
@@ -108,10 +107,10 @@ public class DefaultEmailSenderProvider implements EmailSenderProvider {
                 multipart.addBodyPart(htmlPart);
             }
 
-            Message msg = new MimeMessage(session);
+            MimeMessage msg = new MimeMessage(session);
             msg.setFrom(new InternetAddress(from));
             msg.setHeader("To", address);
-            msg.setSubject(subject);
+            msg.setSubject(subject, "utf-8");
             msg.setContent(multipart);
             msg.saveChanges();
             msg.setSentDate(new Date());
diff --git a/services/src/main/java/org/keycloak/exportimport/util/ExportUtils.java b/services/src/main/java/org/keycloak/exportimport/util/ExportUtils.java
index cf0c5ca..1b2caf9 100755
--- a/services/src/main/java/org/keycloak/exportimport/util/ExportUtils.java
+++ b/services/src/main/java/org/keycloak/exportimport/util/ExportUtils.java
@@ -22,15 +22,61 @@ import com.fasterxml.jackson.core.JsonFactory;
 import com.fasterxml.jackson.core.JsonGenerator;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.AuthorizationProviderFactory;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.authorization.store.ResourceStore;
+import org.keycloak.authorization.store.ScopeStore;
+import org.keycloak.authorization.store.StoreFactory;
 import org.keycloak.common.Version;
 import org.keycloak.common.util.Base64;
-import org.keycloak.models.*;
+import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.component.ComponentModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientTemplateModel;
+import org.keycloak.models.FederatedIdentityModel;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleContainerModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserConsentModel;
+import org.keycloak.models.UserCredentialValueModel;
+import org.keycloak.models.UserFederationManager;
+import org.keycloak.models.UserModel;
 import org.keycloak.models.utils.ModelToRepresentation;
-import org.keycloak.representations.idm.*;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.ClientTemplateRepresentation;
+import org.keycloak.representations.idm.ComponentExportRepresentation;
+import org.keycloak.representations.idm.CredentialRepresentation;
+import org.keycloak.representations.idm.FederatedIdentityRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.RolesRepresentation;
+import org.keycloak.representations.idm.ScopeMappingRepresentation;
+import org.keycloak.representations.idm.UserConsentRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+import org.keycloak.util.JsonSerialization;
 
 import java.io.IOException;
 import java.io.OutputStream;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static org.keycloak.models.utils.ModelToRepresentation.toRepresentation;
 
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
@@ -56,7 +102,7 @@ public class ExportUtils {
         List<ClientModel> clients = realm.getClients();
         List<ClientRepresentation> clientReps = new ArrayList<>();
         for (ClientModel app : clients) {
-            ClientRepresentation clientRep = exportClient(app);
+            ClientRepresentation clientRep = exportClient(session, app);
             clientReps.add(clientRep);
         }
         rep.setClients(clientReps);
@@ -178,20 +224,164 @@ public class ExportUtils {
             }
         }
 
+        // components
+        MultivaluedHashMap<String, ComponentExportRepresentation> components = exportComponents(realm, realm.getId());
+        rep.setComponents(components);
+
         return rep;
     }
 
+    public static MultivaluedHashMap<String, ComponentExportRepresentation> exportComponents(RealmModel realm, String parentId) {
+        List<ComponentModel> componentList = realm.getComponents(parentId);
+        MultivaluedHashMap<String, ComponentExportRepresentation> components = new MultivaluedHashMap<>();
+        for (ComponentModel component : componentList) {
+            ComponentExportRepresentation compRep = new ComponentExportRepresentation();
+            compRep.setId(component.getId());
+            compRep.setProviderId(component.getProviderId());
+            compRep.setConfig(component.getConfig());
+            compRep.setName(component.getName());
+            compRep.setSubComponents(exportComponents(realm, component.getId()));
+            components.add(component.getProviderType(), compRep);
+        }
+        return components;
+    }
+
     /**
      * Full export of application including claims and secret
      * @param client
      * @return full ApplicationRepresentation
      */
-    public static ClientRepresentation exportClient(ClientModel client) {
+    public static ClientRepresentation exportClient(KeycloakSession session, ClientModel client) {
         ClientRepresentation clientRep = ModelToRepresentation.toRepresentation(client);
         clientRep.setSecret(client.getSecret());
+        clientRep.setAuthorizationSettings(exportAuthorizationSettings(session,client));
         return clientRep;
     }
 
+    public static ResourceServerRepresentation exportAuthorizationSettings(KeycloakSession session, ClientModel client) {
+        AuthorizationProviderFactory providerFactory = (AuthorizationProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(AuthorizationProvider.class);
+        AuthorizationProvider authorization = providerFactory.create(session, client.getRealm());
+        StoreFactory storeFactory = authorization.getStoreFactory();
+        ResourceServer settingsModel = authorization.getStoreFactory().getResourceServerStore().findByClient(client.getId());
+
+        if (settingsModel == null) {
+            return null;
+        }
+
+        ResourceServerRepresentation representation = toRepresentation(settingsModel, client);
+
+        representation.setId(null);
+        representation.setName(null);
+        representation.setClientId(null);
+
+        List<ResourceRepresentation> resources = storeFactory.getResourceStore().findByResourceServer(settingsModel.getId())
+                .stream().map(resource -> {
+                    ResourceRepresentation rep = toRepresentation(resource, settingsModel, authorization);
+
+                    if (rep.getOwner().getId().equals(settingsModel.getClientId())) {
+                        rep.setOwner(null);
+                    } else {
+                        rep.getOwner().setId(null);
+                    }
+                    rep.setId(null);
+                    rep.setPolicies(null);
+                    rep.getScopes().forEach(scopeRepresentation -> {
+                        scopeRepresentation.setId(null);
+                        scopeRepresentation.setIconUri(null);
+                    });
+
+                    return rep;
+                }).collect(Collectors.toList());
+
+        representation.setResources(resources);
+
+        List<PolicyRepresentation> policies = new ArrayList<>();
+        PolicyStore policyStore = storeFactory.getPolicyStore();
+
+        policies.addAll(policyStore.findByResourceServer(settingsModel.getId())
+                .stream().filter(policy -> !policy.getType().equals("resource") && !policy.getType().equals("scope"))
+                .map(policy -> createPolicyRepresentation(authorization, policy)).collect(Collectors.toList()));
+        policies.addAll(policyStore.findByResourceServer(settingsModel.getId())
+                .stream().filter(policy -> policy.getType().equals("resource") || policy.getType().equals("scope"))
+                .map(policy -> createPolicyRepresentation(authorization, policy)).collect(Collectors.toList()));
+
+        representation.setPolicies(policies);
+
+        List<ScopeRepresentation> scopes = storeFactory.getScopeStore().findByResourceServer(settingsModel.getId()).stream().map(scope -> {
+            ScopeRepresentation rep = toRepresentation(scope, authorization);
+
+            rep.setId(null);
+            rep.setPolicies(null);
+            rep.setResources(null);
+
+            return rep;
+        }).collect(Collectors.toList());
+
+        representation.setScopes(scopes);
+
+        return representation;
+    }
+
+    private static PolicyRepresentation createPolicyRepresentation(AuthorizationProvider authorizationProvider, Policy policy) {
+        KeycloakSession session = authorizationProvider.getKeycloakSession();
+        RealmModel realm = authorizationProvider.getRealm();
+        StoreFactory storeFactory = authorizationProvider.getStoreFactory();
+        try {
+            PolicyRepresentation rep = toRepresentation(policy, authorizationProvider);
+
+            rep.setId(null);
+            rep.setDependentPolicies(null);
+
+            Map<String, String> config = rep.getConfig();
+
+            String roles = config.get("roles");
+
+            if (roles != null && !roles.isEmpty()) {
+                List<Map> rolesMap = JsonSerialization.readValue(roles, List.class);
+                config.put("roles", JsonSerialization.writeValueAsString(rolesMap.stream().map(roleMap -> {
+                    roleMap.put("id", realm.getRoleById(roleMap.get("id").toString()).getName());
+                    return roleMap;
+                }).collect(Collectors.toList())));
+            }
+
+            String users = config.get("users");
+
+            if (users != null && !users.isEmpty()) {
+                UserFederationManager userManager = session.users();
+                List<String> userIds = JsonSerialization.readValue(users, List.class);
+                config.put("users", JsonSerialization.writeValueAsString(userIds.stream().map(userId -> userManager.getUserById(userId, realm).getUsername()).collect(Collectors.toList())));
+            }
+
+            String scopes = config.get("scopes");
+
+            if (scopes != null && !scopes.isEmpty()) {
+                ScopeStore scopeStore = storeFactory.getScopeStore();
+                List<String> scopeIds = JsonSerialization.readValue(scopes, List.class);
+                config.put("scopes", JsonSerialization.writeValueAsString(scopeIds.stream().map(scopeId -> scopeStore.findById(scopeId).getName()).collect(Collectors.toList())));
+            }
+
+            String policyResources = config.get("resources");
+
+            if (policyResources != null && !policyResources.isEmpty()) {
+                ResourceStore resourceStore = storeFactory.getResourceStore();
+                List<String> resourceIds = JsonSerialization.readValue(policyResources, List.class);
+                config.put("resources", JsonSerialization.writeValueAsString(resourceIds.stream().map(resourceId -> resourceStore.findById(resourceId).getName()).collect(Collectors.toList())));
+            }
+
+            Set<Policy> associatedPolicies = policy.getAssociatedPolicies();
+
+            if (!associatedPolicies.isEmpty()) {
+                config.put("applyPolicies", JsonSerialization.writeValueAsString(associatedPolicies.stream().map(associated -> associated.getName()).collect(Collectors.toList())));
+            }
+
+            rep.setAssociatedPolicies(null);
+
+            return rep;
+        } catch (Exception e) {
+            throw new RuntimeException("Error while exporting policy [" + policy.getName() + "].", e);
+        }
+    }
+
     public static List<RoleRepresentation> exportRoles(Collection<RoleModel> roles) {
         List<RoleRepresentation> roleReps = new ArrayList<RoleRepresentation>();
 
@@ -319,7 +509,7 @@ public class ExportUtils {
         userRep.setFederationLink(user.getFederationLink());
 
         // Grants
-        List<UserConsentModel> consents = user.getConsents();
+        List<UserConsentModel> consents = session.users().getConsents(realm, user);
         LinkedList<UserConsentRepresentation> consentReps = new LinkedList<UserConsentRepresentation>();
         for (UserConsentModel consent : consents) {
             UserConsentRepresentation consentRep = ModelToRepresentation.toRepresentation(consent);
diff --git a/services/src/main/java/org/keycloak/forms/account/freemarker/model/ApplicationsBean.java b/services/src/main/java/org/keycloak/forms/account/freemarker/model/ApplicationsBean.java
index 0b8ec67..f845903 100755
--- a/services/src/main/java/org/keycloak/forms/account/freemarker/model/ApplicationsBean.java
+++ b/services/src/main/java/org/keycloak/forms/account/freemarker/model/ApplicationsBean.java
@@ -64,7 +64,7 @@ public class ApplicationsBean {
             MultivaluedHashMap<String, ClientRoleEntry> resourceRolesGranted = new MultivaluedHashMap<String, ClientRoleEntry>();
             List<String> claimsGranted = new LinkedList<String>();
             if (client.isConsentRequired()) {
-                UserConsentModel consent = user.getConsentByClient(client.getId());
+                UserConsentModel consent = session.users().getConsentByClient(realm, user, client.getId());
 
                 if (consent != null) {
                     processRoles(consent.getGrantedRoles(), realmRolesGranted, resourceRolesGranted);
diff --git a/services/src/main/java/org/keycloak/partialimport/PartialImportManager.java b/services/src/main/java/org/keycloak/partialimport/PartialImportManager.java
index 59d6217..705d230 100644
--- a/services/src/main/java/org/keycloak/partialimport/PartialImportManager.java
+++ b/services/src/main/java/org/keycloak/partialimport/PartialImportManager.java
@@ -62,7 +62,7 @@ public class PartialImportManager {
             try {
                 partialImport.prepare(rep, realm, session);
             } catch (ErrorResponseException error) {
-                if (session.getTransaction().isActive()) session.getTransaction().setRollbackOnly();
+                if (session.getTransactionManager().isActive()) session.getTransactionManager().setRollbackOnly();
                 return error.getResponse();
             }
         }
@@ -72,7 +72,7 @@ public class PartialImportManager {
                 partialImport.removeOverwrites(realm, session);
                 results.addAllResults(partialImport.doImport(rep, realm, session));
             } catch (ErrorResponseException error) {
-                if (session.getTransaction().isActive()) session.getTransaction().setRollbackOnly();
+                if (session.getTransactionManager().isActive()) session.getTransactionManager().setRollbackOnly();
                 return error.getResponse();
             }
         }
@@ -84,8 +84,8 @@ public class PartialImportManager {
             }
         }
 
-        if (session.getTransaction().isActive()) {
-            session.getTransaction().commit();
+        if (session.getTransactionManager().isActive()) {
+            session.getTransactionManager().commit();
         }
 
         return Response.ok(results).build();
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/AccessTokenIntrospectionProvider.java b/services/src/main/java/org/keycloak/protocol/oidc/AccessTokenIntrospectionProvider.java
new file mode 100644
index 0000000..0378765
--- /dev/null
+++ b/services/src/main/java/org/keycloak/protocol/oidc/AccessTokenIntrospectionProvider.java
@@ -0,0 +1,83 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.protocol.oidc;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.keycloak.RSATokenVerifier;
+import org.keycloak.common.VerificationException;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.services.ErrorResponseException;
+import org.keycloak.util.JsonSerialization;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AccessTokenIntrospectionProvider implements TokenIntrospectionProvider {
+
+    private final KeycloakSession session;
+    private final TokenManager tokenManager;
+    private final RealmModel realm;
+
+    public AccessTokenIntrospectionProvider(KeycloakSession session) {
+        this.session = session;
+        this.realm = session.getContext().getRealm();
+        this.tokenManager = new TokenManager();
+    }
+
+    public Response introspect(String token) {
+        try {
+            AccessToken toIntrospect = toAccessToken(token);
+            RealmModel realm = this.session.getContext().getRealm();
+            ObjectNode tokenMetadata;
+
+            boolean active = tokenManager.isTokenValid(session, realm, toIntrospect);
+
+            if (active) {
+                tokenMetadata = JsonSerialization.createObjectNode(toIntrospect);
+                tokenMetadata.put("client_id", toIntrospect.getIssuedFor());
+                tokenMetadata.put("username", toIntrospect.getPreferredUsername());
+            } else {
+                tokenMetadata = JsonSerialization.createObjectNode();
+            }
+
+            tokenMetadata.put("active", active);
+
+            return Response.ok(JsonSerialization.writeValueAsBytes(tokenMetadata)).type(MediaType.APPLICATION_JSON_TYPE).build();
+        } catch (Exception e) {
+            throw new RuntimeException("Error creating token introspection response.", e);
+        }
+    }
+
+    protected AccessToken toAccessToken(String token) {
+        try {
+            return RSATokenVerifier.toAccessToken(token, realm.getPublicKey());
+        } catch (VerificationException e) {
+            throw new ErrorResponseException("invalid_request", "Invalid token.", Response.Status.UNAUTHORIZED);
+        }
+    }
+
+    @Override
+    public void close() {
+
+    }
+}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/AccessTokenIntrospectionProviderFactory.java b/services/src/main/java/org/keycloak/protocol/oidc/AccessTokenIntrospectionProviderFactory.java
new file mode 100644
index 0000000..19c9f18
--- /dev/null
+++ b/services/src/main/java/org/keycloak/protocol/oidc/AccessTokenIntrospectionProviderFactory.java
@@ -0,0 +1,55 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.protocol.oidc;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AccessTokenIntrospectionProviderFactory implements TokenIntrospectionProviderFactory {
+
+    public static final String ACCESS_TOKEN_TYPE = "access_token";
+
+    @Override
+    public TokenIntrospectionProvider create(KeycloakSession session) {
+        return new AccessTokenIntrospectionProvider(session);
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return ACCESS_TOKEN_TYPE;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
index 0122657..931b04c 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
@@ -26,6 +26,8 @@ import javax.ws.rs.GET;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 
+import org.keycloak.OAuth2Constants;
+import org.keycloak.OAuthErrorException;
 import org.keycloak.authentication.AuthenticationProcessor;
 import org.keycloak.constants.AdapterConstants;
 import org.keycloak.events.Details;
@@ -40,6 +42,7 @@ import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.protocol.AuthorizationEndpointBase;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.protocol.oidc.utils.OIDCRedirectUriBuilder;
 import org.keycloak.protocol.oidc.utils.OIDCResponseMode;
 import org.keycloak.protocol.oidc.utils.OIDCResponseType;
 import org.keycloak.protocol.oidc.utils.RedirectUtils;
@@ -50,6 +53,7 @@ import org.keycloak.services.managers.ClientSessionCode;
 import org.keycloak.services.messages.Messages;
 import org.keycloak.services.resources.LoginActionsService;
 import org.keycloak.services.util.CacheControlUtil;
+import org.keycloak.util.TokenUtil;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -95,6 +99,10 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
         KNOWN_REQ_PARAMS.add(OIDCLoginProtocol.PROMPT_PARAM);
         KNOWN_REQ_PARAMS.add(AdapterConstants.KC_IDP_HINT);
         KNOWN_REQ_PARAMS.add(OIDCLoginProtocol.NONCE_PARAM);
+        KNOWN_REQ_PARAMS.add(OIDCLoginProtocol.MAX_AGE_PARAM);
+        KNOWN_REQ_PARAMS.add(OIDCLoginProtocol.UI_LOCALES_PARAM);
+        KNOWN_REQ_PARAMS.add(OIDCLoginProtocol.REQUEST_PARAM);
+        KNOWN_REQ_PARAMS.add(OIDCLoginProtocol.REQUEST_URI_PARAM);
     }
 
     private enum Action {
@@ -106,6 +114,7 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
 
     private Action action;
     private OIDCResponseType parsedResponseType;
+    private OIDCResponseMode parsedResponseMode;
 
     private String clientId;
     private String redirectUri;
@@ -117,6 +126,7 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
     private String loginHint;
     private String prompt;
     private String nonce;
+    private String maxAge;
     private String idpHint;
     protected Map<String, String> additionalReqParams = new HashMap<>();
 
@@ -139,14 +149,27 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
         prompt = params.getFirst(OIDCLoginProtocol.PROMPT_PARAM);
         idpHint = params.getFirst(AdapterConstants.KC_IDP_HINT);
         nonce = params.getFirst(OIDCLoginProtocol.NONCE_PARAM);
+        maxAge = params.getFirst(OIDCLoginProtocol.MAX_AGE_PARAM);
 
         extractAdditionalReqParams(params);
 
         checkSsl();
         checkRealm();
-        checkResponseType();
         checkClient();
         checkRedirectUri();
+        Response errorResponse = checkResponseType();
+        if (errorResponse != null) {
+            return errorResponse;
+        }
+
+        if (!TokenUtil.isOIDCRequest(scope)) {
+            logger.oidcScopeMissing();
+        }
+
+        errorResponse = checkOIDCParams(params);
+        if (errorResponse != null) {
+            return errorResponse;
+        }
 
         createClientSession();
         // So back button doesn't work
@@ -234,28 +257,24 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
             throw new ErrorPageException(session, Messages.CLIENT_NOT_FOUND);
         }
 
-        if (client.isBearerOnly()) {
-            event.error(Errors.NOT_ALLOWED);
-            throw new ErrorPageException(session, Messages.BEARER_ONLY);
-        }
-
-        if ((parsedResponseType.hasResponseType(OIDCResponseType.CODE) || parsedResponseType.hasResponseType(OIDCResponseType.NONE)) && !client.isStandardFlowEnabled()) {
-            event.error(Errors.NOT_ALLOWED);
-            throw new ErrorPageException(session, Messages.STANDARD_FLOW_DISABLED);
+        if (!client.isEnabled()) {
+            event.error(Errors.CLIENT_DISABLED);
+            throw new ErrorPageException(session, Messages.CLIENT_DISABLED);
         }
 
-        if (parsedResponseType.isImplicitOrHybridFlow() && !client.isImplicitFlowEnabled()) {
+        if (client.isBearerOnly()) {
             event.error(Errors.NOT_ALLOWED);
-            throw new ErrorPageException(session, Messages.IMPLICIT_FLOW_DISABLED);
+            throw new ErrorPageException(session, Messages.BEARER_ONLY);
         }
 
         session.getContext().setClient(client);
     }
 
-    private void checkResponseType() {
+    private Response checkResponseType() {
         if (responseType == null) {
+            logger.missingParameter(OAuth2Constants.RESPONSE_TYPE);
             event.error(Errors.INVALID_REQUEST);
-            throw new ErrorPageException(session, Messages.MISSING_PARAMETER, OIDCLoginProtocol.RESPONSE_TYPE_PARAM);
+            return redirectErrorToClient(OIDCResponseMode.QUERY, OAuthErrorException.INVALID_REQUEST, "Missing parameter: response_type");
         }
 
         event.detail(Details.RESPONSE_TYPE, responseType);
@@ -266,26 +285,81 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
                 action = Action.CODE;
             }
         } catch (IllegalArgumentException iae) {
-            logger.error(iae);
+            logger.error(iae.getMessage());
             event.error(Errors.INVALID_REQUEST);
-            throw new ErrorPageException(session, Messages.INVALID_PARAMETER, OIDCLoginProtocol.RESPONSE_TYPE_PARAM);
+            return redirectErrorToClient(OIDCResponseMode.QUERY, OAuthErrorException.UNSUPPORTED_RESPONSE_TYPE, null);
         }
 
+        OIDCResponseMode parsedResponseMode = null;
         try {
-            OIDCResponseMode parsedResponseMode = OIDCResponseMode.parse(responseMode, parsedResponseType);
-            event.detail(Details.RESPONSE_MODE, parsedResponseMode.toString().toLowerCase());
-
-            // Disallowed by OIDC specs
-            if (parsedResponseType.isImplicitOrHybridFlow() && parsedResponseMode == OIDCResponseMode.QUERY) {
-                logger.responseModeQueryNotAllowed();
-                event.error(Errors.INVALID_REQUEST);
-                throw new ErrorPageException(session, Messages.INVALID_PARAMETER, OIDCLoginProtocol.RESPONSE_MODE_PARAM);
-            }
-
+            parsedResponseMode = OIDCResponseMode.parse(responseMode, parsedResponseType);
         } catch (IllegalArgumentException iae) {
+            logger.invalidParameter(OIDCLoginProtocol.RESPONSE_MODE_PARAM);
+            event.error(Errors.INVALID_REQUEST);
+            return redirectErrorToClient(OIDCResponseMode.QUERY, OAuthErrorException.INVALID_REQUEST, "Invalid parameter: response_mode");
+        }
+
+        event.detail(Details.RESPONSE_MODE, parsedResponseMode.toString().toLowerCase());
+
+        // Disallowed by OIDC specs
+        if (parsedResponseType.isImplicitOrHybridFlow() && parsedResponseMode == OIDCResponseMode.QUERY) {
+            logger.responseModeQueryNotAllowed();
             event.error(Errors.INVALID_REQUEST);
-            throw new ErrorPageException(session, Messages.INVALID_PARAMETER, OIDCLoginProtocol.RESPONSE_MODE_PARAM);
+            return redirectErrorToClient(OIDCResponseMode.QUERY, OAuthErrorException.INVALID_REQUEST, "Response_mode 'query' not allowed for implicit or hybrid flow");
+        }
+
+        if ((parsedResponseType.hasResponseType(OIDCResponseType.CODE) || parsedResponseType.hasResponseType(OIDCResponseType.NONE)) && !client.isStandardFlowEnabled()) {
+            logger.flowNotAllowed("Standard");
+            event.error(Errors.NOT_ALLOWED);
+            return redirectErrorToClient(parsedResponseMode, OAuthErrorException.UNSUPPORTED_RESPONSE_TYPE, "Client is not allowed to initiate browser login with given response_type. Standard flow is disabled for the client.");
         }
+
+        if (parsedResponseType.isImplicitOrHybridFlow() && !client.isImplicitFlowEnabled()) {
+            logger.flowNotAllowed("Implicit");
+            event.error(Errors.NOT_ALLOWED);
+            return redirectErrorToClient(parsedResponseMode, OAuthErrorException.UNSUPPORTED_RESPONSE_TYPE, "Client is not allowed to initiate browser login with given response_type. Implicit flow is disabled for the client.");
+        }
+
+        this.parsedResponseMode = parsedResponseMode;
+
+        return null;
+    }
+
+    private Response checkOIDCParams(MultivaluedMap<String, String> params) {
+        if (params.getFirst(OIDCLoginProtocol.REQUEST_PARAM) != null) {
+            logger.unsupportedParameter(OIDCLoginProtocol.REQUEST_PARAM);
+            event.error(Errors.INVALID_REQUEST);
+            return redirectErrorToClient(parsedResponseMode, OAuthErrorException.REQUEST_NOT_SUPPORTED, null);
+        }
+
+        if (params.getFirst(OIDCLoginProtocol.REQUEST_URI_PARAM) != null) {
+            logger.unsupportedParameter(OIDCLoginProtocol.REQUEST_URI_PARAM);
+            event.error(Errors.INVALID_REQUEST);
+            return redirectErrorToClient(parsedResponseMode, OAuthErrorException.REQUEST_URI_NOT_SUPPORTED, null);
+        }
+
+        if (parsedResponseType.isImplicitOrHybridFlow() && nonce == null) {
+            logger.missingParameter(OIDCLoginProtocol.NONCE_PARAM);
+            event.error(Errors.INVALID_REQUEST);
+            return redirectErrorToClient(parsedResponseMode, OAuthErrorException.INVALID_REQUEST, "Missing parameter: nonce");
+        }
+
+        return null;
+    }
+
+    private Response redirectErrorToClient(OIDCResponseMode responseMode, String error, String errorDescription) {
+        OIDCRedirectUriBuilder errorResponseBuilder = OIDCRedirectUriBuilder.fromUri(redirectUri, responseMode)
+                .addParam(OAuth2Constants.ERROR, error);
+
+        if (errorDescription != null) {
+            errorResponseBuilder.addParam(OAuth2Constants.ERROR_DESCRIPTION, errorDescription);
+        }
+
+        if (state != null) {
+            errorResponseBuilder.addParam(OAuth2Constants.STATE, state);
+        }
+
+        return errorResponseBuilder.build();
     }
 
     private void checkRedirectUri() {
@@ -309,6 +383,7 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
 
         if (state != null) clientSession.setNote(OIDCLoginProtocol.STATE_PARAM, state);
         if (nonce != null) clientSession.setNote(OIDCLoginProtocol.NONCE_PARAM, nonce);
+        if (maxAge != null) clientSession.setNote(OIDCLoginProtocol.MAX_AGE_PARAM, maxAge);
         if (scope != null) clientSession.setNote(OIDCLoginProtocol.SCOPE_PARAM, scope);
         if (loginHint != null) clientSession.setNote(OIDCLoginProtocol.LOGIN_HINT_PARAM, loginHint);
         if (prompt != null) clientSession.setNote(OIDCLoginProtocol.PROMPT_PARAM, prompt);
@@ -338,7 +413,7 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
         this.event.event(EventType.LOGIN);
         clientSession.setNote(Details.AUTH_TYPE, CODE_AUTH_TYPE);
 
-        return handleBrowserAuthenticationRequest(clientSession, new OIDCLoginProtocol(session, realm, uriInfo, headers, event), prompt != null && prompt.equals("none"), false);
+        return handleBrowserAuthenticationRequest(clientSession, new OIDCLoginProtocol(session, realm, uriInfo, headers, event), TokenUtil.hasPrompt(prompt, OIDCLoginProtocol.PROMPT_VALUE_NONE), false);
     }
 
     private Response buildRegister() {
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java
index 3f8d32a..85fea77 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/LogoutEndpoint.java
@@ -187,7 +187,7 @@ public class LogoutEndpoint {
             throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "No refresh token", Response.Status.BAD_REQUEST);
         }
         try {
-            RefreshToken token = tokenManager.verifyRefreshToken(realm, refreshToken);
+            RefreshToken token = tokenManager.verifyRefreshToken(realm, refreshToken, false);
             UserSessionModel userSessionModel = session.sessions().getUserSession(realm, token.getSessionState());
             if (userSessionModel != null) {
                 logout(userSessionModel);
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
index 1ff3da9..a79e679 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java
@@ -68,6 +68,9 @@ import java.util.Map;
  */
 public class TokenEndpoint {
 
+    // Flag if code was already exchanged for token
+    private static final String CODE_EXCHANGED = "CODE_EXCHANGED";
+
     private static final ServicesLogger logger = ServicesLogger.ROOT_LOGGER;
     private MultivaluedMap<String, String> formParams;
     private ClientModel client;
@@ -132,7 +135,7 @@ public class TokenEndpoint {
 
     @Path("introspect")
     public Object introspect() {
-        TokenIntrospectionEndpoint tokenIntrospectionEndpoint = new TokenIntrospectionEndpoint(this.realm, this.tokenManager, this.event);
+        TokenIntrospectionEndpoint tokenIntrospectionEndpoint = new TokenIntrospectionEndpoint(this.realm, this.event);
 
         ResteasyProviderFactory.getInstance().injectProperties(tokenIntrospectionEndpoint);
 
@@ -149,7 +152,7 @@ public class TokenEndpoint {
 
     private void checkSsl() {
         if (!uriInfo.getBaseUri().getScheme().equals("https") && realm.getSslRequired().isRequired(clientConnection)) {
-            throw new ErrorResponseException("invalid_request", "HTTPS required", Response.Status.FORBIDDEN);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "HTTPS required", Response.Status.FORBIDDEN);
         }
     }
 
@@ -165,13 +168,13 @@ public class TokenEndpoint {
         clientAuthAttributes = clientAuth.getClientAuthAttributes();
 
         if (client.isBearerOnly()) {
-            throw new ErrorResponseException("invalid_client", "Bearer-only not allowed", Response.Status.BAD_REQUEST);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_CLIENT, "Bearer-only not allowed", Response.Status.BAD_REQUEST);
         }
     }
 
     private void checkGrantType() {
         if (grantType == null) {
-            throw new ErrorResponseException("invalid_request", "Missing form parameter: " + OIDCLoginProtocol.GRANT_TYPE_PARAM, Response.Status.BAD_REQUEST);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Missing form parameter: " + OIDCLoginProtocol.GRANT_TYPE_PARAM, Response.Status.BAD_REQUEST);
         }
 
         if (grantType.equals(OAuth2Constants.AUTHORIZATION_CODE)) {
@@ -197,45 +200,52 @@ public class TokenEndpoint {
         String code = formParams.getFirst(OAuth2Constants.CODE);
         if (code == null) {
             event.error(Errors.INVALID_CODE);
-            throw new ErrorResponseException("invalid_request", "Missing parameter: " + OAuth2Constants.CODE, Response.Status.BAD_REQUEST);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Missing parameter: " + OAuth2Constants.CODE, Response.Status.BAD_REQUEST);
         }
 
         ClientSessionCode accessCode = ClientSessionCode.parse(code, session, realm);
         if (accessCode == null) {
             String[] parts = code.split("\\.");
             if (parts.length == 2) {
-                try {
-                    event.detail(Details.CODE_ID, new String(parts[1]));
-                } catch (Throwable t) {
-                }
+                event.detail(Details.CODE_ID, parts[1]);
             }
             event.error(Errors.INVALID_CODE);
-            throw new ErrorResponseException("invalid_grant", "Code not found", Response.Status.BAD_REQUEST);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_GRANT, "Code not found", Response.Status.BAD_REQUEST);
         }
 
         ClientSessionModel clientSession = accessCode.getClientSession();
         event.detail(Details.CODE_ID, clientSession.getId());
+
+        String codeExchanged = clientSession.getNote(CODE_EXCHANGED);
+        if (codeExchanged != null && Boolean.parseBoolean(codeExchanged)) {
+            session.sessions().removeClientSession(realm, clientSession);
+
+            event.error(Errors.INVALID_CODE);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_GRANT, "Code used already", Response.Status.BAD_REQUEST);
+        }
+
         if (!accessCode.isValid(ClientSessionModel.Action.CODE_TO_TOKEN.name(), ClientSessionCode.ActionType.CLIENT)) {
             event.error(Errors.INVALID_CODE);
-            throw new ErrorResponseException("invalid_grant", "Code is expired", Response.Status.BAD_REQUEST);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_GRANT, "Code is expired", Response.Status.BAD_REQUEST);
         }
 
         accessCode.setAction(null);
+        clientSession.setNote(CODE_EXCHANGED, "true");
         UserSessionModel userSession = clientSession.getUserSession();
 
         if (userSession == null) {
             event.error(Errors.USER_SESSION_NOT_FOUND);
-            throw new ErrorResponseException("invalid_grant", "User session not found", Response.Status.BAD_REQUEST);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_GRANT, "User session not found", Response.Status.BAD_REQUEST);
         }
 
         UserModel user = userSession.getUser();
         if (user == null) {
             event.error(Errors.USER_NOT_FOUND);
-            throw new ErrorResponseException("invalid_grant", "User not found", Response.Status.BAD_REQUEST);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_GRANT, "User not found", Response.Status.BAD_REQUEST);
         }
         if (!user.isEnabled()) {
             event.error(Errors.USER_DISABLED);
-            throw new ErrorResponseException("invalid_grant", "User disabled", Response.Status.BAD_REQUEST);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_GRANT, "User disabled", Response.Status.BAD_REQUEST);
         }
 
         event.user(userSession.getUser());
@@ -244,22 +254,22 @@ public class TokenEndpoint {
         String redirectUri = clientSession.getNote(OIDCLoginProtocol.REDIRECT_URI_PARAM);
         if (redirectUri != null && !redirectUri.equals(formParams.getFirst(OAuth2Constants.REDIRECT_URI))) {
             event.error(Errors.INVALID_CODE);
-            throw new ErrorResponseException("invalid_grant", "Incorrect redirect_uri", Response.Status.BAD_REQUEST);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_GRANT, "Incorrect redirect_uri", Response.Status.BAD_REQUEST);
         }
 
         if (!client.getClientId().equals(clientSession.getClient().getClientId())) {
             event.error(Errors.INVALID_CODE);
-            throw new ErrorResponseException("invalid_grant", "Auth error", Response.Status.BAD_REQUEST);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_GRANT, "Auth error", Response.Status.BAD_REQUEST);
         }
 
         if (!client.isStandardFlowEnabled()) {
             event.error(Errors.NOT_ALLOWED);
-            throw new ErrorResponseException("invalid_grant", "Client not allowed to exchange code", Response.Status.BAD_REQUEST);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_GRANT, "Client not allowed to exchange code", Response.Status.BAD_REQUEST);
         }
 
         if (!AuthenticationManager.isSessionValid(realm, userSession)) {
             event.error(Errors.USER_SESSION_NOT_FOUND);
-            throw new ErrorResponseException("invalid_grant", "Session not active", Response.Status.BAD_REQUEST);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_GRANT, "Session not active", Response.Status.BAD_REQUEST);
         }
 
         updateClientSession(clientSession);
@@ -354,12 +364,12 @@ public class TokenEndpoint {
 
         if (!client.isDirectAccessGrantsEnabled()) {
             event.error(Errors.NOT_ALLOWED);
-            throw new ErrorResponseException("invalid_grant", "Client not allowed for direct access grants", Response.Status.BAD_REQUEST);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_GRANT, "Client not allowed for direct access grants", Response.Status.BAD_REQUEST);
         }
 
         if (client.isConsentRequired()) {
             event.error(Errors.CONSENT_DENIED);
-            throw new ErrorResponseException("invalid_client", "Client requires user consent", Response.Status.BAD_REQUEST);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_CLIENT, "Client requires user consent", Response.Status.BAD_REQUEST);
         }
         String scope = formParams.getFirst(OAuth2Constants.SCOPE);
 
@@ -387,7 +397,7 @@ public class TokenEndpoint {
         UserModel user = clientSession.getAuthenticatedUser();
         if (user.getRequiredActions() != null && user.getRequiredActions().size() > 0) {
             event.error(Errors.RESOLVE_REQUIRED_ACTIONS);
-            throw new ErrorResponseException("invalid_grant", "Account is not fully set up", Response.Status.BAD_REQUEST);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_GRANT, "Account is not fully set up", Response.Status.BAD_REQUEST);
 
         }
         processor.attachSession();
@@ -409,24 +419,24 @@ public class TokenEndpoint {
     public Response buildClientCredentialsGrant() {
         if (client.isBearerOnly()) {
             event.error(Errors.INVALID_CLIENT);
-            throw new ErrorResponseException("unauthorized_client", "Bearer-only client not allowed to retrieve service account", Response.Status.UNAUTHORIZED);
+            throw new ErrorResponseException(OAuthErrorException.UNAUTHORIZED_CLIENT, "Bearer-only client not allowed to retrieve service account", Response.Status.UNAUTHORIZED);
         }
         if (client.isPublicClient()) {
             event.error(Errors.INVALID_CLIENT);
-            throw new ErrorResponseException("unauthorized_client", "Public client not allowed to retrieve service account", Response.Status.UNAUTHORIZED);
+            throw new ErrorResponseException(OAuthErrorException.UNAUTHORIZED_CLIENT, "Public client not allowed to retrieve service account", Response.Status.UNAUTHORIZED);
         }
         if (!client.isServiceAccountsEnabled()) {
             event.error(Errors.INVALID_CLIENT);
-            throw new ErrorResponseException("unauthorized_client", "Client not enabled to retrieve service account", Response.Status.UNAUTHORIZED);
+            throw new ErrorResponseException(OAuthErrorException.UNAUTHORIZED_CLIENT, "Client not enabled to retrieve service account", Response.Status.UNAUTHORIZED);
         }
 
-        UserModel clientUser = session.users().getUserByServiceAccountClient(client);
+        UserModel clientUser = session.users().getServiceAccount(client);
 
         if (clientUser == null || client.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, ServiceAccountConstants.CLIENT_ID_PROTOCOL_MAPPER) == null) {
             // May need to handle bootstrap here as well
             logger.debugf("Service account user for client '%s' not found or default protocol mapper for service account not found. Creating now", client.getClientId());
             new ClientManager(new RealmManager(session)).enableServiceAccount(client);
-            clientUser = session.users().getUserByServiceAccountClient(client);
+            clientUser = session.users().getServiceAccount(client);
         }
 
         String clientUsername = clientUser.getUsername();
@@ -435,7 +445,7 @@ public class TokenEndpoint {
 
         if (!clientUser.isEnabled()) {
             event.error(Errors.USER_DISABLED);
-            throw new ErrorResponseException("invalid_request", "User '" + clientUsername + "' disabled", Response.Status.UNAUTHORIZED);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "User '" + clientUsername + "' disabled", Response.Status.UNAUTHORIZED);
         }
 
         String scope = formParams.getFirst(OAuth2Constants.SCOPE);
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenIntrospectionEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenIntrospectionEndpoint.java
index 323a6ff..f6c59c8 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenIntrospectionEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenIntrospectionEndpoint.java
@@ -16,26 +16,19 @@
  */
 package org.keycloak.protocol.oidc.endpoints;
 
-import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.HttpRequest;
-import org.keycloak.OAuthErrorException;
-import org.keycloak.RSATokenVerifier;
 import org.keycloak.common.ClientConnection;
-import org.keycloak.common.VerificationException;
 import org.keycloak.events.Errors;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.events.EventType;
-import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
-import org.keycloak.protocol.oidc.TokenManager;
-import org.keycloak.protocol.oidc.TokenManager.TokenValidation;
+import org.keycloak.protocol.oidc.AccessTokenIntrospectionProviderFactory;
+import org.keycloak.protocol.oidc.TokenIntrospectionProvider;
 import org.keycloak.protocol.oidc.utils.AuthorizeClientUtil;
-import org.keycloak.representations.AccessToken;
 import org.keycloak.services.ErrorResponseException;
-import org.keycloak.util.JsonSerialization;
 
 import javax.ws.rs.POST;
 import javax.ws.rs.core.Context;
@@ -52,8 +45,6 @@ import javax.ws.rs.core.UriInfo;
  */
 public class TokenIntrospectionEndpoint {
 
-    private static final String TOKEN_TYPE_ACCESS_TOKEN = "access_token";
-    private static final String TOKEN_TYPE_REFRESH_TOKEN = "refresh_token";
     private static final String PARAM_TOKEN_TYPE_HINT = "token_type_hint";
     private static final String PARAM_TOKEN = "token";
 
@@ -72,12 +63,10 @@ public class TokenIntrospectionEndpoint {
     private ClientConnection clientConnection;
 
     private final RealmModel realm;
-    private final TokenManager tokenManager;
     private final EventBuilder event;
 
-    public TokenIntrospectionEndpoint(RealmModel realm, TokenManager tokenManager, EventBuilder event) {
+    public TokenIntrospectionEndpoint(RealmModel realm, EventBuilder event) {
         this.realm = realm;
-        this.tokenManager = tokenManager;
         this.event = event;
     }
 
@@ -94,7 +83,7 @@ public class TokenIntrospectionEndpoint {
         String tokenTypeHint = formParams.getFirst(PARAM_TOKEN_TYPE_HINT);
 
         if (tokenTypeHint == null) {
-            tokenTypeHint = TOKEN_TYPE_ACCESS_TOKEN;
+            tokenTypeHint = AccessTokenIntrospectionProviderFactory.ACCESS_TOKEN_TYPE;
         }
 
         String token = formParams.getFirst(PARAM_TOKEN);
@@ -103,39 +92,26 @@ public class TokenIntrospectionEndpoint {
             throw throwErrorResponseException(Errors.INVALID_REQUEST, "Token not provided.", Status.BAD_REQUEST);
         }
 
+        TokenIntrospectionProvider provider = this.session.getProvider(TokenIntrospectionProvider.class, tokenTypeHint);
+
+        if (provider == null) {
+            throw throwErrorResponseException(Errors.INVALID_REQUEST, "Unsupported token type [" + tokenTypeHint + "].", Status.BAD_REQUEST);
+        }
+
         try {
-            AccessToken toIntrospect = toAccessToken(tokenTypeHint, token);
-            ObjectNode tokenMetadata;
-
-            boolean active = tokenManager.isTokenValid(session, realm, toIntrospect);
-            if (active) {
-                tokenMetadata = JsonSerialization.createObjectNode(toIntrospect);
-                tokenMetadata.put("client_id", toIntrospect.getIssuedFor());
-                tokenMetadata.put("username", toIntrospect.getPreferredUsername());
-            } else {
-                tokenMetadata = JsonSerialization.createObjectNode();
-            }
 
-            tokenMetadata.put("active", active);
+            Response response = provider.introspect(token);
 
             this.event.success();
 
-            return Response.ok(JsonSerialization.writeValueAsBytes(tokenMetadata)).build();
+            return response;
+        } catch (ErrorResponseException ere) {
+            throw ere;
         } catch (Exception e) {
             throw throwErrorResponseException(Errors.INVALID_REQUEST, "Failed to introspect token.", Status.BAD_REQUEST);
         }
     }
 
-    private AccessToken toAccessToken(String tokenTypeHint, String token) throws JWSInputException, OAuthErrorException {
-        if (TOKEN_TYPE_ACCESS_TOKEN.equals(tokenTypeHint)) {
-            return toAccessToken(token);
-        } else if (TOKEN_TYPE_REFRESH_TOKEN.equals(tokenTypeHint)) {
-            return this.tokenManager.toRefreshToken(this.realm, token);
-        } else {
-            throw throwErrorResponseException(Errors.INVALID_REQUEST, "Unsupported token type [" + tokenTypeHint + "].", Status.BAD_REQUEST);
-        }
-    }
-
     private void authorizeClient() {
         try {
             ClientModel client = AuthorizeClientUtil.authorizeClient(session, event).getClient();
@@ -153,14 +129,6 @@ public class TokenIntrospectionEndpoint {
         }
     }
 
-    private AccessToken toAccessToken(String tokenString) {
-        try {
-            return RSATokenVerifier.toAccessToken(tokenString, realm.getPublicKey());
-        } catch (VerificationException e) {
-            throw new ErrorResponseException("invalid_request", "Invalid token.", Status.UNAUTHORIZED);
-        }
-    }
-
     private void checkSsl() {
         if (!uriInfo.getBaseUri().getScheme().equals("https") && realm.getSslRequired().isRequired(clientConnection)) {
             throw new ErrorResponseException("invalid_request", "HTTPS required", Status.FORBIDDEN);
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java
index 33ae2d5..ad23283 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/UserInfoEndpoint.java
@@ -24,6 +24,7 @@ import org.keycloak.OAuthErrorException;
 import org.keycloak.RSATokenVerifier;
 import org.keycloak.common.VerificationException;
 import org.keycloak.events.Details;
+import org.keycloak.events.Errors;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.events.EventType;
 import org.keycloak.models.ClientModel;
@@ -40,8 +41,6 @@ import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.resources.Cors;
 import org.keycloak.services.Urls;
 
-import javax.ws.rs.Consumes;
-import javax.ws.rs.FormParam;
 import javax.ws.rs.GET;
 import javax.ws.rs.OPTIONS;
 import javax.ws.rs.POST;
@@ -51,7 +50,6 @@ import javax.ws.rs.core.Context;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.Status;
 import javax.ws.rs.core.UriInfo;
 import java.util.HashMap;
 import java.util.Map;
@@ -105,9 +103,17 @@ public class UserInfoEndpoint {
     @Path("/")
     @POST
     @NoCache
-    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
     @Produces(MediaType.APPLICATION_JSON)
-    public Response issueUserInfoPost(@FormParam("access_token") String accessToken) {
+    public Response issueUserInfoPost() {
+        // Try header first
+        HttpHeaders headers = request.getHttpHeaders();
+        String accessToken = this.appAuthManager.extractAuthorizationHeaderToken(headers);
+
+        // Fallback to form parameter
+        if (accessToken == null) {
+            accessToken = request.getDecodedFormParameters().getFirst("access_token");
+        }
+
         return issueUserInfo(accessToken);
     }
 
@@ -116,30 +122,61 @@ public class UserInfoEndpoint {
                 .event(EventType.USER_INFO_REQUEST)
                 .detail(Details.AUTH_METHOD, Details.VALIDATE_ACCESS_TOKEN);
 
+        if (tokenString == null) {
+            event.error(Errors.INVALID_TOKEN);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Token not provided", Response.Status.BAD_REQUEST);
+        }
+
         AccessToken token = null;
         try {
             token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()), true, true);
         } catch (VerificationException e) {
-            throw new ErrorResponseException(OAuthErrorException.INVALID_GRANT, "Token invalid: " + e.getMessage(), Status.FORBIDDEN);
+            event.error(Errors.INVALID_TOKEN);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_TOKEN, "Token invalid: " + e.getMessage(), Response.Status.UNAUTHORIZED);
         }
 
         UserSessionModel userSession = session.sessions().getUserSession(realm, token.getSessionState());
         ClientSessionModel clientSession = session.sessions().getClientSession(token.getClientSession());
-        if (userSession == null || clientSession == null || !AuthenticationManager.isSessionValid(realm, userSession)) {
-            throw new ErrorResponseException(OAuthErrorException.INVALID_GRANT, "Token invalid", Status.FORBIDDEN);
+
+        if (userSession == null) {
+            event.error(Errors.USER_SESSION_NOT_FOUND);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "User session not found", Response.Status.BAD_REQUEST);
         }
 
-        ClientModel clientModel = realm.getClientByClientId(token.getIssuedFor());
+        event.session(userSession);
+
         UserModel userModel = userSession.getUser();
+        if (userModel == null) {
+            event.error(Errors.USER_NOT_FOUND);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "User not found", Response.Status.BAD_REQUEST);
+        }
+
+        event.user(userModel)
+                .detail(Details.USERNAME, userModel.getUsername());
+
+
+        if (clientSession == null || !AuthenticationManager.isSessionValid(realm, userSession)) {
+            event.error(Errors.SESSION_EXPIRED);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_TOKEN, "Session expired", Response.Status.UNAUTHORIZED);
+        }
+
+        ClientModel clientModel = realm.getClientByClientId(token.getIssuedFor());
+        if (clientModel == null) {
+            event.error(Errors.CLIENT_NOT_FOUND);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Client not found", Response.Status.BAD_REQUEST);
+        }
+
+        event.client(clientModel);
+
+        if (!clientModel.isEnabled()) {
+            event.error(Errors.CLIENT_DISABLED);
+            throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Client disabled", Response.Status.BAD_REQUEST);
+        }
+
         AccessToken userInfo = new AccessToken();
-        tokenManager.transformAccessToken(session, userInfo, realm, clientModel, userModel, userSession, clientSession);
-
-        event
-            .detail(Details.USERNAME, userModel.getUsername())
-            .client(clientModel)
-            .session(userSession)
-            .user(userModel)
-            .success();
+        tokenManager.transformUserInfoAccessToken(session, userInfo, realm, clientModel, userModel, userSession, clientSession);
+
+        event.success();
 
         Map<String, Object> claims = new HashMap<String, Object>();
         claims.putAll(userInfo.getOtherClaims());
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/installation/KeycloakOIDCClientInstallation.java b/services/src/main/java/org/keycloak/protocol/oidc/installation/KeycloakOIDCClientInstallation.java
index f3f502d..6fda3f0 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/installation/KeycloakOIDCClientInstallation.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/installation/KeycloakOIDCClientInstallation.java
@@ -20,12 +20,16 @@ package org.keycloak.protocol.oidc.installation;
 import org.keycloak.Config;
 import org.keycloak.authentication.ClientAuthenticator;
 import org.keycloak.authentication.ClientAuthenticatorFactory;
+import org.keycloak.authorization.admin.AuthorizationService;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.Constants;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
 import org.keycloak.protocol.ClientInstallationProvider;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
 import org.keycloak.services.managers.ClientManager;
 import org.keycloak.util.JsonSerialization;
 
@@ -34,6 +38,7 @@ import javax.ws.rs.core.Response;
 import java.io.IOException;
 import java.net.URI;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -59,6 +64,9 @@ public class KeycloakOIDCClientInstallation implements ClientInstallationProvide
             Map<String, Object> adapterConfig = getClientCredentialsAdapterConfig(session, client);
             rep.setCredentials(adapterConfig);
         }
+
+        configureAuthorizationSettings(session, client, rep);
+
         String json = null;
         try {
             json = JsonSerialization.writeValueAsPrettyString(rep);
@@ -143,4 +151,23 @@ public class KeycloakOIDCClientInstallation implements ClientInstallationProvide
         return MediaType.APPLICATION_JSON;
     }
 
+    private void configureAuthorizationSettings(KeycloakSession session, ClientModel client, ClientManager.InstallationAdapterConfig rep) {
+        if (new AuthorizationService(session, client, null).isEnabled()) {
+            PolicyEnforcerConfig enforcerConfig = new PolicyEnforcerConfig();
+
+            enforcerConfig.setEnforcementMode(null);
+            enforcerConfig.setCreateResources(null);
+            enforcerConfig.setOnlineIntrospection(null);
+
+            rep.setEnforcerConfig(enforcerConfig);
+
+            Set<RoleModel> clientRoles = client.getRoles();
+
+            if (clientRoles.size() == 1) {
+                if (clientRoles.iterator().next().getName().equals(Constants.AUTHZ_UMA_PROTECTION)) {
+                    rep.setUseResourceRoleMappings(null);
+                }
+            }
+        }
+    }
 }
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/AbstractUserRoleMappingMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/AbstractUserRoleMappingMapper.java
new file mode 100755
index 0000000..3e639aa
--- /dev/null
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/AbstractUserRoleMappingMapper.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.protocol.oidc.mappers;
+
+import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.IDToken;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * Base class for mapping of user role mappings to an ID and Access Token claim.
+ *
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+abstract class AbstractUserRoleMappingMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper {
+
+    @Override
+    public AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
+                                            UserSessionModel userSession, ClientSessionModel clientSession) {
+
+        if (!OIDCAttributeMapperHelper.includeInAccessToken(mappingModel)) {
+            return token;
+        }
+
+        setClaim(token, mappingModel, userSession);
+        return token;
+    }
+
+    @Override
+    public IDToken transformIDToken(IDToken token, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) {
+
+        if (!OIDCAttributeMapperHelper.includeInIDToken(mappingModel)) {
+            return token;
+        }
+
+        setClaim(token, mappingModel, userSession);
+        return token;
+    }
+
+
+    protected abstract void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession);
+
+    /**
+     * Returns the role names extracted from the given {@code roleModels} while recursively traversing "Composite Roles".
+     * <p>
+     * Optionally prefixes each role name with the given {@code prefix}.
+     * </p>
+     *
+     * @param roleModels
+     * @param prefix     the prefix to apply, may be {@literal null}
+     * @return
+     */
+    protected Set<String> flattenRoleModelToRoleNames(Set<RoleModel> roleModels, String prefix) {
+
+        Set<String> roleNames = new LinkedHashSet<>();
+
+        Deque<RoleModel> stack = new ArrayDeque<>(roleModels);
+        while (!stack.isEmpty()) {
+
+            RoleModel current = stack.pop();
+
+            if (current.isComposite()) {
+                for (RoleModel compositeRoleModel : current.getComposites()) {
+                    stack.push(compositeRoleModel);
+                }
+            }
+
+            String roleName = current.getName();
+
+            if (prefix != null && !prefix.trim().isEmpty()) {
+                roleName = prefix.trim() + roleName;
+            }
+
+            roleNames.add(roleName);
+        }
+
+        return roleNames;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAttributeMapperHelper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAttributeMapperHelper.java
index 1cc87d9..f452261 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAttributeMapperHelper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/OIDCAttributeMapperHelper.java
@@ -18,6 +18,7 @@
 package org.keycloak.protocol.oidc.mappers;
 
 import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.protocol.ProtocolMapper;
 import org.keycloak.protocol.ProtocolMapperUtils;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.provider.ProviderConfigProperty;
@@ -48,6 +49,10 @@ public class OIDCAttributeMapperHelper {
     public static final String INCLUDE_IN_ID_TOKEN_LABEL = "includeInIdToken.label";
     public static final String INCLUDE_IN_ID_TOKEN_HELP_TEXT = "includeInIdToken.tooltip";
 
+    public static final String INCLUDE_IN_USERINFO = "userinfo.token.claim";
+    public static final String INCLUDE_IN_USERINFO_LABEL = "includeInUserInfo.label";
+    public static final String INCLUDE_IN_USERINFO_HELP_TEXT = "includeInUserInfo.tooltip";
+
     public static Object mapAttributeValue(ProtocolMapperModel mappingModel, Object attributeValue) {
         if (attributeValue == null) return null;
 
@@ -115,10 +120,19 @@ public class OIDCAttributeMapperHelper {
     }
 
     public static ProtocolMapperModel createClaimMapper(String name,
+                                                        String userAttribute,
+                                                        String tokenClaimName, String claimType,
+                                                        boolean consentRequired, String consentText,
+                                                        boolean accessToken, boolean idToken,
+                                                        String mapperId) {
+        return createClaimMapper(name, userAttribute,tokenClaimName, claimType, consentRequired, consentText, accessToken, idToken, false, mapperId);
+    }
+
+    public static ProtocolMapperModel createClaimMapper(String name,
                                   String userAttribute,
                                   String tokenClaimName, String claimType,
                                   boolean consentRequired, String consentText,
-                                  boolean accessToken, boolean idToken,
+                                  boolean accessToken, boolean idToken, boolean userinfo,
                                   String mapperId) {
         ProtocolMapperModel mapper = new ProtocolMapperModel();
         mapper.setName(name);
@@ -132,6 +146,7 @@ public class OIDCAttributeMapperHelper {
         config.put(JSON_TYPE, claimType);
         if (accessToken) config.put(INCLUDE_IN_ACCESS_TOKEN, "true");
         if (idToken) config.put(INCLUDE_IN_ID_TOKEN, "true");
+        if (userinfo) config.put(INCLUDE_IN_USERINFO, "true");
         mapper.setConfig(config);
         return mapper;
     }
@@ -144,11 +159,14 @@ public class OIDCAttributeMapperHelper {
         return "true".equals(mappingModel.getConfig().get(INCLUDE_IN_ACCESS_TOKEN));
     }
 
-
     public static boolean isMultivalued(ProtocolMapperModel mappingModel) {
         return "true".equals(mappingModel.getConfig().get(ProtocolMapperUtils.MULTIVALUED));
     }
 
+    public static boolean includeInUserInfo(ProtocolMapperModel mappingModel){
+        return "true".equals(mappingModel.getConfig().get(INCLUDE_IN_USERINFO));
+    }
+
     public static void addAttributeConfig(List<ProviderConfigProperty> configProperties) {
         ProviderConfigProperty property;
         property = new ProviderConfigProperty();
@@ -183,5 +201,12 @@ public class OIDCAttributeMapperHelper {
         property.setDefaultValue("true");
         property.setHelpText(INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT);
         configProperties.add(property);
+        property = new ProviderConfigProperty();
+        property.setName(INCLUDE_IN_USERINFO);
+        property.setLabel(INCLUDE_IN_USERINFO_LABEL);
+        property.setType(ProviderConfigProperty.BOOLEAN_TYPE);
+        property.setDefaultValue("false");
+        property.setHelpText(INCLUDE_IN_USERINFO_HELP_TEXT);
+        configProperties.add(property);
     }
 }
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserAttributeMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserAttributeMapper.java
index 558d3a7..56e7a48 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserAttributeMapper.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserAttributeMapper.java
@@ -39,7 +39,7 @@ import java.util.List;
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
  */
-public class UserAttributeMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper {
+public class UserAttributeMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper {
 
     private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
 
@@ -113,11 +113,22 @@ public class UserAttributeMapper extends AbstractOIDCProtocolMapper implements O
         return token;
     }
 
+    @Override
+    public AccessToken transformUserInfoToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) {
+
+        if (!OIDCAttributeMapperHelper.includeInUserInfo(mappingModel)) {
+            return token;
+        }
+
+        setClaim(token, mappingModel, userSession);
+        return token;
+    }
+
     public static ProtocolMapperModel createClaimMapper(String name,
-                                      String userAttribute,
-                                      String tokenClaimName, String claimType,
-                                      boolean consentRequired, String consentText,
-                                      boolean accessToken, boolean idToken, boolean multivalued) {
+                                                        String userAttribute,
+                                                        String tokenClaimName, String claimType,
+                                                        boolean consentRequired, String consentText,
+                                                        boolean accessToken, boolean idToken, boolean multivalued) {
         ProtocolMapperModel mapper = OIDCAttributeMapperHelper.createClaimMapper(name, userAttribute,
                 tokenClaimName, claimType,
                 consentRequired, consentText,
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserClientRoleMappingMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserClientRoleMappingMapper.java
new file mode 100755
index 0000000..dcb55a8
--- /dev/null
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserClientRoleMappingMapper.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.protocol.oidc.mappers;
+
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.protocol.ProtocolMapperUtils;
+import org.keycloak.provider.ProviderConfigProperty;
+import org.keycloak.representations.IDToken;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Allows mapping of user client role mappings to an ID and Access Token claim.
+ *
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+public class UserClientRoleMappingMapper extends AbstractUserRoleMappingMapper {
+
+    public static final String PROVIDER_ID = "oidc-usermodel-client-role-mapper";
+
+    private static final List<ProviderConfigProperty> CONFIG_PROPERTIES = new ArrayList<ProviderConfigProperty>();
+
+    static {
+
+        ProviderConfigProperty clientId = new ProviderConfigProperty();
+        clientId.setName(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID);
+        clientId.setLabel(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID_LABEL);
+        clientId.setHelpText(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID_HELP_TEXT);
+        clientId.setType(ProviderConfigProperty.STRING_TYPE);
+        CONFIG_PROPERTIES.add(clientId);
+
+        ProviderConfigProperty clientRolePrefix = new ProviderConfigProperty();
+        clientRolePrefix.setName(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_ROLE_PREFIX);
+        clientRolePrefix.setLabel(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_ROLE_PREFIX_LABEL);
+        clientRolePrefix.setHelpText(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_ROLE_PREFIX_HELP_TEXT);
+        clientRolePrefix.setType(ProviderConfigProperty.STRING_TYPE);
+        CONFIG_PROPERTIES.add(clientRolePrefix);
+
+        OIDCAttributeMapperHelper.addAttributeConfig(CONFIG_PROPERTIES);
+    }
+
+    public List<ProviderConfigProperty> getConfigProperties() {
+        return CONFIG_PROPERTIES;
+    }
+
+    @Override
+    public String getId() {
+        return PROVIDER_ID;
+    }
+
+    @Override
+    public String getDisplayType() {
+        return "User Client Role";
+    }
+
+    @Override
+    public String getDisplayCategory() {
+        return TOKEN_MAPPER_CATEGORY;
+    }
+
+    @Override
+    public String getHelpText() {
+        return "Map a user client role to a token claim.";
+    }
+
+    protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
+
+        UserModel user = userSession.getUser();
+
+        String clientId = mappingModel.getConfig().get(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID);
+        if (clientId != null) {
+
+            ClientModel clientModel = userSession.getRealm().getClientByClientId(clientId.trim());
+            Set<RoleModel> clientRoleMappings = user.getClientRoleMappings(clientModel);
+
+            String rolePrefix = mappingModel.getConfig().get(ProtocolMapperUtils.USER_MODEL_CLIENT_ROLE_MAPPING_ROLE_PREFIX);
+            Set<String> clientRoleNames = flattenRoleModelToRoleNames(clientRoleMappings, rolePrefix);
+
+            OIDCAttributeMapperHelper.mapClaim(token, mappingModel, clientRoleNames);
+        }
+    }
+}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserInfoTokenMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserInfoTokenMapper.java
new file mode 100644
index 0000000..a93e62b
--- /dev/null
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserInfoTokenMapper.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.protocol.oidc.mappers;
+
+import org.keycloak.models.ClientSessionModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.representations.AccessToken;
+
+/**
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+public interface UserInfoTokenMapper {
+
+    AccessToken transformUserInfoToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
+                                     UserSessionModel userSession, ClientSessionModel clientSession);
+}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserRealmRoleMappingMapper.java b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserRealmRoleMappingMapper.java
new file mode 100755
index 0000000..3346070
--- /dev/null
+++ b/services/src/main/java/org/keycloak/protocol/oidc/mappers/UserRealmRoleMappingMapper.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.protocol.oidc.mappers;
+
+import org.keycloak.models.ProtocolMapperModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.protocol.ProtocolMapperUtils;
+import org.keycloak.provider.ProviderConfigProperty;
+import org.keycloak.representations.IDToken;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Allows mapping of user realm role mappings to an ID and Access Token claim.
+ *
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+public class UserRealmRoleMappingMapper extends AbstractUserRoleMappingMapper {
+
+    public static final String PROVIDER_ID = "oidc-usermodel-realm-role-mapper";
+
+    private static final List<ProviderConfigProperty> CONFIG_PROPERTIES = new ArrayList<ProviderConfigProperty>();
+
+    static {
+
+        ProviderConfigProperty realmRolePrefix = new ProviderConfigProperty();
+        realmRolePrefix.setName(ProtocolMapperUtils.USER_MODEL_REALM_ROLE_MAPPING_ROLE_PREFIX);
+        realmRolePrefix.setLabel(ProtocolMapperUtils.USER_MODEL_REALM_ROLE_MAPPING_ROLE_PREFIX_LABEL);
+        realmRolePrefix.setHelpText(ProtocolMapperUtils.USER_MODEL_REALM_ROLE_MAPPING_ROLE_PREFIX_HELP_TEXT);
+        realmRolePrefix.setType(ProviderConfigProperty.STRING_TYPE);
+        CONFIG_PROPERTIES.add(realmRolePrefix);
+
+        OIDCAttributeMapperHelper.addAttributeConfig(CONFIG_PROPERTIES);
+    }
+
+    public List<ProviderConfigProperty> getConfigProperties() {
+        return CONFIG_PROPERTIES;
+    }
+
+    @Override
+    public String getId() {
+        return PROVIDER_ID;
+    }
+
+    @Override
+    public String getDisplayType() {
+        return "User Realm Role";
+    }
+
+    @Override
+    public String getDisplayCategory() {
+        return TOKEN_MAPPER_CATEGORY;
+    }
+
+    @Override
+    public String getHelpText() {
+        return "Map a user realm role to a token claim.";
+    }
+
+    protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
+
+        UserModel user = userSession.getUser();
+
+        String rolePrefix = mappingModel.getConfig().get(ProtocolMapperUtils.USER_MODEL_REALM_ROLE_MAPPING_ROLE_PREFIX);
+        Set<String> realmRoleNames = flattenRoleModelToRoleNames(user.getRoleMappings(), rolePrefix);
+
+        OIDCAttributeMapperHelper.mapClaim(token, mappingModel, realmRoleNames);
+    }
+}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCClientDescriptionConverter.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCClientDescriptionConverter.java
index c55b482..392b3ce 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCClientDescriptionConverter.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCClientDescriptionConverter.java
@@ -17,11 +17,8 @@
 
 package org.keycloak.protocol.oidc;
 
-import org.keycloak.Config;
 import org.keycloak.exportimport.ClientDescriptionConverter;
-import org.keycloak.exportimport.ClientDescriptionConverterFactory;
 import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.representations.oidc.OIDCClientRepresentation;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.services.clientregistration.oidc.DescriptionConverter;
@@ -32,46 +29,28 @@ import java.io.IOException;
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
-public class OIDCClientDescriptionConverter implements ClientDescriptionConverter, ClientDescriptionConverterFactory {
+public class OIDCClientDescriptionConverter implements ClientDescriptionConverter {
 
-    public static final String ID = "openid-connect";
+    private final KeycloakSession session;
 
-    @Override
-    public boolean isSupported(String description) {
-        description = description.trim();
-        return (description.startsWith("{") && description.endsWith("}") && description.contains("\"redirect_uris\""));
+    public OIDCClientDescriptionConverter(KeycloakSession session) {
+        this.session = session;
     }
 
+
     @Override
     public ClientRepresentation convertToInternal(String description) {
         try {
             OIDCClientRepresentation clientOIDC = JsonSerialization.readValue(description, OIDCClientRepresentation.class);
-            return DescriptionConverter.toInternal(clientOIDC);
+            return DescriptionConverter.toInternal(session, clientOIDC);
         } catch (IOException e) {
             throw new RuntimeException(e);
         }
     }
 
     @Override
-    public ClientDescriptionConverter create(KeycloakSession session) {
-        return this;
-    }
-
-    @Override
-    public void init(Config.Scope config) {
-    }
-
-    @Override
-    public void postInit(KeycloakSessionFactory factory) {
-    }
-
-    @Override
     public void close() {
     }
 
-    @Override
-    public String getId() {
-        return ID;
-    }
 
 }
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCClientDescriptionConverterFactory.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCClientDescriptionConverterFactory.java
new file mode 100644
index 0000000..fe29f50
--- /dev/null
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCClientDescriptionConverterFactory.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.protocol.oidc;
+
+import org.keycloak.Config;
+import org.keycloak.exportimport.ClientDescriptionConverter;
+import org.keycloak.exportimport.ClientDescriptionConverterFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OIDCClientDescriptionConverterFactory implements ClientDescriptionConverterFactory {
+
+    public static final String ID = "openid-connect";
+
+    @Override
+    public boolean isSupported(String description) {
+        description = description.trim();
+        return (description.startsWith("{") && description.endsWith("}") && description.contains("\"redirect_uris\""));
+    }
+
+    @Override
+    public ClientDescriptionConverter create(KeycloakSession session) {
+        return new OIDCClientDescriptionConverter(session);
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public void close() {
+    }
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
index 8bef72e..3c4c3aa 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocol.java
@@ -17,6 +17,8 @@
 package org.keycloak.protocol.oidc;
 
 import org.keycloak.OAuth2Constants;
+import org.keycloak.OAuthErrorException;
+import org.keycloak.common.util.Time;
 import org.keycloak.events.Details;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.events.EventType;
@@ -32,8 +34,10 @@ import org.keycloak.protocol.oidc.utils.OIDCResponseMode;
 import org.keycloak.protocol.oidc.utils.OIDCResponseType;
 import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.services.ServicesLogger;
+import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.managers.ClientSessionCode;
 import org.keycloak.services.managers.ResourceAdminManager;
+import org.keycloak.util.TokenUtil;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response;
@@ -56,13 +60,29 @@ public class OIDCLoginProtocol implements LoginProtocol {
     public static final String REDIRECT_URI_PARAM = "redirect_uri";
     public static final String CLIENT_ID_PARAM = "client_id";
     public static final String NONCE_PARAM = "nonce";
-    public static final String PROMPT_PARAM = "prompt";
+    public static final String MAX_AGE_PARAM = OAuth2Constants.MAX_AGE;
+    public static final String PROMPT_PARAM = OAuth2Constants.PROMPT;
     public static final String LOGIN_HINT_PARAM = "login_hint";
+    public static final String REQUEST_PARAM = "request";
+    public static final String REQUEST_URI_PARAM = "request_uri";
+    public static final String UI_LOCALES_PARAM = OAuth2Constants.UI_LOCALES_PARAM;
+
     public static final String LOGOUT_REDIRECT_URI = "OIDC_LOGOUT_REDIRECT_URI";
     public static final String ISSUER = "iss";
 
     public static final String RESPONSE_MODE_PARAM = "response_mode";
 
+    public static final String PROMPT_VALUE_NONE = "none";
+    public static final String PROMPT_VALUE_LOGIN = "login";
+    public static final String PROMPT_VALUE_CONSENT = "consent";
+    public static final String PROMPT_VALUE_SELECT_ACCOUNT = "select_account";
+
+    // Client authentication methods
+    public static final String CLIENT_SECRET_BASIC = "client_secret_basic";
+    public static final String CLIENT_SECRET_POST = "client_secret_post";
+    public static final String CLIENT_SECRET_JWT = "client_secret_jwt";
+    public static final String PRIVATE_KEY_JWT = "private_key_jwt";
+
     private static final ServicesLogger logger = ServicesLogger.ROOT_LOGGER;
 
     protected KeycloakSession session;
@@ -151,17 +171,31 @@ public class OIDCLoginProtocol implements LoginProtocol {
         // Implicit or hybrid flow
         if (responseType.isImplicitOrHybridFlow()) {
             TokenManager tokenManager = new TokenManager();
-            AccessTokenResponse res = tokenManager.responseBuilder(realm, clientSession.getClient(), event, session, userSession, clientSession)
-                    .generateAccessToken()
-                    .generateIDToken()
-                    .build();
+            TokenManager.AccessTokenResponseBuilder responseBuilder = tokenManager.responseBuilder(realm, clientSession.getClient(), event, session, userSession, clientSession)
+                    .generateAccessToken();
+
+            if (responseType.hasResponseType(OIDCResponseType.ID_TOKEN)) {
+
+                responseBuilder.generateIDToken();
+
+                if (responseType.hasResponseType(OIDCResponseType.TOKEN)) {
+                    responseBuilder.generateAccessTokenHash();
+                }
+
+                if (responseType.hasResponseType(OIDCResponseType.CODE)) {
+                    responseBuilder.generateCodeHash(accessCode.getCode());
+                }
+
+            }
+
+            AccessTokenResponse res = responseBuilder.build();
 
             if (responseType.hasResponseType(OIDCResponseType.ID_TOKEN)) {
-                redirectUri.addParam("id_token", res.getIdToken());
+                redirectUri.addParam(OAuth2Constants.ID_TOKEN, res.getIdToken());
             }
 
             if (responseType.hasResponseType(OIDCResponseType.TOKEN)) {
-                redirectUri.addParam("access_token", res.getToken());
+                redirectUri.addParam(OAuth2Constants.ACCESS_TOKEN, res.getToken());
                 redirectUri.addParam("token_type", res.getTokenType());
                 redirectUri.addParam("session_state", res.getSessionState());
                 redirectUri.addParam("expires_in", String.valueOf(res.getExpiresIn()));
@@ -192,14 +226,14 @@ public class OIDCLoginProtocol implements LoginProtocol {
         switch (error) {
             case CANCELLED_BY_USER:
             case CONSENT_DENIED:
-                return "access_denied";
+                return OAuthErrorException.ACCESS_DENIED;
             case PASSIVE_INTERACTION_REQUIRED:
-                return "interaction_required";
+                return OAuthErrorException.INTERACTION_REQUIRED;
             case PASSIVE_LOGIN_REQUIRED:
-                return "login_required";
+                return OAuthErrorException.LOGIN_REQUIRED;
             default:
                 logger.untranslatedProtocol(error.name());
-                return "access_denied";
+                return OAuthErrorException.SERVER_ERROR;
         }
     }
 
@@ -235,6 +269,36 @@ public class OIDCLoginProtocol implements LoginProtocol {
         }
     }
 
+
+    @Override
+    public boolean requireReauthentication(UserSessionModel userSession, ClientSessionModel clientSession) {
+        return isPromptLogin(clientSession) || isAuthTimeExpired(userSession, clientSession);
+    }
+
+    protected boolean isPromptLogin(ClientSessionModel clientSession) {
+        String prompt = clientSession.getNote(OIDCLoginProtocol.PROMPT_PARAM);
+        return TokenUtil.hasPrompt(prompt, OIDCLoginProtocol.PROMPT_VALUE_LOGIN);
+    }
+
+    protected boolean isAuthTimeExpired(UserSessionModel userSession, ClientSessionModel clientSession) {
+        String authTime = userSession.getNote(AuthenticationManager.AUTH_TIME);
+        String maxAge = clientSession.getNote(OIDCLoginProtocol.MAX_AGE_PARAM);
+        if (maxAge == null) {
+            return false;
+        }
+
+        int authTimeInt = authTime==null ? 0 : Integer.parseInt(authTime);
+        int maxAgeInt = Integer.parseInt(maxAge);
+
+        if (authTimeInt + maxAgeInt < Time.currentTime()) {
+            logger.debugf("Authentication time is expired, needs to reauthenticate. userSession=%s, clientId=%s, maxAge=%d, authTime=%d", userSession.getId(),
+                    clientSession.getClient().getId(), maxAgeInt, authTimeInt);
+            return true;
+        }
+
+        return false;
+    }
+
     @Override
     public void close() {
 
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java
index 75b3f46..7afec32 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolService.java
@@ -19,7 +19,6 @@ package org.keycloak.protocol.oidc;
 
 import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
-import org.keycloak.OAuth2Constants;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.jose.jwk.JWK;
 import org.keycloak.jose.jwk.JWKBuilder;
@@ -31,7 +30,7 @@ import org.keycloak.protocol.oidc.endpoints.LoginStatusIframeEndpoint;
 import org.keycloak.protocol.oidc.endpoints.LogoutEndpoint;
 import org.keycloak.protocol.oidc.endpoints.TokenEndpoint;
 import org.keycloak.protocol.oidc.endpoints.UserInfoEndpoint;
-import org.keycloak.protocol.oidc.representations.JSONWebKeySet;
+import org.keycloak.jose.jwk.JSONWebKeySet;
 import org.keycloak.services.ServicesLogger;
 import org.keycloak.services.resources.RealmsResource;
 
@@ -99,6 +98,16 @@ public class OIDCLoginProtocolService {
         return uriBuilder.path(OIDCLoginProtocolService.class, "token");
     }
 
+    public static UriBuilder certsUrl(UriBuilder baseUriBuilder) {
+        UriBuilder uriBuilder = tokenServiceBaseUrl(baseUriBuilder);
+        return uriBuilder.path(OIDCLoginProtocolService.class, "certs");
+    }
+
+    public static UriBuilder userInfoUrl(UriBuilder baseUriBuilder) {
+        UriBuilder uriBuilder = tokenServiceBaseUrl(baseUriBuilder);
+        return uriBuilder.path(OIDCLoginProtocolService.class, "issueUserInfo");
+    }
+
     public static UriBuilder tokenIntrospectionUrl(UriBuilder baseUriBuilder) {
         return tokenUrl(baseUriBuilder).path(TokenEndpoint.class, "introspect");
     }
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java
index d9471f8..eb5b5b4 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProvider.java
@@ -18,11 +18,16 @@
 package org.keycloak.protocol.oidc;
 
 import org.keycloak.OAuth2Constants;
+import org.keycloak.authentication.ClientAuthenticator;
+import org.keycloak.authentication.ClientAuthenticatorFactory;
+import org.keycloak.jose.jws.Algorithm;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.protocol.oidc.endpoints.TokenEndpoint;
 import org.keycloak.protocol.oidc.representations.OIDCConfigurationRepresentation;
 import org.keycloak.protocol.oidc.utils.OIDCResponseType;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.representations.IDToken;
 import org.keycloak.services.clientregistration.ClientRegistrationService;
 import org.keycloak.services.clientregistration.oidc.OIDCClientRegistrationProviderFactory;
 import org.keycloak.services.resources.RealmsResource;
@@ -31,6 +36,8 @@ import org.keycloak.wellknown.WellKnownProvider;
 
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
+
+import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -39,7 +46,7 @@ import java.util.List;
  */
 public class OIDCWellKnownProvider implements WellKnownProvider {
 
-    public static final List<String> DEFAULT_ID_TOKEN_SIGNING_ALG_VALUES_SUPPORTED = list("RS256");
+    public static final List<String> DEFAULT_ID_TOKEN_SIGNING_ALG_VALUES_SUPPORTED = list(Algorithm.RS256.toString());
 
     public static final List<String> DEFAULT_GRANT_TYPES_SUPPORTED = list(OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.IMPLICIT, OAuth2Constants.REFRESH_TOKEN, OAuth2Constants.PASSWORD, OAuth2Constants.CLIENT_CREDENTIALS);
 
@@ -49,6 +56,16 @@ public class OIDCWellKnownProvider implements WellKnownProvider {
 
     public static final List<String> DEFAULT_RESPONSE_MODES_SUPPORTED = list("query", "fragment", "form_post");
 
+    public static final List<String> DEFAULT_CLIENT_AUTH_SIGNING_ALG_VALUES_SUPPORTED = list(Algorithm.RS256.toString());
+
+    // The exact list depends on protocolMappers
+    public static final List<String> DEFAULT_CLAIMS_SUPPORTED= list("sub", "iss", IDToken.AUTH_TIME, IDToken.NAME, IDToken.GIVEN_NAME, IDToken.FAMILY_NAME, IDToken.PREFERRED_USERNAME, IDToken.EMAIL);
+
+    public static final List<String> DEFAULT_CLAIM_TYPES_SUPPORTED= list("normal");
+
+    // TODO: Add more of OIDC scopes
+    public static final List<String> SCOPES_SUPPORTED= list(OAuth2Constants.SCOPE_OPENID, OAuth2Constants.OFFLINE_ACCESS);
+
     private KeycloakSession session;
 
     public OIDCWellKnownProvider(KeycloakSession session) {
@@ -78,6 +95,18 @@ public class OIDCWellKnownProvider implements WellKnownProvider {
         config.setResponseModesSupported(DEFAULT_RESPONSE_MODES_SUPPORTED);
         config.setGrantTypesSupported(DEFAULT_GRANT_TYPES_SUPPORTED);
 
+        config.setTokenEndpointAuthMethodsSupported(getClientAuthMethodsSupported());
+        config.setTokenEndpointAuthSigningAlgValuesSupported(DEFAULT_CLIENT_AUTH_SIGNING_ALG_VALUES_SUPPORTED);
+
+        config.setClaimsSupported(DEFAULT_CLAIMS_SUPPORTED);
+        config.setClaimTypesSupported(DEFAULT_CLAIM_TYPES_SUPPORTED);
+        config.setClaimsParameterSupported(false);
+
+        config.setScopesSupported(SCOPES_SUPPORTED);
+
+        config.setRequestParameterSupported(false);
+        config.setRequestUriParameterSupported(false);
+
         return config;
     }
 
@@ -93,4 +122,16 @@ public class OIDCWellKnownProvider implements WellKnownProvider {
         return s;
     }
 
+    private List<String> getClientAuthMethodsSupported() {
+        List<String> result = new ArrayList<>();
+
+        List<ProviderFactory> providerFactories = session.getKeycloakSessionFactory().getProviderFactories(ClientAuthenticator.class);
+        for (ProviderFactory factory : providerFactories) {
+            ClientAuthenticatorFactory clientAuthFactory = (ClientAuthenticatorFactory) factory;
+            result.addAll(clientAuthFactory.getProtocolAuthenticatorMethods(OIDCLoginProtocol.LOGIN_PROTOCOL));
+        }
+
+        return result;
+    }
+
 }
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProviderFactory.java b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProviderFactory.java
index 3135047..91ef686 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProviderFactory.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OIDCWellKnownProviderFactory.java
@@ -28,6 +28,8 @@ import org.keycloak.wellknown.WellKnownProviderFactory;
  */
 public class OIDCWellKnownProviderFactory implements WellKnownProviderFactory {
 
+    public static final String PROVIDER_ID = "openid-configuration";
+
     @Override
     public WellKnownProvider create(KeycloakSession session) {
         return new OIDCWellKnownProvider(session);
@@ -47,7 +49,7 @@ public class OIDCWellKnownProviderFactory implements WellKnownProviderFactory {
 
     @Override
     public String getId() {
-        return "openid-configuration";
+        return PROVIDER_ID;
     }
 
 }
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/RefreshTokenIntrospectionProvider.java b/services/src/main/java/org/keycloak/protocol/oidc/RefreshTokenIntrospectionProvider.java
new file mode 100644
index 0000000..23c675b
--- /dev/null
+++ b/services/src/main/java/org/keycloak/protocol/oidc/RefreshTokenIntrospectionProvider.java
@@ -0,0 +1,30 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.protocol.oidc;
+
+import org.keycloak.models.KeycloakSession;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class RefreshTokenIntrospectionProvider extends AccessTokenIntrospectionProvider {
+
+    public RefreshTokenIntrospectionProvider(KeycloakSession session) {
+        super(session);
+    }
+}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/RefreshTokenIntrospectionProviderFactory.java b/services/src/main/java/org/keycloak/protocol/oidc/RefreshTokenIntrospectionProviderFactory.java
new file mode 100644
index 0000000..9f5ef76
--- /dev/null
+++ b/services/src/main/java/org/keycloak/protocol/oidc/RefreshTokenIntrospectionProviderFactory.java
@@ -0,0 +1,38 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.keycloak.protocol.oidc;
+
+import org.keycloak.models.KeycloakSession;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class RefreshTokenIntrospectionProviderFactory extends AccessTokenIntrospectionProviderFactory {
+
+    private static final String REFRESH_TOKEN_TYPE = "refresh_token";
+
+    @Override
+    public TokenIntrospectionProvider create(KeycloakSession session) {
+        return new RefreshTokenIntrospectionProvider(session);
+    }
+
+    @Override
+    public String getId() {
+        return REFRESH_TOKEN_TYPE;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/representations/OIDCConfigurationRepresentation.java b/services/src/main/java/org/keycloak/protocol/oidc/representations/OIDCConfigurationRepresentation.java
index 138a58e..0421e16 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/representations/OIDCConfigurationRepresentation.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/representations/OIDCConfigurationRepresentation.java
@@ -70,6 +70,30 @@ public class OIDCConfigurationRepresentation {
     @JsonProperty("registration_endpoint")
     private String registrationEndpoint;
 
+    @JsonProperty("token_endpoint_auth_methods_supported")
+    private List<String> tokenEndpointAuthMethodsSupported;
+
+    @JsonProperty("token_endpoint_auth_signing_alg_values_supported")
+    private List<String> tokenEndpointAuthSigningAlgValuesSupported;
+
+    @JsonProperty("claims_supported")
+    private List<String> claimsSupported;
+
+    @JsonProperty("claim_types_supported")
+    private List<String> claimTypesSupported;
+
+    @JsonProperty("claims_parameter_supported")
+    private Boolean claimsParameterSupported;
+
+    @JsonProperty("scopes_supported")
+    private List<String> scopesSupported;
+
+    @JsonProperty("request_parameter_supported")
+    private Boolean requestParameterSupported;
+
+    @JsonProperty("request_uri_parameter_supported")
+    private Boolean requestUriParameterSupported;
+
     protected Map<String, Object> otherClaims = new HashMap<String, Object>();
 
     public String getIssuer() {
@@ -176,6 +200,70 @@ public class OIDCConfigurationRepresentation {
         this.registrationEndpoint = registrationEndpoint;
     }
 
+    public List<String> getTokenEndpointAuthMethodsSupported() {
+        return tokenEndpointAuthMethodsSupported;
+    }
+
+    public void setTokenEndpointAuthMethodsSupported(List<String> tokenEndpointAuthMethodsSupported) {
+        this.tokenEndpointAuthMethodsSupported = tokenEndpointAuthMethodsSupported;
+    }
+
+    public List<String> getTokenEndpointAuthSigningAlgValuesSupported() {
+        return tokenEndpointAuthSigningAlgValuesSupported;
+    }
+
+    public void setTokenEndpointAuthSigningAlgValuesSupported(List<String> tokenEndpointAuthSigningAlgValuesSupported) {
+        this.tokenEndpointAuthSigningAlgValuesSupported = tokenEndpointAuthSigningAlgValuesSupported;
+    }
+
+    public List<String> getClaimsSupported() {
+        return claimsSupported;
+    }
+
+    public void setClaimsSupported(List<String> claimsSupported) {
+        this.claimsSupported = claimsSupported;
+    }
+
+    public List<String> getClaimTypesSupported() {
+        return claimTypesSupported;
+    }
+
+    public void setClaimTypesSupported(List<String> claimTypesSupported) {
+        this.claimTypesSupported = claimTypesSupported;
+    }
+
+    public Boolean getClaimsParameterSupported() {
+        return claimsParameterSupported;
+    }
+
+    public void setClaimsParameterSupported(Boolean claimsParameterSupported) {
+        this.claimsParameterSupported = claimsParameterSupported;
+    }
+
+    public List<String> getScopesSupported() {
+        return scopesSupported;
+    }
+
+    public void setScopesSupported(List<String> scopesSupported) {
+        this.scopesSupported = scopesSupported;
+    }
+
+    public Boolean getRequestParameterSupported() {
+        return requestParameterSupported;
+    }
+
+    public void setRequestParameterSupported(Boolean requestParameterSupported) {
+        this.requestParameterSupported = requestParameterSupported;
+    }
+
+    public Boolean getRequestUriParameterSupported() {
+        return requestUriParameterSupported;
+    }
+
+    public void setRequestUriParameterSupported(Boolean requestUriParameterSupported) {
+        this.requestUriParameterSupported = requestUriParameterSupported;
+    }
+
     @JsonAnyGetter
     public Map<String, Object> getOtherClaims() {
         return otherClaims;
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
index bbd41c0..ac1d8e1 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/TokenManager.java
@@ -24,9 +24,11 @@ import org.keycloak.OAuthErrorException;
 import org.keycloak.events.Details;
 import org.keycloak.events.Errors;
 import org.keycloak.events.EventBuilder;
+import org.keycloak.jose.jws.Algorithm;
 import org.keycloak.jose.jws.JWSBuilder;
 import org.keycloak.jose.jws.JWSInput;
 import org.keycloak.jose.jws.JWSInputException;
+import org.keycloak.jose.jws.crypto.HashProvider;
 import org.keycloak.jose.jws.crypto.RSAProvider;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.ClientSessionModel;
@@ -44,6 +46,7 @@ import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.protocol.ProtocolMapper;
 import org.keycloak.protocol.oidc.mappers.OIDCAccessTokenMapper;
 import org.keycloak.protocol.oidc.mappers.OIDCIDTokenMapper;
+import org.keycloak.protocol.oidc.mappers.UserInfoTokenMapper;
 import org.keycloak.protocol.oidc.utils.OIDCResponseType;
 import org.keycloak.protocol.oidc.utils.WebOriginsUtils;
 import org.keycloak.representations.AccessToken;
@@ -78,6 +81,10 @@ import java.util.Set;
  */
 public class TokenManager {
     protected static final ServicesLogger logger = ServicesLogger.ROOT_LOGGER;
+    private static final String JWT = "JWT";
+
+    // Harcoded for now
+    Algorithm jwsAlgorithm = Algorithm.RS256;
 
     public static void applyScope(RoleModel role, RoleModel scope, Set<RoleModel> visited, Set<RoleModel> requested) {
         if (visited.contains(scope)) return;
@@ -198,6 +205,11 @@ public class TokenManager {
             return false;
         }
 
+        ClientSessionModel clientSession = session.sessions().getClientSession(realm, token.getClientSession());
+        if (clientSession == null) {
+            return false;
+        }
+
         return true;
     }
 
@@ -238,16 +250,23 @@ public class TokenManager {
     }
 
     public RefreshToken verifyRefreshToken(RealmModel realm, String encodedRefreshToken) throws OAuthErrorException {
+        return verifyRefreshToken(realm, encodedRefreshToken, true);
+    }
+
+    public RefreshToken verifyRefreshToken(RealmModel realm, String encodedRefreshToken, boolean checkExpiration) throws OAuthErrorException {
         try {
             RefreshToken refreshToken = toRefreshToken(realm, encodedRefreshToken);
 
-            if (refreshToken.getExpiration() != 0 && refreshToken.isExpired()) {
-                throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Refresh token expired");
-            }
+            if (checkExpiration) {
+                if (refreshToken.getExpiration() != 0 && refreshToken.isExpired()) {
+                    throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Refresh token expired");
+                }
 
-            if (refreshToken.getIssuedAt() < realm.getNotBefore()) {
-                throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale refresh token");
+                if (refreshToken.getIssuedAt() < realm.getNotBefore()) {
+                    throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale refresh token");
+                }
             }
+
             return refreshToken;
         } catch (JWSInputException e) {
             throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token", e);
@@ -492,6 +511,27 @@ public class TokenManager {
         }
         return token;
     }
+
+    public AccessToken transformUserInfoAccessToken(KeycloakSession session, AccessToken token, RealmModel realm, ClientModel client, UserModel user,
+                                            UserSessionModel userSession, ClientSessionModel clientSession) {
+        Set<ProtocolMapperModel> mappings = new ClientSessionCode(realm, clientSession).getRequestedProtocolMappers();
+        KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
+        for (ProtocolMapperModel mapping : mappings) {
+
+            ProtocolMapper mapper = (ProtocolMapper)sessionFactory.getProviderFactory(ProtocolMapper.class, mapping.getProtocolMapper());
+            if (mapper == null || !(mapper instanceof OIDCAccessTokenMapper)) continue;
+
+            if(mapper instanceof UserInfoTokenMapper){
+                token = ((UserInfoTokenMapper)mapper).transformUserInfoToken(token, mapping, session, userSession, clientSession);
+                continue;
+            }
+
+            token = ((OIDCAccessTokenMapper)mapper).transformAccessToken(token, mapping, session, userSession, clientSession);
+
+        }
+        return token;
+    }
+
     public void transformIDToken(KeycloakSession session, IDToken token, RealmModel realm, ClientModel client, UserModel user,
                                       UserSessionModel userSession, ClientSessionModel clientSession) {
         Set<ProtocolMapperModel> mappings = new ClientSessionCode(realm, clientSession).getRequestedProtocolMappers();
@@ -517,6 +557,17 @@ public class TokenManager {
         token.issuedFor(client.getClientId());
         token.issuer(clientSession.getNote(OIDCLoginProtocol.ISSUER));
         token.setNonce(clientSession.getNote(OIDCLoginProtocol.NONCE_PARAM));
+
+        // Best effort for "acr" value. Use 0 if clientSession was authenticated through cookie ( SSO )
+        // TODO: Add better acr support. See KEYCLOAK-3314
+        String acr = (AuthenticationManager.isSSOAuthentication(clientSession)) ? "0" : "1";
+        token.setAcr(acr);
+
+        String authTime = session.getNote(AuthenticationManager.AUTH_TIME);
+        if (authTime != null) {
+            token.setAuthTime(Integer.parseInt(authTime));
+        }
+
         if (session != null) {
             token.setSessionState(session.getId());
         }
@@ -570,8 +621,10 @@ public class TokenManager {
 
     public String encodeToken(RealmModel realm, Object token) {
         String encodedToken = new JWSBuilder()
+                .type(JWT)
+                .kid(realm.getKeyId())
                 .jsonContent(token)
-                .rsa256(realm.getPrivateKey());
+                .sign(jwsAlgorithm, realm.getPrivateKey());
         return encodedToken;
     }
 
@@ -591,6 +644,9 @@ public class TokenManager {
         RefreshToken refreshToken;
         IDToken idToken;
 
+        boolean generateAccessTokenHash = false;
+        String codeHash;
+
         public AccessTokenResponseBuilder(RealmModel realm, ClientModel client, EventBuilder event, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) {
             this.realm = realm;
             this.client = client;
@@ -656,12 +712,23 @@ public class TokenManager {
             idToken.issuedFor(accessToken.getIssuedFor());
             idToken.issuer(accessToken.getIssuer());
             idToken.setNonce(accessToken.getNonce());
+            idToken.setAuthTime(accessToken.getAuthTime());
             idToken.setSessionState(accessToken.getSessionState());
             idToken.expiration(accessToken.getExpiration());
+            idToken.setAcr(accessToken.getAcr());
             transformIDToken(session, idToken, realm, client, userSession.getUser(), userSession, clientSession);
             return this;
         }
 
+        public AccessTokenResponseBuilder generateAccessTokenHash() {
+            generateAccessTokenHash = true;
+            return this;
+        }
+
+        public AccessTokenResponseBuilder generateCodeHash(String code) {
+            codeHash = HashProvider.oidcHash(jwsAlgorithm, code);
+            return this;
+        }
 
 
         public AccessTokenResponse build() {
@@ -679,12 +746,8 @@ public class TokenManager {
             }
 
             AccessTokenResponse res = new AccessTokenResponse();
-            if (idToken != null) {
-                String encodedToken = new JWSBuilder().jsonContent(idToken).rsa256(realm.getPrivateKey());
-                res.setIdToken(encodedToken);
-            }
             if (accessToken != null) {
-                String encodedToken = new JWSBuilder().jsonContent(accessToken).rsa256(realm.getPrivateKey());
+                String encodedToken = new JWSBuilder().type(JWT).kid(realm.getKeyId()).jsonContent(accessToken).sign(jwsAlgorithm, realm.getPrivateKey());
                 res.setToken(encodedToken);
                 res.setTokenType("bearer");
                 res.setSessionState(accessToken.getSessionState());
@@ -692,8 +755,21 @@ public class TokenManager {
                     res.setExpiresIn(accessToken.getExpiration() - Time.currentTime());
                 }
             }
+
+            if (generateAccessTokenHash) {
+                String atHash = HashProvider.oidcHash(jwsAlgorithm, res.getToken());
+                idToken.setAccessTokenHash(atHash);
+            }
+            if (codeHash != null) {
+                idToken.setCodeHash(codeHash);
+            }
+
+            if (idToken != null) {
+                String encodedToken = new JWSBuilder().type(JWT).kid(realm.getKeyId()).jsonContent(idToken).sign(jwsAlgorithm, realm.getPrivateKey());
+                res.setIdToken(encodedToken);
+            }
             if (refreshToken != null) {
-                String encodedToken = new JWSBuilder().jsonContent(refreshToken).rsa256(realm.getPrivateKey());
+                String encodedToken = new JWSBuilder().type(JWT).kid(realm.getKeyId()).jsonContent(refreshToken).sign(jwsAlgorithm, realm.getPrivateKey());
                 res.setRefreshToken(encodedToken);
                 if (refreshToken.getExpiration() != 0) {
                     res.setRefreshExpiresIn(refreshToken.getExpiration() - Time.currentTime());
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java b/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java
index 6e5a309..a7ba7c3 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/AuthorizeClientUtil.java
@@ -17,15 +17,20 @@
 
 package org.keycloak.protocol.oidc.utils;
 
+import java.util.List;
 import java.util.Map;
 
 import org.jboss.resteasy.spi.HttpRequest;
 import org.keycloak.authentication.AuthenticationProcessor;
+import org.keycloak.authentication.ClientAuthenticator;
+import org.keycloak.authentication.ClientAuthenticatorFactory;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.models.AuthenticationFlowModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.provider.ProviderFactory;
 import org.keycloak.services.ErrorResponseException;
 
 import javax.ws.rs.WebApplicationException;
@@ -70,6 +75,18 @@ public class AuthorizeClientUtil {
         return processor;
     }
 
+    public static ClientAuthenticatorFactory findClientAuthenticatorForOIDCAuthMethod(KeycloakSession session, String oidcAuthMethod) {
+        List<ProviderFactory> providerFactories = session.getKeycloakSessionFactory().getProviderFactories(ClientAuthenticator.class);
+        for (ProviderFactory factory : providerFactories) {
+            ClientAuthenticatorFactory clientAuthFactory = (ClientAuthenticatorFactory) factory;
+            if (clientAuthFactory.getProtocolAuthenticatorMethods(OIDCLoginProtocol.LOGIN_PROTOCOL).contains(oidcAuthMethod)) {
+                return clientAuthFactory;
+            }
+        }
+
+        return null;
+    }
+
     public static class ClientAuthResult {
 
         private final ClientModel client;
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/utils/JWKSUtils.java b/services/src/main/java/org/keycloak/protocol/oidc/utils/JWKSUtils.java
new file mode 100644
index 0000000..c856a81
--- /dev/null
+++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/JWKSUtils.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.protocol.oidc.utils;
+
+import java.io.IOException;
+import java.security.PublicKey;
+
+import org.keycloak.broker.provider.util.SimpleHttp;
+import org.keycloak.jose.jwk.JSONWebKeySet;
+import org.keycloak.jose.jwk.JWK;
+import org.keycloak.jose.jwk.JWKParser;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class JWKSUtils {
+
+    public static JSONWebKeySet sendJwksRequest(String jwksURI) throws IOException {
+        String keySetString = SimpleHttp.doGet(jwksURI).asString();
+        return JsonSerialization.readValue(keySetString, JSONWebKeySet.class);
+    }
+
+
+    public static PublicKey getKeyForUse(JSONWebKeySet keySet, JWK.Use requestedUse) {
+        for (JWK jwk : keySet.getKeys()) {
+            JWKParser parser = JWKParser.create(jwk);
+            if (parser.getJwk().getPublicKeyUse().equals(requestedUse.asString()) && parser.isAlgorithmSupported(jwk.getKeyType())) {
+                return parser.toPublicKey();
+            }
+        }
+
+        return null;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCRedirectUriBuilder.java b/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCRedirectUriBuilder.java
index d09bc47..cffad4f 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCRedirectUriBuilder.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCRedirectUriBuilder.java
@@ -39,6 +39,7 @@ public abstract class OIDCRedirectUriBuilder {
     }
 
     public abstract OIDCRedirectUriBuilder addParam(String paramName, String paramValue);
+
     public abstract Response build();
 
 
@@ -125,7 +126,7 @@ public abstract class OIDCRedirectUriBuilder {
 
         @Override
         public OIDCRedirectUriBuilder addParam(String paramName, String paramValue) {
-            params.put(paramName, Encode.encodeQueryParam(paramValue));
+            params.put(paramName, paramValue);
             return this;
         }
 
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCResponseType.java b/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCResponseType.java
index bab5396..c836a68 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCResponseType.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/OIDCResponseType.java
@@ -78,7 +78,7 @@ public class OIDCResponseType {
             throw new IllegalStateException("No responseType provided");
         }
         if (responseTypes.contains(NONE) && responseTypes.size() > 1) {
-            throw new IllegalArgumentException("None not allowed with some other response_type");
+            throw new IllegalArgumentException("'None' not allowed with some other response_type");
         }
 
         // response_type value "token" alone is not mentioned in OIDC specification, however it is supported by OAuth2. We allow it just to be compatible with pure OAuth2 clients like swagger.ui
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/utils/RedirectUtils.java b/services/src/main/java/org/keycloak/protocol/oidc/utils/RedirectUtils.java
index e564090..441cd57 100644
--- a/services/src/main/java/org/keycloak/protocol/oidc/utils/RedirectUtils.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/utils/RedirectUtils.java
@@ -69,13 +69,8 @@ public class RedirectUtils {
 
     private static String verifyRedirectUri(UriInfo uriInfo, String rootUrl, String redirectUri, RealmModel realm, Set<String> validRedirects) {
         if (redirectUri == null) {
-            if (validRedirects.size() != 1) return null;
-            String validRedirect = validRedirects.iterator().next();
-            int idx = validRedirect.indexOf("/*");
-            if (idx > -1) {
-                validRedirect = validRedirect.substring(0, idx);
-            }
-            redirectUri = validRedirect;
+            logger.debug("No Redirect URI parameter specified");
+            return null;
         } else if (validRedirects.isEmpty()) {
             logger.debug("No Redirect URIs supplied");
             redirectUri = null;
diff --git a/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java b/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java
index 32d2272..da73139 100755
--- a/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java
+++ b/services/src/main/java/org/keycloak/protocol/ProtocolMapperUtils.java
@@ -22,6 +22,7 @@ import org.keycloak.models.ProtocolMapperModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
+import org.keycloak.provider.ProviderConfigProperty;
 import org.keycloak.provider.ProviderFactory;
 
 import java.lang.reflect.Method;
@@ -31,6 +32,8 @@ import java.lang.reflect.Method;
  * @version $Revision: 1 $
  */
 public class ProtocolMapperUtils {
+
+    public static final String USER_ROLE = "user.role";
     public static final String USER_ATTRIBUTE = "user.attribute";
     public static final String USER_SESSION_NOTE = "user.session.note";
     public static final String MULTIVALUED = "multivalued";
@@ -38,6 +41,19 @@ public class ProtocolMapperUtils {
     public static final String USER_MODEL_PROPERTY_HELP_TEXT = "usermodel.prop.tooltip";
     public static final String USER_MODEL_ATTRIBUTE_LABEL = "usermodel.attr.label";
     public static final String USER_MODEL_ATTRIBUTE_HELP_TEXT = "usermodel.attr.tooltip";
+
+    public static final String USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID = "usermodel.clientRoleMapping.clientId";
+    public static final String USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID_LABEL = "usermodel.clientRoleMapping.clientId.label";
+    public static final String USER_MODEL_CLIENT_ROLE_MAPPING_CLIENT_ID_HELP_TEXT = "usermodel.clientRoleMapping.clientId.tooltip";
+
+    public static final String USER_MODEL_CLIENT_ROLE_MAPPING_ROLE_PREFIX = "usermodel.clientRoleMapping.rolePrefix";
+    public static final String USER_MODEL_CLIENT_ROLE_MAPPING_ROLE_PREFIX_LABEL = "usermodel.clientRoleMapping.rolePrefix.label";
+    public static final String USER_MODEL_CLIENT_ROLE_MAPPING_ROLE_PREFIX_HELP_TEXT = "usermodel.clientRoleMapping.rolePrefix.tooltip";
+
+    public static final String USER_MODEL_REALM_ROLE_MAPPING_ROLE_PREFIX = "usermodel.realmRoleMapping.rolePrefix";
+    public static final String USER_MODEL_REALM_ROLE_MAPPING_ROLE_PREFIX_LABEL = "usermodel.realmRoleMapping.rolePrefix.label";
+    public static final String USER_MODEL_REALM_ROLE_MAPPING_ROLE_PREFIX_HELP_TEXT = "usermodel.realmRoleMapping.rolePrefix.tooltip";
+
     public static final String USER_SESSION_MODEL_NOTE_LABEL = "userSession.modelNote.label";
     public static final String USER_SESSION_MODEL_NOTE_HELP_TEXT = "userSession.modelNote.tooltip";
     public static final String MULTIVALUED_LABEL = "multivalued.label";
diff --git a/services/src/main/java/org/keycloak/protocol/saml/installation/KeycloakSamlClientInstallation.java b/services/src/main/java/org/keycloak/protocol/saml/installation/KeycloakSamlClientInstallation.java
index ca9de35..4a91db9 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/installation/KeycloakSamlClientInstallation.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/installation/KeycloakSamlClientInstallation.java
@@ -96,6 +96,7 @@ public class KeycloakSamlClientInstallation implements ClientInstallationProvide
         buffer.append(">\n");
         buffer.append("            <SingleSignOnService signRequest=\"").append(Boolean.toString(samlClient.requiresClientSignature())).append("\"\n");
         buffer.append("                                 validateResponseSignature=\"").append(Boolean.toString(samlClient.requiresRealmSignature())).append("\"\n");
+        buffer.append("                                 validateAssertionSignature=\"").append(Boolean.toString(samlClient.requiresAssertionSignature())).append("\"\n");
         buffer.append("                                 requestBinding=\"POST\"\n");
         UriBuilder bindingUrlBuilder = UriBuilder.fromUri(baseUri);
         String bindingUrl = RealmsResource.protocolUrl(bindingUrlBuilder)
diff --git a/services/src/main/java/org/keycloak/protocol/saml/profile/ecp/authenticator/HttpBasicAuthenticator.java b/services/src/main/java/org/keycloak/protocol/saml/profile/ecp/authenticator/HttpBasicAuthenticator.java
index 68d62b3..7daf470 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/profile/ecp/authenticator/HttpBasicAuthenticator.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/profile/ecp/authenticator/HttpBasicAuthenticator.java
@@ -43,7 +43,7 @@ public class HttpBasicAuthenticator implements AuthenticatorFactory {
 
     @Override
     public String getDisplayType() {
-        return null;
+        return "HTTP Basic Authentication";
     }
 
     @Override
@@ -68,7 +68,7 @@ public class HttpBasicAuthenticator implements AuthenticatorFactory {
 
     @Override
     public String getHelpText() {
-        return null;
+        return "Validates username and password from Authorization HTTP header";
     }
 
     @Override
diff --git a/services/src/main/java/org/keycloak/protocol/saml/SamlConfigAttributes.java b/services/src/main/java/org/keycloak/protocol/saml/SamlConfigAttributes.java
index cacd211..3356c31 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/SamlConfigAttributes.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/SamlConfigAttributes.java
@@ -17,7 +17,7 @@
 
 package org.keycloak.protocol.saml;
 
-import org.keycloak.services.resources.admin.ClientAttributeCertificateResource;
+import org.keycloak.services.util.CertificateInfoHelper;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -35,7 +35,7 @@ public interface SamlConfigAttributes {
     String SAML_ASSERTION_SIGNATURE = "saml.assertion.signature";
     String SAML_ENCRYPT = "saml.encrypt";
     String SAML_CLIENT_SIGNATURE_ATTRIBUTE = "saml.client.signature";
-    String SAML_SIGNING_CERTIFICATE_ATTRIBUTE = "saml.signing." + ClientAttributeCertificateResource.X509CERTIFICATE;
-    String SAML_ENCRYPTION_CERTIFICATE_ATTRIBUTE = "saml.encryption." + ClientAttributeCertificateResource.X509CERTIFICATE;
-    String SAML_ENCRYPTION_PRIVATE_KEY_ATTRIBUTE = "saml.encryption." + ClientAttributeCertificateResource.PRIVATE_KEY;
+    String SAML_SIGNING_CERTIFICATE_ATTRIBUTE = "saml.signing." + CertificateInfoHelper.X509CERTIFICATE;
+    String SAML_ENCRYPTION_CERTIFICATE_ATTRIBUTE = "saml.encryption." + CertificateInfoHelper.X509CERTIFICATE;
+    String SAML_ENCRYPTION_PRIVATE_KEY_ATTRIBUTE = "saml.encryption." + CertificateInfoHelper.PRIVATE_KEY;
 }
diff --git a/services/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java b/services/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
index 042779f..42fd549 100755
--- a/services/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
+++ b/services/src/main/java/org/keycloak/protocol/saml/SamlProtocol.java
@@ -375,8 +375,15 @@ public class SamlProtocol implements LoginProtocol {
         Document samlDocument = null;
         try {
             ResponseType samlModel = builder.buildModel();
-            transformAttributeStatement(attributeStatementMappers, samlModel, session, userSession, clientSession);
-            populateRoles(roleListMapper, samlModel, session, userSession, clientSession);
+            final AttributeStatementType attributeStatement = populateAttributeStatements(attributeStatementMappers, session, userSession, clientSession);
+            populateRoles(roleListMapper, session, userSession, clientSession, attributeStatement);
+
+            // SAML Spec 2.7.3 AttributeStatement must contain one or more Attribute or EncryptedAttribute
+            if (attributeStatement.getAttributes().size() > 0) {
+                AssertionType assertion = samlModel.getAssertions().get(0).getAssertion();
+                assertion.addStatement(attributeStatement);
+            }
+
             samlModel = transformLoginResponse(loginResponseMappers, samlModel, session, userSession, clientSession);
             samlDocument = builder.buildDocument(samlModel);
         } catch (Exception e) {
@@ -437,19 +444,14 @@ public class SamlProtocol implements LoginProtocol {
         }
     }
 
-    public void transformAttributeStatement(List<ProtocolMapperProcessor<SAMLAttributeStatementMapper>> attributeStatementMappers, ResponseType response, KeycloakSession session, UserSessionModel userSession,
-            ClientSessionModel clientSession) {
-        AssertionType assertion = response.getAssertions().get(0).getAssertion();
+    public AttributeStatementType populateAttributeStatements(List<ProtocolMapperProcessor<SAMLAttributeStatementMapper>> attributeStatementMappers, KeycloakSession session, UserSessionModel userSession,
+                                                              ClientSessionModel clientSession) {
         AttributeStatementType attributeStatement = new AttributeStatementType();
-
         for (ProtocolMapperProcessor<SAMLAttributeStatementMapper> processor : attributeStatementMappers) {
             processor.mapper.transformAttributeStatement(attributeStatement, processor.model, session, userSession, clientSession);
         }
 
-        // SAML Spec 2.7.3 AttributeStatement must contain one or more Attribute or EncryptedAttribute
-        if (attributeStatement.getAttributes().size() > 0) {
-            assertion.addStatement(attributeStatement);
-        }
+        return attributeStatement;
     }
 
     public ResponseType transformLoginResponse(List<ProtocolMapperProcessor<SAMLLoginResponseMapper>> mappers, ResponseType response, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) {
@@ -459,17 +461,11 @@ public class SamlProtocol implements LoginProtocol {
         return response;
     }
 
-    public void populateRoles(ProtocolMapperProcessor<SAMLRoleListMapper> roleListMapper, ResponseType response, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) {
+    public void populateRoles(ProtocolMapperProcessor<SAMLRoleListMapper> roleListMapper, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession,
+                              final AttributeStatementType existingAttributeStatement) {
         if (roleListMapper == null)
             return;
-        AssertionType assertion = response.getAssertions().get(0).getAssertion();
-        AttributeStatementType attributeStatement = new AttributeStatementType();
-        roleListMapper.mapper.mapRoles(attributeStatement, roleListMapper.model, session, userSession, clientSession);
-
-        // SAML Spec 2.7.3 AttributeStatement must contain one or more Attribute or EncryptedAttribute
-        if (attributeStatement.getAttributes().size() > 0) {
-            assertion.addStatement(attributeStatement);
-        }
+        roleListMapper.mapper.mapRoles(existingAttributeStatement, roleListMapper.model, session, userSession, clientSession);
     }
 
     public static String getLogoutServiceUrl(UriInfo uriInfo, ClientModel client, String bindingType) {
@@ -629,6 +625,12 @@ public class SamlProtocol implements LoginProtocol {
         return logoutBuilder;
     }
 
+    @Override
+    public boolean requireReauthentication(UserSessionModel userSession, ClientSessionModel clientSession) {
+        // Not yet supported
+        return false;
+    }
+
     private JaxrsSAML2BindingBuilder createBindingBuilder(SamlClient samlClient) {
         JaxrsSAML2BindingBuilder binding = new JaxrsSAML2BindingBuilder();
         if (samlClient.requiresRealmSignature()) {
diff --git a/services/src/main/java/org/keycloak/provider/DefaultProviderLoader.java b/services/src/main/java/org/keycloak/provider/DefaultProviderLoader.java
index 26aa19d..5f4b19d 100644
--- a/services/src/main/java/org/keycloak/provider/DefaultProviderLoader.java
+++ b/services/src/main/java/org/keycloak/provider/DefaultProviderLoader.java
@@ -33,6 +33,15 @@ public class DefaultProviderLoader implements ProviderLoader {
     }
 
     @Override
+    public List<Spi> loadSpis() {
+        LinkedList<Spi> list = new LinkedList<>();
+        for (Spi spi : ServiceLoader.load(Spi.class, classLoader)) {
+            list.add(spi);
+        }
+        return list;
+    }
+
+    @Override
     public List<ProviderFactory> load(Spi spi) {
         LinkedList<ProviderFactory> list = new LinkedList<ProviderFactory>();
         for (ProviderFactory f : ServiceLoader.load(spi.getProviderFactoryClass(), classLoader)) {
diff --git a/services/src/main/java/org/keycloak/provider/ProviderManager.java b/services/src/main/java/org/keycloak/provider/ProviderManager.java
index 997c68a..e5d9712 100644
--- a/services/src/main/java/org/keycloak/provider/ProviderManager.java
+++ b/services/src/main/java/org/keycloak/provider/ProviderManager.java
@@ -16,8 +16,10 @@
  */
 package org.keycloak.provider;
 
+import org.keycloak.common.util.MultivaluedHashMap;
 import org.keycloak.services.ServicesLogger;
 
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.IdentityHashMap;
 import java.util.LinkedList;
@@ -33,7 +35,8 @@ public class ProviderManager {
     private static final ServicesLogger logger = ServicesLogger.ROOT_LOGGER;
 
     private List<ProviderLoader> loaders = new LinkedList<ProviderLoader>();
-    private Map<String, List<ProviderFactory>> cache = new HashMap<String, List<ProviderFactory>>();
+    private MultivaluedHashMap<Class<? extends Provider>, ProviderFactory> cache = new MultivaluedHashMap<>();
+
 
     public ProviderManager(ClassLoader baseClassLoader, String... resources) {
         List<ProviderLoaderFactory> factories = new LinkedList<ProviderLoaderFactory>();
@@ -65,10 +68,26 @@ public class ProviderManager {
         }
     }
 
+    public ProviderManager(ClassLoader baseClassLoader) {
+        loaders.add(new DefaultProviderLoader(baseClassLoader));
+    }
+
+    public synchronized List<Spi> loadSpis() {
+        // Use a map to prevent duplicates, since the loaders may have overlapping classpaths.
+        Map<String, Spi> spiMap = new HashMap<>();
+        for (ProviderLoader loader : loaders) {
+            List<Spi> spis = loader.loadSpis();
+            if (spis != null) {
+                for (Spi spi : spis) {
+                    spiMap.put(spi.getName(), spi);
+                }
+            }
+        }
+        return new LinkedList<>(spiMap.values());
+    }
+
     public synchronized List<ProviderFactory> load(Spi spi) {
-        List<ProviderFactory> factories = cache.get(spi.getName());
-        if (factories == null) {
-            factories = new LinkedList<ProviderFactory>();
+        if (!cache.containsKey(spi.getProviderClass())) {
             IdentityHashMap factoryClasses = new IdentityHashMap();
             for (ProviderLoader loader : loaders) {
                 List<ProviderFactory> f = loader.load(spi);
@@ -76,14 +95,26 @@ public class ProviderManager {
                     for (ProviderFactory pf: f) {
                         // make sure there are no duplicates
                         if (!factoryClasses.containsKey(pf.getClass())) {
-                            factories.add(pf);
+                            cache.add(spi.getProviderClass(), pf);
                             factoryClasses.put(pf.getClass(), pf);
                         }
                     }
                 }
             }
         }
-        return factories;
+        List<ProviderFactory> rtn = cache.get(spi.getProviderClass());
+        return rtn == null ? Collections.EMPTY_LIST : rtn;
+    }
+
+    /**
+     * returns a copy of internal factories.
+     *
+     * @return
+     */
+    public synchronized MultivaluedHashMap<Class<? extends Provider>, ProviderFactory> getLoadedFactories() {
+        MultivaluedHashMap<Class<? extends Provider>, ProviderFactory> copy = new MultivaluedHashMap<>();
+        copy.addAll(cache);
+        return copy;
     }
 
     public synchronized ProviderFactory load(Spi spi, String providerId) {
diff --git a/services/src/main/java/org/keycloak/provider/ProviderManagerDeployer.java b/services/src/main/java/org/keycloak/provider/ProviderManagerDeployer.java
new file mode 100644
index 0000000..e8ed910
--- /dev/null
+++ b/services/src/main/java/org/keycloak/provider/ProviderManagerDeployer.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.provider;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface ProviderManagerDeployer {
+    void deploy(ProviderManager pm);
+    void undeploy(ProviderManager pm);
+}
diff --git a/services/src/main/java/org/keycloak/provider/ProviderManagerRegistry.java b/services/src/main/java/org/keycloak/provider/ProviderManagerRegistry.java
new file mode 100644
index 0000000..69cd92e
--- /dev/null
+++ b/services/src/main/java/org/keycloak/provider/ProviderManagerRegistry.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.provider;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ProviderManagerRegistry {
+    public static final ProviderManagerRegistry SINGLETON = new ProviderManagerRegistry();
+    protected List<ProviderManager> preBoot = Collections.synchronizedList(new LinkedList<>());
+    protected AtomicReference<ProviderManagerDeployer> deployerRef = new AtomicReference<>();
+
+    public void setDeployer(ProviderManagerDeployer deployer) {
+        this.deployerRef.set(deployer);
+    }
+
+    public void deploy(ProviderManager pm) {
+        ProviderManagerDeployer deployer = getDeployer();
+        if (deployer == null) {
+            preBoot.add(pm);
+        } else {
+            deployer.deploy(pm);
+        }
+
+    }
+
+    public void undeploy(ProviderManager pm) {
+        preBoot.remove(pm);
+        ProviderManagerDeployer deployer = getDeployer();
+        if (deployer != null) {
+            deployer.undeploy(pm);
+        }
+    }
+
+    public ProviderManagerDeployer getDeployer() {
+        return deployerRef.get();
+    }
+
+    public List<ProviderManager> getPreBoot() {
+        return preBoot;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/scripting/DefaultScriptingProvider.java b/services/src/main/java/org/keycloak/scripting/DefaultScriptingProvider.java
new file mode 100644
index 0000000..140ec04
--- /dev/null
+++ b/services/src/main/java/org/keycloak/scripting/DefaultScriptingProvider.java
@@ -0,0 +1,81 @@
+package org.keycloak.scripting;
+
+import org.keycloak.models.ScriptModel;
+
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+
+/**
+ * A {@link ScriptingProvider} that uses a {@link ScriptEngineManager} to evaluate scripts with a {@link ScriptEngine}.
+ *
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+public class DefaultScriptingProvider implements ScriptingProvider {
+
+    private final ScriptEngineManager scriptEngineManager;
+
+    public DefaultScriptingProvider(ScriptEngineManager scriptEngineManager) {
+        this.scriptEngineManager = scriptEngineManager;
+    }
+
+    @Override
+    public InvocableScript prepareScript(ScriptModel script) {
+        return prepareScript(script, ScriptBindingsConfigurer.EMPTY);
+    }
+
+    @Override
+    public InvocableScript prepareScript(ScriptModel script, ScriptBindingsConfigurer bindingsConfigurer) {
+
+        if (script == null) {
+            throw new NullPointerException("script must not be null");
+        }
+
+        if (script.getCode() == null || script.getCode().trim().isEmpty()) {
+            throw new IllegalArgumentException("script must not be null or empty");
+        }
+
+        if (bindingsConfigurer == null) {
+            throw new NullPointerException("bindingsConfigurer must not be null");
+        }
+
+        ScriptEngine engine = lookupScriptEngineFor(script);
+
+        if (engine == null) {
+            throw new IllegalStateException("Could not find ScriptEngine for script: " + script);
+        }
+
+        configureBindings(bindingsConfigurer, engine);
+
+        loadScriptIntoEngine(script, engine);
+
+        return new InvocableScript(script, engine);
+    }
+
+    private void configureBindings(ScriptBindingsConfigurer bindingsConfigurer, ScriptEngine engine) {
+
+        Bindings bindings = engine.createBindings();
+        bindingsConfigurer.configureBindings(bindings);
+        engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
+    }
+
+    private void loadScriptIntoEngine(ScriptModel script, ScriptEngine engine) {
+
+        try {
+            engine.eval(script.getCode());
+        } catch (ScriptException se) {
+            throw new ScriptExecutionException(script, se);
+        }
+    }
+
+    private ScriptEngine lookupScriptEngineFor(ScriptModel script) {
+        return scriptEngineManager.getEngineByMimeType(script.getMimeType());
+    }
+
+    @Override
+    public void close() {
+        //NOOP
+    }
+}
diff --git a/services/src/main/java/org/keycloak/scripting/DefaultScriptingProviderFactory.java b/services/src/main/java/org/keycloak/scripting/DefaultScriptingProviderFactory.java
new file mode 100644
index 0000000..2e8a431
--- /dev/null
+++ b/services/src/main/java/org/keycloak/scripting/DefaultScriptingProviderFactory.java
@@ -0,0 +1,42 @@
+package org.keycloak.scripting;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+import javax.script.ScriptEngineManager;
+
+/**
+ * @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
+ */
+public class DefaultScriptingProviderFactory implements ScriptingProviderFactory {
+
+    static final String ID = "script-based-auth";
+
+    private final ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
+
+    @Override
+    public ScriptingProvider create(KeycloakSession session) {
+        return new DefaultScriptingProvider(scriptEngineManager);
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+        //NOOP
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+        //NOOP
+    }
+
+    @Override
+    public void close() {
+        //NOOP
+    }
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/AbstractClientRegistrationProvider.java b/services/src/main/java/org/keycloak/services/clientregistration/AbstractClientRegistrationProvider.java
index ffda262..88b5a34 100755
--- a/services/src/main/java/org/keycloak/services/clientregistration/AbstractClientRegistrationProvider.java
+++ b/services/src/main/java/org/keycloak/services/clientregistration/AbstractClientRegistrationProvider.java
@@ -21,6 +21,7 @@ import org.keycloak.events.EventBuilder;
 import org.keycloak.events.EventType;
 import org.keycloak.models.ClientInitialAccessModel;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientRegistrationTrustedHostModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ModelDuplicateException;
 import org.keycloak.models.utils.ModelToRepresentation;
@@ -54,8 +55,9 @@ public abstract class AbstractClientRegistrationProvider implements ClientRegist
 
             client = ModelToRepresentation.toRepresentation(clientModel);
 
-            String registrationAccessToken = ClientRegistrationTokenUtils.updateRegistrationAccessToken(session, clientModel);
+            client.setSecret(clientModel.getSecret());
 
+            String registrationAccessToken = ClientRegistrationTokenUtils.updateRegistrationAccessToken(session, clientModel);
             client.setRegistrationAccessToken(registrationAccessToken);
 
             if (auth.isInitialAccessToken()) {
@@ -63,6 +65,11 @@ public abstract class AbstractClientRegistrationProvider implements ClientRegist
                 initialAccessModel.decreaseRemainingCount();
             }
 
+            if (auth.isRegistrationHostTrusted()) {
+                ClientRegistrationTrustedHostModel trustedHost = auth.getTrustedHostModel();
+                trustedHost.decreaseRemainingCount();
+            }
+
             event.client(client.getClientId()).success();
             return client;
         } catch (ModelDuplicateException e) {
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationAuth.java b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationAuth.java
index 5564ef2..93c2648 100644
--- a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationAuth.java
+++ b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationAuth.java
@@ -18,22 +18,23 @@
 package org.keycloak.services.clientregistration;
 
 import org.jboss.resteasy.spi.Failure;
-import org.jboss.resteasy.spi.NotFoundException;
-import org.jboss.resteasy.spi.UnauthorizedException;
 import org.keycloak.Config;
+import org.keycloak.OAuthErrorException;
 import org.keycloak.authentication.AuthenticationProcessor;
 import org.keycloak.common.util.Time;
+import org.keycloak.events.Details;
 import org.keycloak.events.Errors;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.models.AdminRoles;
 import org.keycloak.models.ClientInitialAccessModel;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.ClientRegistrationTrustedHostModel;
 import org.keycloak.models.Constants;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.protocol.oidc.utils.AuthorizeClientUtil;
 import org.keycloak.representations.JsonWebToken;
-import org.keycloak.services.ForbiddenException;
+import org.keycloak.services.ErrorResponseException;
 import org.keycloak.util.TokenUtil;
 
 import javax.ws.rs.core.HttpHeaders;
@@ -54,6 +55,8 @@ public class ClientRegistrationAuth {
     private JsonWebToken jwt;
     private ClientInitialAccessModel initialAccessModel;
 
+    private ClientRegistrationTrustedHostModel trustedHostModel;
+
     public ClientRegistrationAuth(KeycloakSession session, EventBuilder event) {
         this.session = session;
         this.event = event;
@@ -65,6 +68,9 @@ public class ClientRegistrationAuth {
 
         String authorizationHeader = session.getContext().getRequestHeaders().getRequestHeaders().getFirst(HttpHeaders.AUTHORIZATION);
         if (authorizationHeader == null) {
+
+            // Try trusted hosts
+            trustedHostModel = ClientRegistrationHostUtils.getTrustedHost(session.getContext().getConnection().getRemoteAddr(), session, realm);
             return;
         }
 
@@ -73,19 +79,24 @@ public class ClientRegistrationAuth {
             return;
         }
 
-        jwt = ClientRegistrationTokenUtils.verifyToken(realm, uri, split[1]);
-        if (jwt == null) {
-            throw unauthorized();
+        ClientRegistrationTokenUtils.TokenVerification tokenVerification = ClientRegistrationTokenUtils.verifyToken(realm, uri, split[1]);
+        if (tokenVerification.getError() != null) {
+            throw unauthorized(tokenVerification.getError().getMessage());
         }
+        jwt = tokenVerification.getJwt();
 
         if (isInitialAccessToken()) {
             initialAccessModel = session.sessions().getClientInitialAccessModel(session.getContext().getRealm(), jwt.getId());
             if (initialAccessModel == null) {
-                throw unauthorized();
+                throw unauthorized("Initial Access Token not found");
             }
         }
     }
 
+    public boolean isRegistrationHostTrusted() {
+        return trustedHostModel != null;
+    }
+
     private boolean isBearerToken() {
         return jwt != null && TokenUtil.TOKEN_TYPE_BEARER.equals(jwt.getType());
     }
@@ -101,7 +112,10 @@ public class ClientRegistrationAuth {
     public void requireCreate() {
         init();
 
-        if (isBearerToken()) {
+        if (isRegistrationHostTrusted()) {
+            // Client registrations from trusted hosts
+            return;
+        } else if (isBearerToken()) {
             if (hasRole(AdminRoles.MANAGE_CLIENTS, AdminRoles.CREATE_CLIENT)) {
                 return;
             } else {
@@ -115,7 +129,7 @@ public class ClientRegistrationAuth {
             }
         }
 
-        throw unauthorized();
+        throw unauthorized("Not authenticated to view client. Host not trusted and Token is missing or invalid.");
     }
 
     public void requireView(ClientModel client) {
@@ -131,18 +145,18 @@ public class ClientRegistrationAuth {
                 throw forbidden();
             }
         } else if (isRegistrationAccessToken()) {
-            if (client.getRegistrationToken() != null && client != null && client.getRegistrationToken().equals(jwt.getId())) {
+            if (client.getRegistrationToken() != null && client.getRegistrationToken().equals(jwt.getId())) {
                 return;
             }
         } else if (isInitialAccessToken()) {
-            throw unauthorized();
+            throw unauthorized("Not initial access token");
         } else {
             if (authenticateClient(client)) {
                 return;
             }
         }
 
-        throw unauthorized();
+        throw unauthorized("Not authorized to view client. Missing or invalid token or bad client credentials.");
     }
 
     public void requireUpdate(ClientModel client) {
@@ -163,13 +177,17 @@ public class ClientRegistrationAuth {
             }
         }
 
-        throw unauthorized();
+        throw unauthorized("Not authorized to update client. Missing or invalid token.");
     }
 
     public ClientInitialAccessModel getInitialAccessModel() {
         return initialAccessModel;
     }
 
+    public ClientRegistrationTrustedHostModel getTrustedHostModel() {
+        return trustedHostModel;
+    }
+
     private boolean hasRole(String... role) {
         try {
             Map<String, Object> otherClaims = jwt.getOtherClaims();
@@ -218,36 +236,36 @@ public class ClientRegistrationAuth {
         Response response = processor.authenticateClient();
         if (response != null) {
             event.client(client.getClientId()).error(Errors.NOT_ALLOWED);
-            throw unauthorized();
+            throw unauthorized("Failed to authenticate client");
         }
 
         ClientModel authClient = processor.getClient();
-        if (client == null) {
+        if (authClient == null) {
             event.client(client.getClientId()).error(Errors.NOT_ALLOWED);
-            throw unauthorized();
+            throw unauthorized("No client authenticated");
         }
 
         if (!authClient.getClientId().equals(client.getClientId())) {
             event.client(client.getClientId()).error(Errors.NOT_ALLOWED);
-            throw unauthorized();
+            throw unauthorized("Different client authenticated");
         }
 
         return true;
     }
 
-    private Failure unauthorized() {
-        event.error(Errors.NOT_ALLOWED);
-        return new UnauthorizedException();
+    private Failure unauthorized(String errorDescription) {
+        event.detail(Details.REASON, errorDescription).error(Errors.INVALID_TOKEN);
+        throw new ErrorResponseException(OAuthErrorException.INVALID_TOKEN, errorDescription, Response.Status.UNAUTHORIZED);
     }
 
     private Failure forbidden() {
         event.error(Errors.NOT_ALLOWED);
-        return new ForbiddenException();
+        throw new ErrorResponseException(OAuthErrorException.INSUFFICIENT_SCOPE, "Forbidden", Response.Status.FORBIDDEN);
     }
 
     private Failure notFound() {
-        event.error(Errors.NOT_ALLOWED);
-        return new NotFoundException("Client not found");
+        event.error(Errors.CLIENT_NOT_FOUND);
+        throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Client not found", Response.Status.NOT_FOUND);
     }
 
 }
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationHostUtils.java b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationHostUtils.java
new file mode 100644
index 0000000..93cd984
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationHostUtils.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.services.clientregistration;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.List;
+
+import org.jboss.logging.Logger;
+import org.keycloak.models.ClientRegistrationTrustedHostModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ClientRegistrationHostUtils {
+
+    private static final Logger logger = Logger.getLogger(ClientRegistrationHostUtils.class);
+
+    /**
+     * @return null if host from request is not trusted. Otherwise return trusted host model
+     */
+    public static ClientRegistrationTrustedHostModel getTrustedHost(String hostAddress, KeycloakSession session, RealmModel realm) {
+        logger.debugf("Verifying remote host : %s", hostAddress);
+
+        List<ClientRegistrationTrustedHostModel> trustedHosts = session.sessions().listClientRegistrationTrustedHosts(realm);
+
+        for (ClientRegistrationTrustedHostModel realmTrustedHost : trustedHosts) {
+            try {
+                if (realmTrustedHost.getRemainingCount() <= 0) {
+                    continue;
+                }
+
+                String realmHostIPAddress = InetAddress.getByName(realmTrustedHost.getHostName()).getHostAddress();
+                logger.debugf("Trying host '%s' of address '%s'", realmTrustedHost.getHostName(), realmHostIPAddress);
+                if (realmHostIPAddress.equals(hostAddress)) {
+                    logger.debugf("Successfully verified host : %s", realmTrustedHost.getHostName());
+                    return realmTrustedHost;
+                }
+            } catch (UnknownHostException uhe) {
+                logger.debugf("Unknown host from realm configuration: %s", realmTrustedHost.getHostName());
+            }
+        }
+
+        logger.debugf("Failed to verify remote host : %s", hostAddress);
+        return null;
+    }
+
+}
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationTokenUtils.java b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationTokenUtils.java
index 2fe65cc..2f33e5d 100755
--- a/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationTokenUtils.java
+++ b/services/src/main/java/org/keycloak/services/clientregistration/ClientRegistrationTokenUtils.java
@@ -56,40 +56,44 @@ public class ClientRegistrationTokenUtils {
         return createToken(realm, uri, model.getId(), TYPE_INITIAL_ACCESS_TOKEN, model.getExpiration() > 0 ? model.getTimestamp() + model.getExpiration() : 0);
     }
 
-    public static JsonWebToken verifyToken(RealmModel realm, UriInfo uri, String token) {
+    public static TokenVerification verifyToken(RealmModel realm, UriInfo uri, String token) {
+        if (token == null) {
+            return TokenVerification.error(new RuntimeException("Missing token"));
+        }
+
         JWSInput input;
         try {
             input = new JWSInput(token);
         } catch (JWSInputException e) {
-            return null;
+            return TokenVerification.error(new RuntimeException("Invalid token", e));
         }
 
         if (!RSAProvider.verify(input, realm.getPublicKey())) {
-            return null;
+            return TokenVerification.error(new RuntimeException("Failed verify token"));
         }
 
         JsonWebToken jwt;
         try {
             jwt = input.readJsonContent(JsonWebToken.class);
         } catch (JWSInputException e) {
-            return null;
+            return TokenVerification.error(new RuntimeException("Token is not JWT", e));
         }
 
         if (!getIssuer(realm, uri).equals(jwt.getIssuer())) {
-            return null;
+            return TokenVerification.error(new RuntimeException("Issuer from token don't match with the realm issuer."));
         }
 
         if (!jwt.isActive()) {
-            return null;
+            return TokenVerification.error(new RuntimeException("Token not active."));
         }
 
         if (!(TokenUtil.TOKEN_TYPE_BEARER.equals(jwt.getType()) ||
                 TYPE_INITIAL_ACCESS_TOKEN.equals(jwt.getType()) ||
                 TYPE_REGISTRATION_ACCESS_TOKEN.equals(jwt.getType()))) {
-            return null;
+            return TokenVerification.error(new RuntimeException("Invalid type of token"));
         }
 
-        return jwt;
+        return TokenVerification.success(jwt);
     }
 
     private static String createToken(RealmModel realm, UriInfo uri, String id, String type, int expiration) {
@@ -112,4 +116,31 @@ public class ClientRegistrationTokenUtils {
         return Urls.realmIssuer(uri.getBaseUri(), realm.getName());
     }
 
+    protected static class TokenVerification {
+
+        private final JsonWebToken jwt;
+        private final RuntimeException error;
+
+        public static TokenVerification success(JsonWebToken jwt) {
+            return new TokenVerification(jwt, null);
+        }
+
+        public static TokenVerification error(RuntimeException error) {
+            return new TokenVerification(null, error);
+        }
+
+        private TokenVerification(JsonWebToken jwt, RuntimeException error) {
+            this.jwt = jwt;
+            this.error = error;
+        }
+
+        public JsonWebToken getJwt() {
+            return jwt;
+        }
+
+        public RuntimeException getError() {
+            return error;
+        }
+    }
+
 }
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/oidc/DescriptionConverter.java b/services/src/main/java/org/keycloak/services/clientregistration/oidc/DescriptionConverter.java
index cfbf42d..3ddcc59 100644
--- a/services/src/main/java/org/keycloak/services/clientregistration/oidc/DescriptionConverter.java
+++ b/services/src/main/java/org/keycloak/services/clientregistration/oidc/DescriptionConverter.java
@@ -18,24 +18,38 @@
 package org.keycloak.services.clientregistration.oidc;
 
 import org.keycloak.OAuth2Constants;
+import org.keycloak.authentication.ClientAuthenticator;
+import org.keycloak.authentication.ClientAuthenticatorFactory;
+import org.keycloak.authentication.authenticators.client.ClientIdAndSecretAuthenticator;
+import org.keycloak.authentication.authenticators.client.JWTClientAuthenticator;
+import org.keycloak.jose.jwk.JSONWebKeySet;
+import org.keycloak.jose.jwk.JWK;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.protocol.oidc.utils.AuthorizeClientUtil;
+import org.keycloak.protocol.oidc.utils.JWKSUtils;
 import org.keycloak.protocol.oidc.utils.OIDCResponseType;
+import org.keycloak.representations.idm.CertificateRepresentation;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.oidc.OIDCClientRepresentation;
 import org.keycloak.services.clientregistration.ClientRegistrationException;
+import org.keycloak.services.util.CertificateInfoHelper;
 
+import java.io.IOException;
 import java.net.URI;
+import java.security.PublicKey;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
 public class DescriptionConverter {
 
-    public static ClientRepresentation toInternal(OIDCClientRepresentation clientOIDC) throws ClientRegistrationException {
+    public static ClientRepresentation toInternal(KeycloakSession session, OIDCClientRepresentation clientOIDC) throws ClientRegistrationException {
         ClientRepresentation client = new ClientRepresentation();
         client.setClientId(clientOIDC.getClientId());
         client.setName(clientOIDC.getClientName());
@@ -60,15 +74,79 @@ public class DescriptionConverter {
             throw new ClientRegistrationException(iae.getMessage(), iae);
         }
 
+        String authMethod = clientOIDC.getTokenEndpointAuthMethod();
+        ClientAuthenticatorFactory clientAuthFactory;
+        if (authMethod == null) {
+            clientAuthFactory = (ClientAuthenticatorFactory) session.getKeycloakSessionFactory().getProviderFactory(ClientAuthenticator.class, KeycloakModelUtils.getDefaultClientAuthenticatorType());
+        } else {
+            clientAuthFactory = AuthorizeClientUtil.findClientAuthenticatorForOIDCAuthMethod(session, authMethod);
+        }
+
+        if (clientAuthFactory == null) {
+            throw new ClientRegistrationException("Not found clientAuthenticator for requested token_endpoint_auth_method");
+        }
+        client.setClientAuthenticatorType(clientAuthFactory.getId());
+
+        // Externalize to ClientAuthenticator itself?
+        if (authMethod != null && authMethod.equals(OIDCLoginProtocol.PRIVATE_KEY_JWT)) {
+
+            PublicKey publicKey = retrievePublicKey(clientOIDC);
+            if (publicKey == null) {
+                throw new ClientRegistrationException("Didn't find key of supported keyType for use " + JWK.Use.SIG.asString());
+            }
+
+            String publicKeyPem = KeycloakModelUtils.getPemFromKey(publicKey);
+
+            CertificateRepresentation rep = new CertificateRepresentation();
+            rep.setPublicKey(publicKeyPem);
+            CertificateInfoHelper.updateClientRepresentationCertificateInfo(client, rep, JWTClientAuthenticator.ATTR_PREFIX);
+        }
+
         return client;
     }
 
-    public static OIDCClientRepresentation toExternalResponse(ClientRepresentation client, URI uri) {
+
+    private static PublicKey retrievePublicKey(OIDCClientRepresentation clientOIDC) {
+        if (clientOIDC.getJwksUri() == null && clientOIDC.getJwks() == null) {
+            throw new ClientRegistrationException("Requested client authentication method '%s' but jwks_uri nor jwks were available in config");
+        }
+
+        if (clientOIDC.getJwksUri() != null && clientOIDC.getJwks() != null) {
+            throw new ClientRegistrationException("Illegal to use both jwks_uri and jwks");
+        }
+
+        JSONWebKeySet keySet;
+        if (clientOIDC.getJwks() != null) {
+            keySet = clientOIDC.getJwks();
+        } else {
+            try {
+                keySet = JWKSUtils.sendJwksRequest(clientOIDC.getJwksUri());
+            } catch (IOException ioe) {
+                throw new ClientRegistrationException("Failed to send JWKS request to specified jwks_uri", ioe);
+            }
+        }
+
+        return JWKSUtils.getKeyForUse(keySet, JWK.Use.SIG);
+    }
+
+
+    public static OIDCClientRepresentation toExternalResponse(KeycloakSession session, ClientRepresentation client, URI uri) {
         OIDCClientRepresentation response = new OIDCClientRepresentation();
         response.setClientId(client.getClientId());
+
+        ClientAuthenticatorFactory clientAuth = (ClientAuthenticatorFactory) session.getKeycloakSessionFactory().getProviderFactory(ClientAuthenticator.class, client.getClientAuthenticatorType());
+        Set<String> oidcClientAuthMethods = clientAuth.getProtocolAuthenticatorMethods(OIDCLoginProtocol.LOGIN_PROTOCOL);
+        if (oidcClientAuthMethods != null && !oidcClientAuthMethods.isEmpty()) {
+            response.setTokenEndpointAuthMethod(oidcClientAuthMethods.iterator().next());
+        }
+
+        if (client.getClientAuthenticatorType().equals(ClientIdAndSecretAuthenticator.PROVIDER_ID)) {
+            response.setClientSecret(client.getSecret());
+            response.setClientSecretExpiresAt(0);
+        }
+
         response.setClientName(client.getName());
         response.setClientUri(client.getBaseUrl());
-        response.setClientSecret(client.getSecret());
         response.setRedirectUris(client.getRedirectUris());
         response.setRegistrationAccessToken(client.getRegistrationAccessToken());
         response.setRegistrationClientUri(uri.toString());
diff --git a/services/src/main/java/org/keycloak/services/clientregistration/oidc/OIDCClientRegistrationProvider.java b/services/src/main/java/org/keycloak/services/clientregistration/oidc/OIDCClientRegistrationProvider.java
index 84dfc78..8bc1ecb 100755
--- a/services/src/main/java/org/keycloak/services/clientregistration/oidc/OIDCClientRegistrationProvider.java
+++ b/services/src/main/java/org/keycloak/services/clientregistration/oidc/OIDCClientRegistrationProvider.java
@@ -53,10 +53,10 @@ public class OIDCClientRegistrationProvider extends AbstractClientRegistrationPr
         }
 
         try {
-            ClientRepresentation client = DescriptionConverter.toInternal(clientOIDC);
+            ClientRepresentation client = DescriptionConverter.toInternal(session, clientOIDC);
             client = create(client);
             URI uri = session.getContext().getUri().getAbsolutePathBuilder().path(client.getClientId()).build();
-            clientOIDC = DescriptionConverter.toExternalResponse(client, uri);
+            clientOIDC = DescriptionConverter.toExternalResponse(session, client, uri);
             clientOIDC.setClientIdIssuedAt(Time.currentTime());
             return Response.created(uri).entity(clientOIDC).build();
         } catch (ClientRegistrationException cre) {
@@ -70,7 +70,7 @@ public class OIDCClientRegistrationProvider extends AbstractClientRegistrationPr
     @Produces(MediaType.APPLICATION_JSON)
     public Response getOIDC(@PathParam("clientId") String clientId) {
         ClientRepresentation client = get(clientId);
-        OIDCClientRepresentation clientOIDC = DescriptionConverter.toExternalResponse(client, session.getContext().getUri().getRequestUri());
+        OIDCClientRepresentation clientOIDC = DescriptionConverter.toExternalResponse(session, client, session.getContext().getUri().getRequestUri());
         return Response.ok(clientOIDC).build();
     }
 
@@ -79,10 +79,10 @@ public class OIDCClientRegistrationProvider extends AbstractClientRegistrationPr
     @Consumes(MediaType.APPLICATION_JSON)
     public Response updateOIDC(@PathParam("clientId") String clientId, OIDCClientRepresentation clientOIDC) {
         try {
-            ClientRepresentation client = DescriptionConverter.toInternal(clientOIDC);
+            ClientRepresentation client = DescriptionConverter.toInternal(session, clientOIDC);
             client = update(clientId, client);
             URI uri = session.getContext().getUri().getAbsolutePathBuilder().path(client.getClientId()).build();
-            clientOIDC = DescriptionConverter.toExternalResponse(client, uri);
+            clientOIDC = DescriptionConverter.toExternalResponse(session, client, uri);
             return Response.ok(clientOIDC).build();
         } catch (ClientRegistrationException cre) {
             logger.clientRegistrationException(cre.getMessage());
diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java
index 26db8cf..1fae787 100644
--- a/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java
+++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakSession.java
@@ -21,6 +21,9 @@ import org.keycloak.models.cache.CacheRealmProvider;
 import org.keycloak.models.cache.CacheUserProvider;
 import org.keycloak.provider.Provider;
 import org.keycloak.provider.ProviderFactory;
+import org.keycloak.scripting.ScriptingProvider;
+import org.keycloak.storage.UserStorageManager;
+import org.keycloak.storage.federated.UserFederatedStorageProvider;
 
 import java.util.*;
 
@@ -33,10 +36,14 @@ public class DefaultKeycloakSession implements KeycloakSession {
     private final Map<Integer, Provider> providers = new HashMap<>();
     private final List<Provider> closable = new LinkedList<Provider>();
     private final DefaultKeycloakTransactionManager transactionManager;
+    private final Map<String, Object> attributes = new HashMap<>();
     private RealmProvider model;
     private UserProvider userModel;
+    private UserStorageManager userStorageManager;
+    private ScriptingProvider scriptingProvider;
     private UserSessionProvider sessionProvider;
     private UserFederationManager federationManager;
+    private UserFederatedStorageProvider userFederatedStorageProvider;
     private KeycloakContext context;
 
     public DefaultKeycloakSession(DefaultKeycloakSessionFactory factory) {
@@ -75,7 +82,22 @@ public class DefaultKeycloakSession implements KeycloakSession {
     }
 
     @Override
-    public KeycloakTransactionManager getTransaction() {
+    public Object getAttribute(String attribute) {
+        return attributes.get(attribute);
+    }
+
+    @Override
+    public Object removeAttribute(String attribute) {
+        return attributes.remove(attribute);
+    }
+
+    @Override
+    public void setAttribute(String name, Object value) {
+        attributes.put(name, value);
+    }
+
+    @Override
+    public KeycloakTransactionManager getTransactionManager() {
         return transactionManager;
     }
 
@@ -85,6 +107,25 @@ public class DefaultKeycloakSession implements KeycloakSession {
     }
 
     @Override
+    public UserFederatedStorageProvider userFederatedStorage() {
+        if (userFederatedStorageProvider == null) {
+            userFederatedStorageProvider = getProvider(UserFederatedStorageProvider.class);
+        }
+        return userFederatedStorageProvider;
+    }
+
+    @Override
+    public UserProvider userLocalStorage() {
+        return getProvider(UserProvider.class);
+    }
+
+    @Override
+    public UserProvider userStorageManager() {
+        if (userStorageManager == null) userStorageManager = new UserStorageManager(this);
+        return userStorageManager;
+    }
+
+    @Override
     public UserProvider userStorage() {
         if (userModel == null) {
             userModel = getUserProvider();
@@ -168,4 +209,13 @@ public class DefaultKeycloakSession implements KeycloakSession {
         }
     }
 
+    @Override
+    public ScriptingProvider scripting() {
+
+        if (scriptingProvider == null) {
+            scriptingProvider = getProvider(ScriptingProvider.class);
+        }
+
+        return scriptingProvider;
+    }
 }
diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
index 90b495c..45bef3c 100755
--- a/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
+++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakSessionFactory.java
@@ -17,6 +17,7 @@
 package org.keycloak.services;
 
 import org.keycloak.Config;
+import org.keycloak.common.util.MultivaluedHashMap;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.provider.Provider;
@@ -24,26 +25,31 @@ import org.keycloak.provider.ProviderEvent;
 import org.keycloak.provider.ProviderEventListener;
 import org.keycloak.provider.ProviderFactory;
 import org.keycloak.provider.ProviderManager;
+import org.keycloak.provider.ProviderManagerDeployer;
+import org.keycloak.provider.ProviderManagerRegistry;
 import org.keycloak.provider.Spi;
-import org.keycloak.services.ServicesLogger;
+import org.keycloak.transaction.JtaRegistration;
+import org.keycloak.transaction.JtaTransactionManagerLookup;
+import org.keycloak.transaction.JtaTransactionWrapper;
 
+import javax.transaction.TransactionManager;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.ServiceLoader;
 import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 
-public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory {
+public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory, ProviderManagerDeployer {
 
     private static final ServicesLogger logger = ServicesLogger.ROOT_LOGGER;
 
     private Set<Spi> spis = new HashSet<>();
-    private Map<Class<? extends Provider>, String> provider = new HashMap<Class<? extends Provider>, String>();
-    private Map<Class<? extends Provider>, Map<String, ProviderFactory>> factoriesMap = new HashMap<Class<? extends Provider>, Map<String, ProviderFactory>>();
-    protected CopyOnWriteArrayList<ProviderEventListener> listeners = new CopyOnWriteArrayList<ProviderEventListener>();
+    private Map<Class<? extends Provider>, String> provider = new HashMap<>();
+    private volatile Map<Class<? extends Provider>, Map<String, ProviderFactory>> factoriesMap = new HashMap<>();
+    protected CopyOnWriteArrayList<ProviderEventListener> listeners = new CopyOnWriteArrayList<>();
+    private TransactionManager tm;
 
     // TODO: Likely should be changed to int and use Time.currentTime() to be compatible with all our "time" reps
     protected long serverStartupTimestamp;
@@ -69,18 +75,159 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory {
         serverStartupTimestamp = System.currentTimeMillis();
 
         ProviderManager pm = new ProviderManager(getClass().getClassLoader(), Config.scope().getArray("providers"));
-
-        ServiceLoader<Spi> load = ServiceLoader.load(Spi.class, getClass().getClassLoader());
-        loadSPIs(pm, load);
+        spis.addAll(pm.loadSpis());
+        factoriesMap = loadFactories(pm);
+        for (ProviderManager manager : ProviderManagerRegistry.SINGLETON.getPreBoot()) {
+            Map<Class<? extends Provider>, Map<String, ProviderFactory>> factoryMap = loadFactories(manager);
+            for (Map.Entry<Class<? extends Provider>,  Map<String, ProviderFactory>> entry : factoryMap.entrySet()) {
+                Map<String, ProviderFactory> factories = factoriesMap.get(entry.getKey());
+                if (factories == null) {
+                    factoriesMap.put(entry.getKey(), entry.getValue());
+                } else {
+                    factories.putAll(entry.getValue());
+                }
+            }
+        }
+        checkProvider();
         for ( Map<String, ProviderFactory> factories : factoriesMap.values()) {
             for (ProviderFactory factory : factories.values()) {
                 factory.postInit(this);
             }
         }
+        // make the session factory ready for hot deployment
+        ProviderManagerRegistry.SINGLETON.setDeployer(this);
+
+        JtaTransactionManagerLookup lookup = (JtaTransactionManagerLookup)getProviderFactory(JtaTransactionManagerLookup.class);
+        if (lookup != null) tm = lookup.getTransactionManager();
+    }
+    protected Map<Class<? extends Provider>, Map<String, ProviderFactory>> getFactoriesCopy() {
+        Map<Class<? extends Provider>, Map<String, ProviderFactory>> copy = new HashMap<>();
+        for (Map.Entry<Class<? extends Provider>, Map<String, ProviderFactory>> entry : factoriesMap.entrySet()) {
+            Map<String, ProviderFactory> valCopy = new HashMap<>();
+            valCopy.putAll(entry.getValue());
+            copy.put(entry.getKey(), valCopy);
+        }
+        return copy;
+
+    }
+
+    @Override
+    public void deploy(ProviderManager pm) {
+        Map<Class<? extends Provider>, Map<String, ProviderFactory>> copy = getFactoriesCopy();
+        Map<Class<? extends Provider>, Map<String, ProviderFactory>> newFactories = loadFactories(pm);
+        List<ProviderFactory> undeployed = new LinkedList<>();
+
+        for (Map.Entry<Class<? extends Provider>, Map<String, ProviderFactory>> entry : newFactories.entrySet()) {
+            Map<String, ProviderFactory> current = copy.get(entry.getKey());
+            if (current == null) {
+                copy.put(entry.getKey(), entry.getValue());
+            } else {
+                for (ProviderFactory f : entry.getValue().values()) {
+                    ProviderFactory old = current.remove(f.getId());
+                    if (old != null) undeployed.add(old);
+                }
+                current.putAll(entry.getValue());
+            }
+
+        }
+        factoriesMap = copy;
+        for (ProviderFactory factory : undeployed) {
+            factory.close();
+        }
+    }
+
+    @Override
+    public void undeploy(ProviderManager pm) {
+        // we make a copy to avoid concurrent access exceptions
+        Map<Class<? extends Provider>, Map<String, ProviderFactory>> copy = getFactoriesCopy();
+        MultivaluedHashMap<Class<? extends Provider>, ProviderFactory> factories = pm.getLoadedFactories();
+        List<ProviderFactory> undeployed = new LinkedList<>();
+        for (Map.Entry<Class<? extends Provider>, List<ProviderFactory>> entry : factories.entrySet()) {
+            Map<String, ProviderFactory> registered = copy.get(entry.getKey());
+            for (ProviderFactory factory : entry.getValue()) {
+                undeployed.add(factory);
+                if (registered != null) {
+                    registered.remove(factory.getId());
+                }
+            }
+        }
+        factoriesMap = copy;
+        for (ProviderFactory factory : undeployed) {
+            factory.close();
+        }
+    }
+
+    protected void checkProvider() {
+        for (Spi spi : spis) {
+            String provider = Config.getProvider(spi.getName());
+            if (provider != null) {
+                this.provider.put(spi.getProviderClass(), provider);
+                if (getProviderFactory(spi.getProviderClass(), provider) == null) {
+                    throw new RuntimeException("Failed to find provider " + provider + " for " + spi.getName());
+                }
+            } else {
+                Map<String, ProviderFactory> factories = factoriesMap.get(spi.getProviderClass());
+                if (factories != null && factories.size() == 1) {
+                    provider = factories.values().iterator().next().getId();
+                    this.provider.put(spi.getProviderClass(), provider);
+                }
+            }
+        }
     }
 
-    protected void loadSPIs(ProviderManager pm, ServiceLoader<Spi> load) {
-        for (Spi spi : load) {
+    protected Map<Class<? extends Provider>, Map<String, ProviderFactory>> loadFactories(ProviderManager pm) {
+        Map<Class<? extends Provider>, Map<String, ProviderFactory>> factoryMap = new HashMap<>();
+        Set<Spi> spiList = spis;
+
+        for (Spi spi : spiList) {
+
+            Map<String, ProviderFactory> factories = new HashMap<String, ProviderFactory>();
+            factoryMap.put(spi.getProviderClass(), factories);
+
+            String provider = Config.getProvider(spi.getName());
+            if (provider != null) {
+
+                ProviderFactory factory = pm.load(spi, provider);
+                if (factory == null) {
+                    continue;
+                }
+
+                Config.Scope scope = Config.scope(spi.getName(), provider);
+                if (scope.getBoolean("enabled", true)) {
+
+                    factory.init(scope);
+
+                    if (spi.isInternal() && !isInternal(factory)) {
+                        logger.spiMayChange(factory.getId(), factory.getClass().getName(), spi.getName());
+                    }
+
+                    factories.put(factory.getId(), factory);
+
+                    logger.debugv("Loaded SPI {0} (provider = {1})", spi.getName(), provider);
+                }
+            } else {
+                for (ProviderFactory factory : pm.load(spi)) {
+                    Config.Scope scope = Config.scope(spi.getName(), factory.getId());
+                    if (scope.getBoolean("enabled", true)) {
+                        factory.init(scope);
+
+                        if (spi.isInternal() && !isInternal(factory)) {
+                            logger.spiMayChange(factory.getId(), factory.getClass().getName(), spi.getName());
+                        }
+
+                        factories.put(factory.getId(), factory);
+                    } else {
+                        logger.debugv("SPI {0} provider {1} disabled", spi.getName(), factory.getId());
+                    }
+                }
+            }
+        }
+        return factoryMap;
+
+    }
+
+    protected void loadSPIs(ProviderManager pm, List<Spi> spiList) {
+        for (Spi spi : spiList) {
             spis.add(spi);
 
             Map<String, ProviderFactory> factories = new HashMap<String, ProviderFactory>();
@@ -134,7 +281,11 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory {
     }
 
     public KeycloakSession create() {
-        return new DefaultKeycloakSession(this);
+        KeycloakSession session =  new DefaultKeycloakSession(this);
+        if (tm != null) {
+            session.getTransactionManager().enlist(new JtaTransactionWrapper(tm));
+        }
+        return session;
     }
 
     <T extends Provider> String getDefaultProvider(Class<T> clazz) {
@@ -153,7 +304,11 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory {
 
     @Override
     public <T extends Provider> ProviderFactory<T> getProviderFactory(Class<T> clazz, String id) {
-         return factoriesMap.get(clazz).get(id);
+        Map<String, ProviderFactory> map = factoriesMap.get(clazz);
+        if (map == null) {
+            return null;
+        }
+        return map.get(id);
     }
 
     @Override
@@ -175,6 +330,7 @@ public class DefaultKeycloakSessionFactory implements KeycloakSessionFactory {
     }
 
     public void close() {
+        ProviderManagerRegistry.SINGLETON.setDeployer(null);
         for (Map<String, ProviderFactory> factories : factoriesMap.values()) {
             for (ProviderFactory factory : factories.values()) {
                 factory.close();
diff --git a/services/src/main/java/org/keycloak/services/ErrorResponseException.java b/services/src/main/java/org/keycloak/services/ErrorResponseException.java
index c29f0f3..538374c 100644
--- a/services/src/main/java/org/keycloak/services/ErrorResponseException.java
+++ b/services/src/main/java/org/keycloak/services/ErrorResponseException.java
@@ -18,6 +18,7 @@
 package org.keycloak.services;
 
 import org.keycloak.OAuth2Constants;
+import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
 
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.MediaType;
@@ -42,12 +43,8 @@ public class ErrorResponseException extends WebApplicationException {
 
     @Override
     public Response getResponse() {
-        Map<String, String> e = new HashMap<String, String>();
-        e.put(OAuth2Constants.ERROR, error);
-        if (errorDescription != null) {
-            e.put(OAuth2Constants.ERROR_DESCRIPTION, errorDescription);
-        }
-        return Response.status(status).entity(e).type(MediaType.APPLICATION_JSON_TYPE).build();
+        OAuth2ErrorRepresentation errorRep = new OAuth2ErrorRepresentation(error, errorDescription);
+        return Response.status(status).entity(errorRep).type(MediaType.APPLICATION_JSON_TYPE).build();
     }
 
 }
diff --git a/services/src/main/java/org/keycloak/services/filters/KeycloakSessionServletFilter.java b/services/src/main/java/org/keycloak/services/filters/KeycloakSessionServletFilter.java
index 282fd31..4187645 100755
--- a/services/src/main/java/org/keycloak/services/filters/KeycloakSessionServletFilter.java
+++ b/services/src/main/java/org/keycloak/services/filters/KeycloakSessionServletFilter.java
@@ -23,6 +23,8 @@ import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.models.KeycloakTransaction;
 
+import javax.servlet.AsyncEvent;
+import javax.servlet.AsyncListener;
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
@@ -80,22 +82,53 @@ public class KeycloakSessionServletFilter implements Filter {
         session.getContext().setConnection(connection);
         ResteasyProviderFactory.pushContext(ClientConnection.class, connection);
 
-        KeycloakTransaction tx = session.getTransaction();
+        KeycloakTransaction tx = session.getTransactionManager();
         ResteasyProviderFactory.pushContext(KeycloakTransaction.class, tx);
         tx.begin();
 
         try {
             filterChain.doFilter(servletRequest, servletResponse);
         } finally {
-            // KeycloakTransactionCommitter is responsible for committing the transaction, but if an exception is thrown it's not invoked and transaction
-            // should be rolled back
-            if (session.getTransaction() != null && session.getTransaction().isActive()) {
-                session.getTransaction().rollback();
+            if (servletRequest.isAsyncStarted()) {
+                servletRequest.getAsyncContext().addListener(createAsyncLifeCycleListener(session));
+            } else {
+                closeSession(session);
+            }
+        }
+    }
+
+    private AsyncListener createAsyncLifeCycleListener(final KeycloakSession session) {
+        return new AsyncListener() {
+            @Override
+            public void onComplete(AsyncEvent event) {
+                closeSession(session);
             }
 
-            session.close();
-            ResteasyProviderFactory.clearContextData();
+            @Override
+            public void onTimeout(AsyncEvent event) {
+                closeSession(session);
+            }
+
+            @Override
+            public void onError(AsyncEvent event) {
+                closeSession(session);
+            }
+
+            @Override
+            public void onStartAsync(AsyncEvent event) {
+            }
+        };
+    }
+
+    private void closeSession(KeycloakSession session) {
+        // KeycloakTransactionCommitter is responsible for committing the transaction, but if an exception is thrown it's not invoked and transaction
+        // should be rolled back
+        if (session.getTransactionManager() != null && session.getTransactionManager().isActive()) {
+            session.getTransactionManager().rollback();
         }
+
+        session.close();
+        ResteasyProviderFactory.clearContextData();
     }
 
     @Override
diff --git a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
index 99276d0..356922e 100755
--- a/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
+++ b/services/src/main/java/org/keycloak/services/managers/ApplianceBootstrap.java
@@ -84,6 +84,8 @@ public class ApplianceBootstrap {
 
     public void createMasterRealmUser(String username, String password) {
         RealmModel realm = session.realms().getRealm(Config.getAdminRealm());
+        session.getContext().setRealm(realm);
+
         if (session.users().getUsersCount(realm) > 0) {
             throw new IllegalStateException("Can't create initial user as users already exists");
         }
diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
index c2c774c..e53ac00 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -61,6 +61,12 @@ import java.util.Set;
  */
 public class AuthenticationManager {
     public static final String END_AFTER_REQUIRED_ACTIONS = "END_AFTER_REQUIRED_ACTIONS";
+
+    // userSession note with authTime (time when authentication flow including requiredActions was finished)
+    public static final String AUTH_TIME = "AUTH_TIME";
+    // clientSession note with flag that clientSession was authenticated through SSO cookie
+    public static final String SSO_AUTH = "SSO_AUTH";
+
     protected static ServicesLogger logger = ServicesLogger.ROOT_LOGGER;
     public static final String FORM_USERNAME = "username";
     // used for auth login
@@ -78,7 +84,7 @@ public class AuthenticationManager {
         }
         int currentTime = Time.currentTime();
         int max = userSession.getStarted() + realm.getSsoSessionMaxLifespan();
-        return userSession != null && userSession.getLastSessionRefresh() + realm.getSsoSessionIdleTimeout() > currentTime && max > currentTime;
+        return userSession.getLastSessionRefresh() + realm.getSsoSessionIdleTimeout() > currentTime && max > currentTime;
     }
 
     public static void expireUserSessionCookie(KeycloakSession session, UserSessionModel userSession, RealmModel realm, UriInfo uriInfo, HttpHeaders headers, ClientConnection connection) {
@@ -403,9 +409,23 @@ public class AuthenticationManager {
         createLoginCookie(session, realm, userSession.getUser(), userSession, uriInfo, clientConnection);
         if (userSession.getState() != UserSessionModel.State.LOGGED_IN) userSession.setState(UserSessionModel.State.LOGGED_IN);
         if (userSession.isRememberMe()) createRememberMeCookie(realm, userSession.getUser().getUsername(), uriInfo, clientConnection);
+
+        // Update userSession note with authTime. But just if flag SSO_AUTH is not set
+        if (!isSSOAuthentication(clientSession)) {
+            int authTime = Time.currentTime();
+            userSession.setNote(AUTH_TIME, String.valueOf(authTime));
+        }
+
         return protocol.authenticated(userSession, new ClientSessionCode(realm, clientSession));
 
     }
+
+    public static boolean isSSOAuthentication(ClientSessionModel clientSession) {
+        String ssoAuth = clientSession.getNote(SSO_AUTH);
+        return Boolean.parseBoolean(ssoAuth);
+    }
+
+
     public static Response nextActionAfterAuthentication(KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession,
                                                   ClientConnection clientConnection,
                                                   HttpRequest request, UriInfo uriInfo, EventBuilder event) {
@@ -443,7 +463,7 @@ public class AuthenticationManager {
 
         if (client.isConsentRequired()) {
 
-            UserConsentModel grantedConsent = user.getConsentByClient(client.getId());
+            UserConsentModel grantedConsent = session.users().getConsentByClient(realm, user, client.getId());
 
             ClientSessionCode accessCode = new ClientSessionCode(realm, clientSession);
             for (RoleModel r : accessCode.getRequestedRoles()) {
@@ -497,7 +517,7 @@ public class AuthenticationManager {
 
         if (client.isConsentRequired()) {
 
-            UserConsentModel grantedConsent = user.getConsentByClient(client.getId());
+            UserConsentModel grantedConsent = session.users().getConsentByClient(realm, user, client.getId());
 
             List<RoleModel> realmRoles = new LinkedList<>();
             MultivaluedMap<String, RoleModel> resourceRoles = new MultivaluedMapImpl<>();
@@ -550,6 +570,10 @@ public class AuthenticationManager {
                                                Set<String> requiredActions) {
         for (String action : requiredActions) {
             RequiredActionProviderModel model = realm.getRequiredActionProviderByAlias(action);
+            if (!model.isEnabled()) {
+                continue;
+            }
+
             RequiredActionFactory factory = (RequiredActionFactory)session.getKeycloakSessionFactory().getProviderFactory(RequiredActionProvider.class, model.getProviderId());
             if (factory == null) {
                 throw new RuntimeException("Unable to find factory for Required Action: " + model.getProviderId() + " did you forget to declare it in a META-INF/services file?");
diff --git a/services/src/main/java/org/keycloak/services/managers/ClientManager.java b/services/src/main/java/org/keycloak/services/managers/ClientManager.java
index a8120e9..7bdf5b1 100644
--- a/services/src/main/java/org/keycloak/services/managers/ClientManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/ClientManager.java
@@ -35,6 +35,7 @@ import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
 import org.keycloak.representations.adapters.config.BaseRealmConfig;
 import org.keycloak.common.util.Time;
+import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.services.ServicesLogger;
 
@@ -102,7 +103,7 @@ public class ClientManager {
                 sessionsPersister.onClientRemoved(realm, client);
             }
 
-            UserModel serviceAccountUser = realmManager.getSession().users().getUserByServiceAccountClient(client);
+            UserModel serviceAccountUser = realmManager.getSession().users().getServiceAccount(client);
             if (serviceAccountUser != null) {
                 new UserManager(realmManager.getSession()).removeUser(realm, serviceAccountUser);
             }
@@ -149,7 +150,7 @@ public class ClientManager {
         client.setServiceAccountsEnabled(true);
 
         // Add dedicated user for this service account
-        if (realmManager.getSession().users().getUserByServiceAccountClient(client) == null) {
+        if (realmManager.getSession().users().getServiceAccount(client) == null) {
             String username = ServiceAccountConstants.SERVICE_ACCOUNT_USER_PREFIX + client.getClientId();
             logger.debugf("Creating service account user '%s'", username);
 
@@ -207,6 +208,8 @@ public class ClientManager {
         protected Boolean publicClient;
         @JsonProperty("credentials")
         protected Map<String, Object> credentials;
+        @JsonProperty("policy-enforcer")
+        protected PolicyEnforcerConfig enforcerConfig;
 
         public Boolean isUseResourceRoleMappings() {
             return useResourceRoleMappings;
@@ -247,6 +250,14 @@ public class ClientManager {
         public void setBearerOnly(Boolean bearerOnly) {
             this.bearerOnly = bearerOnly;
         }
+
+        public PolicyEnforcerConfig getEnforcerConfig() {
+            return this.enforcerConfig;
+        }
+
+        public void setEnforcerConfig(PolicyEnforcerConfig enforcerConfig) {
+            this.enforcerConfig = enforcerConfig;
+        }
     }
 
 
diff --git a/services/src/main/java/org/keycloak/services/managers/DefaultBruteForceProtector.java b/services/src/main/java/org/keycloak/services/managers/DefaultBruteForceProtector.java
index 665dcd3..28fc29d 100644
--- a/services/src/main/java/org/keycloak/services/managers/DefaultBruteForceProtector.java
+++ b/services/src/main/java/org/keycloak/services/managers/DefaultBruteForceProtector.java
@@ -22,7 +22,7 @@ import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
-import org.keycloak.models.UsernameLoginFailureModel;
+import org.keycloak.models.UserLoginFailureModel;
 import org.keycloak.services.ServicesLogger;
 
 import java.util.ArrayList;
@@ -55,18 +55,18 @@ public class DefaultBruteForceProtector implements Runnable, BruteForceProtector
 
     protected abstract class LoginEvent implements Comparable<LoginEvent> {
         protected final String realmId;
-        protected final String username;
+        protected final String userId;
         protected final String ip;
 
-        protected LoginEvent(String realmId, String username, String ip) {
+        protected LoginEvent(String realmId, String userId, String ip) {
             this.realmId = realmId;
-            this.username = username;
+            this.userId = userId;
             this.ip = ip;
         }
 
         @Override
         public int compareTo(LoginEvent o) {
-            return username.compareTo(o.username);
+            return userId.compareTo(o.userId);
         }
     }
 
@@ -79,8 +79,8 @@ public class DefaultBruteForceProtector implements Runnable, BruteForceProtector
     protected class FailedLogin extends LoginEvent {
         protected final CountDownLatch latch = new CountDownLatch(1);
 
-        public FailedLogin(String realmId, String username, String ip) {
-            super(realmId, username, ip);
+        public FailedLogin(String realmId, String userId, String ip) {
+            super(realmId, userId, ip);
         }
     }
 
@@ -92,11 +92,11 @@ public class DefaultBruteForceProtector implements Runnable, BruteForceProtector
         logger.debug("failure");
         RealmModel realm = getRealmModel(session, event);
         logFailure(event);
-        UserModel user = session.users().getUserByUsername(event.username.toString(), realm);
-        UsernameLoginFailureModel userLoginFailure = getUserModel(session, event);
+        UserModel user = session.users().getUserById(event.userId, realm);
+        UserLoginFailureModel userLoginFailure = getUserModel(session, event);
         if (user != null) {
             if (userLoginFailure == null) {
-                userLoginFailure = session.sessions().addUserLoginFailure(realm, event.username.toLowerCase());
+                userLoginFailure = session.sessions().addUserLoginFailure(realm, event.userId);
             }
             userLoginFailure.setLastIPFailure(event.ip);
             long currentTime = System.currentTimeMillis();
@@ -135,10 +135,10 @@ public class DefaultBruteForceProtector implements Runnable, BruteForceProtector
     }
 
 
-    protected UsernameLoginFailureModel getUserModel(KeycloakSession session, LoginEvent event) {
+    protected UserLoginFailureModel getUserModel(KeycloakSession session, LoginEvent event) {
         RealmModel realm = getRealmModel(session, event);
         if (realm == null) return null;
-        UsernameLoginFailureModel user = session.sessions().getUserLoginFailure(realm, event.username.toLowerCase());
+        UserLoginFailureModel user = session.sessions().getUserLoginFailure(realm, event.userId);
         if (user == null) return null;
         return user;
     }
@@ -177,7 +177,7 @@ public class DefaultBruteForceProtector implements Runnable, BruteForceProtector
                         queue.drainTo(events, TRANSACTION_SIZE);
                         Collections.sort(events); // we sort to avoid deadlock due to ordered updates.  Maybe I'm overthinking this.
                         KeycloakSession session = factory.create();
-                        session.getTransaction().begin();
+                        session.getTransactionManager().begin();
                         try {
                             for (LoginEvent event : events) {
                                 if (event instanceof FailedLogin) {
@@ -186,9 +186,9 @@ public class DefaultBruteForceProtector implements Runnable, BruteForceProtector
                                     run = false;
                                 }
                             }
-                            session.getTransaction().commit();
+                            session.getTransactionManager().commit();
                         } catch (Exception e) {
-                            session.getTransaction().rollback();
+                            session.getTransactionManager().rollback();
                             throw e;
                         } finally {
                             for (LoginEvent event : events) {
@@ -212,7 +212,7 @@ public class DefaultBruteForceProtector implements Runnable, BruteForceProtector
     }
 
     protected void logFailure(LoginEvent event) {
-        logger.loginFailure(event.username, event.ip);
+        logger.loginFailure(event.userId, event.ip);
         failures++;
         long delta = 0;
         if (lastFailure > 0) {
@@ -227,9 +227,9 @@ public class DefaultBruteForceProtector implements Runnable, BruteForceProtector
     }
 
     @Override
-    public void failedLogin(RealmModel realm, String username, ClientConnection clientConnection) {
+    public void failedLogin(RealmModel realm, UserModel user, ClientConnection clientConnection) {
         try {
-            FailedLogin event = new FailedLogin(realm.getId(), username, clientConnection.getRemoteAddr());
+            FailedLogin event = new FailedLogin(realm.getId(), user.getId(), clientConnection.getRemoteAddr());
             queue.offer(event);
             // wait a minimum of seconds for type to process so that a hacker
             // cannot flood with failed logins and overwhelm the queue and not have notBefore updated to block next requests
@@ -241,17 +241,17 @@ public class DefaultBruteForceProtector implements Runnable, BruteForceProtector
     }
 
     @Override
-    public boolean isTemporarilyDisabled(KeycloakSession session, RealmModel realm, String username) {
-        UsernameLoginFailureModel failure = session.sessions().getUserLoginFailure(realm, username.toLowerCase());
-        if (failure == null) {
-            return false;
+    public boolean isTemporarilyDisabled(KeycloakSession session, RealmModel realm, UserModel user) {
+        UserLoginFailureModel failure = session.sessions().getUserLoginFailure(realm, user.getId());
+
+        if (failure != null) {
+            int currTime = (int) (System.currentTimeMillis() / 1000);
+            if (currTime < failure.getFailedLoginNotBefore()) {
+                logger.debugv("Current: {0} notBefore: {1}", currTime, failure.getFailedLoginNotBefore());
+                return true;
+            }
         }
 
-        int currTime = (int)(System.currentTimeMillis()/1000);
-        if (currTime < failure.getFailedLoginNotBefore()) {
-            logger.debugv("Current: {0} notBefore: {1}", currTime , failure.getFailedLoginNotBefore());
-            return true;
-        }
         return false;
     }
 
diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
index 4ff5588..1add03d 100755
--- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
@@ -47,7 +47,6 @@ import org.keycloak.representations.idm.OAuthClientRepresentation;
 import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.RoleRepresentation;
-import org.keycloak.timer.TimerProvider;
 
 import java.util.Collections;
 import java.util.HashSet;
@@ -120,6 +119,9 @@ public class RealmManager implements RealmImporter {
         setupAuthenticationFlows(realm);
         setupRequiredActions(realm);
         setupOfflineTokens(realm);
+        setupAuthorizationServices(realm);
+
+        fireRealmPostCreate(realm);
 
         return realm;
     }
@@ -220,7 +222,7 @@ public class RealmManager implements RealmImporter {
 
         realm.setEventsListeners(Collections.singleton("jboss-logging"));
 
-        realm.setPasswordPolicy(new PasswordPolicy("hashIterations(20000)"));
+        realm.setPasswordPolicy(PasswordPolicy.parse(session, "hashIterations(20000)"));
     }
 
     public boolean removeRealm(RealmModel realm) {
@@ -489,6 +491,10 @@ public class RealmManager implements RealmImporter {
         for (final UserFederationProviderModel fedProvider : federationProviders) {
             usersSyncManager.notifyToRefreshPeriodicSync(session, realm, fedProvider, false);
         }
+
+        setupAuthorizationServices(realm);
+        fireRealmPostCreate(realm);
+
         return realm;
     }
 
@@ -581,4 +587,22 @@ public class RealmManager implements RealmImporter {
         return session.users().searchForUser(searchString.trim(), realmModel);
     }
 
+    private void setupAuthorizationServices(RealmModel realm) {
+        KeycloakModelUtils.setupAuthorizationServices(realm);
+    }
+
+    private void fireRealmPostCreate(RealmModel realm) {
+        session.getKeycloakSessionFactory().publish(new RealmModel.RealmPostCreateEvent() {
+            @Override
+            public RealmModel getCreatedRealm() {
+                return realm;
+            }
+            @Override
+            public KeycloakSession getKeycloakSession() {
+                return session;
+            }
+        });
+
+    }
+
 }
diff --git a/services/src/main/java/org/keycloak/services/messages/Messages.java b/services/src/main/java/org/keycloak/services/messages/Messages.java
index 556a495..d9d3c4e 100755
--- a/services/src/main/java/org/keycloak/services/messages/Messages.java
+++ b/services/src/main/java/org/keycloak/services/messages/Messages.java
@@ -188,6 +188,8 @@ public class Messages {
 
     public static final String CLIENT_NOT_FOUND = "clientNotFoundMessage";
 
+    public static final String CLIENT_DISABLED = "clientDisabledMessage";
+
     public static final String INVALID_PARAMETER = "invalidParameterMessage";
 
     public static final String IDENTITY_PROVIDER_LOGIN_FAILURE = "identityProviderLoginFailure";
diff --git a/services/src/main/java/org/keycloak/services/resources/AbstractSecuredLocalService.java b/services/src/main/java/org/keycloak/services/resources/AbstractSecuredLocalService.java
index 547424c..2a8c0bb 100755
--- a/services/src/main/java/org/keycloak/services/resources/AbstractSecuredLocalService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AbstractSecuredLocalService.java
@@ -34,6 +34,7 @@ import org.keycloak.services.managers.Auth;
 import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.util.CookieHelper;
 import org.keycloak.common.util.UriUtils;
+import org.keycloak.util.TokenUtil;
 
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
@@ -237,15 +238,14 @@ public abstract class AbstractSecuredLocalService {
 
         public Response redirect(UriInfo uriInfo, String redirectUri) {
             String state = getStateCode();
+            String scopeParam = TokenUtil.attachOIDCScope(scope);
 
             UriBuilder uriBuilder = UriBuilder.fromUri(authUrl)
                     .queryParam(OAuth2Constants.CLIENT_ID, clientId)
                     .queryParam(OAuth2Constants.REDIRECT_URI, redirectUri)
                     .queryParam(OAuth2Constants.STATE, state)
-                    .queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE);
-            if (scope != null) {
-                uriBuilder.queryParam(OAuth2Constants.SCOPE, scope);
-            }
+                    .queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE)
+                    .queryParam(OAuth2Constants.SCOPE, scopeParam);
 
             URI url = uriBuilder.build();
 
diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java
index 4907707..bf6fb88 100755
--- a/services/src/main/java/org/keycloak/services/resources/AccountService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java
@@ -16,7 +16,7 @@
  */
 package org.keycloak.services.resources;
 
-import org.jboss.logging.Logger;
+import org.keycloak.events.Errors;
 import org.keycloak.forms.account.AccountPages;
 import org.keycloak.forms.account.AccountProvider;
 import org.keycloak.events.Details;
@@ -500,7 +500,7 @@ public class AccountService extends AbstractSecuredLocalService {
 
         // Revoke grant in UserModel
         UserModel user = auth.getUser();
-        user.revokeConsentForClient(client.getId());
+        session.users().revokeConsentForClient(realm, user, client.getId());
         new UserSessionManager(session).revokeOfflineToken(user, client);
 
         // Logout clientSessions for this user and client
@@ -612,26 +612,34 @@ public class AccountService extends AbstractSecuredLocalService {
         String passwordNew = formData.getFirst("password-new");
         String passwordConfirm = formData.getFirst("password-confirm");
 
+        EventBuilder errorEvent = event.clone().event(EventType.UPDATE_PASSWORD_ERROR)
+                .client(auth.getClient())
+                .user(auth.getClientSession().getUserSession().getUser());
+
         if (requireCurrent) {
             if (Validation.isBlank(password)) {
                 setReferrerOnPage();
+                errorEvent.error(Errors.PASSWORD_MISSING);
                 return account.setError(Messages.MISSING_PASSWORD).createResponse(AccountPages.PASSWORD);
             }
 
             UserCredentialModel cred = UserCredentialModel.password(password);
             if (!session.users().validCredentials(session, realm, user, cred)) {
                 setReferrerOnPage();
+                errorEvent.error(Errors.INVALID_USER_CREDENTIALS);
                 return account.setError(Messages.INVALID_PASSWORD_EXISTING).createResponse(AccountPages.PASSWORD);
             }
         }
 
         if (Validation.isBlank(passwordNew)) {
             setReferrerOnPage();
+            errorEvent.error(Errors.PASSWORD_MISSING);
             return account.setError(Messages.MISSING_PASSWORD).createResponse(AccountPages.PASSWORD);
         }
 
         if (!passwordNew.equals(passwordConfirm)) {
             setReferrerOnPage();
+            errorEvent.error(Errors.PASSWORD_CONFIRM_ERROR);
             return account.setError(Messages.INVALID_PASSWORD_CONFIRM).createResponse(AccountPages.PASSWORD);
         }
 
@@ -639,14 +647,17 @@ public class AccountService extends AbstractSecuredLocalService {
             session.users().updateCredential(realm, user, UserCredentialModel.password(passwordNew));
         } catch (ModelReadOnlyException mre) {
             setReferrerOnPage();
+            errorEvent.error(Errors.NOT_ALLOWED);
             return account.setError(Messages.READ_ONLY_PASSWORD).createResponse(AccountPages.PASSWORD);
-        }catch (ModelException me) {
+        } catch (ModelException me) {
             logger.failedToUpdatePassword(me);
             setReferrerOnPage();
+            errorEvent.detail(Details.REASON, me.getMessage()).error(Errors.PASSWORD_REJECTED);
             return account.setError(me.getMessage(), me.getParameters()).createResponse(AccountPages.PASSWORD);
-        }catch (Exception ape) {
+        } catch (Exception ape) {
             logger.failedToUpdatePassword(ape);
             setReferrerOnPage();
+            errorEvent.detail(Details.REASON, ape.getMessage()).error(Errors.PASSWORD_REJECTED);
             return account.setError(ape.getMessage()).createResponse(AccountPages.PASSWORD);
         }
 
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminEventBuilder.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminEventBuilder.java
index 4a271b1..f4f2c89 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/AdminEventBuilder.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminEventBuilder.java
@@ -26,6 +26,7 @@ import org.keycloak.events.EventStoreProvider;
 import org.keycloak.events.admin.AdminEvent;
 import org.keycloak.events.admin.AuthDetails;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
@@ -86,8 +87,13 @@ public class AdminEventBuilder {
         return this;
     }
 
-    public AdminEventBuilder operation(OperationType e) {
-        adminEvent.setOperationType(e);
+    public AdminEventBuilder operation(OperationType operationType) {
+        adminEvent.setOperationType(operationType);
+        return this;
+    }
+
+    public AdminEventBuilder resource(ResourceType resourceType){
+        adminEvent.setResourceType(resourceType);
         return this;
     }
 
@@ -178,12 +184,6 @@ public class AdminEventBuilder {
         return path.substring(path.indexOf(realmRelative) + realmRelative.length());
     }
 
-    public void error(String error) {
-        adminEvent.setOperationType(OperationType.valueOf(adminEvent.getOperationType().name() + "_ERROR"));
-        adminEvent.setError(error);
-        send();
-    }
-
     public AdminEventBuilder representation(Object value) {
         if (value == null || value.equals("")) {
             return this;
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AttackDetectionResource.java b/services/src/main/java/org/keycloak/services/resources/admin/AttackDetectionResource.java
index 6ffa12c..bf92524 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/AttackDetectionResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AttackDetectionResource.java
@@ -19,9 +19,11 @@ package org.keycloak.services.resources.admin;
 import org.jboss.resteasy.annotations.cache.NoCache;
 import org.keycloak.common.ClientConnection;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
-import org.keycloak.models.UsernameLoginFailureModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserLoginFailureModel;
 import org.keycloak.services.ServicesLogger;
 import org.keycloak.services.managers.BruteForceProtector;
 
@@ -64,7 +66,7 @@ public class AttackDetectionResource {
     public AttackDetectionResource(RealmAuth auth, RealmModel realm, AdminEventBuilder adminEvent) {
         this.auth = auth;
         this.realm = realm;
-        this.adminEvent = adminEvent.realm(realm);
+        this.adminEvent = adminEvent.realm(realm).resource(ResourceType.USER_LOGIN_FAILURE);
 
         auth.init(RealmAuth.Resource.USER);
     }
@@ -72,14 +74,14 @@ public class AttackDetectionResource {
     /**
      * Get status of a username in brute force detection
      *
-     * @param username
+     * @param userId
      * @return
      */
     @GET
-    @Path("brute-force/usernames/{username}")
+    @Path("brute-force/users/{userId}")
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
-    public Map<String, Object> bruteForceUserStatus(@PathParam("username") String username) {
+    public Map<String, Object> bruteForceUserStatus(@PathParam("userId") String userId) {
         auth.requireView();
 
         Map<String, Object> data = new HashMap<>();
@@ -89,9 +91,11 @@ public class AttackDetectionResource {
         data.put("lastIPFailure", "n/a");
         if (!realm.isBruteForceProtected()) return data;
 
-        UsernameLoginFailureModel model = session.sessions().getUserLoginFailure(realm, username.toLowerCase());
+        UserModel user = session.users().getUserById(userId, realm);
+
+        UserLoginFailureModel model = session.sessions().getUserLoginFailure(realm, userId);
         if (model == null) return data;
-        if (session.getProvider(BruteForceProtector.class).isTemporarilyDisabled(session, realm, username)) {
+        if (session.getProvider(BruteForceProtector.class).isTemporarilyDisabled(session, realm, user)) {
             data.put("disabled", true);
         }
         data.put("numFailures", model.getNumFailures());
@@ -105,16 +109,16 @@ public class AttackDetectionResource {
      *
      * This can release temporary disabled user
      *
-     * @param username
+     * @param userId
      */
-    @Path("brute-force/usernames/{username}")
+    @Path("brute-force/users/{userId}")
     @DELETE
-    public void clearBruteForceForUser(@PathParam("username") String username) {
+    public void clearBruteForceForUser(@PathParam("userId") String userId) {
         auth.requireManage();
 
-        UsernameLoginFailureModel model = session.sessions().getUserLoginFailure(realm, username.toLowerCase());
+        UserLoginFailureModel model = session.sessions().getUserLoginFailure(realm, userId);
         if (model != null) {
-            session.sessions().removeUserLoginFailure(realm, username);
+            session.sessions().removeUserLoginFailure(realm, userId);
             adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
         }
     }
@@ -125,7 +129,7 @@ public class AttackDetectionResource {
      * This can release temporary disabled users
      *
      */
-    @Path("brute-force/usernames")
+    @Path("brute-force/users")
     @DELETE
     public void clearAllBruteForce() {
         auth.requireManage();
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java b/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java
index b481a75..4e1d7a4 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java
@@ -29,6 +29,7 @@ import org.keycloak.authentication.FormAuthenticator;
 import org.keycloak.authentication.RequiredActionFactory;
 import org.keycloak.authentication.RequiredActionProvider;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.AuthenticationExecutionModel;
 import org.keycloak.models.AuthenticationFlowModel;
 import org.keycloak.models.AuthenticatorConfigModel;
@@ -89,7 +90,7 @@ public class AuthenticationManagementResource {
         this.session = session;
         this.auth = auth;
         this.auth.init(RealmAuth.Resource.REALM);
-        this.adminEvent = adminEvent;
+        this.adminEvent = adminEvent.resource(ResourceType.AUTH_FLOW);
     }
 
     /**
@@ -375,7 +376,7 @@ public class AuthenticationManagementResource {
         execution = realm.addAuthenticatorExecution(execution);
 
         data.put("id", execution.getId());
-        adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(data).success();
+        adminEvent.operation(OperationType.CREATE).resource(ResourceType.AUTH_EXECUTION_FLOW).resourcePath(uriInfo).representation(data).success();
     }
 
     private int getNextPriority(AuthenticationFlowModel parentFlow) {
@@ -428,7 +429,7 @@ public class AuthenticationManagementResource {
         execution = realm.addAuthenticatorExecution(execution);
 
         data.put("id", execution.getId());
-        adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(data).success();
+        adminEvent.operation(OperationType.CREATE).resource(ResourceType.AUTH_EXECUTION).resourcePath(uriInfo).representation(data).success();
     }
 
     /**
@@ -498,6 +499,15 @@ public class AuthenticationManagementResource {
                     rep.getRequirementChoices().add(choice.name());
                 }
                 rep.setId(execution.getId());
+
+                if (factory.isConfigurable()) {
+                    AuthenticatorConfigModel authenticatorConfig = realm.getAuthenticatorConfigById(execution.getAuthenticatorConfig());
+
+                    if (authenticatorConfig != null) {
+                        rep.setAlias(authenticatorConfig.getAlias());
+                    }
+                }
+
                 rep.setRequirement(execution.getRequirement().name());
                 rep.setProviderId(execution.getAuthenticator());
                 rep.setAuthenticationConfig(execution.getAuthenticatorConfig());
@@ -527,14 +537,14 @@ public class AuthenticationManagementResource {
 
         AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(rep.getId());
         if (model == null) {
-            session.getTransaction().setRollbackOnly();
+            session.getTransactionManager().setRollbackOnly();
             throw new NotFoundException("Illegal execution");
 
         }
         if (!model.getRequirement().name().equals(rep.getRequirement())) {
             model.setRequirement(AuthenticationExecutionModel.Requirement.valueOf(rep.getRequirement()));
             realm.updateAuthenticatorExecution(model);
-            adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
+            adminEvent.operation(OperationType.UPDATE).resource(ResourceType.AUTH_EXECUTION).resourcePath(uriInfo).representation(rep).success();
         }
     }
 
@@ -558,7 +568,7 @@ public class AuthenticationManagementResource {
         model.setPriority(getNextPriority(parentFlow));
         model = realm.addAuthenticatorExecution(model);
 
-        adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, model.getId()).representation(execution).success();
+        adminEvent.operation(OperationType.CREATE).resource(ResourceType.AUTH_EXECUTION).resourcePath(uriInfo, model.getId()).representation(execution).success();
         return Response.created(uriInfo.getAbsolutePathBuilder().path(model.getId()).build()).build();
     }
 
@@ -587,7 +597,7 @@ public class AuthenticationManagementResource {
 
         AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
         if (model == null) {
-            session.getTransaction().setRollbackOnly();
+            session.getTransactionManager().setRollbackOnly();
             throw new NotFoundException("Illegal execution");
 
         }
@@ -611,7 +621,7 @@ public class AuthenticationManagementResource {
         model.setPriority(tmp);
         realm.updateAuthenticatorExecution(model);
 
-        adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).success();
+        adminEvent.operation(OperationType.UPDATE).resource(ResourceType.AUTH_EXECUTION).resourcePath(uriInfo).success();
     }
 
     public List<AuthenticationExecutionModel> getSortedExecutions(AuthenticationFlowModel parentFlow) {
@@ -633,7 +643,7 @@ public class AuthenticationManagementResource {
 
         AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
         if (model == null) {
-            session.getTransaction().setRollbackOnly();
+            session.getTransactionManager().setRollbackOnly();
             throw new NotFoundException("Illegal execution");
 
         }
@@ -656,7 +666,7 @@ public class AuthenticationManagementResource {
         next.setPriority(tmp);
         realm.updateAuthenticatorExecution(next);
 
-        adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).success();
+        adminEvent.operation(OperationType.UPDATE).resource(ResourceType.AUTH_EXECUTION).resourcePath(uriInfo).success();
     }
 
 
@@ -673,7 +683,7 @@ public class AuthenticationManagementResource {
 
         AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
         if (model == null) {
-            session.getTransaction().setRollbackOnly();
+            session.getTransactionManager().setRollbackOnly();
             throw new NotFoundException("Illegal execution");
 
         }
@@ -689,7 +699,7 @@ public class AuthenticationManagementResource {
 
         realm.removeAuthenticatorExecution(model);
 
-        adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
+        adminEvent.operation(OperationType.DELETE).resource(ResourceType.AUTH_EXECUTION).resourcePath(uriInfo).success();
     }
 
 
@@ -709,7 +719,7 @@ public class AuthenticationManagementResource {
 
         AuthenticationExecutionModel model = realm.getAuthenticationExecutionById(execution);
         if (model == null) {
-            session.getTransaction().setRollbackOnly();
+            session.getTransactionManager().setRollbackOnly();
             throw new NotFoundException("Illegal execution");
 
         }
@@ -719,7 +729,7 @@ public class AuthenticationManagementResource {
         realm.updateAuthenticatorExecution(model);
 
         json.setId(config.getId());
-        adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(json).success();
+        adminEvent.operation(OperationType.CREATE).resource(ResourceType.AUTH_EXECUTION).resourcePath(uriInfo).representation(json).success();
         return Response.created(uriInfo.getAbsolutePathBuilder().path(config.getId()).build()).build();
     }
 
@@ -802,7 +812,7 @@ public class AuthenticationManagementResource {
         requiredAction = realm.addRequiredActionProvider(requiredAction);
 
         data.put("id", requiredAction.getId());
-        adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(data).success();
+        adminEvent.operation(OperationType.CREATE).resource(ResourceType.REQUIRED_ACTION).resourcePath(uriInfo).representation(data).success();
     }
 
 
@@ -881,7 +891,7 @@ public class AuthenticationManagementResource {
         update.setConfig(rep.getConfig());
         realm.updateRequiredActionProvider(update);
 
-        adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
+        adminEvent.operation(OperationType.UPDATE).resource(ResourceType.REQUIRED_ACTION).resourcePath(uriInfo).representation(rep).success();
     }
 
     /**
@@ -899,7 +909,7 @@ public class AuthenticationManagementResource {
         }
         realm.removeRequiredActionProvider(model);
 
-        adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
+        adminEvent.operation(OperationType.DELETE).resource(ResourceType.REQUIRED_ACTION).resourcePath(uriInfo).success();
     }
 
     /**
@@ -981,7 +991,7 @@ public class AuthenticationManagementResource {
         auth.requireManage();
 
         AuthenticatorConfigModel config = realm.addAuthenticatorConfig(RepresentationToModel.toModel(rep));
-        adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, config.getId()).representation(rep).success();
+        adminEvent.operation(OperationType.CREATE).resource(ResourceType.AUTHENTICATOR_CONFIG).resourcePath(uriInfo, config.getId()).representation(rep).success();
         return Response.created(uriInfo.getAbsolutePathBuilder().path(config.getId()).build()).build();
     }
 
@@ -1031,7 +1041,7 @@ public class AuthenticationManagementResource {
 
         realm.removeAuthenticatorConfig(config);
 
-        adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
+        adminEvent.operation(OperationType.DELETE).resource(ResourceType.AUTHENTICATOR_CONFIG).resourcePath(uriInfo).success();
     }
 
     /**
@@ -1054,6 +1064,6 @@ public class AuthenticationManagementResource {
         exists.setAlias(rep.getAlias());
         exists.setConfig(rep.getConfig());
         realm.updateAuthenticatorConfig(exists);
-        adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
+        adminEvent.operation(OperationType.UPDATE).resource(ResourceType.AUTHENTICATOR_CONFIG).resourcePath(uriInfo).representation(rep).success();
     }
 }
\ No newline at end of file
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java
index 895bd64..f29ed8c 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java
@@ -24,14 +24,20 @@ import org.jboss.resteasy.spi.NotAcceptableException;
 import org.jboss.resteasy.spi.NotFoundException;
 import org.keycloak.common.util.StreamUtil;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
+import org.keycloak.jose.jwk.JSONWebKeySet;
+import org.keycloak.jose.jwk.JWK;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.protocol.oidc.utils.JWKSUtils;
 import org.keycloak.representations.KeyStoreConfig;
 import org.keycloak.representations.idm.CertificateRepresentation;
 import org.keycloak.services.ErrorResponseException;
 import org.keycloak.common.util.PemUtils;
+import org.keycloak.services.util.CertificateInfoHelper;
+import org.keycloak.util.JsonSerialization;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
@@ -48,6 +54,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.security.KeyStore;
 import java.security.PrivateKey;
+import java.security.PublicKey;
 import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
 import java.util.List;
@@ -59,17 +66,12 @@ import java.util.Map;
  */
 public class ClientAttributeCertificateResource {
 
-    public static final String PRIVATE_KEY = "private.key";
-    public static final String X509CERTIFICATE = "certificate";
-
     protected RealmModel realm;
     private RealmAuth auth;
     protected ClientModel client;
     protected KeycloakSession session;
     protected AdminEventBuilder adminEvent;
     protected String attributePrefix;
-    protected String privateAttribute;
-    protected String certificateAttribute;
 
     public ClientAttributeCertificateResource(RealmModel realm, RealmAuth auth, ClientModel client, KeycloakSession session, String attributePrefix, AdminEventBuilder adminEvent) {
         this.realm = realm;
@@ -77,9 +79,7 @@ public class ClientAttributeCertificateResource {
         this.client = client;
         this.session = session;
         this.attributePrefix = attributePrefix;
-        this.privateAttribute = attributePrefix + "." + PRIVATE_KEY;
-        this.certificateAttribute = attributePrefix + "." + X509CERTIFICATE;
-        this.adminEvent = adminEvent;
+        this.adminEvent = adminEvent.resource(ResourceType.CLIENT);
     }
 
     /**
@@ -97,9 +97,7 @@ public class ClientAttributeCertificateResource {
             throw new NotFoundException("Could not find client");
         }
 
-        CertificateRepresentation info = new CertificateRepresentation();
-        info.setCertificate(client.getAttribute(certificateAttribute));
-        info.setPrivateKey(client.getAttribute(privateAttribute));
+        CertificateRepresentation info = CertificateInfoHelper.getCertificateFromClient(client, attributePrefix);
         return info;
     }
 
@@ -121,8 +119,7 @@ public class ClientAttributeCertificateResource {
 
         CertificateRepresentation info = KeycloakModelUtils.generateKeyPairCertificate(client.getClientId());
 
-        client.setAttribute(privateAttribute, info.getPrivateKey());
-        client.setAttribute(certificateAttribute, info.getCertificate());
+        CertificateInfoHelper.updateClientModelCertificateInfo(client, info, attributePrefix);
 
         adminEvent.operation(OperationType.ACTION).resourcePath(session.getContext().getUri()).representation(info).success();
 
@@ -150,18 +147,12 @@ public class ClientAttributeCertificateResource {
 
         CertificateRepresentation info = getCertFromRequest(uriInfo, input);
 
-        if (info.getPrivateKey() != null) {
-            client.setAttribute(privateAttribute, info.getPrivateKey());
-        } else if (info.getCertificate() != null) {
-            client.removeAttribute(privateAttribute);
-        } else {
+        try {
+            CertificateInfoHelper.updateClientModelCertificateInfo(client, info, attributePrefix);
+        } catch (IllegalStateException ise) {
             throw new ErrorResponseException("certificate-not-found", "Certificate or key with given alias not found in the keystore", Response.Status.BAD_REQUEST);
         }
 
-        if (info.getCertificate() != null) {
-            client.setAttribute(certificateAttribute, info.getCertificate());
-        }
-
         adminEvent.operation(OperationType.ACTION).resourcePath(session.getContext().getUri()).representation(info).success();
         return info;
     }
@@ -171,7 +162,7 @@ public class ClientAttributeCertificateResource {
      *
      * @param uriInfo
      * @param input
-     * @return
+     * @return information extracted from uploaded certificate - not necessarily the new state of certificate on the server
      * @throws IOException
      */
     @POST
@@ -186,11 +177,12 @@ public class ClientAttributeCertificateResource {
         }
 
         CertificateRepresentation info = getCertFromRequest(uriInfo, input);
+        info.setPrivateKey(null);
 
-        if (info.getCertificate() != null) {
-            client.setAttribute(certificateAttribute, info.getCertificate());
-        } else {
-            throw new ErrorResponseException("certificate-not-found", "Certificate with given alias not found in the keystore", Response.Status.BAD_REQUEST);
+        try {
+            CertificateInfoHelper.updateClientModelCertificateInfo(client, info, attributePrefix);
+        } catch (IllegalStateException ise) {
+            throw new ErrorResponseException("certificate-not-found", "Certificate or key with given alias not found in the keystore", Response.Status.BAD_REQUEST);
         }
 
         adminEvent.operation(OperationType.ACTION).resourcePath(session.getContext().getUri()).representation(info).success();
@@ -208,10 +200,16 @@ public class ClientAttributeCertificateResource {
             info.setCertificate(pem);
             return info;
 
+        } else if (keystoreFormat.equals("JSON Web Key Set (JWK)")) {
+            InputStream stream = inputParts.get(0).getBody(InputStream.class, null);
+            JSONWebKeySet keySet = JsonSerialization.readValue(stream, JSONWebKeySet.class);
+            PublicKey publicKey = JWKSUtils.getKeyForUse(keySet, JWK.Use.SIG);
+            String publicKeyPem = KeycloakModelUtils.getPemFromKey(publicKey);
+            info.setPublicKey(publicKeyPem);
+            return info;
         }
 
 
-
         String keyAlias = uploadForm.get("keyAlias").get(0).getBodyAsString();
         List<InputPart> keyPasswordPart = uploadForm.get("keyPassword");
         char[] keyPassword = keyPasswordPart != null ? keyPasswordPart.get(0).getBodyAsString().toCharArray() : null;
@@ -270,8 +268,10 @@ public class ClientAttributeCertificateResource {
             throw new NotAcceptableException("Only support jks or pkcs12 format.");
         }
 
-        String privatePem = client.getAttribute(privateAttribute);
-        String certPem = client.getAttribute(certificateAttribute);
+        CertificateRepresentation info = CertificateInfoHelper.getCertificateFromClient(client, attributePrefix);
+        String privatePem = info.getPrivateKey();
+        String certPem = info.getCertificate();
+
         if (privatePem == null && certPem == null) {
             throw new NotFoundException("keypair not generated for client");
         }
@@ -320,7 +320,10 @@ public class ClientAttributeCertificateResource {
         CertificateRepresentation info = KeycloakModelUtils.generateKeyPairCertificate(client.getClientId());
         byte[] rtn = getKeystore(config, info.getPrivateKey(), info.getCertificate());
 
-        client.setAttribute(certificateAttribute, info.getCertificate());
+        info.setPrivateKey(null);
+
+        CertificateInfoHelper.updateClientModelCertificateInfo(client, info, attributePrefix);
+
         adminEvent.operation(OperationType.ACTION).resourcePath(session.getContext().getUri()).representation(info).success();
         return rtn;
     }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientInitialAccessResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientInitialAccessResource.java
index a2c35d8..696af18 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientInitialAccessResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientInitialAccessResource.java
@@ -18,6 +18,7 @@
 package org.keycloak.services.resources.admin;
 
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.ClientInitialAccessModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
@@ -49,7 +50,7 @@ public class ClientInitialAccessResource {
     public ClientInitialAccessResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
         this.auth = auth;
         this.realm = realm;
-        this.adminEvent = adminEvent;
+        this.adminEvent = adminEvent.resource(ResourceType.CLIENT_INITIAL_ACCESS_MODEL);
 
         auth.init(RealmAuth.Resource.CLIENT);
     }
@@ -73,8 +74,8 @@ public class ClientInitialAccessResource {
 
         adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, clientInitialAccessModel.getId()).representation(config).success();
 
-        if (session.getTransaction().isActive()) {
-            session.getTransaction().commit();
+        if (session.getTransactionManager().isActive()) {
+            session.getTransactionManager().commit();
         }
 
         ClientInitialAccessPresentation rep = wrap(clientInitialAccessModel);
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientRegistrationTrustedHostResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientRegistrationTrustedHostResource.java
new file mode 100644
index 0000000..000885f
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientRegistrationTrustedHostResource.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.services.resources.admin;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.jboss.resteasy.spi.NotFoundException;
+import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
+import org.keycloak.models.ClientRegistrationTrustedHostModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.ModelDuplicateException;
+import org.keycloak.models.RealmModel;
+import org.keycloak.representations.idm.ClientRegistrationTrustedHostRepresentation;
+import org.keycloak.services.ErrorResponse;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ClientRegistrationTrustedHostResource {
+
+    private final RealmAuth auth;
+    private final RealmModel realm;
+    private final AdminEventBuilder adminEvent;
+
+    @Context
+    protected KeycloakSession session;
+
+    @Context
+    protected UriInfo uriInfo;
+
+    public ClientRegistrationTrustedHostResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
+        this.auth = auth;
+        this.realm = realm;
+        this.adminEvent = adminEvent.resource(ResourceType.CLIENT_REGISTRATION_TRUSTED_HOST_MODEL);
+
+        auth.init(RealmAuth.Resource.CLIENT);
+    }
+
+    /**
+     * Create a new initial access token.
+     *
+     * @param config
+     * @return
+     */
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response create(ClientRegistrationTrustedHostRepresentation config) {
+        auth.requireManage();
+
+        if (config.getHostName() == null) {
+            return ErrorResponse.error("hostName not provided in config", Response.Status.BAD_REQUEST);
+        }
+
+        int count = config.getCount() != null ? config.getCount() : 1;
+
+        try {
+            ClientRegistrationTrustedHostModel clientRegTrustedHostModel = session.sessions().createClientRegistrationTrustedHostModel(realm, config.getHostName(), count);
+
+            adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, clientRegTrustedHostModel.getHostName()).representation(config).success();
+
+            return Response.created(uriInfo.getAbsolutePathBuilder().path(clientRegTrustedHostModel.getHostName()).build()).build();
+        } catch (ModelDuplicateException mde) {
+            return ErrorResponse.exists(mde.getMessage());
+        }
+    }
+
+    /**
+     * Update a new initial access token.
+     *
+     * @param config
+     * @return
+     */
+    @PUT
+    @Path("{hostname}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response update(final @PathParam("hostname") String hostName, ClientRegistrationTrustedHostRepresentation config) {
+        auth.requireManage();
+
+        if (config.getHostName() == null || !hostName.equals(config.getHostName())) {
+            return ErrorResponse.error("hostName not provided in config or not compatible", Response.Status.BAD_REQUEST);
+        }
+
+        if (config.getCount() == null) {
+            return ErrorResponse.error("count needs to be available", Response.Status.BAD_REQUEST);
+        }
+
+        if (config.getRemainingCount() != null && config.getRemainingCount() > config.getCount()) {
+            return ErrorResponse.error("remainingCount can't be bigger than count", Response.Status.BAD_REQUEST);
+        }
+
+        ClientRegistrationTrustedHostModel hostModel = session.sessions().getClientRegistrationTrustedHostModel(realm, config.getHostName());
+        if (hostModel == null) {
+            return ErrorResponse.error("hostName record not found", Response.Status.NOT_FOUND);
+        }
+
+        hostModel.setCount(config.getCount());
+        hostModel.setRemainingCount(config.getRemainingCount());
+
+        adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(config).success();
+        return Response.noContent().build();
+    }
+
+    /**
+     * Get an initial access token.
+     *
+     * @param hostName
+     * @return
+     */
+    @GET
+    @Path("{hostname}")
+    @Produces(MediaType.APPLICATION_JSON)
+    public ClientRegistrationTrustedHostRepresentation getConfig(final @PathParam("hostname") String hostName) {
+        auth.requireView();
+
+        ClientRegistrationTrustedHostModel hostModel = session.sessions().getClientRegistrationTrustedHostModel(realm, hostName);
+        if (hostModel == null) {
+            throw new NotFoundException("hostName record not found");
+        }
+
+        return wrap(hostModel);
+    }
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public List<ClientRegistrationTrustedHostRepresentation> list() {
+        auth.requireView();
+
+        List<ClientRegistrationTrustedHostModel> models = session.sessions().listClientRegistrationTrustedHosts(realm);
+        List<ClientRegistrationTrustedHostRepresentation> reps = new LinkedList<>();
+        for (ClientRegistrationTrustedHostModel m : models) {
+            ClientRegistrationTrustedHostRepresentation r = wrap(m);
+            reps.add(r);
+        }
+        return reps;
+    }
+
+    @DELETE
+    @Path("{hostname}")
+    public void delete(final @PathParam("hostname") String hostName) {
+        auth.requireManage();
+
+        session.sessions().removeClientRegistrationTrustedHostModel(realm, hostName);
+        adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
+    }
+
+    private ClientRegistrationTrustedHostRepresentation wrap(ClientRegistrationTrustedHostModel model) {
+        return ClientRegistrationTrustedHostRepresentation.create(model.getHostName(), model.getCount(), model.getRemainingCount());
+    }
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
index 08177b9..fc5b3c9 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
@@ -20,7 +20,9 @@ import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.BadRequestException;
 import org.jboss.resteasy.spi.NotFoundException;
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.keycloak.authorization.admin.AuthorizationService;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.KeycloakSession;
@@ -98,7 +100,7 @@ public class ClientResource {
         this.auth = auth;
         this.client = clientModel;
         this.session = session;
-        this.adminEvent = adminEvent;
+        this.adminEvent = adminEvent.resource(ResourceType.CLIENT);
 
         auth.init(RealmAuth.Resource.CLIENT);
     }
@@ -133,12 +135,18 @@ public class ClientResource {
         }
     }
 
-    public static void updateClientFromRep(ClientRepresentation rep, ClientModel client, KeycloakSession session) throws ModelDuplicateException {
+    public void updateClientFromRep(ClientRepresentation rep, ClientModel client, KeycloakSession session) throws ModelDuplicateException {
         if (TRUE.equals(rep.isServiceAccountsEnabled()) && !client.isServiceAccountsEnabled()) {
             new ClientManager(new RealmManager(session)).enableServiceAccount(client);
         }
 
         RepresentationToModel.updateClient(rep, client);
+
+        if (TRUE.equals(rep.getAuthorizationServicesEnabled())) {
+            authorization().enable();
+        } else {
+            authorization().disable();
+        }
     }
 
     /**
@@ -156,7 +164,11 @@ public class ClientResource {
             throw new NotFoundException("Could not find client");
         }
 
-        return ModelToRepresentation.toRepresentation(client);
+        ClientRepresentation representation = ModelToRepresentation.toRepresentation(client);
+
+        representation.setAuthorizationServicesEnabled(authorization().isEnabled());
+
+        return representation;
     }
 
     /**
@@ -304,11 +316,11 @@ public class ClientResource {
             throw new NotFoundException("Could not find client");
         }
 
-        UserModel user = session.users().getUserByServiceAccountClient(client);
+        UserModel user = session.users().getServiceAccount(client);
         if (user == null) {
             if (client.isServiceAccountsEnabled()) {
                 new ClientManager(new RealmManager(session)).enableServiceAccount(client);
-                user = session.users().getUserByServiceAccountClient(client);
+                user = session.users().getServiceAccount(client);
             } else {
                 throw new BadRequestException("Service account not enabled for the client '" + client.getClientId() + "'");
             }
@@ -332,7 +344,7 @@ public class ClientResource {
             throw new NotFoundException("Could not find client");
         }
 
-        adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
+        adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).resource(ResourceType.CLIENT).success();
         return new ResourceAdminManager(session).pushClientRevocationPolicy(uriInfo.getRequestUri(), realm, client);
 
     }
@@ -485,7 +497,7 @@ public class ClientResource {
         }
         if (logger.isDebugEnabled()) logger.debug("Register node: " + node);
         client.registerNode(node, Time.currentTime());
-        adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, node).success();
+        adminEvent.operation(OperationType.CREATE).resource(ResourceType.CLUSTER_NODE).resourcePath(uriInfo, node).success();
     }
 
     /**
@@ -510,7 +522,7 @@ public class ClientResource {
             throw new NotFoundException("Client does not have node ");
         }
         client.unregisterNode(node);
-        adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
+        adminEvent.operation(OperationType.DELETE).resource(ResourceType.CLUSTER_NODE).resourcePath(uriInfo).success();
     }
 
     /**
@@ -533,8 +545,16 @@ public class ClientResource {
 
         logger.debug("Test availability of cluster nodes");
         GlobalRequestResult result = new ResourceAdminManager(session).testNodesAvailability(uriInfo.getRequestUri(), realm, client);
-        adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).representation(result).success();
+        adminEvent.operation(OperationType.ACTION).resource(ResourceType.CLUSTER_NODE).resourcePath(uriInfo).representation(result).success();
         return result;
     }
 
+    @Path("/authz")
+    public AuthorizationService authorization() {
+        AuthorizationService resource = new AuthorizationService(this.session, this.client, this.auth);
+
+        ResteasyProviderFactory.getInstance().injectProperties(resource);
+
+        return resource;
+    }
 }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientRoleMappingsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientRoleMappingsResource.java
index a1c0433..11fe9ef 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientRoleMappingsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientRoleMappingsResource.java
@@ -19,6 +19,7 @@ package org.keycloak.services.resources.admin;
 import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.NotFoundException;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ModelException;
@@ -70,7 +71,7 @@ public class ClientRoleMappingsResource {
         this.auth = auth;
         this.user = user;
         this.client = client;
-        this.adminEvent = adminEvent;
+        this.adminEvent = adminEvent.resource(ResourceType.CLIENT_ROLE_MAPPING);
     }
 
     /**
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java
index 8690862..207f8d1 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientsResource.java
@@ -20,6 +20,7 @@ import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.NotFoundException;
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ModelDuplicateException;
@@ -63,7 +64,7 @@ public class ClientsResource {
     public ClientsResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
         this.realm = realm;
         this.auth = auth;
-        this.adminEvent = adminEvent;
+        this.adminEvent = adminEvent.resource(ResourceType.CLIENT);
 
         auth.init(RealmAuth.Resource.CLIENT);
     }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientTemplateResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientTemplateResource.java
index 94e2382..baf9bb6 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientTemplateResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientTemplateResource.java
@@ -20,6 +20,7 @@ import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.NotFoundException;
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.ClientTemplateModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ModelDuplicateException;
@@ -73,7 +74,7 @@ public class ClientTemplateResource {
         this.auth = auth;
         this.template = template;
         this.session = session;
-        this.adminEvent = adminEvent;
+        this.adminEvent = adminEvent.resource(ResourceType.CLIENT_TEMPLATE);
 
         auth.init(RealmAuth.Resource.CLIENT);
     }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientTemplatesResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientTemplatesResource.java
index 6015a3e..46bcb55 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientTemplatesResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientTemplatesResource.java
@@ -20,6 +20,7 @@ import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.NotFoundException;
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.ClientTemplateModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ModelDuplicateException;
@@ -61,7 +62,7 @@ public class ClientTemplatesResource {
     public ClientTemplatesResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
         this.realm = realm;
         this.auth = auth;
-        this.adminEvent = adminEvent;
+        this.adminEvent = adminEvent.resource(ResourceType.CLIENT_TEMPLATE);
 
         auth.init(RealmAuth.Resource.CLIENT);
     }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ComponentResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ComponentResource.java
new file mode 100644
index 0000000..4ba8fa3
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ComponentResource.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.services.resources.admin;
+
+import org.jboss.resteasy.spi.NotFoundException;
+import org.keycloak.common.ClientConnection;
+import org.keycloak.component.ComponentModel;
+import org.keycloak.events.admin.OperationType;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.utils.ModelToRepresentation;
+import org.keycloak.models.utils.RepresentationToModel;
+import org.keycloak.protocol.oidc.TokenManager;
+import org.keycloak.representations.idm.ComponentRepresentation;
+import org.keycloak.services.ServicesLogger;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ComponentResource {
+    protected static final ServicesLogger logger = ServicesLogger.ROOT_LOGGER;
+
+    protected RealmModel realm;
+
+    private RealmAuth auth;
+
+    private AdminEventBuilder adminEvent;
+
+    @Context
+    protected ClientConnection clientConnection;
+
+    @Context
+    protected UriInfo uriInfo;
+
+    @Context
+    protected KeycloakSession session;
+
+    @Context
+    protected HttpHeaders headers;
+
+    public ComponentResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
+        this.auth = auth;
+        this.realm = realm;
+        this.adminEvent = adminEvent;
+
+        auth.init(RealmAuth.Resource.USER);
+    }
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public List<ComponentRepresentation> getComponents(@QueryParam("parent") String parent, @QueryParam("type") String type) {
+        auth.requireManage();
+        List<ComponentModel> components = Collections.EMPTY_LIST;
+        if (parent == null) {
+            components = realm.getComponents();
+
+        } else if (type == null) {
+            components = realm.getComponents(parent);
+        } else {
+            components = realm.getComponents(parent, type);
+        }
+        List<ComponentRepresentation> reps = new LinkedList<>();
+        for (ComponentModel component : components) {
+            ComponentRepresentation rep = ModelToRepresentation.toRepresentation(component);
+            reps.add(rep);
+        }
+        return reps;
+    }
+
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response create(ComponentRepresentation rep) {
+        auth.requireManage();
+        ComponentModel model = RepresentationToModel.toModel(rep);
+        if (model.getParentId() == null) model.setParentId(realm.getId());
+        adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, model.getId()).representation(rep).success();
+
+
+
+        model = realm.addComponentModel(model);
+        return Response.created(uriInfo.getAbsolutePathBuilder().path(model.getId()).build()).build();
+    }
+
+    @GET
+    @Path("{id}")
+    public ComponentRepresentation getComponent(@PathParam("id") String id) {
+        auth.requireManage();
+        ComponentModel model = realm.getComponent(id);
+        if (model == null) {
+            throw new NotFoundException("Could not find component");
+        }
+        return ModelToRepresentation.toRepresentation(model);
+
+
+    }
+
+    @PUT
+    @Path("{id}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void updateComponent(@PathParam("id") String id, ComponentRepresentation rep) {
+        auth.requireManage();
+        ComponentModel model = realm.getComponent(id);
+        if (model == null) {
+            throw new NotFoundException("Could not find component");
+        }
+        model = RepresentationToModel.toModel(rep);
+        model.setId(id);
+        adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo, model.getId()).representation(rep).success();
+        realm.updateComponent(model);
+
+    }
+    @DELETE
+    @Path("{id}")
+    public void removeComponent(@PathParam("id") String id) {
+        auth.requireManage();
+        ComponentModel model = realm.getComponent(id);
+        if (model == null) {
+            throw new NotFoundException("Could not find component");
+        }
+        adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo, model.getId()).success();
+        realm.removeComponent(model);
+
+    }
+
+
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/GroupResource.java b/services/src/main/java/org/keycloak/services/resources/admin/GroupResource.java
index a22002c..e3cc87f 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/GroupResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/GroupResource.java
@@ -20,6 +20,7 @@ import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.NotFoundException;
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.GroupModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
@@ -62,7 +63,7 @@ public class GroupResource {
         this.realm = realm;
         this.session = session;
         this.auth = auth;
-        this.adminEvent = adminEvent;
+        this.adminEvent = adminEvent.resource(ResourceType.GROUP);
         this.group = group;
     }
 
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/GroupsResource.java b/services/src/main/java/org/keycloak/services/resources/admin/GroupsResource.java
index 7b164a5..f670f57 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/GroupsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/GroupsResource.java
@@ -20,6 +20,7 @@ import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.NotFoundException;
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.GroupModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
@@ -53,7 +54,7 @@ public class GroupsResource {
         this.realm = realm;
         this.session = session;
         this.auth = auth;
-        this.adminEvent = adminEvent;
+        this.adminEvent = adminEvent.resource(ResourceType.GROUP);
         auth.init(RealmAuth.Resource.USER);
 
     }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
index a664b75..d92bd46 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProviderResource.java
@@ -22,6 +22,7 @@ import org.keycloak.broker.provider.IdentityProvider;
 import org.keycloak.broker.provider.IdentityProviderFactory;
 import org.keycloak.broker.provider.IdentityProviderMapper;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.IdentityProviderMapperModel;
 import org.keycloak.models.IdentityProviderModel;
@@ -82,7 +83,7 @@ public class IdentityProviderResource {
         this.session = session;
         this.identityProviderModel = identityProviderModel;
         this.auth = auth;
-        this.adminEvent = adminEvent;
+        this.adminEvent = adminEvent.resource(ResourceType.IDENTITY_PROVIDER);
     }
 
     /**
@@ -317,7 +318,7 @@ public class IdentityProviderResource {
         IdentityProviderMapperModel model = RepresentationToModel.toModel(mapper);
         model = realm.addIdentityProviderMapper(model);
 
-        adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, model.getId())
+        adminEvent.operation(OperationType.CREATE).resource(ResourceType.IDENTITY_PROVIDER_MAPPER).resourcePath(uriInfo, model.getId())
             .representation(mapper).success();
 
         return Response.created(uriInfo.getAbsolutePathBuilder().path(model.getId()).build()).build();
@@ -367,7 +368,7 @@ public class IdentityProviderResource {
         if (model == null) throw new NotFoundException("Model not found");
         model = RepresentationToModel.toModel(rep);
         realm.updateIdentityProviderMapper(model);
-        adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
+        adminEvent.operation(OperationType.UPDATE).resource(ResourceType.IDENTITY_PROVIDER_MAPPER).resourcePath(uriInfo).representation(rep).success();
 
     }
 
@@ -389,7 +390,7 @@ public class IdentityProviderResource {
         IdentityProviderMapperModel model = realm.getIdentityProviderMapperById(id);
         if (model == null) throw new NotFoundException("Model not found");
         realm.removeIdentityProviderMapper(model);
-        adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
+        adminEvent.operation(OperationType.DELETE).resource(ResourceType.IDENTITY_PROVIDER_MAPPER).resourcePath(uriInfo).success();
 
     }
 
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java
index 953cb38..958a849 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/IdentityProvidersResource.java
@@ -25,6 +25,7 @@ import org.keycloak.broker.provider.IdentityProvider;
 import org.keycloak.broker.provider.IdentityProviderFactory;
 import org.keycloak.connections.httpclient.HttpClientProvider;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.IdentityProviderModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ModelDuplicateException;
@@ -71,7 +72,7 @@ public class IdentityProvidersResource {
         this.session = session;
         this.auth = auth;
         this.auth.init(RealmAuth.Resource.IDENTITY_PROVIDER);
-        this.adminEvent = adminEvent;
+        this.adminEvent = adminEvent.resource(ResourceType.IDENTITY_PROVIDER);
     }
 
     /**
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java
index 3ea8fd1..a7195e1 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/info/ServerInfoAdminResource.java
@@ -33,8 +33,16 @@ import javax.ws.rs.core.Context;
 
 import org.keycloak.broker.provider.IdentityProvider;
 import org.keycloak.broker.provider.IdentityProviderFactory;
+import org.keycloak.common.util.MultivaluedHashMap;
 import org.keycloak.events.EventType;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
+import org.keycloak.models.PasswordPolicy;
+import org.keycloak.policy.PasswordPolicyProvider;
+import org.keycloak.policy.PasswordPolicyProviderFactory;
+import org.keycloak.provider.*;
+import org.keycloak.representations.idm.ComponentTypeRepresentation;
+import org.keycloak.representations.idm.PasswordPolicyTypeRepresentation;
 import org.keycloak.theme.Theme;
 import org.keycloak.theme.ThemeProvider;
 import org.keycloak.models.KeycloakSession;
@@ -44,10 +52,6 @@ import org.keycloak.protocol.ClientInstallationProvider;
 import org.keycloak.protocol.LoginProtocol;
 import org.keycloak.protocol.LoginProtocolFactory;
 import org.keycloak.protocol.ProtocolMapper;
-import org.keycloak.provider.ProviderConfigProperty;
-import org.keycloak.provider.ProviderFactory;
-import org.keycloak.provider.ServerInfoAwareProviderFactory;
-import org.keycloak.provider.Spi;
 import org.keycloak.representations.idm.ConfigPropertyRepresentation;
 import org.keycloak.representations.idm.ProtocolMapperRepresentation;
 import org.keycloak.representations.idm.ProtocolMapperTypeRepresentation;
@@ -65,7 +69,7 @@ import org.keycloak.representations.info.ThemeInfoRepresentation;
  */
 public class ServerInfoAdminResource {
 
-    private static final Map<String, List<String>> ENUMS = createEnumsMap(EventType.class, OperationType.class);
+    private static final Map<String, List<String>> ENUMS = createEnumsMap(EventType.class, OperationType.class, ResourceType.class);
 
     @Context
     private KeycloakSession session;
@@ -88,11 +92,13 @@ public class ServerInfoAdminResource {
         setProtocolMapperTypes(info);
         setBuiltinProtocolMappers(info);
         setClientInstallations(info);
+        setPasswordPolicies(info);
         info.setEnums(ENUMS);
         return info;
     }
 
     private void setProviders(ServerInfoRepresentation info) {
+        info.setComponentTypes(new HashMap<>());
         LinkedHashMap<String, SpiInfoRepresentation> spiReps = new LinkedHashMap<>();
 
         List<Spi> spis = new LinkedList<>(session.getKeycloakSessionFactory().getSpis());
@@ -119,6 +125,21 @@ public class ServerInfoAdminResource {
                     if (ServerInfoAwareProviderFactory.class.isAssignableFrom(pi.getClass())) {
                         provider.setOperationalInfo(((ServerInfoAwareProviderFactory) pi).getOperationalInfo());
                     }
+                    if (pi instanceof ConfiguredProvider) {
+                        ComponentTypeRepresentation rep = new ComponentTypeRepresentation();
+                        rep.setId(pi.getId());
+                        ConfiguredProvider configured = (ConfiguredProvider)pi;
+                        rep.setHelpText(configured.getHelpText());
+                        List<ProviderConfigProperty> configProperties = configured.getConfigProperties();
+                        if (configProperties == null) configProperties = Collections.EMPTY_LIST;
+                        rep.setProperties(ModelToRepresentation.toRepresentation(configProperties));
+                        List<ComponentTypeRepresentation> reps = info.getComponentTypes().get(spi.getProviderClass().getName());
+                        if (reps == null) {
+                            reps = new LinkedList<>();
+                            info.getComponentTypes().put(spi.getProviderClass().getName(), reps);
+                        }
+                        reps.add(rep);
+                    }
                     providers.put(name, provider);
                 }
             }
@@ -223,15 +244,7 @@ public class ServerInfoAdminResource {
             rep.setCategory(mapper.getDisplayCategory());
             rep.setProperties(new LinkedList<ConfigPropertyRepresentation>());
             List<ProviderConfigProperty> configProperties = mapper.getConfigProperties();
-            for (ProviderConfigProperty prop : configProperties) {
-                ConfigPropertyRepresentation propRep = new ConfigPropertyRepresentation();
-                propRep.setName(prop.getName());
-                propRep.setLabel(prop.getLabel());
-                propRep.setType(prop.getType());
-                propRep.setDefaultValue(prop.getDefaultValue());
-                propRep.setHelpText(prop.getHelpText());
-                rep.getProperties().add(propRep);
-            }
+            rep.setProperties(ModelToRepresentation.toRepresentation(configProperties));
             types.add(rep);
         }
     }
@@ -248,6 +261,20 @@ public class ServerInfoAdminResource {
         }
     }
 
+    private void setPasswordPolicies(ServerInfoRepresentation info) {
+        info.setPasswordPolicies(new LinkedList<>());
+        for (ProviderFactory f : session.getKeycloakSessionFactory().getProviderFactories(PasswordPolicyProvider.class)) {
+            PasswordPolicyProviderFactory factory = (PasswordPolicyProviderFactory) f;
+            PasswordPolicyTypeRepresentation rep = new PasswordPolicyTypeRepresentation();
+            rep.setId(factory.getId());
+            rep.setDisplayName(factory.getDisplayName());
+            rep.setConfigType(factory.getConfigType());
+            rep.setDefaultValue(factory.getDefaultConfigValue());
+            rep.setMultipleSupported(factory.isMultiplSupported());
+            info.getPasswordPolicies().add(rep);
+        }
+    }
+
     private static Map<String, List<String>> createEnumsMap(Class... enums) {
         Map<String, List<String>> m = new HashMap<>();
         for (Class e : enums) {
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ProtocolMappersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ProtocolMappersResource.java
index bb3d325..b9da2bf 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ProtocolMappersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ProtocolMappersResource.java
@@ -19,6 +19,7 @@ package org.keycloak.services.resources.admin;
 import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.NotFoundException;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ModelDuplicateException;
 import org.keycloak.models.ProtocolMapperContainerModel;
@@ -70,7 +71,7 @@ public class ProtocolMappersResource {
     public ProtocolMappersResource(ProtocolMapperContainerModel client, RealmAuth auth, AdminEventBuilder adminEvent) {
         this.auth = auth;
         this.client = client;
-        this.adminEvent = adminEvent;
+        this.adminEvent = adminEvent.resource(ResourceType.PROTOCOL_MAPPER);
 
         auth.init(Resource.CLIENT);
     }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
index 6c265bd..4fd941b 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
@@ -31,6 +31,7 @@ import org.keycloak.events.EventType;
 import org.keycloak.events.admin.AdminEvent;
 import org.keycloak.events.admin.AdminEventQuery;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.exportimport.ClientDescriptionConverter;
 import org.keycloak.exportimport.ClientDescriptionConverterFactory;
 import org.keycloak.jose.jws.JWSBuilder;
@@ -86,6 +87,7 @@ import javax.ws.rs.core.UriInfo;
 
 import java.security.PrivateKey;
 import java.security.PublicKey;
+import java.security.cert.X509Certificate;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -126,7 +128,7 @@ public class RealmAdminResource {
         this.auth = auth;
         this.realm = realm;
         this.tokenManager = tokenManager;
-        this.adminEvent = adminEvent.realm(realm);
+        this.adminEvent = adminEvent.realm(realm).resource(ResourceType.REALM);
 
         auth.init(RealmAuth.Resource.REALM);
         auth.requireAny();
@@ -205,6 +207,31 @@ public class RealmAdminResource {
         return resource;
     }
 
+
+    /**
+     * Base path for managing client initial access tokens
+     *
+     * @return
+     */
+    @Path("clients-trusted-hosts")
+    public ClientRegistrationTrustedHostResource getClientRegistrationTrustedHost() {
+        ClientRegistrationTrustedHostResource resource = new ClientRegistrationTrustedHostResource(realm, auth, adminEvent);
+        ResteasyProviderFactory.getInstance().injectProperties(resource);
+        return resource;
+    }
+
+    /**
+     * Base path for managing components under this realm.
+     *
+     * @return
+     */
+    @Path("components")
+    public ComponentResource getComponents() {
+        ComponentResource resource = new ComponentResource(realm, auth, adminEvent);
+        ResteasyProviderFactory.getInstance().injectProperties(resource);
+        return resource;
+    }
+
     /**
      * base path for managing realm-level roles of this realm
      *
@@ -268,7 +295,18 @@ public class RealmAdminResource {
                 }
             }
 
-            RepresentationToModel.updateRealm(rep, realm);
+            if (!"GENERATE".equals(rep.getPublicKey()) && (rep.getCertificate() != null)) {
+                try {
+                    X509Certificate cert = PemUtils.decodeCertificate(rep.getCertificate());
+                    if (cert == null) {
+                        return ErrorResponse.error("Failed to decode certificate", Status.BAD_REQUEST);
+                    }
+                } catch (Exception e)  {
+                    return ErrorResponse.error("Failed to decode certificate", Status.BAD_REQUEST);
+                }
+            }
+
+            RepresentationToModel.updateRealm(rep, realm, session);
 
             // Refresh periodic sync tasks for configured federationProviders
             List<UserFederationProviderModel> federationProviders = realm.getUserFederationProviders();
@@ -309,7 +347,7 @@ public class RealmAdminResource {
      */
     @Path("users")
     public UsersResource users() {
-        UsersResource users = new UsersResource(realm, auth, tokenManager, adminEvent);
+        UsersResource users = new UsersResource(realm, auth, adminEvent);
         ResteasyProviderFactory.getInstance().injectProperties(users);
         //resourceContext.initResource(users);
         return users;
@@ -389,7 +427,7 @@ public class RealmAdminResource {
         UserSessionModel userSession = session.sessions().getUserSession(realm, sessionId);
         if (userSession == null) throw new NotFoundException("Sesssion not found");
         AuthenticationManager.backchannelLogout(session, realm, userSession, uriInfo, connection, headers, true);
-        adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
+        adminEvent.operation(OperationType.DELETE).resource(ResourceType.USER_SESSION).resourcePath(uriInfo).success();
 
     }
 
@@ -484,9 +522,9 @@ public class RealmAdminResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public List<EventRepresentation> getEvents(@QueryParam("type") List<String> types, @QueryParam("client") String client,
-            @QueryParam("user") String user, @QueryParam("dateFrom") String dateFrom, @QueryParam("dateTo") String dateTo,
-            @QueryParam("ipAddress") String ipAddress, @QueryParam("first") Integer firstResult,
-            @QueryParam("max") Integer maxResults) {
+                                               @QueryParam("user") String user, @QueryParam("dateFrom") String dateFrom, @QueryParam("dateTo") String dateTo,
+                                               @QueryParam("ipAddress") String ipAddress, @QueryParam("first") Integer firstResult,
+                                               @QueryParam("max") Integer maxResults) {
         auth.init(RealmAuth.Resource.EVENTS).requireView();
 
         EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
@@ -573,10 +611,11 @@ public class RealmAdminResource {
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
     public List<AdminEventRepresentation> getEvents(@QueryParam("operationTypes") List<String> operationTypes, @QueryParam("authRealm") String authRealm, @QueryParam("authClient") String authClient,
-            @QueryParam("authUser") String authUser, @QueryParam("authIpAddress") String authIpAddress,
-            @QueryParam("resourcePath") String resourcePath, @QueryParam("dateFrom") String dateFrom,
-            @QueryParam("dateTo") String dateTo, @QueryParam("first") Integer firstResult,
-            @QueryParam("max") Integer maxResults) {
+                                                    @QueryParam("authUser") String authUser, @QueryParam("authIpAddress") String authIpAddress,
+                                                    @QueryParam("resourcePath") String resourcePath, @QueryParam("dateFrom") String dateFrom,
+                                                    @QueryParam("dateTo") String dateTo, @QueryParam("first") Integer firstResult,
+                                                    @QueryParam("max") Integer maxResults,
+                                                    @QueryParam("resourceTypes") List<String> resourceTypes) {
         auth.init(RealmAuth.Resource.EVENTS).requireView();
 
         EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
@@ -610,6 +649,16 @@ public class RealmAdminResource {
             query.operation(t);
         }
 
+        if (resourceTypes != null && !resourceTypes.isEmpty()) {
+            ResourceType[] t = new ResourceType[resourceTypes.size()];
+            for (int i = 0; i < t.length; i++) {
+                t[i] = ResourceType.valueOf(resourceTypes.get(i));
+            }
+            query.resourceType(t);
+        }
+
+
+
         if(dateFrom != null) {
             SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
             Date from = null;
@@ -733,7 +782,7 @@ public class RealmAdminResource {
         }
         realm.addDefaultGroup(group);
 
-        adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).success();
+        adminEvent.operation(OperationType.CREATE).resource(ResourceType.GROUP).resourcePath(uriInfo).success();
     }
 
     @DELETE
@@ -748,7 +797,7 @@ public class RealmAdminResource {
         }
         realm.removeDefaultGroup(group);
 
-        adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
+        adminEvent.operation(OperationType.DELETE).resource(ResourceType.GROUP).resourcePath(uriInfo).success();
     }
 
 
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAuth.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAuth.java
index 440241d..176c480 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAuth.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAuth.java
@@ -31,7 +31,7 @@ public class RealmAuth {
     private Resource resource;
 
     public enum Resource {
-        CLIENT, USER, REALM, EVENTS, IDENTITY_PROVIDER, IMPERSONATION
+        CLIENT, USER, REALM, EVENTS, IDENTITY_PROVIDER, IMPERSONATION, AUTHORIZATION
     }
 
     private AdminAuth auth;
@@ -89,6 +89,8 @@ public class RealmAuth {
                 return AdminRoles.VIEW_EVENTS;
             case IDENTITY_PROVIDER:
                 return AdminRoles.VIEW_IDENTITY_PROVIDERS;
+            case AUTHORIZATION:
+                return AdminRoles.VIEW_AUTHORIZATION;
             default:
                 throw new IllegalStateException();
         }
@@ -108,6 +110,8 @@ public class RealmAuth {
                 return AdminRoles.MANAGE_IDENTITY_PROVIDERS;
             case IMPERSONATION:
                 return ImpersonationConstants.IMPERSONATION_ROLE;
+            case AUTHORIZATION:
+                return AdminRoles.MANAGE_AUTHORIZATION;
             default:
                 throw new IllegalStateException();
         }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
index c6407c7..1a9a5c3 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmsAdminResource.java
@@ -105,15 +105,16 @@ public class RealmsAdminResource {
             ClientModel adminApp = auth.getRealm().getClientByClientId(realmManager.getRealmAdminClientId(auth.getRealm()));
             addRealmRep(reps, auth.getRealm(), adminApp);
         }
+
+        if (reps.isEmpty()) {
+            throw new ForbiddenException();
+        }
+
         logger.debug(("getRealms()"));
         return reps;
     }
 
     protected void addRealmRep(List<RealmRepresentation> reps, RealmModel realm, ClientModel realmManagementClient) {
-        if (!auth.hasOneOfAppRole(realmManagementClient, AdminRoles.ALL_REALM_ROLES)) {
-            throw new ForbiddenException();
-        }
-
         if (auth.hasAppRole(realmManagementClient, AdminRoles.VIEW_REALM)) {
             reps.add(ModelToRepresentation.toRepresentation(realm, false));
         } else if (auth.hasOneOfAppRole(realmManagementClient, AdminRoles.ALL_REALM_ROLES)) {
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java
index 99ec68a..8136db4 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleByIdResource.java
@@ -19,6 +19,7 @@ package org.keycloak.services.resources.admin;
 import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.NotFoundException;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
@@ -116,6 +117,13 @@ public class RoleByIdResource extends RoleResource {
 
         RoleModel role = getRoleModel(id);
         deleteRole(role);
+
+        if (role.isClientRole()) {
+            adminEvent.resource(ResourceType.CLIENT_ROLE);
+        } else {
+            adminEvent.resource(ResourceType.REALM_ROLE);
+        }
+
         adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
     }
 
@@ -133,6 +141,13 @@ public class RoleByIdResource extends RoleResource {
 
         RoleModel role = getRoleModel(id);
         updateRole(rep, role);
+
+        if (role.isClientRole()) {
+            adminEvent.resource(ResourceType.CLIENT_ROLE);
+        } else {
+            adminEvent.resource(ResourceType.REALM_ROLE);
+        }
+
         adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
     }
 
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
index e116ca3..15e163d 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleContainerResource.java
@@ -20,6 +20,7 @@ package org.keycloak.services.resources.admin;
 import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.NotFoundException;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.ModelDuplicateException;
 import org.keycloak.models.RealmModel;
@@ -116,6 +117,13 @@ public class RoleContainerResource extends RoleResource {
             role.setScopeParamRequired(scopeParamRequired);
 
             rep.setId(role.getId());
+
+            if (role.isClientRole()) {
+                adminEvent.resource(ResourceType.CLIENT_ROLE);
+            } else {
+                adminEvent.resource(ResourceType.REALM_ROLE);
+            }
+
             adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, role.getName()).representation(rep).success();
 
             return Response.created(uriInfo.getAbsolutePathBuilder().path(role.getName()).build()).build();
@@ -164,13 +172,18 @@ public class RoleContainerResource extends RoleResource {
             throw new NotFoundException("Could not find client");
         }
 
-        RoleRepresentation rep = getRole(roleName);
         RoleModel role = roleContainer.getRole(roleName);
         if (role == null) {
             throw new NotFoundException("Could not find role");
         }
         deleteRole(role);
 
+        if (role.isClientRole()) {
+            adminEvent.resource(ResourceType.CLIENT_ROLE);
+        } else {
+            adminEvent.resource(ResourceType.REALM_ROLE);
+        }
+
         adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
 
     }
@@ -199,6 +212,12 @@ public class RoleContainerResource extends RoleResource {
         try {
             updateRole(rep, role);
 
+            if (role.isClientRole()) {
+                adminEvent.resource(ResourceType.CLIENT_ROLE);
+            } else {
+                adminEvent.resource(ResourceType.REALM_ROLE);
+            }
+
             adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
 
             return Response.noContent().build();
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleMapperResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleMapperResource.java
index 79ae4dc..ecaa474 100644
--- a/services/src/main/java/org/keycloak/services/resources/admin/RoleMapperResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleMapperResource.java
@@ -20,6 +20,7 @@ import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.NotFoundException;
 import org.keycloak.common.ClientConnection;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.ModelException;
@@ -88,7 +89,7 @@ public class RoleMapperResource {
     public RoleMapperResource(RealmModel realm, RealmAuth auth,  RoleMapperModel roleMapper, AdminEventBuilder adminEvent) {
         this.auth = auth;
         this.realm = realm;
-        this.adminEvent = adminEvent;
+        this.adminEvent = adminEvent.resource(ResourceType.REALM_ROLE_MAPPING);
         this.roleMapper = roleMapper;
 
     }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RoleResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RoleResource.java
index f05572e..6e65c33 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RoleResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RoleResource.java
@@ -19,6 +19,7 @@ package org.keycloak.services.resources.admin;
 
 import org.jboss.resteasy.spi.NotFoundException;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
@@ -67,6 +68,12 @@ public abstract class RoleResource {
             role.addCompositeRole(composite);
         }
 
+        if (role.isClientRole()) {
+            adminEvent.resource(ResourceType.CLIENT_ROLE);
+        } else {
+            adminEvent.resource(ResourceType.REALM_ROLE);
+        }
+
         adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo).representation(roles).success();
     }
 
@@ -111,6 +118,12 @@ public abstract class RoleResource {
             role.removeCompositeRole(composite);
         }
 
+        if (role.isClientRole()) {
+            adminEvent.resource(ResourceType.CLIENT_ROLE);
+        } else {
+            adminEvent.resource(ResourceType.REALM_ROLE);
+        }
+
         adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).representation(roles).success();
     }
 }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedClientResource.java
index eb685e4..903c2ce 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedClientResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedClientResource.java
@@ -20,6 +20,7 @@ package org.keycloak.services.resources.admin;
 import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.NotFoundException;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
@@ -60,7 +61,7 @@ public class ScopeMappedClientResource {
         this.scopeContainer = scopeContainer;
         this.session = session;
         this.scopedClient = scopedClient;
-        this.adminEvent = adminEvent;
+        this.adminEvent = adminEvent.resource(ResourceType.CLIENT_SCOPE_MAPPING);
     }
 
     /**
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java
index bf3cb88..e4fe22f 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ScopeMappedResource.java
@@ -20,6 +20,7 @@ package org.keycloak.services.resources.admin;
 import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.NotFoundException;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
@@ -65,7 +66,7 @@ public class ScopeMappedResource {
         this.auth = auth;
         this.scopeContainer = scopeContainer;
         this.session = session;
-        this.adminEvent = adminEvent;
+        this.adminEvent = adminEvent.resource(ResourceType.REALM_SCOPE_MAPPING);
     }
 
     /**
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UserFederationProviderResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UserFederationProviderResource.java
index c8cf4fd..dca3829 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UserFederationProviderResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UserFederationProviderResource.java
@@ -42,6 +42,7 @@ import javax.ws.rs.core.UriInfo;
 import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.NotFoundException;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.mappers.FederationConfigValidationException;
 import org.keycloak.mappers.UserFederationMapper;
 import org.keycloak.mappers.UserFederationMapperFactory;
@@ -87,7 +88,7 @@ public class UserFederationProviderResource {
         this.realm = realm;
         this.auth = auth;
         this.federationProviderModel = federationProviderModel;
-        this.adminEvent = adminEvent;
+        this.adminEvent = adminEvent.resource(ResourceType.USER_FEDERATION_PROVIDER);
     }
 
     /**
@@ -311,7 +312,7 @@ public class UserFederationProviderResource {
 
         model = realm.addUserFederationMapper(model);
 
-        adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, model.getId())
+        adminEvent.operation(OperationType.CREATE).resource(ResourceType.USER_FEDERATION_MAPPER).resourcePath(uriInfo, model.getId())
                 .representation(mapper).success();
 
         return Response.created(uriInfo.getAbsolutePathBuilder().path(model.getId()).build()).build();
@@ -364,7 +365,7 @@ public class UserFederationProviderResource {
         validateModel(model);
 
         realm.updateUserFederationMapper(model);
-        adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
+        adminEvent.operation(OperationType.UPDATE).resource(ResourceType.USER_FEDERATION_MAPPER).resourcePath(uriInfo).representation(rep).success();
 
     }
 
@@ -386,7 +387,7 @@ public class UserFederationProviderResource {
         UserFederationMapperModel model = realm.getUserFederationMapperById(id);
         if (model == null) throw new NotFoundException("Model not found");
         realm.removeUserFederationMapper(model);
-        adminEvent.operation(OperationType.DELETE).resourcePath(uriInfo).success();
+        adminEvent.operation(OperationType.DELETE).resource(ResourceType.USER_FEDERATION_MAPPER).resourcePath(uriInfo).success();
 
     }
 
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UserFederationProvidersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UserFederationProvidersResource.java
index eff1de7..b782462 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UserFederationProvidersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UserFederationProvidersResource.java
@@ -21,7 +21,9 @@ import org.jboss.resteasy.spi.NotFoundException;
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.common.constants.KerberosConstants;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.mappers.FederationConfigValidationException;
+import org.keycloak.models.AuthenticationExecutionModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserFederationProvider;
@@ -83,7 +85,7 @@ public class UserFederationProvidersResource {
     public UserFederationProvidersResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
         this.auth = auth;
         this.realm = realm;
-        this.adminEvent = adminEvent;
+        this.adminEvent = adminEvent.resource(ResourceType.USER_FEDERATION_PROVIDER);
 
         auth.init(RealmAuth.Resource.USER);
     }
@@ -98,7 +100,8 @@ public class UserFederationProvidersResource {
     public static boolean checkKerberosCredential(KeycloakSession session, RealmModel realm, UserFederationProviderModel model) {
         String allowKerberosCfg = model.getConfig().get(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION);
         if (Boolean.valueOf(allowKerberosCfg)) {
-            CredentialHelper.setAlternativeCredential(session, CredentialRepresentation.KERBEROS, realm);
+            CredentialHelper.setOrReplaceAuthenticationRequirement(session, realm, CredentialRepresentation.KERBEROS,
+                    AuthenticationExecutionModel.Requirement.ALTERNATIVE, AuthenticationExecutionModel.Requirement.DISABLED);
             return true;
         }
 
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
index 82ca7dc..3986988 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
@@ -28,6 +28,7 @@ import org.keycloak.events.Details;
 import org.keycloak.events.EventBuilder;
 import org.keycloak.events.EventType;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.ClientSessionModel;
 import org.keycloak.models.Constants;
@@ -46,7 +47,6 @@ import org.keycloak.models.UserSessionModel;
 import org.keycloak.models.utils.ModelToRepresentation;
 import org.keycloak.models.utils.RepresentationToModel;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
-import org.keycloak.protocol.oidc.TokenManager;
 import org.keycloak.protocol.oidc.utils.RedirectUtils;
 import org.keycloak.provider.ProviderFactory;
 import org.keycloak.representations.idm.CredentialRepresentation;
@@ -81,7 +81,6 @@ import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
 import javax.ws.rs.WebApplicationException;
 
-import java.io.IOException;
 import java.net.URI;
 import java.text.MessageFormat;
 import java.util.ArrayList;
@@ -94,15 +93,14 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
-import org.keycloak.models.UsernameLoginFailureModel;
+import org.keycloak.models.UserLoginFailureModel;
 import org.keycloak.services.managers.BruteForceProtector;
 import org.keycloak.services.managers.UserSessionManager;
 import org.keycloak.services.resources.AccountService;
 import org.keycloak.common.util.Time;
 import org.keycloak.services.validation.Validation;
-import org.keycloak.theme.Theme;
-import org.keycloak.theme.Theme.Type;
-import org.keycloak.theme.ThemeProvider;
+
+import static org.keycloak.events.admin.ResourceType.GROUP_MEMBERSHIP;
 
 /**
  * Base resource for managing users
@@ -131,10 +129,10 @@ public class UsersResource {
     @Context
     protected HttpHeaders headers;
 
-    public UsersResource(RealmModel realm, RealmAuth auth, TokenManager tokenManager, AdminEventBuilder adminEvent) {
+    public UsersResource(RealmModel realm, RealmAuth auth, AdminEventBuilder adminEvent) {
         this.auth = auth;
         this.realm = realm;
-        this.adminEvent = adminEvent;
+        this.adminEvent = adminEvent.resource(ResourceType.USER);
 
         auth.init(RealmAuth.Resource.USER);
     }
@@ -166,8 +164,8 @@ public class UsersResource {
                 attrsToRemove = Collections.emptySet();
             }
 
-            if (rep.isEnabled() != null && rep.isEnabled() && rep.getUsername() != null) {
-                UsernameLoginFailureModel failureModel = session.sessions().getUserLoginFailure(realm, rep.getUsername().toLowerCase());
+            if (rep.isEnabled() != null && rep.isEnabled()) {
+                UserLoginFailureModel failureModel = session.sessions().getUserLoginFailure(realm, id);
                 if (failureModel != null) {
                     failureModel.clearFailures();
                 }
@@ -176,14 +174,16 @@ public class UsersResource {
             updateUserFromRep(user, rep, attrsToRemove, realm, session, true);
             adminEvent.operation(OperationType.UPDATE).resourcePath(uriInfo).representation(rep).success();
 
-            if (session.getTransaction().isActive()) {
-                session.getTransaction().commit();
+            if (session.getTransactionManager().isActive()) {
+                session.getTransactionManager().commit();
             }
             return Response.noContent().build();
         } catch (ModelDuplicateException e) {
             return ErrorResponse.exists("User exists with same username or email");
         } catch (ModelReadOnlyException re) {
             return ErrorResponse.exists("User is read only!");
+        } catch (ModelException me) {
+            return ErrorResponse.exists("Could not update user!");
         }
     }
 
@@ -216,16 +216,21 @@ public class UsersResource {
 
             adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, user.getId()).representation(rep).success();
 
-            if (session.getTransaction().isActive()) {
-                session.getTransaction().commit();
+            if (session.getTransactionManager().isActive()) {
+                session.getTransactionManager().commit();
             }
 
             return Response.created(uriInfo.getAbsolutePathBuilder().path(user.getId()).build()).build();
         } catch (ModelDuplicateException e) {
-            if (session.getTransaction().isActive()) {
-                session.getTransaction().setRollbackOnly();
+            if (session.getTransactionManager().isActive()) {
+                session.getTransactionManager().setRollbackOnly();
             }
             return ErrorResponse.exists("User exists with same username or email");
+        } catch (ModelException me){
+            if (session.getTransactionManager().isActive()) {
+                session.getTransactionManager().setRollbackOnly();
+            }
+            return ErrorResponse.exists("Could not create user");
         }
     }
 
@@ -293,7 +298,7 @@ public class UsersResource {
             rep.setFederatedIdentities(reps);
         }
 
-        if (session.getProvider(BruteForceProtector.class).isTemporarilyDisabled(session, realm, rep.getUsername())) {
+        if (session.getProvider(BruteForceProtector.class).isTemporarilyDisabled(session, realm, user)) {
             rep.setEnabled(false);
         }
 
@@ -520,7 +525,7 @@ public class UsersResource {
         Set<ClientModel> offlineClients = new UserSessionManager(session).findClientsWithOfflineToken(realm, user);
 
         for (ClientModel client : realm.getClients()) {
-            UserConsentModel consent = user.getConsentByClient(client.getId());
+            UserConsentModel consent = session.users().getConsentByClient(realm, user, client.getId());
             boolean hasOfflineToken = offlineClients.contains(client);
 
             if (consent == null && !hasOfflineToken) {
@@ -569,7 +574,7 @@ public class UsersResource {
         }
 
         ClientModel client = realm.getClientByClientId(clientId);
-        boolean revokedConsent = user.revokeConsentForClient(client.getId());
+        boolean revokedConsent = session.users().revokeConsentForClient(realm, user, client.getId());
         boolean revokedOfflineToken = new UserSessionManager(session).revokeOfflineToken(user, client);
 
         if (revokedConsent) {
@@ -679,7 +684,7 @@ public class UsersResource {
             if (username != null) {
                 attributes.put(UserModel.USERNAME, username);
             }
-            userModels = session.users().searchForUserByAttributes(attributes, realm, firstResult, maxResults);
+            userModels = session.users().searchForUser(attributes, realm, firstResult, maxResults);
         } else {
             userModels = session.users().getUsers(realm, firstResult, maxResults, false);
         }
@@ -959,7 +964,7 @@ public class UsersResource {
         try {
             if (user.isMemberOf(group)){
                 user.leaveGroup(group);
-                adminEvent.operation(OperationType.DELETE).representation(ModelToRepresentation.toRepresentation(group, true)).resourcePath(uriInfo).success();
+                adminEvent.operation(OperationType.DELETE).resource(ResourceType.GROUP_MEMBERSHIP).representation(ModelToRepresentation.toRepresentation(group, true)).resourcePath(uriInfo).success();
             }
         } catch (ModelException me) {
             Properties messages = AdminRoot.getMessages(session, realm, auth.getAuth().getToken().getLocale());
@@ -984,7 +989,7 @@ public class UsersResource {
         }
         if (!user.isMemberOf(group)){
             user.joinGroup(group);
-            adminEvent.operation(OperationType.CREATE).representation(ModelToRepresentation.toRepresentation(group, true)).resourcePath(uriInfo).success();
+            adminEvent.operation(OperationType.CREATE).resource(ResourceType.GROUP_MEMBERSHIP).representation(ModelToRepresentation.toRepresentation(group, true)).resourcePath(uriInfo).success();
         }
     }
 
diff --git a/services/src/main/java/org/keycloak/services/resources/ClientsManagementService.java b/services/src/main/java/org/keycloak/services/resources/ClientsManagementService.java
index c633587..898ad3c 100755
--- a/services/src/main/java/org/keycloak/services/resources/ClientsManagementService.java
+++ b/services/src/main/java/org/keycloak/services/resources/ClientsManagementService.java
@@ -19,6 +19,7 @@ package org.keycloak.services.resources;
 import org.jboss.resteasy.spi.BadRequestException;
 import org.jboss.resteasy.spi.HttpRequest;
 import org.jboss.resteasy.spi.UnauthorizedException;
+import org.keycloak.OAuthErrorException;
 import org.keycloak.common.ClientConnection;
 import org.keycloak.OAuth2Constants;
 import org.keycloak.constants.AdapterConstants;
@@ -30,6 +31,7 @@ import org.keycloak.models.ClientModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.protocol.oidc.utils.AuthorizeClientUtil;
+import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
 import org.keycloak.services.ForbiddenException;
 import org.keycloak.services.ServicesLogger;
 import org.keycloak.common.util.Time;
@@ -172,11 +174,9 @@ public class ClientsManagementService {
         ClientModel client = AuthorizeClientUtil.authorizeClient(session, event).getClient();
 
         if (client.isPublicClient()) {
-            Map<String, String> error = new HashMap<String, String>();
-            error.put(OAuth2Constants.ERROR, "invalid_client");
-            error.put(OAuth2Constants.ERROR_DESCRIPTION, "Public clients not allowed");
+            OAuth2ErrorRepresentation errorRep = new OAuth2ErrorRepresentation(OAuthErrorException.INVALID_CLIENT, "Public clients not allowed");
             event.error(Errors.INVALID_CLIENT);
-            throw new BadRequestException("Public clients not allowed", javax.ws.rs.core.Response.status(javax.ws.rs.core.Response.Status.BAD_REQUEST).entity(error).type(MediaType.APPLICATION_JSON_TYPE).build());
+            throw new BadRequestException("Public clients not allowed", javax.ws.rs.core.Response.status(javax.ws.rs.core.Response.Status.BAD_REQUEST).entity(errorRep).type(MediaType.APPLICATION_JSON_TYPE).build());
         }
 
         return client;
@@ -185,11 +185,9 @@ public class ClientsManagementService {
     protected String getClientClusterHost(MultivaluedMap<String, String> formData) {
         String clientClusterHost = formData.getFirst(AdapterConstants.CLIENT_CLUSTER_HOST);
         if (clientClusterHost == null || clientClusterHost.length() == 0) {
-            Map<String, String> error = new HashMap<String, String>();
-            error.put(OAuth2Constants.ERROR, "invalid_request");
-            error.put(OAuth2Constants.ERROR_DESCRIPTION, "Client cluster host not specified");
+            OAuth2ErrorRepresentation errorRep = new OAuth2ErrorRepresentation( OAuthErrorException.INVALID_REQUEST, "Client cluster host not specified");
             event.error(Errors.INVALID_CODE);
-            throw new BadRequestException("Cluster host not specified", javax.ws.rs.core.Response.status(javax.ws.rs.core.Response.Status.BAD_REQUEST).entity(error).type(MediaType.APPLICATION_JSON_TYPE).build());
+            throw new BadRequestException("Cluster host not specified", javax.ws.rs.core.Response.status(javax.ws.rs.core.Response.Status.BAD_REQUEST).entity(errorRep).type(MediaType.APPLICATION_JSON_TYPE).build());
         }
 
         return clientClusterHost;
diff --git a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
index 1c6f23d..9181817 100755
--- a/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
+++ b/services/src/main/java/org/keycloak/services/resources/IdentityBrokerService.java
@@ -55,6 +55,7 @@ import org.keycloak.provider.ProviderFactory;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.services.managers.AppAuthManager;
 import org.keycloak.services.managers.AuthenticationManager.AuthResult;
+import org.keycloak.services.managers.BruteForceProtector;
 import org.keycloak.services.managers.ClientSessionCode;
 import org.keycloak.services.messages.Messages;
 import org.keycloak.services.ErrorResponse;
@@ -338,8 +339,10 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
             return ErrorPage.error(session, Messages.ACCOUNT_DISABLED);
         }
         if (realm.isBruteForceProtected()) {
-            event.error(Errors.USER_TEMPORARILY_DISABLED);
-            return ErrorPage.error(session, Messages.ACCOUNT_DISABLED);
+            if (session.getProvider(BruteForceProtector.class).isTemporarilyDisabled(session, realm, user)) {
+                event.error(Errors.USER_TEMPORARILY_DISABLED);
+                return ErrorPage.error(session, Messages.ACCOUNT_DISABLED);
+            }
         }
         return null;
     }
@@ -832,17 +835,17 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
 
     private void fireErrorEvent(String message, Throwable throwable) {
         if (!this.event.getEvent().getType().toString().endsWith("_ERROR")) {
-            boolean newTransaction = !this.session.getTransaction().isActive();
+            boolean newTransaction = !this.session.getTransactionManager().isActive();
 
             try {
                 if (newTransaction) {
-                    this.session.getTransaction().begin();
+                    this.session.getTransactionManager().begin();
                 }
 
                 this.event.error(message);
 
                 if (newTransaction) {
-                    this.session.getTransaction().commit();
+                    this.session.getTransactionManager().commit();
                 }
             } catch (Exception e) {
                 logger.couldNotFireEvent(e);
@@ -866,8 +869,8 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
     }
 
     private void rollback() {
-        if (this.session.getTransaction().isActive()) {
-            this.session.getTransaction().rollback();
+        if (this.session.getTransactionManager().isActive()) {
+            this.session.getTransactionManager().rollback();
         }
     }
 
diff --git a/services/src/main/java/org/keycloak/services/resources/JsResource.java b/services/src/main/java/org/keycloak/services/resources/JsResource.java
index 32161a4..c74abf0 100755
--- a/services/src/main/java/org/keycloak/services/resources/JsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/JsResource.java
@@ -44,55 +44,90 @@ public class JsResource {
     @GET
     @Path("/keycloak.js")
     @Produces("text/javascript")
-    public Response getJs() {
-        InputStream inputStream = getClass().getClassLoader().getResourceAsStream("keycloak.js");
-        if (inputStream != null) {
-            CacheControl cacheControl = new CacheControl();
-            cacheControl.setNoTransform(false);
-            cacheControl.setMaxAge(Config.scope("theme").getInt("staticMaxAge", -1));
+    public Response getKeycloakJs() {
+        return getJs("keycloak.js");
+    }
 
-            return Response.ok(inputStream).type("text/javascript").cacheControl(cacheControl).build();
-        } else {
+    @GET
+    @Path("/{version}/keycloak.js")
+    @Produces("text/javascript")
+    public Response getKeycloakJsWithVersion(@PathParam("version") String version) {
+        if (!version.equals(Version.RESOURCES_VERSION)) {
             return Response.status(Response.Status.NOT_FOUND).build();
         }
+
+        return getKeycloakJs();
     }
 
     @GET
-    @Path("/{version}/keycloak.js")
+    @Path("/keycloak.min.js")
+    @Produces("text/javascript")
+    public Response getKeycloakMinJs() {
+        return getJs("keycloak.min.js");
+    }
+
+    @GET
+    @Path("/{version}/keycloak.min.js")
     @Produces("text/javascript")
-    public Response getJsWithVersion(@PathParam("version") String version) {
+    public Response getKeycloakMinJsWithVersion(@PathParam("version") String version) {
         if (!version.equals(Version.RESOURCES_VERSION)) {
             return Response.status(Response.Status.NOT_FOUND).build();
         }
 
-        return getJs();
+        return getKeycloakMinJs();
     }
 
+    /**
+     * Get keycloak-authz.js file for javascript clients
+     *
+     * @return
+     */
     @GET
-    @Path("/keycloak.min.js")
+    @Path("/keycloak-authz.js")
     @Produces("text/javascript")
-    public Response getMinJs() {
-        InputStream inputStream = getClass().getClassLoader().getResourceAsStream("keycloak.min.js");
-        if (inputStream != null) {
-            CacheControl cacheControl = new CacheControl();
-            cacheControl.setNoTransform(false);
-            cacheControl.setMaxAge(Config.scope("theme").getInt("staticMaxAge", -1));
+    public Response getKeycloakAuthzJs() {
+        return getJs("keycloak-authz.js");
+    }
 
-            return Response.ok(inputStream).type("text/javascript").cacheControl(cacheControl).build();
-        } else {
+    @GET
+    @Path("/{version}/keycloak-authz.js")
+    @Produces("text/javascript")
+    public Response getKeycloakAuthzJsWithVersion(@PathParam("version") String version) {
+        if (!version.equals(Version.RESOURCES_VERSION)) {
             return Response.status(Response.Status.NOT_FOUND).build();
         }
+
+        return getKeycloakAuthzJs();
     }
 
     @GET
-    @Path("/{version}/keycloak.min.js")
+    @Path("/keycloak-authz.min.js")
     @Produces("text/javascript")
-    public Response getMinJsWithVersion(@PathParam("version") String version) {
+    public Response getKeycloakAuthzMinJs() {
+        return getJs("keycloak-authz.min.js");
+    }
+
+    @GET
+    @Path("/{version}/keycloak-authz.min.js")
+    @Produces("text/javascript")
+    public Response getKeycloakAuthzMinJsWithVersion(@PathParam("version") String version) {
         if (!version.equals(Version.RESOURCES_VERSION)) {
             return Response.status(Response.Status.NOT_FOUND).build();
         }
 
-        return getMinJs();
+        return getKeycloakAuthzMinJs();
     }
 
+    private Response getJs(String name) {
+        InputStream inputStream = getClass().getClassLoader().getResourceAsStream(name);
+        if (inputStream != null) {
+            CacheControl cacheControl = new CacheControl();
+            cacheControl.setNoTransform(false);
+            cacheControl.setMaxAge(Config.scope("theme").getInt("staticMaxAge", -1));
+
+            return Response.ok(inputStream).type("text/javascript").cacheControl(cacheControl).build();
+        } else {
+            return Response.status(Response.Status.NOT_FOUND).build();
+        }
+    }
 }
diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
index d6d44d4..5e1cd9f 100644
--- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -26,7 +26,8 @@ import org.keycloak.exportimport.ExportImportManager;
 import org.keycloak.migration.MigrationModelManager;
 import org.keycloak.models.*;
 import org.keycloak.models.dblock.DBLockProvider;
-import org.keycloak.services.managers.DBLockManager;
+import org.keycloak.models.dblock.DBLockManager;
+import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.models.utils.PostMigrationEvent;
 import org.keycloak.models.utils.RepresentationToModel;
 import org.keycloak.representations.idm.RealmRepresentation;
@@ -91,62 +92,37 @@ public class KeycloakApplication extends Application {
 
         singletons.add(new ObjectMapperResolver(Boolean.parseBoolean(System.getProperty("keycloak.jsonPrettyPrint", "false"))));
 
-        ExportImportManager exportImportManager;
-
-        DBLockManager dbLockManager = new DBLockManager(sessionFactory.create());
-        dbLockManager.checkForcedUnlock();
-        DBLockProvider dbLock = dbLockManager.getDBLock();
-        dbLock.waitForLock();
-        try {
-            migrateModel();
-
-            KeycloakSession session = sessionFactory.create();
-            try {
-                session.getTransaction().begin();
+        ExportImportManager[] exportImportManager = new ExportImportManager[1];
 
-                ApplianceBootstrap applianceBootstrap = new ApplianceBootstrap(session);
-                exportImportManager = new ExportImportManager(session);
+        KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
 
-                boolean createMasterRealm = applianceBootstrap.isNewInstall();
-                if (exportImportManager.isRunImport() && exportImportManager.isImportMasterIncluded()) {
-                    createMasterRealm = false;
-                }
-
-                if (createMasterRealm) {
-                    applianceBootstrap.createMasterRealm(contextPath);
-                }
-                session.getTransaction().commit();
-            } catch (RuntimeException re) {
-                if (session.getTransaction().isActive()) {
-                    session.getTransaction().rollback();
+            @Override
+            public void run(KeycloakSession lockSession) {
+                DBLockManager dbLockManager = new DBLockManager(lockSession);
+                dbLockManager.checkForcedUnlock();
+                DBLockProvider dbLock = dbLockManager.getDBLock();
+                dbLock.waitForLock();
+                try {
+                    exportImportManager[0] = migrateAndBootstrap();
+                } finally {
+                    dbLock.releaseLock();
                 }
-                throw re;
-            } finally {
-                session.close();
             }
 
-            if (exportImportManager.isRunImport()) {
-                exportImportManager.runImport();
-            } else {
-                importRealms();
-            }
+        });
 
-            importAddUser();
-        } finally {
-            dbLock.releaseLock();
-        }
 
-        if (exportImportManager.isRunExport()) {
-            exportImportManager.runExport();
+        if (exportImportManager[0].isRunExport()) {
+            exportImportManager[0].runExport();
         }
 
         boolean bootstrapAdminUser = false;
         KeycloakSession session = sessionFactory.create();
         try {
-            session.getTransaction().begin();
+            session.getTransactionManager().begin();
             bootstrapAdminUser = new ApplianceBootstrap(session).isNoMasterUser();
 
-            session.getTransaction().commit();
+            session.getTransactionManager().commit();
         } finally {
             session.close();
         }
@@ -158,14 +134,57 @@ public class KeycloakApplication extends Application {
         setupScheduledTasks(sessionFactory);
     }
 
+
+    // Migrate model, bootstrap master realm, import realms and create admin user. This is done with acquired dbLock
+    protected ExportImportManager migrateAndBootstrap() {
+        ExportImportManager exportImportManager;
+        migrateModel();
+
+        KeycloakSession session = sessionFactory.create();
+        try {
+            session.getTransactionManager().begin();
+
+            ApplianceBootstrap applianceBootstrap = new ApplianceBootstrap(session);
+            exportImportManager = new ExportImportManager(session);
+
+            boolean createMasterRealm = applianceBootstrap.isNewInstall();
+            if (exportImportManager.isRunImport() && exportImportManager.isImportMasterIncluded()) {
+                createMasterRealm = false;
+            }
+
+            if (createMasterRealm) {
+                applianceBootstrap.createMasterRealm(contextPath);
+            }
+            session.getTransactionManager().commit();
+        } catch (RuntimeException re) {
+            if (session.getTransactionManager().isActive()) {
+                session.getTransactionManager().rollback();
+            }
+            throw re;
+        } finally {
+            session.close();
+        }
+
+        if (exportImportManager.isRunImport()) {
+            exportImportManager.runImport();
+        } else {
+            importRealms();
+        }
+
+        importAddUser();
+
+        return exportImportManager;
+    }
+
+
     protected void migrateModel() {
         KeycloakSession session = sessionFactory.create();
         try {
-            session.getTransaction().begin();
+            session.getTransactionManager().begin();
             MigrationModelManager.migrate(session);
-            session.getTransaction().commit();
+            session.getTransactionManager().commit();
         } catch (Exception e) {
-            session.getTransaction().rollback();
+            session.getTransactionManager().rollback();
             logger.migrationFailure(e);
             throw e;
         } finally {
@@ -275,7 +294,7 @@ public class KeycloakApplication extends Application {
         KeycloakSession session = sessionFactory.create();
         boolean exists = false;
         try {
-            session.getTransaction().begin();
+            session.getTransactionManager().begin();
 
             try {
                 RealmManager manager = new RealmManager(session);
@@ -294,9 +313,9 @@ public class KeycloakApplication extends Application {
                     RealmModel realm = manager.importRealm(rep);
                     logger.importedRealm(realm.getName(), from);
                 }
-                session.getTransaction().commit();
+                session.getTransactionManager().commit();
             } catch (Throwable t) {
-                session.getTransaction().rollback();
+                session.getTransactionManager().rollback();
                 if (!exists) {
                     logger.unableToImportRealm(t, rep.getRealm(), from);
                 }
@@ -326,7 +345,7 @@ public class KeycloakApplication extends Application {
                     for (UserRepresentation userRep : realmRep.getUsers()) {
                         KeycloakSession session = sessionFactory.create();
                         try {
-                            session.getTransaction().begin();
+                            session.getTransactionManager().begin();
 
                             RealmModel realm = session.realms().getRealmByName(realmRep.getRealm());
                             if (realm == null) {
@@ -338,13 +357,13 @@ public class KeycloakApplication extends Application {
                                 RepresentationToModel.createRoleMappings(userRep, user, realm);
                             }
 
-                            session.getTransaction().commit();
+                            session.getTransactionManager().commit();
                             logger.addUserSuccess(userRep.getUsername(), realmRep.getRealm());
                         } catch (ModelDuplicateException e) {
-                            session.getTransaction().rollback();
+                            session.getTransactionManager().rollback();
                             logger.addUserFailedUserExists(userRep.getUsername(), realmRep.getRealm());
                         } catch (Throwable t) {
-                            session.getTransaction().rollback();
+                            session.getTransactionManager().rollback();
                             logger.addUserFailed(t, userRep.getUsername(), realmRep.getRealm());
                         } finally {
                             session.close();
diff --git a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
index fab5815..66dee2e 100755
--- a/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
+++ b/services/src/main/java/org/keycloak/services/resources/LoginActionsService.java
@@ -667,10 +667,10 @@ public class LoginActionsService {
             return response;
         }
 
-        UserConsentModel grantedConsent = user.getConsentByClient(client.getId());
+        UserConsentModel grantedConsent = session.users().getConsentByClient(realm, user, client.getId());
         if (grantedConsent == null) {
             grantedConsent = new UserConsentModel(client);
-            user.addConsent(grantedConsent);
+            session.users().addConsent(realm, user, grantedConsent);
         }
         for (RoleModel role : accessCode.getRequestedRoles()) {
             grantedConsent.addGrantedRole(role);
@@ -680,7 +680,7 @@ public class LoginActionsService {
                 grantedConsent.addGrantedProtocolMapper(protocolMapper);
             }
         }
-        user.updateConsent(grantedConsent);
+        session.users().updateConsent(realm, user, grantedConsent);
 
         event.detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED);
         event.success();
@@ -892,7 +892,7 @@ public class LoginActionsService {
                 return AuthenticationManager.finishedRequiredActions(session, userSession, clientSession, clientConnection, request, uriInfo, event);
 
             }
-       }
+        }
         if (context.getStatus() == RequiredActionContext.Status.CHALLENGE) {
             return context.getChallenge();
         }
diff --git a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
index ae743f3..1e42e7b 100755
--- a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
@@ -18,6 +18,8 @@ package org.keycloak.services.resources;
 
 import org.jboss.resteasy.spi.HttpRequest;
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.AuthorizationService;
 import org.keycloak.common.ClientConnection;
 import org.keycloak.common.util.KeycloakUriBuilder;
 import org.keycloak.events.EventBuilder;
@@ -40,8 +42,12 @@ import javax.ws.rs.NotFoundException;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
-import javax.ws.rs.core.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.ResponseBuilder;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
 import java.net.URI;
 
 /**
@@ -93,14 +99,23 @@ public class RealmsResource {
         return uriInfo.getBaseUriBuilder().path(RealmsResource.class).path(RealmsResource.class, "getBrokerService");
     }
 
+    public static UriBuilder wellKnownProviderUrl(UriBuilder builder) {
+        return builder.path(RealmsResource.class).path(RealmsResource.class, "getWellKnown");
+    }
+
     @Path("{realm}/protocol/{protocol}")
     public Object getProtocol(final @PathParam("realm") String name,
-                                            final @PathParam("protocol") String protocol) {
+                              final @PathParam("protocol") String protocol) {
         RealmModel realm = init(name);
 
+        LoginProtocolFactory factory = (LoginProtocolFactory)session.getKeycloakSessionFactory().getProviderFactory(LoginProtocol.class, protocol);
+        if(factory == null){
+            logger.debugf("protocol %s not found", protocol);
+            throw new NotFoundException("Protocol not found");
+        }
+
         EventBuilder event = new EventBuilder(realm, session, clientConnection);
 
-        LoginProtocolFactory factory = (LoginProtocolFactory)session.getKeycloakSessionFactory().getProviderFactory(LoginProtocol.class, protocol);
         Object endpoint = factory.createProtocolEndpoint(realm, event);
 
         ResteasyProviderFactory.getInstance().injectProperties(endpoint);
@@ -228,7 +243,7 @@ public class RealmsResource {
     @Path("{realm}/.well-known/{provider}")
     @Produces(MediaType.APPLICATION_JSON)
     public Response getWellKnown(final @PathParam("realm") String name,
-                              final @PathParam("provider") String providerName) {
+                                 final @PathParam("provider") String providerName) {
         init(name);
 
         WellKnownProvider wellKnown = session.getProvider(WellKnownProvider.class, providerName);
@@ -237,6 +252,17 @@ public class RealmsResource {
         return Cors.add(request, responseBuilder).allowedOrigins("*").build();
     }
 
+    @Path("{realm}/authz")
+    public Object getAuthorizationService(@PathParam("realm") String name) {
+        init(name);
+        AuthorizationProvider authorization = this.session.getProvider(AuthorizationProvider.class);
+        AuthorizationService service = new AuthorizationService(authorization);
+
+        ResteasyProviderFactory.getInstance().injectProperties(service);
+
+        return service;
+    }
+
     /**
      * A JAX-RS sub-resource locator that uses the {@link org.keycloak.services.resource.RealmResourceSPI} to resolve sub-resources instances given an <code>unknownPath</code>.
      *
diff --git a/services/src/main/java/org/keycloak/services/scheduled/ClusterAwareScheduledTaskRunner.java b/services/src/main/java/org/keycloak/services/scheduled/ClusterAwareScheduledTaskRunner.java
index 94db9c9..b2a8bf7 100644
--- a/services/src/main/java/org/keycloak/services/scheduled/ClusterAwareScheduledTaskRunner.java
+++ b/services/src/main/java/org/keycloak/services/scheduled/ClusterAwareScheduledTaskRunner.java
@@ -41,7 +41,7 @@ public class ClusterAwareScheduledTaskRunner extends ScheduledTaskRunner {
 
     @Override
     protected void runTask(final KeycloakSession session) {
-        session.getTransaction().begin();
+        session.getTransactionManager().begin();
 
         ClusterProvider clusterProvider = session.getProvider(ClusterProvider.class);
         String taskKey = task.getClass().getSimpleName();
@@ -56,7 +56,7 @@ public class ClusterAwareScheduledTaskRunner extends ScheduledTaskRunner {
 
         });
 
-        session.getTransaction().commit();
+        session.getTransactionManager().commit();
 
         if (result.isExecuted()) {
             logger.debugf("Executed scheduled task %s", taskKey);
diff --git a/services/src/main/java/org/keycloak/services/scheduled/ScheduledTaskRunner.java b/services/src/main/java/org/keycloak/services/scheduled/ScheduledTaskRunner.java
index b49300f..81ff5f6 100644
--- a/services/src/main/java/org/keycloak/services/scheduled/ScheduledTaskRunner.java
+++ b/services/src/main/java/org/keycloak/services/scheduled/ScheduledTaskRunner.java
@@ -45,7 +45,7 @@ public class ScheduledTaskRunner implements Runnable {
         } catch (Throwable t) {
             logger.failedToRunScheduledTask(t, task.getClass().getSimpleName());
 
-            session.getTransaction().rollback();
+            session.getTransactionManager().rollback();
         } finally {
             try {
                 session.close();
@@ -56,9 +56,9 @@ public class ScheduledTaskRunner implements Runnable {
     }
 
     protected void runTask(KeycloakSession session) {
-        session.getTransaction().begin();
+        session.getTransactionManager().begin();
         task.run(session);
-        session.getTransaction().commit();
+        session.getTransactionManager().commit();
 
         logger.debug("Executed scheduled task " + task.getClass().getSimpleName());
     }
diff --git a/services/src/main/java/org/keycloak/services/ServicesLogger.java b/services/src/main/java/org/keycloak/services/ServicesLogger.java
index c50191f..de7eef7 100644
--- a/services/src/main/java/org/keycloak/services/ServicesLogger.java
+++ b/services/src/main/java/org/keycloak/services/ServicesLogger.java
@@ -32,6 +32,8 @@ import static org.jboss.logging.Logger.Level.ERROR;
 import static org.jboss.logging.Logger.Level.FATAL;
 import static org.jboss.logging.Logger.Level.INFO;
 import static org.jboss.logging.Logger.Level.WARN;
+
+import org.jboss.logging.annotations.Once;
 import org.keycloak.email.EmailException;
 import org.keycloak.events.EventListenerProvider;
 import org.keycloak.models.ModelDuplicateException;
@@ -404,6 +406,28 @@ public interface ServicesLogger extends BasicLogger {
     void failedToCloseProviderSession(@Cause Throwable t);
 
     @LogMessage(level = WARN)
-    @Message(id=91, value="Forced release of DB lock at startup requested by System property. Make sure to not use this in production environment! And especially when more cluster nodes are started concurrently.")
-    void forcedReleaseDBLock();
+    @Message(id=91, value="Request is missing scope 'openid' so it's not treated as OIDC, but just pure OAuth2 request. This can have impact in future versions (eg. removed IDToken from the Token Response)")
+    @Once
+    void oidcScopeMissing();
+
+    @LogMessage(level = ERROR)
+    @Message(id=92, value="Missing parameter: %s")
+    void missingParameter(String paramName);
+
+    @LogMessage(level = ERROR)
+    @Message(id=93, value="Invalid parameter value for: %s")
+    void invalidParameter(String paramName);
+
+    @LogMessage(level = ERROR)
+    @Message(id=94, value="Unsupported parameter: %s")
+    void unsupportedParameter(String paramName);
+
+    @LogMessage(level = ERROR)
+    @Message(id=95, value="Client is not allowed to initiate browser login with given response_type. %s flow is disabled for the client.")
+    void flowNotAllowed(String flowName);
+
+    @LogMessage(level = WARN)
+    @Message(id=96, value="Not found JWK of supported keyType under jwks_uri for usage: %s")
+    void supportedJwkNotFound(String usage);
+
 }
diff --git a/services/src/main/java/org/keycloak/services/util/CertificateInfoHelper.java b/services/src/main/java/org/keycloak/services/util/CertificateInfoHelper.java
new file mode 100644
index 0000000..b309927
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/util/CertificateInfoHelper.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.services.util;
+
+import java.util.HashMap;
+
+import org.keycloak.models.ClientModel;
+import org.keycloak.representations.idm.CertificateRepresentation;
+import org.keycloak.representations.idm.ClientRepresentation;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class CertificateInfoHelper {
+
+
+    public static final String PRIVATE_KEY = "private.key";
+    public static final String X509CERTIFICATE = "certificate";
+    public static final String PUBLIC_KEY = "public.key";
+
+
+    public static CertificateRepresentation getCertificateFromClient(ClientModel client, String attributePrefix) {
+        String privateKeyAttribute = attributePrefix + "." + PRIVATE_KEY;
+        String certificateAttribute = attributePrefix + "." + X509CERTIFICATE;
+        String publicKeyAttribute = attributePrefix + "." + PUBLIC_KEY;
+
+        CertificateRepresentation rep = new CertificateRepresentation();
+        rep.setCertificate(client.getAttribute(certificateAttribute));
+        rep.setPublicKey(client.getAttribute(publicKeyAttribute));
+        rep.setPrivateKey(client.getAttribute(privateKeyAttribute));
+
+        return rep;
+    }
+
+
+    public static void updateClientModelCertificateInfo(ClientModel client, CertificateRepresentation rep, String attributePrefix) {
+        String privateKeyAttribute = attributePrefix + "." + PRIVATE_KEY;
+        String certificateAttribute = attributePrefix + "." + X509CERTIFICATE;
+        String publicKeyAttribute = attributePrefix + "." + PUBLIC_KEY;
+
+        if (rep.getPublicKey() == null && rep.getCertificate() == null) {
+            throw new IllegalStateException("Both certificate and publicKey are null!");
+        }
+
+        if (rep.getPublicKey() != null && rep.getCertificate() != null) {
+            throw new IllegalStateException("Both certificate and publicKey are not null!");
+        }
+
+        setOrRemoveAttr(client, privateKeyAttribute, rep.getPrivateKey());
+        setOrRemoveAttr(client, publicKeyAttribute, rep.getPublicKey());
+        setOrRemoveAttr(client, certificateAttribute, rep.getCertificate());
+    }
+
+    private static void setOrRemoveAttr(ClientModel client, String attrName, String attrValue) {
+        if (attrValue != null) {
+            client.setAttribute(attrName, attrValue);
+        } else {
+            client.removeAttribute(attrName);
+        }
+    }
+
+
+    public static void updateClientRepresentationCertificateInfo(ClientRepresentation client, CertificateRepresentation rep, String attributePrefix) {
+        String privateKeyAttribute = attributePrefix + "." + PRIVATE_KEY;
+        String certificateAttribute = attributePrefix + "." + X509CERTIFICATE;
+        String publicKeyAttribute = attributePrefix + "." + PUBLIC_KEY;
+
+        if (rep.getPublicKey() == null && rep.getCertificate() == null) {
+            throw new IllegalStateException("Both certificate and publicKey are null!");
+        }
+
+        if (rep.getPublicKey() != null && rep.getCertificate() != null) {
+            throw new IllegalStateException("Both certificate and publicKey are not null!");
+        }
+
+        setOrRemoveAttr(client, privateKeyAttribute, rep.getPrivateKey());
+        setOrRemoveAttr(client, publicKeyAttribute, rep.getPublicKey());
+        setOrRemoveAttr(client, certificateAttribute, rep.getCertificate());
+    }
+
+    private static void setOrRemoveAttr(ClientRepresentation client, String attrName, String attrValue) {
+        if (attrValue != null) {
+            if (client.getAttributes() == null) {
+                client.setAttributes(new HashMap<>());
+            }
+            client.getAttributes().put(attrName, attrValue);
+        } else {
+            if (client.getAttributes() != null) {
+                client.getAttributes().remove(attrName);
+            }
+        }
+    }
+}
diff --git a/services/src/main/java/org/keycloak/services/util/LocaleHelper.java b/services/src/main/java/org/keycloak/services/util/LocaleHelper.java
index d8a7c80..4c419b3 100755
--- a/services/src/main/java/org/keycloak/services/util/LocaleHelper.java
+++ b/services/src/main/java/org/keycloak/services/util/LocaleHelper.java
@@ -16,6 +16,7 @@
  */
 package org.keycloak.services.util;
 
+import org.keycloak.OAuth2Constants;
 import org.keycloak.models.KeycloakContext;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
@@ -33,7 +34,6 @@ import java.util.Set;
 public class LocaleHelper {
 
     private static final String LOCALE_COOKIE = "KEYCLOAK_LOCALE";
-    private static final String UI_LOCALES_PARAM = "ui_locales";
     private static final String KC_LOCALE_PARAM = "kc_locale";
 
     public static Locale getLocale(KeycloakSession session, RealmModel realm, UserModel user) {
@@ -104,8 +104,8 @@ public class LocaleHelper {
         }
 
         // ui_locales query parameter
-        if (uriInfo != null && uriInfo.getQueryParameters().containsKey(UI_LOCALES_PARAM)) {
-            String localeString = uriInfo.getQueryParameters().getFirst(UI_LOCALES_PARAM);
+        if (uriInfo != null && uriInfo.getQueryParameters().containsKey(OAuth2Constants.UI_LOCALES_PARAM)) {
+            String localeString = uriInfo.getQueryParameters().getFirst(OAuth2Constants.UI_LOCALES_PARAM);
             Locale locale = findLocale(realm.getSupportedLocales(), localeString.split(" "));
             if (locale != null) {
                 return locale;
@@ -135,21 +135,23 @@ public class LocaleHelper {
 
     private static Locale findLocale(Set<String> supportedLocales, String... localeStrings) {
         for (String localeString : localeStrings) {
-            Locale result = null;
-            Locale search = Locale.forLanguageTag(localeString);
-            for (String languageTag : supportedLocales) {
-                Locale locale = Locale.forLanguageTag(languageTag);
-                if (locale.getLanguage().equals(search.getLanguage())) {
-                    if (locale.getCountry().equals("") && result == null) {
-                        result = locale;
-                    }
-                    if (locale.getCountry().equals(search.getCountry())) {
-                        return locale;
+            if (localeString != null) {
+                Locale result = null;
+                Locale search = Locale.forLanguageTag(localeString);
+                for (String languageTag : supportedLocales) {
+                    Locale locale = Locale.forLanguageTag(languageTag);
+                    if (locale.getLanguage().equals(search.getLanguage())) {
+                        if (locale.getCountry().equals("") && result == null) {
+                            result = locale;
+                        }
+                        if (locale.getCountry().equals(search.getCountry())) {
+                            return locale;
+                        }
                     }
                 }
-            }
-            if (result != null) {
-                return result;
+                if (result != null) {
+                    return result;
+                }
             }
         }
         return null;
diff --git a/services/src/main/java/org/keycloak/services/validation/Validation.java b/services/src/main/java/org/keycloak/services/validation/Validation.java
index b5a39bb..eacfa8f 100755
--- a/services/src/main/java/org/keycloak/services/validation/Validation.java
+++ b/services/src/main/java/org/keycloak/services/validation/Validation.java
@@ -22,6 +22,8 @@ import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.PasswordPolicy;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.utils.FormMessage;
+import org.keycloak.policy.PasswordPolicyManagerProvider;
+import org.keycloak.policy.PolicyError;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.services.messages.Messages;
 
@@ -73,7 +75,7 @@ public class Validation {
         }
 
         if (formData.getFirst(FIELD_PASSWORD) != null) {
-            PasswordPolicy.Error err = policy.validate(session, realm.isRegistrationEmailAsUsername()?formData.getFirst(FIELD_EMAIL):formData.getFirst(FIELD_USERNAME), formData.getFirst(FIELD_PASSWORD));
+            PolicyError err = session.getProvider(PasswordPolicyManagerProvider.class).validate(realm.isRegistrationEmailAsUsername() ? formData.getFirst(FIELD_EMAIL) : formData.getFirst(FIELD_USERNAME), formData.getFirst(FIELD_PASSWORD));
             if (err != null)
                 errors.add(new FormMessage(FIELD_PASSWORD, err.getMessage(), err.getParameters()));
         }
diff --git a/services/src/main/java/org/keycloak/theme/ClassLoaderTheme.java b/services/src/main/java/org/keycloak/theme/ClassLoaderTheme.java
old mode 100755
new mode 100644
index 095832f..24f215a
--- a/services/src/main/java/org/keycloak/theme/ClassLoaderTheme.java
+++ b/services/src/main/java/org/keycloak/theme/ClassLoaderTheme.java
@@ -19,7 +19,10 @@ package org.keycloak.theme;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
 import java.net.URL;
+import java.nio.charset.Charset;
 import java.util.Locale;
 import java.util.Properties;
 
@@ -64,7 +67,10 @@ public class ClassLoaderTheme implements Theme {
 
         URL p = classLoader.getResource(themeRoot + "theme.properties");
         if (p != null) {
-            properties.load(p.openStream());
+            Charset encoding = PropertiesUtil.detectEncoding(p.openStream());
+            try (Reader reader = new InputStreamReader(p.openStream(), encoding)) {
+                properties.load(reader);
+            }
             this.parentName = properties.getProperty("parent");
             this.importName = properties.getProperty("import");
         } else {
@@ -127,7 +133,10 @@ public class ClassLoaderTheme implements Theme {
 
         URL url = classLoader.getResource(this.messageRoot + baseBundlename + "_" + locale.toString() + ".properties");
         if (url != null) {
-            m.load(url.openStream());
+            Charset encoding = PropertiesUtil.detectEncoding(url.openStream());
+            try (Reader reader = new InputStreamReader(url.openStream(), encoding)) {
+                m.load(reader);
+            }
         }
         return m;
     }
diff --git a/services/src/main/java/org/keycloak/theme/FolderTheme.java b/services/src/main/java/org/keycloak/theme/FolderTheme.java
old mode 100755
new mode 100644
index d1a2854..04621d7
--- a/services/src/main/java/org/keycloak/theme/FolderTheme.java
+++ b/services/src/main/java/org/keycloak/theme/FolderTheme.java
@@ -21,7 +21,10 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
 import java.net.URL;
+import java.nio.charset.Charset;
 import java.util.Locale;
 import java.util.Properties;
 
@@ -46,7 +49,10 @@ public class FolderTheme implements Theme {
 
         File propertiesFile = new File(themeDir, "theme.properties");
         if (propertiesFile .isFile()) {
-            properties.load(new FileInputStream(propertiesFile));
+            Charset encoding = PropertiesUtil.detectEncoding(new FileInputStream(propertiesFile));
+            try (Reader reader = new InputStreamReader(new FileInputStream(propertiesFile), encoding)) {
+                properties.load(reader);
+            }
             parentName = properties.getProperty("parent");
             importName = properties.getProperty("import");
         }
@@ -121,7 +127,10 @@ public class FolderTheme implements Theme {
 
         File file = new File(themeDir, "messages" + File.separator + baseBundlename + "_" + locale.toString() + ".properties");
         if (file.isFile()) {
-            m.load(new FileInputStream(file));
+            Charset encoding = PropertiesUtil.detectEncoding(new FileInputStream(file));
+            try (Reader reader = new InputStreamReader(new FileInputStream(file), encoding)) {
+                m.load(reader);
+            }
         }
         return m;
     }
diff --git a/services/src/main/java/org/keycloak/theme/FreeMarkerUtil.java b/services/src/main/java/org/keycloak/theme/FreeMarkerUtil.java
index 0d3f98b..5aa6628 100755
--- a/services/src/main/java/org/keycloak/theme/FreeMarkerUtil.java
+++ b/services/src/main/java/org/keycloak/theme/FreeMarkerUtil.java
@@ -68,7 +68,7 @@ public class FreeMarkerUtil {
     private Template getTemplate(String templateName, Theme theme) throws IOException {
         Configuration cfg = new Configuration();
         cfg.setTemplateLoader(new ThemeTemplateLoader(theme));
-        return cfg.getTemplate(templateName);
+        return cfg.getTemplate(templateName, "UTF-8");
     }
 
     class ThemeTemplateLoader extends URLTemplateLoader {
diff --git a/services/src/main/java/org/keycloak/theme/PropertiesUtil.java b/services/src/main/java/org/keycloak/theme/PropertiesUtil.java
new file mode 100644
index 0000000..18387f7
--- /dev/null
+++ b/services/src/main/java/org/keycloak/theme/PropertiesUtil.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.theme;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.jboss.logging.Logger;
+
+/**
+ * @author <a href="mailto:wadahiro@gmail.com">Hiroyuki Wada</a>
+ */
+public class PropertiesUtil {
+
+    private static final Logger logger = Logger.getLogger(PropertiesUtil.class);
+
+    public static final Pattern DETECT_ENCODING_PATTERN = Pattern.compile("^#\\s*encoding:\\s*([\\w.:-]+)",
+            Pattern.CASE_INSENSITIVE);
+
+    public static final Charset DEFAULT_ENCODING = Charset.forName("ISO-8859-1");
+
+    /**
+     * <p>
+     * Detect file encoding from the first line of the property file. If the first line in the file doesn't contain the
+     * comment with the encoding, it uses ISO-8859-1 as default encoding for backwards compatibility.
+     * </p>
+     * <p>
+     * The specified stream is closed before this method returns.
+     * </p>
+     * 
+     * @param in The input stream
+     * @return Encoding
+     * @throws IOException
+     */
+    public static Charset detectEncoding(InputStream in) throws IOException {
+        try (BufferedReader br = new BufferedReader(new InputStreamReader(in, DEFAULT_ENCODING))) {
+            String firstLine = br.readLine();
+            if (firstLine != null) {
+                Matcher matcher = DETECT_ENCODING_PATTERN.matcher(firstLine);
+                if (matcher.find()) {
+                    String encoding = matcher.group(1);
+                    if (Charset.isSupported(encoding)) {
+                        return Charset.forName(encoding);
+                    } else {
+                        logger.warnv("Unsupported encoding: {0}", encoding);
+                    }
+                }
+            }
+        }
+        return DEFAULT_ENCODING;
+    }
+}
diff --git a/services/src/main/java/org/keycloak/transaction/JBossJtaTransactionManagerLookup.java b/services/src/main/java/org/keycloak/transaction/JBossJtaTransactionManagerLookup.java
new file mode 100644
index 0000000..9d0be4a
--- /dev/null
+++ b/services/src/main/java/org/keycloak/transaction/JBossJtaTransactionManagerLookup.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.transaction;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.services.ServicesLogger;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.transaction.TransactionManager;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class JBossJtaTransactionManagerLookup implements JtaTransactionManagerLookup {
+    private static final ServicesLogger logger = ServicesLogger.ROOT_LOGGER;
+    private TransactionManager tm;
+
+    @Override
+    public TransactionManager getTransactionManager() {
+        return tm;
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+        try {
+            InitialContext ctx = new InitialContext();
+            tm = (TransactionManager)ctx.lookup("java:jboss/TransactionManager");
+            if (tm == null) {
+                logger.debug("Could not locate TransactionManager");
+            }
+        } catch (NamingException e) {
+            logger.debug("Could not load TransactionManager", e);
+        }
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    @Override
+    public String getId() {
+        return "jboss";
+    }
+}
diff --git a/services/src/main/java/org/keycloak/transaction/JtaRegistration.java b/services/src/main/java/org/keycloak/transaction/JtaRegistration.java
new file mode 100644
index 0000000..1800c52
--- /dev/null
+++ b/services/src/main/java/org/keycloak/transaction/JtaRegistration.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.transaction;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.services.ServicesLogger;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.transaction.TransactionManager;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class JtaRegistration {
+
+
+
+    public void begin(KeycloakSession session) {
+        TransactionManager tm = session.getProvider(JtaTransactionManagerLookup.class).getTransactionManager();
+        if (tm == null) return;
+
+        session.getTransactionManager().enlist(new JtaTransactionWrapper(tm));
+    }
+}
diff --git a/services/src/main/java/org/keycloak/transaction/JtaTransactionManagerLookup.java b/services/src/main/java/org/keycloak/transaction/JtaTransactionManagerLookup.java
new file mode 100644
index 0000000..ebcf52e
--- /dev/null
+++ b/services/src/main/java/org/keycloak/transaction/JtaTransactionManagerLookup.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.transaction;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+
+import javax.transaction.TransactionManager;
+
+/**
+ * JTA TransactionManager lookup
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface JtaTransactionManagerLookup extends Provider, ProviderFactory<JtaTransactionManagerLookup> {
+    @Override
+    default void close() {
+
+    }
+
+    @Override
+    default JtaTransactionManagerLookup create(KeycloakSession session) {
+        return this;
+    }
+
+    TransactionManager getTransactionManager();
+}
diff --git a/services/src/main/java/org/keycloak/transaction/JtaTransactionWrapper.java b/services/src/main/java/org/keycloak/transaction/JtaTransactionWrapper.java
new file mode 100644
index 0000000..ecc3071
--- /dev/null
+++ b/services/src/main/java/org/keycloak/transaction/JtaTransactionWrapper.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.transaction;
+
+import org.keycloak.models.KeycloakTransaction;
+
+import javax.transaction.InvalidTransactionException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.Status;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import javax.transaction.UserTransaction;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class JtaTransactionWrapper implements KeycloakTransaction {
+    protected TransactionManager tm;
+    protected Transaction ut;
+    protected Transaction suspended;
+
+    public JtaTransactionWrapper(TransactionManager tm) {
+        this.tm = tm;
+        try {
+            suspended = tm.suspend();
+            tm.begin();
+            ut = tm.getTransaction();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void begin() {
+    }
+
+    @Override
+    public void commit() {
+        try {
+            ut.commit();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void rollback() {
+        try {
+            ut.rollback();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        } finally {
+            end();
+        }
+
+    }
+
+    @Override
+    public void setRollbackOnly() {
+        try {
+            ut.setRollbackOnly();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public boolean getRollbackOnly() {
+        try {
+            return ut.getStatus() == Status.STATUS_MARKED_ROLLBACK;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public boolean isActive() {
+        try {
+            return ut.getStatus() == Status.STATUS_ACTIVE;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    protected void end() {
+        if (suspended != null) {
+            try {
+                tm.resume(suspended);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+    }
+}
diff --git a/services/src/main/java/org/keycloak/transaction/TransactionManagerLookupSpi.java b/services/src/main/java/org/keycloak/transaction/TransactionManagerLookupSpi.java
new file mode 100755
index 0000000..f45d897
--- /dev/null
+++ b/services/src/main/java/org/keycloak/transaction/TransactionManagerLookupSpi.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.transaction;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class TransactionManagerLookupSpi implements Spi {
+
+    @Override
+    public boolean isInternal() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return "jta-lookup";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return JtaTransactionManagerLookup.class;
+    }
+
+    @Override
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return JtaTransactionManagerLookup.class;
+    }
+
+}
diff --git a/services/src/main/java/org/keycloak/transaction/UserTransactionWrapper.java b/services/src/main/java/org/keycloak/transaction/UserTransactionWrapper.java
new file mode 100644
index 0000000..c838b18
--- /dev/null
+++ b/services/src/main/java/org/keycloak/transaction/UserTransactionWrapper.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.transaction;
+
+import org.keycloak.models.KeycloakTransaction;
+
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import javax.transaction.Status;
+import javax.transaction.SystemException;
+import javax.transaction.UserTransaction;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class UserTransactionWrapper implements KeycloakTransaction {
+    protected UserTransaction ut;
+
+    public UserTransactionWrapper(UserTransaction ut) {
+        this.ut = ut;
+    }
+
+    @Override
+    public void begin() {
+        try {
+            ut.begin();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void commit() {
+        try {
+            ut.commit();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void rollback() {
+        try {
+            ut.rollback();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+    }
+
+    @Override
+    public void setRollbackOnly() {
+        try {
+            ut.setRollbackOnly();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public boolean getRollbackOnly() {
+        try {
+            return ut.getStatus() == Status.STATUS_MARKED_ROLLBACK;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public boolean isActive() {
+        try {
+            return ut.getStatus() == Status.STATUS_ACTIVE;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/services/src/main/java/org/keycloak/utils/CredentialHelper.java b/services/src/main/java/org/keycloak/utils/CredentialHelper.java
index ab2a17e..7db006a 100755
--- a/services/src/main/java/org/keycloak/utils/CredentialHelper.java
+++ b/services/src/main/java/org/keycloak/utils/CredentialHelper.java
@@ -28,6 +28,7 @@ import org.keycloak.models.AuthenticationExecutionModel;
 import org.keycloak.models.AuthenticationFlowModel;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
+import org.keycloak.services.ServicesLogger;
 
 /**
  * used to set an execution a state based on type.
@@ -37,25 +38,32 @@ import org.keycloak.models.RealmModel;
  */
 public class CredentialHelper {
 
+    protected static final ServicesLogger logger = ServicesLogger.ROOT_LOGGER;
+
     public static void setRequiredCredential(KeycloakSession session, String type, RealmModel realm) {
         AuthenticationExecutionModel.Requirement requirement = AuthenticationExecutionModel.Requirement.REQUIRED;
-        authenticationRequirement(session, realm, type, requirement);
+        setOrReplaceAuthenticationRequirement(session, realm, type, requirement, null);
     }
 
     public static void setAlternativeCredential(KeycloakSession session, String type, RealmModel realm) {
         AuthenticationExecutionModel.Requirement requirement = AuthenticationExecutionModel.Requirement.ALTERNATIVE;
-        authenticationRequirement(session, realm, type, requirement);
+        setOrReplaceAuthenticationRequirement(session, realm, type, requirement, null);
     }
 
-    public static void authenticationRequirement(KeycloakSession session, RealmModel realm, String type, AuthenticationExecutionModel.Requirement requirement) {
+    public static void setOrReplaceAuthenticationRequirement(KeycloakSession session, RealmModel realm, String type, AuthenticationExecutionModel.Requirement requirement, AuthenticationExecutionModel.Requirement currentRequirement) {
         for (AuthenticationFlowModel flow : realm.getAuthenticationFlows()) {
             for (AuthenticationExecutionModel execution : realm.getAuthenticationExecutions(flow.getId())) {
                 String providerId = execution.getAuthenticator();
                 ConfigurableAuthenticatorFactory factory = getConfigurableAuthenticatorFactory(session, providerId);
                 if (factory == null) continue;
                 if (type.equals(factory.getReferenceCategory())) {
-                    execution.setRequirement(requirement);
-                    realm.updateAuthenticatorExecution(execution);
+                    if (currentRequirement == null || currentRequirement.equals(execution.getRequirement())) {
+                        execution.setRequirement(requirement);
+                        realm.updateAuthenticatorExecution(execution);
+                        logger.debugf("Authenticator execution '%s' switched to '%s'", execution.getAuthenticator(), requirement.toString());
+                    } else {
+                        logger.debugf("Skip switch authenticator execution '%s' to '%s' as it's in state %s", execution.getAuthenticator(), requirement.toString(), execution.getRequirement());
+                    }
                 }
             }
         }
diff --git a/services/src/main/resources/idp-metadata-template.xml b/services/src/main/resources/idp-metadata-template.xml
index 8e4bdb8..6b3d5ec 100755
--- a/services/src/main/resources/idp-metadata-template.xml
+++ b/services/src/main/resources/idp-metadata-template.xml
@@ -18,15 +18,30 @@
 
 <EntitiesDescriptor Name="urn:keycloak"
 	xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
-	xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+	xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 	<EntityDescriptor entityID="${idp.entityID}">
 		<IDPSSODescriptor WantAuthnRequestsSigned="true"
 			protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
-            <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>
-            <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
+
+			<KeyDescriptor use="signing">
+				 <dsig:KeyInfo>
+					 <dsig:X509Data>
+						 <dsig:X509Certificate>
+							 ${idp.signing.certificate}
+						 </dsig:X509Certificate>
+					 </dsig:X509Data>
+				 </dsig:KeyInfo>
+			</KeyDescriptor>
+			<SingleLogoutService
+					Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
+					Location="${idp.sls.HTTP-POST}" />
+			<SingleLogoutService
+					Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
+					Location="${idp.sso.HTTP-Redirect}" />
+			<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>
+			<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
 			<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</NameIDFormat>
 			<NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat>
-
 			<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
 				Location="${idp.sso.HTTP-POST}" />
 			<SingleSignOnService
@@ -35,21 +50,6 @@
 			<SingleSignOnService
 				Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
 				Location="${idp.sso.HTTP-POST}" />
-			<SingleLogoutService
-					Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
-					Location="${idp.sls.HTTP-POST}" />
-			<SingleLogoutService
-					Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
-					Location="${idp.sso.HTTP-Redirect}" />
-            <KeyDescriptor use="signing">
-                <dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
-                    <dsig:X509Data>
-                        <dsig:X509Certificate>
-                            ${idp.signing.certificate}
-                        </dsig:X509Certificate>
-                    </dsig:X509Data>
-                </dsig:KeyInfo>
-            </KeyDescriptor>
 		</IDPSSODescriptor>
 	</EntityDescriptor>
 </EntitiesDescriptor>
\ No newline at end of file
diff --git a/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory b/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory
index 8200374..97c9299 100755
--- a/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory
+++ b/services/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory
@@ -18,6 +18,7 @@
 org.keycloak.authentication.authenticators.browser.CookieAuthenticatorFactory
 org.keycloak.authentication.authenticators.browser.UsernamePasswordFormFactory
 org.keycloak.authentication.authenticators.browser.OTPFormAuthenticatorFactory
+org.keycloak.authentication.authenticators.browser.ScriptBasedAuthenticatorFactory
 org.keycloak.authentication.authenticators.browser.SpnegoAuthenticatorFactory
 org.keycloak.authentication.authenticators.directgrant.ValidateOTP
 org.keycloak.authentication.authenticators.directgrant.ValidatePassword
@@ -32,4 +33,4 @@ org.keycloak.authentication.authenticators.broker.IdpConfirmLinkAuthenticatorFac
 org.keycloak.authentication.authenticators.broker.IdpEmailVerificationAuthenticatorFactory
 org.keycloak.authentication.authenticators.broker.IdpUsernamePasswordFormFactory
 org.keycloak.authentication.authenticators.browser.ConditionalOtpFormAuthenticatorFactory
-org.keycloak.protocol.saml.profile.ecp.authenticator.HttpBasicAuthenticator
\ No newline at end of file
+org.keycloak.protocol.saml.profile.ecp.authenticator.HttpBasicAuthenticator
diff --git a/services/src/main/resources/META-INF/services/org.keycloak.authorization.AuthorizationProviderFactory b/services/src/main/resources/META-INF/services/org.keycloak.authorization.AuthorizationProviderFactory
new file mode 100644
index 0000000..3ffe34c
--- /dev/null
+++ b/services/src/main/resources/META-INF/services/org.keycloak.authorization.AuthorizationProviderFactory
@@ -0,0 +1,19 @@
+#
+# JBoss, Home of Professional Open Source.
+# Copyright 2016 Red Hat, Inc., and individual contributors
+# as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.keycloak.authorization.DefaultAuthorizationProviderFactory
\ No newline at end of file
diff --git a/services/src/main/resources/META-INF/services/org.keycloak.exportimport.ClientDescriptionConverterFactory b/services/src/main/resources/META-INF/services/org.keycloak.exportimport.ClientDescriptionConverterFactory
index c9a536f..1ad9238 100755
--- a/services/src/main/resources/META-INF/services/org.keycloak.exportimport.ClientDescriptionConverterFactory
+++ b/services/src/main/resources/META-INF/services/org.keycloak.exportimport.ClientDescriptionConverterFactory
@@ -16,5 +16,5 @@
 #
 
 org.keycloak.exportimport.KeycloakClientDescriptionConverter
-org.keycloak.protocol.oidc.OIDCClientDescriptionConverter
+org.keycloak.protocol.oidc.OIDCClientDescriptionConverterFactory
 org.keycloak.protocol.saml.EntityDescriptorDescriptionConverter
\ No newline at end of file
diff --git a/services/src/main/resources/META-INF/services/org.keycloak.protocol.oidc.TokenIntrospectionProviderFactory b/services/src/main/resources/META-INF/services/org.keycloak.protocol.oidc.TokenIntrospectionProviderFactory
new file mode 100644
index 0000000..ae45923
--- /dev/null
+++ b/services/src/main/resources/META-INF/services/org.keycloak.protocol.oidc.TokenIntrospectionProviderFactory
@@ -0,0 +1,21 @@
+#
+#  Copyright 2016 Red Hat, Inc. and/or its affiliates
+#  and other contributors as indicated by the @author tags.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#
+
+org.keycloak.protocol.oidc.AccessTokenIntrospectionProviderFactory
+org.keycloak.protocol.oidc.RefreshTokenIntrospectionProviderFactory
+org.keycloak.authorization.protection.introspect.RPTIntrospectionProviderFactory
\ No newline at end of file
diff --git a/services/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper b/services/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper
index 1fc31d7..9d1e10e 100755
--- a/services/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper
+++ b/services/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper
@@ -32,6 +32,7 @@ org.keycloak.protocol.saml.mappers.UserAttributeStatementMapper
 org.keycloak.protocol.saml.mappers.UserPropertyAttributeStatementMapper
 org.keycloak.protocol.saml.mappers.UserSessionNoteStatementMapper
 org.keycloak.protocol.saml.mappers.GroupMembershipMapper
-
+org.keycloak.protocol.oidc.mappers.UserClientRoleMappingMapper
+org.keycloak.protocol.oidc.mappers.UserRealmRoleMappingMapper
 
 
diff --git a/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi
index 50bb346..77cba5e 100755
--- a/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi
+++ b/services/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -18,3 +18,5 @@
 org.keycloak.exportimport.ClientDescriptionConverterSpi
 org.keycloak.wellknown.WellKnownSpi
 org.keycloak.services.clientregistration.ClientRegistrationSpi
+org.keycloak.transaction.TransactionManagerLookupSpi
+
diff --git a/services/src/main/resources/META-INF/services/org.keycloak.scripting.ScriptingProviderFactory b/services/src/main/resources/META-INF/services/org.keycloak.scripting.ScriptingProviderFactory
new file mode 100644
index 0000000..84e53a8
--- /dev/null
+++ b/services/src/main/resources/META-INF/services/org.keycloak.scripting.ScriptingProviderFactory
@@ -0,0 +1 @@
+org.keycloak.scripting.DefaultScriptingProviderFactory
\ No newline at end of file
diff --git a/services/src/main/resources/META-INF/services/org.keycloak.transaction.JtaTransactionManagerLookup b/services/src/main/resources/META-INF/services/org.keycloak.transaction.JtaTransactionManagerLookup
new file mode 100644
index 0000000..bc968c4
--- /dev/null
+++ b/services/src/main/resources/META-INF/services/org.keycloak.transaction.JtaTransactionManagerLookup
@@ -0,0 +1 @@
+org.keycloak.transaction.JBossJtaTransactionManagerLookup
\ No newline at end of file
diff --git a/services/src/main/resources/META-INF/services/org.keycloak.wellknown.WellKnownProviderFactory b/services/src/main/resources/META-INF/services/org.keycloak.wellknown.WellKnownProviderFactory
index afc490e..df3dd7a 100644
--- a/services/src/main/resources/META-INF/services/org.keycloak.wellknown.WellKnownProviderFactory
+++ b/services/src/main/resources/META-INF/services/org.keycloak.wellknown.WellKnownProviderFactory
@@ -15,4 +15,5 @@
 # limitations under the License.
 #
 
-org.keycloak.protocol.oidc.OIDCWellKnownProviderFactory
\ No newline at end of file
+org.keycloak.protocol.oidc.OIDCWellKnownProviderFactory
+org.keycloak.authorization.config.UmaWellKnownProviderFactory
\ No newline at end of file
diff --git a/services/src/test/java/org/keycloak/services/util/LocaleHelperTest.java b/services/src/test/java/org/keycloak/services/util/LocaleHelperTest.java
new file mode 100644
index 0000000..5735886
--- /dev/null
+++ b/services/src/test/java/org/keycloak/services/util/LocaleHelperTest.java
@@ -0,0 +1,23 @@
+package org.keycloak.services.util;
+
+import org.junit.Test;
+
+import java.lang.reflect.Method;
+import java.util.Locale;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsNull.nullValue;
+
+public class LocaleHelperTest {
+
+    @Test
+    public void shouldNotExceptionOnNullLocaleAttributeItem() throws Exception {
+        final Method method = LocaleHelper.class.getDeclaredMethod("findLocale", Set.class, String[].class);
+        method.setAccessible(true);
+        Locale foundLocale = (Locale) method.invoke(null, Stream.of("en", "es", "fr").collect(Collectors.toSet()), new String[]{null});
+        assertThat(foundLocale, nullValue());
+    }
+}
diff --git a/services/src/test/java/org/keycloak/test/broker/saml/SAMLDataMarshallerTest.java b/services/src/test/java/org/keycloak/test/broker/saml/SAMLDataMarshallerTest.java
index 84354b9..9a68621 100755
--- a/services/src/test/java/org/keycloak/test/broker/saml/SAMLDataMarshallerTest.java
+++ b/services/src/test/java/org/keycloak/test/broker/saml/SAMLDataMarshallerTest.java
@@ -35,6 +35,8 @@ public class SAMLDataMarshallerTest {
 
     private static final String TEST_ASSERTION = "<saml:Assertion xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" ID=\"ID_29b196c2-d641-45c8-a423-8ed8e54d4cf9\" Version=\"2.0\" IssueInstant=\"2015-11-06T11:00:33.911Z\"><saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">http://localhost:8082/auth/realms/realm-with-saml-idp-basic</saml:Issuer><saml:Subject><saml:NameID xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" Format=\"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified\">test-user</saml:NameID><saml:SubjectConfirmation Method=\"urn:oasis:names:tc:SAML:2.0:cm:bearer\"><saml:SubjectConfirmationData InResponseTo=\"ID_c6b90123-f0bb-4c5c-bf9d-388d5bbe467a\" NotOnOrAfter=\"2015-11-06T11:05:31.911Z\" Recipient=\"http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-idp-basic/endpoint\"></saml:SubjectConfirmationData></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore=\"2015-11-06T11:00:31.911Z\" NotOnOrAfter=\"2015-11-06T11:01:31.911Z\"><saml:AudienceRestriction><saml:Audience>http://localhost:8081/auth/realms/realm-with-broker</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant=\"2015-11-06T11:00:33.923Z\" SessionIndex=\"fa0f4fd3-8a11-44f4-9acb-ee30c5bb8fe5\"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement><saml:AttributeStatement><saml:Attribute Name=\"mobile\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:basic\"><saml:AttributeValue xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xsi:type=\"xs:string\">617-666-7777</saml:AttributeValue></saml:Attribute><saml:Attribute Name=\"urn:oid:1.2.840.113549.1.9.1\" FriendlyName=\"email\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:basic\"><saml:AttributeValue xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xsi:type=\"xs:string\">test-user@localhost</saml:AttributeValue></saml:Attribute></saml:AttributeStatement><saml:AttributeStatement><saml:Attribute Name=\"Role\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:basic\"><saml:AttributeValue xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xsi:type=\"xs:string\">manager</saml:AttributeValue></saml:Attribute></saml:AttributeStatement></saml:Assertion>";
 
+    private static final String TEST_ASSERTION_WITH_NAME_ID = "<saml:Assertion xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" ID=\"ID_29b196c2-d641-45c8-a423-8ed8e54d4cf9\" Version=\"2.0\" IssueInstant=\"2015-11-06T11:00:33.911Z\"><saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">http://localhost:8082/auth/realms/realm-with-saml-idp-basic</saml:Issuer><saml:Subject><saml:NameID xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" Format=\"urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified\">test-user</saml:NameID><saml:SubjectConfirmation Method=\"urn:oasis:names:tc:SAML:2.0:cm:bearer\"><saml:SubjectConfirmationData InResponseTo=\"ID_c6b90123-f0bb-4c5c-bf9d-388d5bbe467a\" NotOnOrAfter=\"2015-11-06T11:05:31.911Z\" Recipient=\"http://localhost:8081/auth/realms/realm-with-broker/broker/kc-saml-idp-basic/endpoint\"></saml:SubjectConfirmationData></saml:SubjectConfirmation></saml:Subject><saml:Conditions NotBefore=\"2015-11-06T11:00:31.911Z\" NotOnOrAfter=\"2015-11-06T11:01:31.911Z\"><saml:AudienceRestriction><saml:Audience>http://localhost:8081/auth/realms/realm-with-broker</saml:Audience></saml:AudienceRestriction></saml:Conditions><saml:AuthnStatement AuthnInstant=\"2015-11-06T11:00:33.923Z\" SessionIndex=\"fa0f4fd3-8a11-44f4-9acb-ee30c5bb8fe5\"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement><saml:AttributeStatement><saml:Attribute Name=\"mobile\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:basic\"><saml:AttributeValue xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xsi:type=\"xs:string\">617-666-7777</saml:AttributeValue></saml:Attribute><saml:Attribute Name=\"urn:oid:1.2.840.113549.1.9.1\" FriendlyName=\"email\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:basic\"><saml:AttributeValue xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xsi:type=\"xs:string\">test-user@localhost</saml:AttributeValue></saml:Attribute></saml:AttributeStatement><saml:AttributeStatement><saml:Attribute Name=\"Role\" NameFormat=\"urn:oasis:names:tc:SAML:2.0:attrname-format:basic\"><saml:AttributeValue><saml:NameID xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" Format=\"urn:oasis:names:tc:SAML:2.0:nameid-format:persistent\">b2c6275838784dba219c92f53ea5493c8ef4da09</saml:NameID></saml:AttributeValue></saml:Attribute></saml:AttributeStatement></saml:Assertion>";
+    
     private static final String TEST_AUTHN_TYPE = "<saml:AuthnStatement xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" AuthnInstant=\"2015-11-06T11:00:33.923Z\" SessionIndex=\"fa0f4fd3-8a11-44f4-9acb-ee30c5bb8fe5\"><saml:AuthnContext><saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef></saml:AuthnContext></saml:AuthnStatement>";
 
     @Test
@@ -68,6 +70,20 @@ public class SAMLDataMarshallerTest {
     }
 
     @Test
+    public void testParseAssertionWitNameId() throws Exception {
+        SAMLDataMarshaller serializer = new SAMLDataMarshaller();
+        AssertionType assertion = serializer.deserialize(TEST_ASSERTION_WITH_NAME_ID, AssertionType.class);
+
+        // test assertion
+        Assert.assertEquals(assertion.getID(), "ID_29b196c2-d641-45c8-a423-8ed8e54d4cf9");
+        Assert.assertEquals(((NameIDType) assertion.getSubject().getSubType().getBaseID()).getValue(), "test-user");
+
+        // back to String
+        String serialized = serializer.serialize(assertion);
+        Assert.assertEquals(TEST_ASSERTION_WITH_NAME_ID, serialized);
+    }
+    
+    @Test
     public void testParseAuthnType() throws Exception {
         SAMLDataMarshaller serializer = new SAMLDataMarshaller();
         AuthnStatementType authnStatement =  serializer.deserialize(TEST_AUTHN_TYPE, AuthnStatementType.class);
diff --git a/services/src/test/java/org/keycloak/theme/PropertiesUtilTest.java b/services/src/test/java/org/keycloak/theme/PropertiesUtilTest.java
new file mode 100644
index 0000000..7e73614
--- /dev/null
+++ b/services/src/test/java/org/keycloak/theme/PropertiesUtilTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.theme;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.Charset;
+
+import org.junit.Test;
+
+/**
+ * @author <a href="mailto:wadahiro@gmail.com">Hiroyuki Wada</a>
+ */
+public class PropertiesUtilTest {
+
+    @Test
+    public void testDetectEncoding() throws Exception {
+        Charset encoding = PropertiesUtil.detectEncoding(new ByteArrayInputStream("# encoding: utf-8\nkey=value".getBytes()));
+        assertEquals(Charset.forName("utf-8"), encoding);
+
+        encoding = PropertiesUtil.detectEncoding(new ByteArrayInputStream("# encoding: Shift_JIS\nkey=value".getBytes()));
+        assertEquals(Charset.forName("Shift_JIS"), encoding);
+    }
+
+    @Test
+    public void testDefaultEncoding() throws Exception {
+        Charset encoding = PropertiesUtil.detectEncoding(new ByteArrayInputStream("key=value".getBytes()));
+        assertEquals(Charset.forName("ISO-8859-1"), encoding);
+
+        encoding = PropertiesUtil.detectEncoding(new ByteArrayInputStream("# encoding: unknown\nkey=value".getBytes()));
+        assertEquals(Charset.forName("ISO-8859-1"), encoding);
+
+        encoding = PropertiesUtil.detectEncoding(new ByteArrayInputStream("\n# encoding: utf-8\nkey=value".getBytes()));
+        assertEquals(Charset.forName("ISO-8859-1"), encoding);
+
+        encoding = PropertiesUtil.detectEncoding(new ByteArrayInputStream("".getBytes()));
+        assertEquals(Charset.forName("ISO-8859-1"), encoding);
+    }
+}
diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml
index 362d749..aca1d78 100755
--- a/testsuite/integration/pom.xml
+++ b/testsuite/integration/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-testsuite-pom</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -29,6 +29,11 @@
     <name>Keycloak Integration TestSuite</name>
     <description />
 
+    <properties>
+        <maven.compiler.target>1.8</maven.compiler.target>
+        <maven.compiler.source>1.8</maven.compiler.source>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>org.bouncycastle</groupId>
@@ -64,6 +69,10 @@
             <artifactId>jboss-jaxrs-api_2.0_spec</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.jboss.spec.javax.transaction</groupId>
+            <artifactId>jboss-transaction-api_1.2_spec</artifactId>
+        </dependency>
+        <dependency>
             <groupId>org.jboss.resteasy</groupId>
             <artifactId>async-http-servlet-3.0</artifactId>
         </dependency>
@@ -135,6 +144,10 @@
         </dependency>
         <dependency>
             <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-authz-client</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
             <artifactId>keycloak-saml-servlet-filter-adapter</artifactId>
         </dependency>
         <dependency>
@@ -400,6 +413,7 @@
                                 <keycloak.user.provider>jpa</keycloak.user.provider>
                                 <keycloak.userSessionPersister.provider>jpa</keycloak.userSessionPersister.provider>
                                 <keycloak.eventsStore.provider>jpa</keycloak.eventsStore.provider>
+                                <keycloak.authorization.provider>jpa</keycloak.authorization.provider>
 
                                 <keycloak.liquibase.logging.level>debug</keycloak.liquibase.logging.level>
                             </systemPropertyVariables>
@@ -439,6 +453,7 @@
                                         <keycloak.user.provider>mongo</keycloak.user.provider>
                                         <keycloak.userSessionPersister.provider>mongo</keycloak.userSessionPersister.provider>
                                         <keycloak.eventsStore.provider>mongo</keycloak.eventsStore.provider>
+                                        <keycloak.authorization.provider>mongo</keycloak.authorization.provider>
                                         <keycloak.connectionsMongo.host>${keycloak.connectionsMongo.host}</keycloak.connectionsMongo.host>
                                         <keycloak.connectionsMongo.port>${keycloak.connectionsMongo.port}</keycloak.connectionsMongo.port>
                                         <keycloak.connectionsMongo.db>${keycloak.connectionsMongo.db}</keycloak.connectionsMongo.db>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
index 15b48fa..a602ffd 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
@@ -203,4 +203,17 @@ public class AdapterTest {
         testStrategy.testAccountManagementSessionsLogout();
     }
 
+    /**
+     * KEYCLOAK-1733
+     */
+    @Test
+    public void testNullQueryParameterAccessToken() throws Exception {
+        testStrategy.testNullQueryParameterAccessToken();
+    }
+
+    @Test
+    public void testRestCallWithAccessTokenAsQueryParameter() throws Exception {
+        testStrategy.testRestCallWithAccessTokenAsQueryParameter();
+
+    }
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
index c5790dc..adea44e 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
@@ -17,34 +17,29 @@
 package org.keycloak.testsuite.adapter;
 
 import org.apache.http.conn.params.ConnManagerParams;
+import org.json.JSONException;
+import org.json.JSONObject;
 import org.junit.Assert;
 import org.junit.rules.ExternalResource;
 import org.keycloak.OAuth2Constants;
 import org.keycloak.adapters.OIDCAuthenticationError;
-import org.keycloak.common.Version;
-import org.keycloak.representations.VersionRepresentation;
 import org.keycloak.admin.client.Keycloak;
+import org.keycloak.common.Version;
+import org.keycloak.common.util.Time;
 import org.keycloak.constants.AdapterConstants;
-import org.keycloak.models.ClientModel;
-import org.keycloak.models.Constants;
-import org.keycloak.models.KeycloakSession;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.UserModel;
+import org.keycloak.models.*;
 import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
+import org.keycloak.representations.VersionRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.services.managers.ResourceAdminManager;
+import org.keycloak.testsuite.KeycloakServer;
 import org.keycloak.testsuite.OAuthClient;
 import org.keycloak.testsuite.pages.AccountSessionsPage;
 import org.keycloak.testsuite.pages.LoginPage;
-import org.keycloak.testsuite.rule.AbstractKeycloakRule;
-import org.keycloak.testsuite.rule.ErrorServlet;
-import org.keycloak.testsuite.rule.KeycloakRule;
-import org.keycloak.testsuite.rule.WebResource;
-import org.keycloak.testsuite.rule.WebRule;
-import org.keycloak.testsuite.KeycloakServer;
+import org.keycloak.testsuite.rule.*;
 import org.keycloak.util.BasicAuthHelper;
-import org.keycloak.common.util.Time;
 import org.openqa.selenium.WebDriver;
 
 import javax.ws.rs.client.Client;
@@ -59,7 +54,6 @@ import java.net.URI;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
-import org.keycloak.representations.idm.UserRepresentation;
 
 /**
  * Tests Undertow Adapter
@@ -144,7 +138,8 @@ public class AdapterTestStrategy extends ExternalResource {
         System.out.println("insecure: ");
         System.out.println(driver.getPageSource());
         Assert.assertTrue(driver.getPageSource().contains("Insecure Page"));
-        if (System.getProperty("insecure.user.principal.unsupported") == null) Assert.assertTrue(driver.getPageSource().contains("UserPrincipal"));
+        if (System.getProperty("insecure.user.principal.unsupported") == null)
+            Assert.assertTrue(driver.getPageSource().contains("UserPrincipal"));
 
         // test logout
 
@@ -270,7 +265,7 @@ public class AdapterTestStrategy extends ExternalResource {
         RealmModel realm = session.realms().getRealmByName("demo");
         int originalIdle = realm.getSsoSessionIdleTimeout();
         realm.setSsoSessionIdleTimeout(1);
-        session.getTransaction().commit();
+        session.getTransactionManager().commit();
         session.close();
 
         Time.setOffset(2);
@@ -283,7 +278,7 @@ public class AdapterTestStrategy extends ExternalResource {
         session = keycloakRule.startSession();
         realm = session.realms().getRealmByName("demo");
         realm.setSsoSessionIdleTimeout(originalIdle);
-        session.getTransaction().commit();
+        session.getTransactionManager().commit();
         session.close();
 
         Time.setOffset(0);
@@ -305,7 +300,7 @@ public class AdapterTestStrategy extends ExternalResource {
         RealmModel realm = session.realms().getRealmByName("demo");
         int originalIdle = realm.getSsoSessionIdleTimeout();
         realm.setSsoSessionIdleTimeout(1);
-        session.getTransaction().commit();
+        session.getTransactionManager().commit();
         session.close();
 
         Time.setOffset(2);
@@ -313,7 +308,7 @@ public class AdapterTestStrategy extends ExternalResource {
         session = keycloakRule.startSession();
         realm = session.realms().getRealmByName("demo");
         session.sessions().removeExpired(realm);
-        session.getTransaction().commit();
+        session.getTransactionManager().commit();
         session.close();
 
         // test SSO
@@ -326,7 +321,7 @@ public class AdapterTestStrategy extends ExternalResource {
         UserModel user = session.users().getUserByUsername("bburke@redhat.com", realm);
         new ResourceAdminManager(session).logoutUser(null, realm, user, session);
         realm.setSsoSessionIdleTimeout(originalIdle);
-        session.getTransaction().commit();
+        session.getTransactionManager().commit();
         session.close();
 
         Time.setOffset(0);
@@ -348,7 +343,7 @@ public class AdapterTestStrategy extends ExternalResource {
         RealmModel realm = session.realms().getRealmByName("demo");
         int original = realm.getSsoSessionMaxLifespan();
         realm.setSsoSessionMaxLifespan(1);
-        session.getTransaction().commit();
+        session.getTransactionManager().commit();
         session.close();
 
         Time.setOffset(2);
@@ -361,7 +356,7 @@ public class AdapterTestStrategy extends ExternalResource {
         session = keycloakRule.startSession();
         realm = session.realms().getRealmByName("demo");
         realm.setSsoSessionMaxLifespan(original);
-        session.getTransaction().commit();
+        session.getTransactionManager().commit();
         session.close();
 
         Time.setOffset(0);
@@ -385,6 +380,26 @@ public class AdapterTestStrategy extends ExternalResource {
     }
 
     /**
+     * KEYCLOAK-1733
+     *
+     * @throws Exception
+     */
+    public void testNullQueryParameterAccessToken() throws Exception {
+        Client client = ClientBuilder.newClient();
+        WebTarget target = client.target(APP_SERVER_BASE_URL + "/customer-db/");
+        Response response = target.request().get();
+        Assert.assertEquals(401, response.getStatus());
+        response.close();
+
+        target = client.target(APP_SERVER_BASE_URL + "/customer-db?access_token=");
+        response = target.request().get();
+        Assert.assertEquals(401, response.getStatus());
+        response.close();
+
+        client.close();
+    }
+
+    /**
      * KEYCLOAK-1368
      * @throws Exception
      */
@@ -406,7 +421,7 @@ public class AdapterTestStrategy extends ExternalResource {
         Assert.assertTrue(errorPageResponse.contains("Error Page"));
         response.close();
         Assert.assertNotNull(ErrorServlet.authError);
-        OIDCAuthenticationError error = (OIDCAuthenticationError)ErrorServlet.authError;
+        OIDCAuthenticationError error = (OIDCAuthenticationError) ErrorServlet.authError;
         Assert.assertEquals(OIDCAuthenticationError.Reason.NO_BEARER_TOKEN, error.getReason());
 
         ErrorServlet.authError = null;
@@ -422,7 +437,7 @@ public class AdapterTestStrategy extends ExternalResource {
         Assert.assertTrue(errorPageResponse.contains("Error Page"));
         response.close();
         Assert.assertNotNull(ErrorServlet.authError);
-        error = (OIDCAuthenticationError)ErrorServlet.authError;
+        error = (OIDCAuthenticationError) ErrorServlet.authError;
         Assert.assertEquals(OIDCAuthenticationError.Reason.INVALID_TOKEN, error.getReason());
 
         client.close();
@@ -464,8 +479,8 @@ public class AdapterTestStrategy extends ExternalResource {
         String header = BasicAuthHelper.createHeader("customer-portal", "password");
         Form form = new Form();
         form.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD)
-            .param("username", "monkey@redhat.com")
-            .param("password", "password");
+                .param("username", "monkey@redhat.com")
+                .param("password", "password");
         Response response = target.request()
                 .header(HttpHeaders.AUTHORIZATION, header)
                 .post(Entity.form(form));
@@ -496,7 +511,6 @@ public class AdapterTestStrategy extends ExternalResource {
     }
 
 
-
     public void testAuthenticated() throws Exception {
         // test login to customer-portal which does a bearer request to customer-db
         driver.navigate().to(APP_SERVER_BASE_URL + "/secure-portal");
@@ -522,6 +536,53 @@ public class AdapterTestStrategy extends ExternalResource {
     }
 
     /**
+     * KEYCLOAK-1733
+     *
+     * @throws Exception
+     */
+    public void testRestCallWithAccessTokenAsQueryParameter() throws Exception {
+        String accessToken = getAccessToken();
+        Client client = ClientBuilder.newClient();
+        try {
+            // test without token
+            Response response = client.target(APP_SERVER_BASE_URL + "/customer-db").request().get();
+            Assert.assertEquals(401, response.getStatus());
+            response.close();
+            // test with access_token as QueryParamter
+            response = client.target(APP_SERVER_BASE_URL + "/customer-db").queryParam("access_token", accessToken).request().get();
+            Assert.assertEquals(200, response.getStatus());
+            response.close();
+        } finally {
+            client.close();
+        }
+    }
+
+    private String getAccessToken() throws JSONException {
+        String tokenUrl = AUTH_SERVER_URL + "/realms/demo/protocol/openid-connect/token";
+
+        Client client = ClientBuilder.newClient();
+        try {
+            WebTarget webTarget = client.target(tokenUrl);
+
+            Form form = new Form();
+            form.param("grant_type", "password");
+            form.param("client_id", "customer-portal-public");
+            form.param("username", "bburke@redhat.com");
+            form.param("password", "password");
+            Response response = webTarget.request().post(Entity.form(form));
+
+            Assert.assertEquals(200, response.getStatus());
+
+            JSONObject jsonObject = new JSONObject(response.readEntity(String.class));
+            System.out.println(jsonObject);
+            response.close();
+            return jsonObject.getString("access_token");
+        } finally {
+            client.close();
+        }
+    }
+
+    /**
      * KEYCLOAK-732
      *
      * @throws Throwable
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/CookieTokenStoreAdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/CookieTokenStoreAdapterTest.java
index 936dfe9..02e34a7 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/CookieTokenStoreAdapterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/CookieTokenStoreAdapterTest.java
@@ -125,7 +125,7 @@ public class CookieTokenStoreAdapterTest {
             RealmModel realm = session.realms().getRealmByName("demo");
             int originalTokenTimeout = realm.getAccessTokenLifespan();
             realm.setAccessTokenLifespan(3);
-            session.getTransaction().commit();
+            session.getTransactionManager().commit();
             session.close();
 
             // login to customer-cookie-portal
@@ -164,7 +164,7 @@ public class CookieTokenStoreAdapterTest {
             session = keycloakRule.startSession();
             realm = session.realms().getRealmByName("demo");
             realm.setAccessTokenLifespan(originalTokenTimeout);
-            session.getTransaction().commit();
+            session.getTransactionManager().commit();
             session.close();
         } finally {
             Time.setOffset(0);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java
index 19da666..6c10322 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adduser/AddUserTest.java
@@ -107,7 +107,7 @@ public class AddUserTest {
 
             List<RoleRepresentation> realmRoles = userResource.roles().realmLevel().listAll();
 
-            assertRoles(realmRoles, "admin", "offline_access");
+            assertRoles(realmRoles, "admin", "offline_access", Constants.AUTHZ_UMA_AUTHORIZATION);
 
             List<ClientRepresentation> clients = realm.clients().findAll();
             String accountId = null;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/AbstractAuthorizationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/AbstractAuthorizationTest.java
new file mode 100644
index 0000000..fbf602e
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/AbstractAuthorizationTest.java
@@ -0,0 +1,127 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.authorization;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.keycloak.admin.client.Keycloak;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.Constants;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakTransactionManager;
+import org.keycloak.models.RealmModel;
+import org.keycloak.representations.AccessTokenResponse;
+
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.ClientRequestFilter;
+import javax.ws.rs.client.Invocation;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.MASTER;
+import static org.keycloak.models.AdminRoles.ADMIN;
+import static org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public abstract class AbstractAuthorizationTest {
+
+    protected static final String TEST_REALM_NAME = "photoz";
+
+    @Rule
+    public KeycloakAuthorizationServerRule keycloak = new KeycloakAuthorizationServerRule(TEST_REALM_NAME);
+
+    private Keycloak adminClient;
+
+    @Before
+    public void onBefore() {
+        adminClient = Keycloak.getInstance(AUTH_SERVER_ROOT, MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID);
+    }
+
+    protected <R> R onAuthorizationSession(Function<AuthorizationProvider, R> function) {
+        KeycloakSession keycloakSession = startKeycloakSession();
+        KeycloakTransactionManager transaction = keycloakSession.getTransactionManager();
+
+        try {
+            AuthorizationProvider authorizationProvider = keycloakSession.getProvider(AuthorizationProvider.class);
+
+            R result = function.apply(authorizationProvider);
+
+            transaction.commit();
+
+            return result;
+        } catch (Exception e) {
+            transaction.rollback();
+            throw new RuntimeException(e);
+        } finally {
+            if (keycloakSession != null) {
+                keycloakSession.close();
+            }
+        }
+    }
+
+    protected void onAuthorizationSession(Consumer<AuthorizationProvider> consumer) {
+        KeycloakSession keycloakSession = startKeycloakSession();
+        KeycloakTransactionManager transaction = keycloakSession.getTransactionManager();
+
+        try {
+            AuthorizationProvider authorizationProvider = keycloakSession.getProvider(AuthorizationProvider.class);
+
+            consumer.accept(authorizationProvider);
+
+            transaction.commit();
+        } catch (Exception e) {
+            transaction.rollback();
+            throw new RuntimeException(e);
+        } finally {
+            if (keycloakSession != null) {
+                keycloakSession.close();
+            }
+        }
+    }
+
+    protected Invocation.Builder newClient(ClientModel client, String authzRelativePath) {
+        return ClientBuilder.newClient()
+                .register((ClientRequestFilter) requestContext -> {
+                    AccessTokenResponse accessToken = adminClient.tokenManager().getAccessToken();
+                    requestContext.getHeaders().add("Authorization", "Bearer " + accessToken.getToken());
+                }).target(AUTH_SERVER_ROOT + "/admin/realms/" + TEST_REALM_NAME + "/clients/" + client.getId() + "/authz" + authzRelativePath).request();
+    }
+
+    protected ClientModel getClientByClientId(String clientId) {
+        KeycloakSession session = this.keycloak.startSession();
+
+        try {
+            RealmModel realm = session.realms().getRealmByName(TEST_REALM_NAME);
+            return realm.getClientByClientId(clientId);
+        } finally {
+            session.close();
+        }
+    }
+
+    private KeycloakSession startKeycloakSession() {
+        KeycloakSession keycloakSession = this.keycloak.startSession();
+
+        keycloakSession.getContext().setRealm(keycloakSession.realms().getRealmByName(TEST_REALM_NAME));
+
+        return keycloakSession;
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/AbstractPhotozAdminTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/AbstractPhotozAdminTest.java
new file mode 100644
index 0000000..1faf21e
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/AbstractPhotozAdminTest.java
@@ -0,0 +1,379 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.authorization;
+
+import org.apache.commons.collections.map.HashedMap;
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.junit.Before;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.Decision;
+import org.keycloak.authorization.common.KeycloakEvaluationContext;
+import org.keycloak.authorization.common.KeycloakIdentity;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.permission.ResourcePermission;
+import org.keycloak.authorization.policy.evaluation.DefaultEvaluation;
+import org.keycloak.authorization.store.PolicyStore;
+import org.keycloak.authorization.store.ResourceServerStore;
+import org.keycloak.authorization.store.ResourceStore;
+import org.keycloak.authorization.store.ScopeStore;
+import org.keycloak.authorization.store.StoreFactory;
+import org.keycloak.common.ClientConnection;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+import org.keycloak.util.JsonSerialization;
+
+import javax.ws.rs.client.Invocation;
+import javax.ws.rs.core.Cookie;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import java.io.IOException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static org.jboss.aesh.terminal.Key.e;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public abstract class AbstractPhotozAdminTest extends AbstractAuthorizationTest {
+
+    protected ResourceServer resourceServer;
+    protected Resource adminResource;
+    protected Policy anyAdminPolicy;
+    protected Policy onlyFromSpecificAddressPolicy;
+    protected Policy administrationPolicy;
+
+    protected Resource albumResource;
+    protected Policy anyUserPolicy;
+
+    @Before
+    public void onBefore() {
+        super.onBefore();
+        this.resourceServer = createResourceServer();
+        this.adminResource = createAdminAlbumResource();
+        this.anyAdminPolicy = createAnyAdminPolicy();
+        this.onlyFromSpecificAddressPolicy = createOnlyFromSpecificAddressPolicy();
+        this.administrationPolicy = createAdministrationPolicy();
+
+        this.albumResource = createAlbumResource();
+        this.anyUserPolicy = createAnyUserPolicy();
+    }
+
+    protected ResourceServer createResourceServer() {
+        return onAuthorizationSession(authorizationProvider -> {
+            StoreFactory storeFactory = authorizationProvider.getStoreFactory();
+            ResourceServerStore resourceServerStore = storeFactory.getResourceServerStore();
+
+            return resourceServerStore.create(getClientByClientId("photoz-restful-api").getId());
+        });
+    }
+
+    protected Map<String, DefaultEvaluation> performEvaluation(List<ResourcePermission> permissions, AccessToken accessToken, ClientConnection clientConnection) {
+        Map<String, DefaultEvaluation> evaluations = new HashedMap();
+
+        onAuthorizationSession(authorizationProvider -> {
+            StoreFactory storeFactory = authorizationProvider.getStoreFactory();
+
+            // during tests we create resource instances, but we need to reload them to get their collections updated
+            List<ResourcePermission> updatedPermissions = permissions.stream().map(permission -> {
+                Resource resource = storeFactory.getResourceStore().findById(permission.getResource().getId());
+                return new ResourcePermission(resource, permission.getScopes(), permission.getResourceServer());
+            }).collect(Collectors.toList());
+
+            authorizationProvider.evaluators().from(updatedPermissions, createEvaluationContext(accessToken, clientConnection, authorizationProvider)).evaluate(new Decision<DefaultEvaluation>() {
+                @Override
+                public void onDecision(DefaultEvaluation evaluation) {
+                    evaluations.put(evaluation.getPolicy().getId(), evaluation);
+                }
+
+                @Override
+                public void onError(Throwable cause) {
+                    throw new RuntimeException("Permission evaluation failed.", cause);
+                }
+            });
+        });
+
+        return evaluations;
+    }
+
+    private KeycloakEvaluationContext createEvaluationContext(AccessToken accessToken, ClientConnection clientConnection, AuthorizationProvider authorizationProvider) {
+        KeycloakSession keycloakSession = authorizationProvider.getKeycloakSession();
+
+        keycloakSession.getContext().setConnection(clientConnection);
+
+        keycloakSession.getContext().setClient(getClientByClientId("photoz-html5-client"));
+
+        ResteasyProviderFactory.pushContext(HttpHeaders.class, createHttpHeaders());
+
+        KeycloakIdentity identity = new KeycloakIdentity(accessToken, keycloakSession);
+
+        return new KeycloakEvaluationContext(identity, keycloakSession);
+    }
+
+    protected AccessToken createAccessToken(Set<String> roles) {
+        AccessToken accessToken = new AccessToken();
+
+        accessToken.setRealmAccess(new AccessToken.Access());
+        accessToken.getRealmAccess().roles(roles);
+
+        return accessToken;
+    }
+
+
+    private HttpHeaders createHttpHeaders() {
+        return new HttpHeaders() {
+            @Override
+            public List<String> getRequestHeader(String name) {
+                return null;
+            }
+
+            @Override
+            public String getHeaderString(String name) {
+                return null;
+            }
+
+            @Override
+            public MultivaluedMap<String, String> getRequestHeaders() {
+                return null;
+            }
+
+            @Override
+            public List<MediaType> getAcceptableMediaTypes() {
+                return null;
+            }
+
+            @Override
+            public List<Locale> getAcceptableLanguages() {
+                return null;
+            }
+
+            @Override
+            public MediaType getMediaType() {
+                return null;
+            }
+
+            @Override
+            public Locale getLanguage() {
+                return null;
+            }
+
+            @Override
+            public Map<String, Cookie> getCookies() {
+                return null;
+            }
+
+            @Override
+            public Date getDate() {
+                return null;
+            }
+
+            @Override
+            public int getLength() {
+                return 0;
+            }
+        };
+    }
+
+    protected ClientConnection createClientConnection(String remoteAddr) {
+        return new ClientConnection() {
+            @Override
+            public String getRemoteAddr() {
+                return remoteAddr;
+            }
+
+            @Override
+            public String getRemoteHost() {
+                return "localhost";
+            }
+
+            @Override
+            public int getRemotePort() {
+                return 0;
+            }
+
+            @Override
+            public String getLocalAddr() {
+                return null;
+            }
+
+            @Override
+            public int getLocalPort() {
+                return 0;
+            }
+        };
+    }
+
+    protected Invocation.Builder newPermissionRequest(String... id) {
+        String idPathParam = "";
+
+        if (id.length != 0) {
+            idPathParam = "/" + id[0];
+        }
+
+        return newClient(getClientByClientId("photoz-restful-api"), "/resource-server/policy" + idPathParam);
+    }
+
+    private Policy createAdministrationPolicy() {
+        return onAuthorizationSession(authorizationProvider -> {
+            StoreFactory storeFactory = authorizationProvider.getStoreFactory();
+            PolicyStore policyStore = storeFactory.getPolicyStore();
+            Policy policy = policyStore.create("Administration Policy", "aggregate", resourceServer);
+
+            policy.addAssociatedPolicy(anyAdminPolicy);
+            policy.addAssociatedPolicy(onlyFromSpecificAddressPolicy);
+
+            return policy;
+        });
+    }
+
+    private Policy createOnlyFromSpecificAddressPolicy() {
+        return onAuthorizationSession(authorizationProvider -> {
+            StoreFactory storeFactory = authorizationProvider.getStoreFactory();
+            PolicyStore policyStore = storeFactory.getPolicyStore();
+            Policy policy = policyStore.create("Only From a Specific Client Address", "js", resourceServer);
+            HashedMap config = new HashedMap();
+
+            config.put("code",
+                    "var contextAttributes = $evaluation.getContext().getAttributes();" +
+                    "var networkAddress = contextAttributes.getValue('kc.client.network.ip_address');" +
+                    "if ('127.0.0.1'.equals(networkAddress.asInetAddress(0).getHostAddress())) {" +
+                        "$evaluation.grant();" +
+                    "}");
+
+            policy.setConfig(config);
+
+            return policy;
+        });
+    }
+
+    private Policy createAnyAdminPolicy() {
+        return onAuthorizationSession(authorizationProvider -> {
+            StoreFactory storeFactory = authorizationProvider.getStoreFactory();
+            PolicyStore policyStore = storeFactory.getPolicyStore();
+            Policy policy = policyStore.create("Any Admin Policy", "role", resourceServer);
+            HashedMap config = new HashedMap();
+            RealmModel realm = authorizationProvider.getKeycloakSession().realms().getRealmByName(TEST_REALM_NAME);
+            RoleModel adminRole = realm.getRole("admin");
+
+            Map role = new HashMap();
+
+            role.put("id", adminRole.getId());
+
+            try {
+                config.put("roles", JsonSerialization.writeValueAsString(new Map[] {role}));
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+
+            policy.setConfig(config);
+
+            return policy;
+        });
+    }
+
+    private Resource createAdminAlbumResource() {
+        ResourceRepresentation representation = new ResourceRepresentation();
+
+        representation.setName("Admin Resources");
+        representation.setType("http://photoz.com/admin");
+        representation.setUri("/admin/*");
+
+        HashSet<ScopeRepresentation> scopes = new HashSet<>();
+
+        scopes.add(new ScopeRepresentation("urn:photoz.com:scopes:album:admin:manage"));
+
+        representation.setScopes(scopes);
+
+        return createResource(representation);
+    }
+
+    private Resource createAlbumResource() {
+        ResourceRepresentation representation = new ResourceRepresentation();
+
+        representation.setName("Album Resource");
+        representation.setType("http://photoz.com/album");
+        representation.setUri("/album/*");
+
+        HashSet<ScopeRepresentation> scopes = new HashSet<>();
+
+        scopes.add(new ScopeRepresentation("urn:photoz.com:scopes:album:view"));
+        scopes.add(new ScopeRepresentation("urn:photoz.com:scopes:album:create"));
+        scopes.add(new ScopeRepresentation("urn:photoz.com:scopes:album:delete"));
+
+        representation.setScopes(scopes);
+
+        return createResource(representation);
+    }
+
+    protected Resource createResource(ResourceRepresentation representation) {
+        return onAuthorizationSession(authorizationProvider -> {
+            StoreFactory storeFactory = authorizationProvider.getStoreFactory();
+            ScopeStore scopeStore = storeFactory.getScopeStore();
+
+            representation.getScopes().forEach(scopeRepresentation -> {
+                scopeStore.create(scopeRepresentation.getName(), resourceServer);
+            });
+
+            ResourceStore resourceStore = storeFactory.getResourceStore();
+            Resource albumResource = resourceStore.create(representation.getName(), resourceServer, resourceServer.getId());
+
+            albumResource.setType(representation.getType());
+            albumResource.setUri(representation.getUri());
+            albumResource.setIconUri(representation.getIconUri());
+
+            return albumResource;
+        });
+    }
+
+    private Policy createAnyUserPolicy() {
+        return onAuthorizationSession(authorizationProvider -> {
+            StoreFactory storeFactory = authorizationProvider.getStoreFactory();
+            PolicyStore policyStore = storeFactory.getPolicyStore();
+            Policy policy = policyStore.create("Any User Policy", "role", resourceServer);
+            HashedMap config = new HashedMap();
+            RealmModel realm = authorizationProvider.getKeycloakSession().realms().getRealmByName(TEST_REALM_NAME);
+            RoleModel userRole = realm.getRole("user");
+
+            Map role = new HashMap();
+
+            role.put("id", userRole.getId());
+
+            try {
+                config.put("roles", JsonSerialization.writeValueAsString(new Map[] {role}));
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+
+            policy.setConfig(config);
+
+            return policy;
+        });
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/AttributeTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/AttributeTest.java
new file mode 100644
index 0000000..86e1ba0
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/AttributeTest.java
@@ -0,0 +1,73 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.authorization;
+
+import org.apache.commons.collections.map.HashedMap;
+import org.junit.Test;
+import org.keycloak.authorization.attribute.Attributes;
+
+import java.net.InetAddress;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Map;
+import java.util.function.Consumer;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.*;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AttributeTest {
+
+    @Test
+    public void testManageAttributes() throws ParseException {
+        Map<String, Collection<String>> map = new HashedMap();
+
+        map.put("integer", asList("1"));
+        map.put("long", asList("" + Long.MAX_VALUE));
+        map.put("string", asList("some string"));
+        map.put("date", asList("12/12/2016"));
+        map.put("ip_network_address", asList("127.0.0.1"));
+        map.put("host_network_address", asList("localhost"));
+        map.put("multi_valued", asList("1", "2", "3", "4"));
+
+        Attributes attributes = Attributes.from(map);
+
+        map.keySet().forEach(new Consumer<String>() {
+            @Override
+            public void accept(String name) {
+                assertTrue(attributes.exists(name));
+            }
+        });
+
+        assertFalse(attributes.exists("not_found"));
+        assertTrue(attributes.containsValue("integer", "1"));
+        assertTrue(attributes.containsValue("multi_valued", "3"));
+
+        assertEquals(1, attributes.getValue("multi_valued").asInt(0));
+        assertEquals(4, attributes.getValue("multi_valued").asInt(3));
+
+        assertEquals(new SimpleDateFormat("dd/MM/yyyy").parse("12/12/2016"), attributes.getValue("date").asDate(0, "dd/MM/yyyy"));
+
+        assertEquals(InetAddress.getLoopbackAddress(), attributes.getValue("ip_network_address").asInetAddress(0));
+        assertEquals(InetAddress.getLoopbackAddress(), attributes.getValue("host_network_address").asInetAddress(0));
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/KeycloakAuthorizationServerRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/KeycloakAuthorizationServerRule.java
new file mode 100644
index 0000000..1df0b61
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/KeycloakAuthorizationServerRule.java
@@ -0,0 +1,47 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.authorization;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.models.RealmModel;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.testsuite.rule.AbstractKeycloakRule;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class KeycloakAuthorizationServerRule extends AbstractKeycloakRule {
+
+    private final String realmName;
+
+    KeycloakAuthorizationServerRule(String realmName) {
+        this.realmName = realmName;
+    }
+
+    @Override
+    protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
+        server.importRealm(getClass().getResourceAsStream("/authorization-test/test-" + realmName + "-realm.json"));
+    }
+
+    @Override
+    protected String[] getTestRealms() {
+        return new String[] {this.realmName};
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/ResourceManagementTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/ResourceManagementTest.java
new file mode 100644
index 0000000..4a6f9b6
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/ResourceManagementTest.java
@@ -0,0 +1,163 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.authorization;
+
+import org.junit.Test;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.Invocation.Builder;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import static org.junit.Assert.*;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ResourceManagementTest extends AbstractPhotozAdminTest {
+
+    @Test
+    public void testCreate() throws Exception {
+        ResourceRepresentation newResource = new ResourceRepresentation();
+
+        newResource.setName("New Resource");
+        newResource.setType("Resource Type");
+        newResource.setIconUri("Resource Icon URI");
+        newResource.setUri("Resource URI");
+
+        Response response = newResourceRequest().post(Entity.entity(newResource, MediaType.APPLICATION_JSON_TYPE));
+
+        assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
+
+        ResourceRepresentation resource = response.readEntity(ResourceRepresentation.class);
+
+        onAuthorizationSession(authorizationProvider -> {
+            Resource resourceModel = authorizationProvider.getStoreFactory().getResourceStore().findById(resource.getId());
+
+            assertNotNull(resourceModel);
+            assertEquals(resource.getId(), resourceModel.getId());
+            assertEquals("New Resource", resourceModel.getName());
+            assertEquals("Resource Type", resourceModel.getType());
+            assertEquals("Resource Icon URI", resourceModel.getIconUri());
+            assertEquals("Resource URI", resourceModel.getUri());
+            assertEquals(resourceServer.getClientId(), resourceModel.getOwner());
+            assertEquals(resourceServer.getId(), resourceModel.getResourceServer().getId());
+        });
+    }
+
+    @Test
+    public void testUpdate() throws Exception {
+        ResourceRepresentation newResource = new ResourceRepresentation();
+
+        newResource.setName("New Resource");
+        newResource.setType("Resource Type");
+        newResource.setIconUri("Resource Icon URI");
+        newResource.setUri("Resource URI");
+
+        Response response = newResourceRequest().post(Entity.entity(newResource, MediaType.APPLICATION_JSON_TYPE));
+
+        assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
+
+        newResource.setName("New Resource Changed");
+        newResource.setType("Resource Type Changed");
+        newResource.setIconUri("Resource Icon URI Changed");
+        newResource.setUri("Resource URI Changed");
+
+        response = newResourceRequest().post(Entity.entity(newResource, MediaType.APPLICATION_JSON_TYPE));
+
+        ResourceRepresentation resource = response.readEntity(ResourceRepresentation.class);
+
+        onAuthorizationSession(authorizationProvider -> {
+            Resource resourceModel = authorizationProvider.getStoreFactory().getResourceStore().findById(resource.getId());
+
+            assertNotNull(resourceModel);
+            assertEquals(resource.getId(), resourceModel.getId());
+            assertEquals("New Resource Changed", resourceModel.getName());
+            assertEquals("Resource Type Changed", resourceModel.getType());
+            assertEquals("Resource Icon URI Changed", resourceModel.getIconUri());
+            assertEquals("Resource URI Changed", resourceModel.getUri());
+            assertEquals(resourceServer.getId(), resourceModel.getResourceServer().getId());
+        });
+    }
+
+    @Test
+    public void testFindById() throws Exception {
+        ResourceRepresentation newResource = new ResourceRepresentation();
+
+        newResource.setName("New Resource");
+        newResource.setType("Resource Type");
+        newResource.setIconUri("Resource Icon URI");
+        newResource.setUri("Resource URI");
+
+        Response response = newResourceRequest().post(Entity.entity(newResource, MediaType.APPLICATION_JSON_TYPE));
+
+        assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
+
+        ResourceRepresentation resource = response.readEntity(ResourceRepresentation.class);
+
+        response = newResourceRequest(resource.getId()).get();
+
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+        resource = response.readEntity(ResourceRepresentation.class);
+
+        assertEquals("New Resource", resource.getName());
+        assertEquals("Resource Type", resource.getType());
+        assertEquals("Resource Icon URI", resource.getIconUri());
+        assertEquals("Resource URI", resource.getUri());
+    }
+
+    @Test
+    public void testDelete() throws Exception {
+        ResourceRepresentation newResource = new ResourceRepresentation();
+
+        newResource.setName("New Resource");
+
+        Response response = newResourceRequest().post(Entity.entity(newResource, MediaType.APPLICATION_JSON_TYPE));
+
+        assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
+
+        ResourceRepresentation resource = response.readEntity(ResourceRepresentation.class);
+
+        assertNotNull(resource.getId());
+
+        response = newResourceRequest(resource.getId()).delete();
+
+        assertEquals(Status.NO_CONTENT.getStatusCode(), response.getStatus());
+
+        onAuthorizationSession(authorizationProvider -> {
+            Resource resourceModel = authorizationProvider.getStoreFactory().getResourceStore().findById(resource.getId());
+
+            assertNull(resourceModel);
+        });
+    }
+
+    private Builder newResourceRequest(String... id) {
+        String idPathParam = "";
+
+        if (id.length != 0) {
+            idPathParam = "/" + id[0];
+        }
+
+        return newClient(getClientByClientId("photoz-restful-api"), "/resource-server/resource" + idPathParam);
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/ResourcePermissionManagementTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/ResourcePermissionManagementTest.java
new file mode 100644
index 0000000..50ab943
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/ResourcePermissionManagementTest.java
@@ -0,0 +1,365 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.authorization;
+
+import org.apache.commons.collections.map.HashedMap;
+import org.junit.Test;
+import org.keycloak.authorization.Decision.Effect;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.Resource;
+import org.keycloak.authorization.permission.ResourcePermission;
+import org.keycloak.authorization.policy.evaluation.DefaultEvaluation;
+import org.keycloak.representations.idm.authorization.DecisionStrategy;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.util.JsonSerialization;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.junit.Assert.*;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ResourcePermissionManagementTest extends AbstractPhotozAdminTest {
+
+    @Test
+    public void testCreateForTypeWithSinglePolicy() throws Exception {
+        PolicyRepresentation newPermission = new PolicyRepresentation();
+
+        newPermission.setName("Admin Resource Policy");
+        newPermission.setType("resource");
+
+        HashedMap config = new HashedMap();
+
+        config.put("defaultResourceType", "http://photoz.com/admin");
+        config.put("applyPolicies", JsonSerialization.writeValueAsString(new String[] {this.administrationPolicy.getId()}));
+
+        newPermission.setConfig(config);
+
+        Response response = newPermissionRequest().post(Entity.entity(newPermission, MediaType.APPLICATION_JSON_TYPE));
+
+        assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
+
+        PolicyRepresentation permission = response.readEntity(PolicyRepresentation.class);
+
+        onAuthorizationSession(authorizationProvider -> {
+            Policy policyModel = authorizationProvider.getStoreFactory().getPolicyStore().findById(permission.getId());
+
+            assertNotNull(policyModel);
+            assertEquals(permission.getId(), policyModel.getId());
+            assertEquals(newPermission.getName(), policyModel.getName());
+            assertEquals(newPermission.getType(), policyModel.getType());
+            assertEquals(resourceServer.getId(), policyModel.getResourceServer().getId());
+        });
+
+        Set<String> roles = new HashSet<>();
+
+        roles.add("admin");
+
+        Map<String, DefaultEvaluation> evaluationsAdminRole = performEvaluation(
+                Arrays.asList(new ResourcePermission(adminResource, Collections.emptyList(), resourceServer)),
+                createAccessToken(roles),
+                createClientConnection("127.0.0.1"));
+
+        assertEquals(1, evaluationsAdminRole.size());
+        assertTrue(evaluationsAdminRole.containsKey(this.administrationPolicy.getId()));
+        assertEquals(Effect.PERMIT, evaluationsAdminRole.get(this.administrationPolicy.getId()).getEffect());
+
+        evaluationsAdminRole = performEvaluation(
+                Arrays.asList(new ResourcePermission(adminResource, Collections.emptyList(), resourceServer)),
+                createAccessToken(roles),
+                createClientConnection("127.0.0.10"));
+
+        assertEquals(1, evaluationsAdminRole.size());
+        assertTrue(evaluationsAdminRole.containsKey(this.administrationPolicy.getId()));
+        assertEquals(Effect.DENY, evaluationsAdminRole.get(this.administrationPolicy.getId()).getEffect());
+
+        roles.clear();
+        roles.add("user");
+
+        Map<String, DefaultEvaluation> evaluationsUserRole = performEvaluation(
+                Arrays.asList(new ResourcePermission(adminResource, Collections.emptyList(), resourceServer)),
+                createAccessToken(roles),
+                createClientConnection("127.0.0.1"));
+
+        assertEquals(1, evaluationsUserRole.size());
+        assertTrue(evaluationsUserRole.containsKey(this.administrationPolicy.getId()));
+        assertEquals(Effect.DENY, evaluationsUserRole.get(this.administrationPolicy.getId()).getEffect());
+    }
+
+    @Test
+    public void testCreateForTypeWithMultiplePolicies() throws Exception {
+        createAlbumResourceTypePermission();
+
+        HashSet<String> roles = new HashSet<>();
+
+        roles.add("admin");
+
+        Map<String, DefaultEvaluation> evaluationsAdminRole = performEvaluation(
+                Arrays.asList(new ResourcePermission(albumResource, Collections.emptyList(), resourceServer)),
+                createAccessToken(roles),
+                createClientConnection("127.0.0.1"));
+
+        assertEquals(2, evaluationsAdminRole.size());
+        assertTrue(evaluationsAdminRole.containsKey(this.administrationPolicy.getId()));
+        assertTrue(evaluationsAdminRole.containsKey(this.anyUserPolicy.getId()));
+        assertEquals(Effect.DENY, evaluationsAdminRole.get(this.anyUserPolicy.getId()).getEffect());
+        assertEquals(Effect.PERMIT, evaluationsAdminRole.get(this.administrationPolicy.getId()).getEffect());
+
+        evaluationsAdminRole = performEvaluation(
+                Arrays.asList(new ResourcePermission(albumResource, Collections.emptyList(), resourceServer)),
+                createAccessToken(roles),
+                createClientConnection("127.0.0.10"));
+
+        assertEquals(2, evaluationsAdminRole.size());
+        assertTrue(evaluationsAdminRole.containsKey(this.administrationPolicy.getId()));
+        assertTrue(evaluationsAdminRole.containsKey(this.anyUserPolicy.getId()));
+        assertEquals(Effect.DENY, evaluationsAdminRole.get(this.anyUserPolicy.getId()).getEffect());
+        assertEquals(Effect.DENY, evaluationsAdminRole.get(this.administrationPolicy.getId()).getEffect());
+
+        roles.clear();
+        roles.add("user");
+
+        Map<String, DefaultEvaluation> evaluationsUserRole = performEvaluation(
+                Arrays.asList(new ResourcePermission(albumResource, Collections.emptyList(), resourceServer)),
+                createAccessToken(roles),
+                createClientConnection("127.0.0.1"));
+
+        assertEquals(2, evaluationsUserRole.size());
+        assertTrue(evaluationsUserRole.containsKey(this.administrationPolicy.getId()));
+        assertTrue(evaluationsUserRole.containsKey(this.anyUserPolicy.getId()));
+        assertEquals(Effect.PERMIT, evaluationsUserRole.get(this.anyUserPolicy.getId()).getEffect());
+        assertEquals(Effect.DENY, evaluationsUserRole.get(this.administrationPolicy.getId()).getEffect());
+    }
+
+    @Test
+    public void testUpdate() throws Exception {
+        PolicyRepresentation permission = createAlbumResourceTypePermission();
+        Map<String, String> config = permission.getConfig();
+
+        config.put("applyPolicies", JsonSerialization.writeValueAsString(new String[] {this.anyUserPolicy.getId()}));
+
+        permission.setConfig(config);
+
+        newPermissionRequest(permission.getId()).put(Entity.entity(permission, MediaType.APPLICATION_JSON_TYPE));
+
+        HashSet<String> roles = new HashSet<>();
+
+        roles.add("admin");
+
+        Map<String, DefaultEvaluation> evaluationsAdminRole = performEvaluation(
+                Arrays.asList(new ResourcePermission(albumResource, Collections.emptyList(), resourceServer)),
+                createAccessToken(roles),
+                createClientConnection("127.0.0.1"));
+
+        assertEquals(1, evaluationsAdminRole.size());
+        assertTrue(evaluationsAdminRole.containsKey(this.anyUserPolicy.getId()));
+        assertEquals(Effect.DENY, evaluationsAdminRole.get(this.anyUserPolicy.getId()).getEffect());
+    }
+
+    @Test
+    public void testDelete() throws Exception {
+        PolicyRepresentation newPermission = createAlbumResourceTypePermission();
+
+        Response delete = newPermissionRequest(newPermission.getId()).delete();
+
+        assertEquals(Status.NO_CONTENT.getStatusCode(), delete.getStatus());
+    }
+
+    @Test
+    public void testFindById() throws Exception {
+        PolicyRepresentation newPermission = createAlbumResourceTypePermission();
+
+        Response response = newPermissionRequest(newPermission.getId()).get();
+
+        PolicyRepresentation permission = response.readEntity(PolicyRepresentation.class);
+
+        assertEquals(newPermission.getId(), permission.getId());
+        assertEquals(newPermission.getName(), permission.getName());
+        assertEquals(newPermission.getType(), permission.getType());
+    }
+
+    @Test
+    public void testCreatePolicyForResource() throws Exception {
+        PolicyRepresentation newPermission = new PolicyRepresentation();
+
+        newPermission.setName("Multiple Resource Policy");
+        newPermission.setType("resource");
+
+        HashedMap config = new HashedMap();
+
+        config.put("resources", JsonSerialization.writeValueAsString(new String[] {this.albumResource.getId(), this.adminResource.getId()}));
+        config.put("applyPolicies", JsonSerialization.writeValueAsString(new String[] {this.onlyFromSpecificAddressPolicy.getId()}));
+
+        newPermission.setConfig(config);
+
+        Response response = newPermissionRequest().post(Entity.entity(newPermission, MediaType.APPLICATION_JSON_TYPE));
+
+        assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
+
+        List<ResourcePermission> permissions = new ArrayList<>();
+
+        permissions.add(new ResourcePermission(this.albumResource, Collections.emptyList(), this.resourceServer));
+
+        Map<String, DefaultEvaluation> evaluations = performEvaluation(
+                permissions,
+                createAccessToken(Collections.emptySet()),
+                createClientConnection("127.0.0.1"));
+
+        assertEquals(1, evaluations.size());
+        assertTrue(evaluations.containsKey(this.onlyFromSpecificAddressPolicy.getId()));
+        assertEquals(Effect.PERMIT, evaluations.get(this.onlyFromSpecificAddressPolicy.getId()).getEffect());
+
+        permissions = new ArrayList<>();
+
+        permissions.add(new ResourcePermission(this.adminResource, Collections.emptyList(), this.resourceServer));
+
+        evaluations = performEvaluation(
+                permissions,
+                createAccessToken(Collections.emptySet()),
+                createClientConnection("127.0.0.1"));
+
+        assertEquals(1, evaluations.size());
+        assertTrue(evaluations.containsKey(this.onlyFromSpecificAddressPolicy.getId()));
+        assertEquals(Effect.PERMIT, evaluations.get(this.onlyFromSpecificAddressPolicy.getId()).getEffect());
+
+        permissions = new ArrayList<>();
+
+        permissions.add(new ResourcePermission(this.adminResource, Collections.emptyList(), this.resourceServer));
+        permissions.add(new ResourcePermission(this.albumResource, Collections.emptyList(), this.resourceServer));
+
+        evaluations = performEvaluation(
+                permissions,
+                createAccessToken(Collections.emptySet()),
+                createClientConnection("127.0.0.1"));
+
+        assertEquals(1, evaluations.size());
+        assertTrue(evaluations.containsKey(this.onlyFromSpecificAddressPolicy.getId()));
+        assertEquals(Effect.PERMIT, evaluations.get(this.onlyFromSpecificAddressPolicy.getId()).getEffect());
+
+        permissions = new ArrayList<>();
+
+        permissions.add(new ResourcePermission(this.adminResource, Collections.emptyList(), this.resourceServer));
+        permissions.add(new ResourcePermission(this.albumResource, Collections.emptyList(), this.resourceServer));
+
+        evaluations = performEvaluation(
+                permissions,
+                createAccessToken(Collections.emptySet()),
+                createClientConnection("127.0.0.10"));
+
+        assertEquals(1, evaluations.size());
+        assertTrue(evaluations.containsKey(this.onlyFromSpecificAddressPolicy.getId()));
+        assertEquals(Effect.DENY, evaluations.get(this.onlyFromSpecificAddressPolicy.getId()).getEffect());
+    }
+
+    /**
+     * Tests if a resource can inherit the policies defined for another resource based on its type
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testInheritPoliciesBasedOnResourceType() throws Exception {
+        createAlbumResourceTypePermission();
+        ResourceRepresentation representation = new ResourceRepresentation();
+
+        representation.setName("Alice Family Album");
+        representation.setType(this.albumResource.getType());
+
+        Resource resource = createResource(representation);
+
+        Set<String> roles = new HashSet<>();
+
+        roles.add("user");
+
+        Map<String, DefaultEvaluation> evaluationsUserRole = performEvaluation(
+                Arrays.asList(new ResourcePermission(resource, Collections.emptyList(), resourceServer)),
+                createAccessToken(roles),
+                createClientConnection("127.0.0.1"));
+
+        assertEquals(2, evaluationsUserRole.size());
+        assertTrue(evaluationsUserRole.containsKey(this.administrationPolicy.getId()));
+        assertTrue(evaluationsUserRole.containsKey(this.anyUserPolicy.getId()));
+        assertEquals(Effect.PERMIT, evaluationsUserRole.get(this.anyUserPolicy.getId()).getEffect());
+        assertEquals(Effect.DENY, evaluationsUserRole.get(this.administrationPolicy.getId()).getEffect());
+
+        ResourceRepresentation someResourceRep = new ResourceRepresentation();
+
+        someResourceRep.setName("Some Resource");
+        someResourceRep.setType("Some non-existent type");
+
+        Resource someResource = createResource(someResourceRep);
+
+        evaluationsUserRole = performEvaluation(
+                Arrays.asList(new ResourcePermission(someResource, Collections.emptyList(), resourceServer)),
+                createAccessToken(roles),
+                createClientConnection("127.0.0.1"));
+
+        // no policies can be applied given that there is no policy defined for this resource or its type
+        assertEquals(0, evaluationsUserRole.size());
+    }
+
+    private PolicyRepresentation createAlbumResourceTypePermission() throws Exception {
+        PolicyRepresentation newPermission = new PolicyRepresentation();
+
+        newPermission.setName("Album Resource Policy");
+        newPermission.setType("resource");
+        newPermission.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE);
+
+        HashedMap config = new HashedMap();
+
+        config.put("defaultResourceType",  albumResource.getType());
+
+        String applyPolicies = JsonSerialization.writeValueAsString(new String[]{this.anyUserPolicy.getId(), this.administrationPolicy.getId()});
+
+        config.put("applyPolicies", applyPolicies);
+
+        newPermission.setConfig(config);
+
+        Response response = newPermissionRequest().post(Entity.entity(newPermission, MediaType.APPLICATION_JSON_TYPE));
+
+        assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
+
+        PolicyRepresentation permission = response.readEntity(PolicyRepresentation.class);
+
+        onAuthorizationSession(authorizationProvider -> {
+            Policy policyModel = authorizationProvider.getStoreFactory().getPolicyStore().findById(permission.getId());
+
+            assertNotNull(policyModel);
+            assertEquals(permission.getId(), policyModel.getId());
+            assertEquals(permission.getName(), policyModel.getName());
+            assertEquals(permission.getType(), policyModel.getType());
+            assertTrue(permission.getConfig().containsValue(albumResource.getType()));
+            assertTrue(permission.getConfig().containsValue(applyPolicies));
+            assertEquals(resourceServer.getId(), policyModel.getResourceServer().getId());
+        });
+
+        return permission;
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/ScopeManagementTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/ScopeManagementTest.java
new file mode 100644
index 0000000..4566fe6
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/authorization/ScopeManagementTest.java
@@ -0,0 +1,148 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.authorization;
+
+import org.junit.Test;
+import org.keycloak.authorization.model.Scope;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.Invocation.Builder;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import static org.junit.Assert.*;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ScopeManagementTest extends AbstractPhotozAdminTest {
+
+    @Test
+    public void testCreate() throws Exception {
+        ScopeRepresentation newScope = new ScopeRepresentation();
+
+        newScope.setName("New Scope");
+        newScope.setIconUri("Icon URI");
+
+        Response response = newScopeRequest().post(Entity.entity(newScope, MediaType.APPLICATION_JSON_TYPE));
+
+        assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
+
+        ScopeRepresentation scope = response.readEntity(ScopeRepresentation.class);
+
+        onAuthorizationSession(authorizationProvider -> {
+            Scope scopeModel = authorizationProvider.getStoreFactory().getScopeStore().findById(scope.getId());
+
+            assertNotNull(scopeModel);
+            assertEquals(scope.getId(), scopeModel.getId());
+            assertEquals("New Scope", scopeModel.getName());
+            assertEquals("Icon URI", scopeModel.getIconUri());
+            assertEquals(resourceServer.getId(), scopeModel.getResourceServer().getId());
+        });
+    }
+
+    @Test
+    public void testUpdate() throws Exception {
+        ScopeRepresentation newScope = new ScopeRepresentation();
+
+        newScope.setName("New Scope");
+        newScope.setIconUri("Icon URI");
+
+        Response response = newScopeRequest().post(Entity.entity(newScope, MediaType.APPLICATION_JSON_TYPE));
+
+        assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
+
+        newScope.setName("New Scope Changed");
+        newScope.setIconUri("Icon URI Changed");
+
+        response = newScopeRequest().post(Entity.entity(newScope, MediaType.APPLICATION_JSON_TYPE));
+
+        ScopeRepresentation scope = response.readEntity(ScopeRepresentation.class);
+
+        onAuthorizationSession(authorizationProvider -> {
+            Scope scopeModel = authorizationProvider.getStoreFactory().getScopeStore().findById(scope.getId());
+
+            assertNotNull(scopeModel);
+            assertEquals(scope.getId(), scopeModel.getId());
+            assertEquals("New Scope Changed", scopeModel.getName());
+            assertEquals("Icon URI Changed", scopeModel.getIconUri());
+            assertEquals(resourceServer.getId(), scopeModel.getResourceServer().getId());
+        });
+    }
+
+    @Test
+    public void testFindById() throws Exception {
+        ScopeRepresentation newScope = new ScopeRepresentation();
+
+        newScope.setName("New Scope");
+        newScope.setIconUri("Icon URI");
+
+        Response response = newScopeRequest().post(Entity.entity(newScope, MediaType.APPLICATION_JSON_TYPE));
+
+        assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
+
+        ScopeRepresentation scope = response.readEntity(ScopeRepresentation.class);
+
+        response = newScopeRequest(scope.getId()).get();
+
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+        scope = response.readEntity(ScopeRepresentation.class);
+
+        assertEquals("New Scope", scope.getName());
+        assertEquals("Icon URI", scope.getIconUri());
+    }
+
+    @Test
+    public void testDelete() throws Exception {
+        ScopeRepresentation newScope = new ScopeRepresentation();
+
+        newScope.setName("New Scope");
+
+        Response response = newScopeRequest().post(Entity.entity(newScope, MediaType.APPLICATION_JSON_TYPE));
+
+        assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
+
+        ScopeRepresentation scope = response.readEntity(ScopeRepresentation.class);
+
+        assertNotNull(scope.getId());
+
+        response = newScopeRequest(scope.getId()).delete();
+
+        assertEquals(Status.NO_CONTENT.getStatusCode(), response.getStatus());
+
+        onAuthorizationSession(authorizationProvider -> {
+            Scope scopeModel = authorizationProvider.getStoreFactory().getScopeStore().findById(scope.getId());
+
+            assertNull(scopeModel);
+        });
+    }
+
+    private Builder newScopeRequest(String... id) {
+        String idPathParam = "";
+
+        if (id.length != 0) {
+            idPathParam = "/" + id[0];
+        }
+
+        return newClient(getClientByClientId("photoz-restful-api"), "/resource-server/scope" + idPathParam);
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java
index 1af21f5..7683d0c 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractKeycloakIdentityProviderTest.java
@@ -72,7 +72,9 @@ public abstract class AbstractKeycloakIdentityProviderTest extends AbstractIdent
 
     @Test
     public void testDisabledUser() {
+        KeycloakSession session = brokerServerRule.startSession();
         setUpdateProfileFirstLogin(session.realms().getRealmByName("realm-with-broker"), IdentityProviderRepresentation.UPFLM_OFF);
+        brokerServerRule.stopSession(session, true);
 
         driver.navigate().to("http://localhost:8081/test-app");
         loginPage.clickSocial(getProviderId());
@@ -81,7 +83,7 @@ public abstract class AbstractKeycloakIdentityProviderTest extends AbstractIdent
         driver.navigate().to("http://localhost:8081/test-app/logout");
 
         try {
-            KeycloakSession session = brokerServerRule.startSession();
+            session = brokerServerRule.startSession();
             session.users().getUserByUsername("test-user", session.realms().getRealmByName("realm-with-broker")).setEnabled(false);
             brokerServerRule.stopSession(session, true);
 
@@ -93,7 +95,7 @@ public abstract class AbstractKeycloakIdentityProviderTest extends AbstractIdent
             assertTrue(errorPage.isCurrent());
             assertEquals("Account is disabled, contact admin.", errorPage.getError());
         } finally {
-            KeycloakSession session = brokerServerRule.startSession();
+            session = brokerServerRule.startSession();
             session.users().getUserByUsername("test-user", session.realms().getRealmByName("realm-with-broker")).setEnabled(true);
             brokerServerRule.stopSession(session, true);
         }
@@ -101,7 +103,9 @@ public abstract class AbstractKeycloakIdentityProviderTest extends AbstractIdent
 
     @Test
     public void testTemporarilyDisabledUser() {
+        KeycloakSession session = brokerServerRule.startSession();
         setUpdateProfileFirstLogin(session.realms().getRealmByName("realm-with-broker"), IdentityProviderRepresentation.UPFLM_OFF);
+        brokerServerRule.stopSession(session, true);
 
         driver.navigate().to("http://localhost:8081/test-app");
         loginPage.clickSocial(getProviderId());
@@ -109,7 +113,7 @@ public abstract class AbstractKeycloakIdentityProviderTest extends AbstractIdent
         driver.navigate().to("http://localhost:8081/test-app/logout");
 
         try {
-            KeycloakSession session = brokerServerRule.startSession();
+            session = brokerServerRule.startSession();
             RealmModel brokerRealm = session.realms().getRealmByName("realm-with-broker");
             brokerRealm.setBruteForceProtected(true);
             brokerRealm.setFailureFactor(2);
@@ -129,7 +133,7 @@ public abstract class AbstractKeycloakIdentityProviderTest extends AbstractIdent
             assertTrue(errorPage.isCurrent());
             assertEquals("Account is disabled, contact admin.", errorPage.getError());
         } finally {
-            KeycloakSession session = brokerServerRule.startSession();
+            session = brokerServerRule.startSession();
             RealmModel brokerRealm = session.realms().getRealmByName("realm-with-broker");
             brokerRealm.setBruteForceProtected(false);
             brokerRealm.setFailureFactor(0);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java
index 28663ff..d79d85f 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/OIDCKeyCloakServerBrokerBasicTest.java
@@ -170,4 +170,14 @@ public class OIDCKeyCloakServerBrokerBasicTest extends AbstractKeycloakIdentityP
     public void testAccountManagementLinkIdentity() {
         super.testAccountManagementLinkIdentity();
     }
+
+    @Test
+    public void testWithLinkedFederationProvider() throws Exception {
+        super.testWithLinkedFederationProvider();
+    }
+
+    @Test
+    public void testAccountManagementLinkedIdentityAlreadyExists() {
+        super.testAccountManagementLinkedIdentityAlreadyExists();
+    }
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/ldap/base/LDAPMultipleAttributesTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/ldap/base/LDAPMultipleAttributesTest.java
index 2e6a10a..fb23b5d 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/ldap/base/LDAPMultipleAttributesTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/ldap/base/LDAPMultipleAttributesTest.java
@@ -166,6 +166,14 @@ public class LDAPMultipleAttributesTest {
 
             postalCodes.add("77332");
             user.setAttribute("postal_code", postalCodes);
+        } finally {
+            keycloakRule.stopSession(session, true);
+        }
+
+        session = keycloakRule.startSession();
+        try {
+            RealmModel appRealm = session.realms().getRealmByName("test");
+            UserModel user = session.users().getUserByUsername("bwilson", appRealm);
             assertPostalCodes(user.getAttribute("postal_code"), "88441", "77332");
         } finally {
             keycloakRule.stopSession(session, true);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/PlainTextPasswordProvider.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/PlainTextPasswordProvider.java
new file mode 100644
index 0000000..f7aba5c
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/PlainTextPasswordProvider.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.federation.storage;
+
+import org.keycloak.hash.PasswordHashProvider;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserCredentialValueModel;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class PlainTextPasswordProvider implements PasswordHashProvider {
+    @Override
+    public UserCredentialValueModel encode(String rawPassword, int iterations) {
+        UserCredentialValueModel model = new UserCredentialValueModel();
+        model.setType(UserCredentialModel.PASSWORD);
+        model.setValue(rawPassword);
+        model.setAlgorithm("text");
+        return model;
+    }
+
+    @Override
+    public boolean verify(String rawPassword, UserCredentialValueModel credential) {
+        return rawPassword.equals(credential.getValue());
+    }
+
+    @Override
+    public void close() {
+
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/PlainTextPasswordProviderFactory.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/PlainTextPasswordProviderFactory.java
new file mode 100644
index 0000000..cdb324c
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/PlainTextPasswordProviderFactory.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.federation.storage;
+
+import org.keycloak.Config;
+import org.keycloak.hash.PasswordHashProvider;
+import org.keycloak.hash.PasswordHashProviderFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class PlainTextPasswordProviderFactory implements PasswordHashProviderFactory {
+    @Override
+    public PasswordHashProvider create(KeycloakSession session) {
+        return new PlainTextPasswordProvider();
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "text";
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserMapStorage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserMapStorage.java
new file mode 100644
index 0000000..7f72e8e
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserMapStorage.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.federation.storage;
+
+import org.keycloak.component.ComponentModel;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserCredentialValueModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.storage.StorageId;
+import org.keycloak.storage.UserStorageProvider;
+import org.keycloak.storage.adapter.AbstractUserAdapterFederatedStorage;
+import org.keycloak.storage.user.UserCredentialValidatorProvider;
+import org.keycloak.storage.user.UserLookupProvider;
+import org.keycloak.storage.user.UserRegistrationProvider;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class UserMapStorage implements UserLookupProvider, UserStorageProvider, UserRegistrationProvider {
+
+    protected Map<String, String> userPasswords;
+    protected ComponentModel model;
+    protected KeycloakSession session;
+
+    public static final AtomicInteger allocations = new AtomicInteger(0);
+    public static final AtomicInteger closings = new AtomicInteger(0);
+
+    public UserMapStorage(KeycloakSession session, ComponentModel model, Map<String, String> userPasswords) {
+        this.session = session;
+        this.model = model;
+        this.userPasswords = userPasswords;
+        allocations.incrementAndGet();
+    }
+
+
+    @Override
+    public UserModel getUserById(String id, RealmModel realm) {
+        StorageId storageId = new StorageId(id);
+        final String username = storageId.getExternalId();
+        if (!userPasswords.containsKey(username)) return null;
+
+        return createUser(realm, username);
+    }
+
+    private UserModel createUser(RealmModel realm, String username) {
+        return new AbstractUserAdapterFederatedStorage(session, realm,  model) {
+            @Override
+            public String getUsername() {
+                return username;
+            }
+
+            @Override
+            public void setUsername(String username) {
+                throw new RuntimeException("Unsupported");
+            }
+
+            @Override
+            public void updateCredential(UserCredentialModel cred) {
+                if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
+                    userPasswords.put(getUsername(), cred.getValue());
+                } else {
+                    super.updateCredential(cred);
+                }
+            }
+
+            @Override
+            public List<UserCredentialValueModel> getCredentialsDirectly() {
+                UserCredentialValueModel pw = new UserCredentialValueModel();
+                pw.setId(getId());
+                pw.setType(UserCredentialModel.PASSWORD);
+                pw.setAlgorithm("text");
+                pw.setValue(userPasswords.get(getUsername()));
+                List<UserCredentialValueModel> creds = new LinkedList<>();
+                creds.addAll(super.getCredentialsDirectly());
+                creds.add(pw);
+                return creds;
+            }
+
+            @Override
+            public void updateCredentialDirectly(UserCredentialValueModel cred) {
+                if (cred.getType().equals(UserCredentialModel.PASSWORD)) {
+                    //userPasswords.put(getUsername(), cred.getValue());
+                } else {
+                    super.updateCredentialDirectly(cred);
+                }
+            }
+        };
+    }
+
+    @Override
+    public UserModel getUserByUsername(String username, RealmModel realm) {
+        if (!userPasswords.containsKey(username)) return null;
+
+        return createUser(realm, username);
+    }
+
+    @Override
+    public UserModel getUserByEmail(String email, RealmModel realm) {
+        return null;
+    }
+
+    @Override
+    public UserModel addUser(RealmModel realm, String username) {
+        userPasswords.put(username, "");
+        return createUser(realm, username);
+    }
+
+    @Override
+    public boolean removeUser(RealmModel realm, UserModel user) {
+        return userPasswords.remove(user.getUsername()) != null;
+    }
+
+    @Override
+    public void grantToAllUsers(RealmModel realm, RoleModel role) {
+
+    }
+
+    @Override
+    public void preRemove(RealmModel realm) {
+
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, GroupModel group) {
+
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, RoleModel role) {
+
+    }
+
+    @Override
+    public void close() {
+        closings.incrementAndGet();
+
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserMapStorageFactory.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserMapStorageFactory.java
new file mode 100644
index 0000000..79e9261
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserMapStorageFactory.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.federation.storage;
+
+import org.keycloak.Config;
+import org.keycloak.component.ComponentModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.storage.UserStorageProviderFactory;
+
+import java.util.Hashtable;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class UserMapStorageFactory implements UserStorageProviderFactory<UserMapStorage> {
+
+
+    public static final String PROVIDER_ID = "user-password-map";
+
+    protected Map<String, String> userPasswords = new Hashtable<>();
+
+    @Override
+    public UserMapStorage create(KeycloakSession session, ComponentModel model) {
+        return new UserMapStorage(session, model, userPasswords);
+    }
+
+    @Override
+    public String getId() {
+        return PROVIDER_ID;
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorage.java
new file mode 100644
index 0000000..c297aca
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorage.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.federation.storage;
+
+import org.keycloak.component.ComponentModel;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.storage.StorageId;
+import org.keycloak.storage.UserStorageProvider;
+import org.keycloak.storage.adapter.AbstractUserAdapter;
+import org.keycloak.storage.adapter.AbstractUserAdapterFederatedStorage;
+import org.keycloak.storage.user.UserCredentialValidatorProvider;
+import org.keycloak.storage.user.UserLookupProvider;
+import org.keycloak.storage.user.UserQueryProvider;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class UserPropertyFileStorage implements UserLookupProvider, UserStorageProvider, UserCredentialValidatorProvider, UserQueryProvider {
+
+    protected Properties userPasswords;
+    protected ComponentModel model;
+    protected KeycloakSession session;
+    protected boolean federatedStorageEnabled;
+
+    public UserPropertyFileStorage(KeycloakSession session, ComponentModel model, Properties userPasswords) {
+        this.session = session;
+        this.model = model;
+        this.userPasswords = userPasswords;
+        this.federatedStorageEnabled = model.getConfig().containsKey("federatedStorage") && Boolean.valueOf(model.getConfig().getFirst("federatedStorage")).booleanValue();
+    }
+
+
+    @Override
+    public UserModel getUserById(String id, RealmModel realm) {
+        StorageId storageId = new StorageId(id);
+        final String username = storageId.getExternalId();
+        if (!userPasswords.containsKey(username)) return null;
+
+        return createUser(realm, username);
+    }
+
+    private UserModel createUser(RealmModel realm, String username) {
+        if (federatedStorageEnabled) {
+            return new AbstractUserAdapterFederatedStorage(session, realm,  model) {
+                @Override
+                public String getUsername() {
+                    return username;
+                }
+
+                @Override
+                public void setUsername(String username) {
+                    throw new RuntimeException("Unsupported");
+                }
+            };
+        } else {
+            return new AbstractUserAdapter(session, realm, model) {
+                @Override
+                public String getUsername() {
+                    return username;
+                }
+            };
+        }
+    }
+
+    @Override
+    public UserModel getUserByUsername(String username, RealmModel realm) {
+        if (!userPasswords.containsKey(username)) return null;
+
+        return createUser(realm, username);
+    }
+
+    @Override
+    public UserModel getUserByEmail(String email, RealmModel realm) {
+        return null;
+    }
+
+    @Override
+    public void preRemove(RealmModel realm) {
+
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, GroupModel group) {
+
+    }
+
+    @Override
+    public void preRemove(RealmModel realm, RoleModel role) {
+
+    }
+
+    @Override
+    public boolean validCredentials(KeycloakSession session, RealmModel realm, UserModel user, List<UserCredentialModel> input) {
+        for (UserCredentialModel cred : input) {
+            if (!cred.getType().equals(UserCredentialModel.PASSWORD)) return false;
+            String password = (String)userPasswords.get(user.getUsername());
+            if (password == null) return false;
+            if (!password.equals(cred.getValue())) return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int getUsersCount(RealmModel realm) {
+        return userPasswords.size();
+    }
+
+    @Override
+    public List<UserModel> getUsers(RealmModel realm) {
+        List<UserModel> users = new LinkedList<>();
+        for (Object username : userPasswords.keySet()) {
+            users.add(createUser(realm, (String)username));
+        }
+        return users;
+    }
+
+    @Override
+    public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm) {
+        return Collections.EMPTY_LIST;
+    }
+
+    @Override
+    public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) {
+        if (maxResults == 0) return Collections.EMPTY_LIST;
+        List<UserModel> users = new LinkedList<>();
+        int count = 0;
+        for (Object un : userPasswords.keySet()) {
+            if (count++ < firstResult) continue;
+            String username = (String)un;
+            users.add(createUser(realm, username));
+            if (users.size() + 1 > maxResults) break;
+        }
+        return users;
+    }
+
+    @Override
+    public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) {
+        if (maxResults == 0) return Collections.EMPTY_LIST;
+        List<UserModel> users = new LinkedList<>();
+        int count = 0;
+        for (Object un : userPasswords.keySet()) {
+            String username = (String)un;
+            if (username.contains(search)) {
+                if (count++ < firstResult) {
+                    continue;
+                }
+                users.add(createUser(realm, username));
+                if (users.size() + 1 > maxResults) break;
+            }
+        }
+        return users;
+    }
+
+    @Override
+    public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
+        if (attributes.size() != 1) return Collections.EMPTY_LIST;
+        String username = attributes.get(UserModel.USERNAME);
+        if (username == null) return Collections.EMPTY_LIST;
+        return searchForUser(username, realm, firstResult, maxResults);
+    }
+
+    @Override
+    public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
+        return Collections.EMPTY_LIST;
+    }
+
+    @Override
+    public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) {
+        return Collections.EMPTY_LIST;
+    }
+
+    @Override
+    public List<UserModel> searchForUser(String search, RealmModel realm) {
+        return getUsers(realm, 0, Integer.MAX_VALUE - 1);
+    }
+
+    @Override
+    public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) {
+        return Collections.EMPTY_LIST;
+    }
+
+    @Override
+    public void close() {
+
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorageFactory.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorageFactory.java
new file mode 100644
index 0000000..291f084
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserPropertyFileStorageFactory.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.federation.storage;
+
+import org.keycloak.Config;
+import org.keycloak.component.ComponentModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.provider.ProviderConfigProperty;
+import org.keycloak.storage.UserStorageProviderFactory;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class UserPropertyFileStorageFactory implements UserStorageProviderFactory<UserPropertyFileStorage> {
+
+
+    public static final String PROVIDER_ID = "user-password-props";
+
+    @Override
+    public UserPropertyFileStorage create(KeycloakSession session, ComponentModel model) {
+        Properties props = new Properties();
+        try {
+            props.load(getClass().getResourceAsStream(model.getConfig().getFirst("propertyFile")));
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        return new UserPropertyFileStorage(session, model, props);
+    }
+
+    @Override
+    public String getId() {
+        return PROVIDER_ID;
+    }
+
+    static List<ProviderConfigProperty> OPTIONS = new LinkedList<>();
+    static {
+        ProviderConfigProperty prop = new ProviderConfigProperty("propertyFile", "Property File", "file that contains name value pairs", ProviderConfigProperty.STRING_TYPE, null);
+        OPTIONS.add(prop);
+        prop = new ProviderConfigProperty("federatedStorage", "User Federated Storage", "use federated storage?", ProviderConfigProperty.BOOLEAN_TYPE, null);
+        OPTIONS.add(prop);
+
+    }
+    @Override
+    public List<ProviderConfigProperty> getConfigProperties() {
+         return OPTIONS;
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageTest.java
new file mode 100644
index 0000000..3c3a6a0
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/UserStorageTest.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.federation.storage;
+
+import org.junit.Assert;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.component.ComponentModel;
+import org.keycloak.models.GroupModel;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.RoleModel;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.cache.infinispan.UserAdapter;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.storage.StorageId;
+import org.keycloak.storage.UserStorageProviderModel;
+import org.keycloak.testsuite.OAuthClient;
+import org.keycloak.testsuite.pages.AppPage;
+import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.rule.KeycloakRule;
+import org.keycloak.testsuite.rule.WebResource;
+import org.keycloak.testsuite.rule.WebRule;
+import org.openqa.selenium.WebDriver;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class UserStorageTest {
+    public static ComponentModel memoryProvider = null;
+    @ClassRule
+    public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
+
+        @Override
+        public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+            UserStorageProviderModel model = new UserStorageProviderModel();
+            model.setName("memory");
+            model.setPriority(0);
+            model.setProviderId(UserMapStorageFactory.PROVIDER_ID);
+            model.setParentId(appRealm.getId());
+            memoryProvider = appRealm.addComponentModel(model);
+
+            model = new UserStorageProviderModel();
+            model.setName("read-only-user-props");
+            model.setPriority(1);
+            model.setProviderId(UserPropertyFileStorageFactory.PROVIDER_ID);
+            model.setParentId(appRealm.getId());
+            model.getConfig().putSingle("propertyFile", "/storage-test/read-only-user-password.properties");
+            appRealm.addComponentModel(model);
+            model = new UserStorageProviderModel();
+            model.setName("user-props");
+            model.setPriority(2);
+            model.setParentId(appRealm.getId());
+            model.setProviderId(UserPropertyFileStorageFactory.PROVIDER_ID);
+            model.getConfig().putSingle("propertyFile", "/storage-test/user-password.properties");
+            model.getConfig().putSingle("federatedStorage", "true");
+            appRealm.addComponentModel(model);
+        }
+    });
+    @Rule
+    public WebRule webRule = new WebRule(this);
+
+    @WebResource
+    protected OAuthClient oauth;
+
+    @WebResource
+    protected WebDriver driver;
+
+    @WebResource
+    protected AppPage appPage;
+
+    @WebResource
+    protected LoginPage loginPage;
+
+    private void loginSuccessAndLogout(String username, String password) {
+        loginPage.open();
+        loginPage.login(username, password);
+        Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
+        Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
+        oauth.openLogout();
+    }
+
+    public void loginBadPassword(String username) {
+        loginPage.open();
+        loginPage.login("username", "badpassword");
+        Assert.assertEquals("Invalid username or password.", loginPage.getError());
+    }
+
+    @Test
+    public void testLoginSuccess() {
+        loginSuccessAndLogout("tbrady", "goat");
+        loginSuccessAndLogout("thor", "hammer");
+        loginBadPassword("tbrady");
+    }
+
+    @Test
+    public void testUpdate() {
+        KeycloakSession session = keycloakRule.startSession();
+        RealmModel realm = session.realms().getRealmByName("test");
+        UserModel thor = session.users().getUserByUsername("thor", realm);
+        thor.setFirstName("Stian");
+        thor.setLastName("Thorgersen");
+        thor.setEmailVerified(true);
+        long thorCreated = System.currentTimeMillis() - 100;
+        thor.setCreatedTimestamp(thorCreated);
+        thor.setEmail("thor@hammer.com");
+        thor.setSingleAttribute("test-attribute", "value");
+        RoleModel role = realm.addRole("foo-role");
+        thor.grantRole(role);
+        GroupModel group = realm.createGroup("my-group");
+        thor.joinGroup(group);
+        thor.addRequiredAction("POOP");
+        keycloakRule.stopSession(session, true);
+
+        session = keycloakRule.startSession();
+        realm = session.realms().getRealmByName("test");
+        thor = session.users().getUserByUsername("thor", realm);
+        Assert.assertEquals("Stian", thor.getFirstName());
+        Assert.assertEquals("Thorgersen", thor.getLastName());
+        Assert.assertEquals("thor@hammer.com", thor.getEmail());
+        Assert.assertEquals("value", thor.getFirstAttribute("test-attribute"));
+        Assert.assertTrue(thor.isEmailVerified());
+        Assert.assertTrue(thor instanceof UserAdapter);
+        Set<RoleModel> roles = thor.getRoleMappings();
+        System.out.println("num roles " + roles.size());
+        Assert.assertTrue(roles.size() > 1);
+        role = realm.getRole("foo-role");
+        Assert.assertTrue(thor.hasRole(role));
+
+        Set<GroupModel> groups = thor.getGroups();
+        boolean foundGroup = false;
+        for (GroupModel g : groups) {
+            if (g.getName().equals("my-group")) foundGroup = true;
+
+        }
+        Assert.assertTrue(foundGroup);
+        System.out.println("num groups " + groups.size());
+        Assert.assertTrue(thor.getRequiredActions().iterator().next().equals("POOP"));
+        thor.removeRequiredAction("POOP");
+        thor.updateCredential(UserCredentialModel.password("lightning"));
+        keycloakRule.stopSession(session, true);
+        loginSuccessAndLogout("thor", "lightning");
+    }
+
+    @Test
+    public void testQuery() {
+        KeycloakSession session = keycloakRule.startSession();
+        RealmModel realm = session.realms().getRealmByName("test");
+
+        // Test paging
+        List<UserModel> localUsers = session.userLocalStorage().getUsers(realm, false);
+        Set<UserModel> queried = new HashSet<>();
+        // tests assumes that local storage is queried first
+        int first = localUsers.size();
+        while (queried.size() < 8) {
+            List<UserModel> results = session.users().getUsers(realm, first, 3);
+            if (results.size() == 0) break;
+            first += results.size();
+            queried.addAll(results);
+
+        }
+        Set<String> usernames = new HashSet<>();
+        for (UserModel user : queried) {
+            usernames.add(user.getUsername());
+            System.out.println(user.getUsername());
+
+        }
+        Assert.assertEquals(8, queried.size());
+        Assert.assertTrue(usernames.contains("thor"));
+        Assert.assertTrue(usernames.contains("zeus"));
+        Assert.assertTrue(usernames.contains("apollo"));
+        Assert.assertTrue(usernames.contains("perseus"));
+        Assert.assertTrue(usernames.contains("tbrady"));
+        Assert.assertTrue(usernames.contains("rob"));
+        Assert.assertTrue(usernames.contains("jules"));
+        Assert.assertTrue(usernames.contains("danny"));
+
+        // test searchForUser
+        List<UserModel> users = session.users().searchForUser("tbrady", realm);
+        Assert.assertTrue(users.size() == 1);
+        Assert.assertTrue(users.get(0).getUsername().equals("tbrady"));
+
+        // test getGroupMembers()
+        GroupModel gods = realm.createGroup("gods");
+        UserModel user = null;
+        user = session.users().getUserByUsername("apollo", realm);
+        user.joinGroup(gods);
+        user = session.users().getUserByUsername("zeus", realm);
+        user.joinGroup(gods);
+        user = session.users().getUserByUsername("thor", realm);
+        user.joinGroup(gods);
+        queried.clear();
+        usernames.clear();
+
+        first = 0;
+        while (queried.size() < 8) {
+            List<UserModel> results = session.users().getGroupMembers(realm, gods, first, 1);
+            if (results.size() == 0) break;
+            first += results.size();
+            queried.addAll(results);
+
+        }
+        for (UserModel u : queried) {
+            usernames.add(u.getUsername());
+            System.out.println(u.getUsername());
+
+        }
+        Assert.assertEquals(3, queried.size());
+        Assert.assertTrue(usernames.contains("apollo"));
+        Assert.assertTrue(usernames.contains("zeus"));
+        Assert.assertTrue(usernames.contains("thor"));
+
+        // search by single attribute
+        System.out.println("search by single attribute");
+        user = session.users().getUserByUsername("thor", realm);
+        user.setSingleAttribute("weapon", "hammer");
+
+        users = session.users().searchForUserByUserAttribute("weapon", "hammer", realm);
+        for (UserModel u : users) {
+            System.out.println(u.getUsername());
+
+        }
+        Assert.assertEquals(1, users.size());
+        Assert.assertEquals("thor", users.get(0).getUsername());
+
+
+        keycloakRule.stopSession(session, true);
+    }
+
+    @Test
+    public void testRegistration() {
+        KeycloakSession session = keycloakRule.startSession();
+        RealmModel realm = session.realms().getRealmByName("test");
+        UserModel user = session.users().addUser(realm, "memuser");
+        user.updateCredential(UserCredentialModel.password("password"));
+        keycloakRule.stopSession(session, true);
+        loginSuccessAndLogout("memuser", "password");
+        loginSuccessAndLogout("memuser", "password");
+        loginSuccessAndLogout("memuser", "password");
+
+        session = keycloakRule.startSession();
+        realm = session.realms().getRealmByName("test");
+        user = session.users().getUserByUsername("memuser", realm);
+        Assert.assertEquals(memoryProvider.getId(), StorageId.resolveProviderId(user));
+        Assert.assertEquals(1, user.getCredentialsDirectly().size());
+        session.users().removeUser(realm, user);
+        Assert.assertNull(session.users().getUserByUsername("memuser", realm));
+        keycloakRule.stopSession(session, true);
+
+    }
+
+    @Test
+    public void testLifecycle() {
+        UserMapStorage.allocations.set(0);
+        UserMapStorage.closings.set(0);
+        KeycloakSession session = keycloakRule.startSession();
+        RealmModel realm = session.realms().getRealmByName("test");
+        UserModel user = session.users().addUser(realm, "memuser");
+        Assert.assertNotNull(user);
+        user = session.users().getUserByUsername("nonexistent", realm);
+        Assert.assertNull(user);
+        keycloakRule.stopSession(session, true);
+        Assert.assertEquals(1, UserMapStorage.allocations.get());
+        Assert.assertEquals(1, UserMapStorage.closings.get());
+
+        session = keycloakRule.startSession();
+        realm = session.realms().getRealmByName("test");
+        user = session.users().getUserByUsername("memuser", realm);
+        session.users().removeUser(realm, user);
+        Assert.assertNull(session.users().getUserByUsername("memuser", realm));
+        keycloakRule.stopSession(session, true);
+
+    }
+
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTest.java
index 37f2b65..0f692fe 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTest.java
@@ -51,6 +51,7 @@ public class SamlAdapterTest {
             initializeSamlSecuredWar("/keycloak-saml/simple-post2", "/sales-post2",  "post.war", classLoader);
             initializeSamlSecuredWar("/keycloak-saml/simple-post-passive", "/sales-post-passive", "post-passive.war", classLoader);
             initializeSamlSecuredWar("/keycloak-saml/signed-post", "/sales-post-sig",  "post-sig.war", classLoader);
+            initializeSamlSecuredWar("/keycloak-saml/sales-post-assertion-and-response-sig", "/sales-post-assertion-and-response-sig",  "sales-post-assertion-and-response-sig.war", classLoader);
             initializeSamlSecuredWar("/keycloak-saml/signed-post-email", "/sales-post-sig-email",  "post-sig-email.war", classLoader);
             initializeSamlSecuredWar("/keycloak-saml/signed-post-transient", "/sales-post-sig-transient",  "post-sig-transient.war", classLoader);
             initializeSamlSecuredWar("/keycloak-saml/signed-post-persistent", "/sales-post-sig-persistent",  "post-sig-persistent.war", classLoader);
@@ -60,6 +61,8 @@ public class SamlAdapterTest {
             initializeSamlSecuredWar("/keycloak-saml/signed-front-get", "/employee-sig-front",  "employee-sig-front.war", classLoader);
             initializeSamlSecuredWar("/keycloak-saml/bad-client-signed-post", "/bad-client-sales-post-sig",  "bad-client-post-sig.war", classLoader);
             initializeSamlSecuredWar("/keycloak-saml/bad-realm-signed-post", "/bad-realm-sales-post-sig",  "bad-realm-post-sig.war", classLoader);
+            initializeSamlSecuredWar("/keycloak-saml/bad-assertion-signed-post", "/bad-assertion-sales-post-sig",  "bad-assertion-post-sig.war", classLoader);
+            initializeSamlSecuredWar("/keycloak-saml/missing-assertion-sig", "/missing-assertion-sig",  "missing-assertion-sig.war", classLoader);
             initializeSamlSecuredWar("/keycloak-saml/encrypted-post", "/sales-post-enc",  "post-enc.war", classLoader);
             System.setProperty("app.server.base.url", "http://localhost:8081");
             initializeSamlSecuredWar("/keycloak-saml/simple-input", "/input-portal",  "input.war", classLoader, InputServlet.class, "/secured/*");
@@ -90,6 +93,16 @@ public class SamlAdapterTest {
     }
 
     @Test
+    public void testPostBadAssertionSignature() {
+        testStrategy.testPostBadAssertionSignature();
+    }
+
+    @Test
+    public void testMissingAssertionSignature() {
+        testStrategy.testMissingAssertionSignature();
+    }
+
+    @Test
     public void testPostSimpleUnauthorized() {
         testStrategy.testPostSimpleUnauthorized( new SamlAdapterTestStrategy.CheckAuthError() {
             @Override
@@ -190,6 +203,11 @@ public class SamlAdapterTest {
     }
 
     @Test
+    public void testPostSignedResponseAndAssertionLoginLogout() {
+        testStrategy.testPostSignedResponseAndAssertionLoginLogout();
+    }
+
+    @Test
     public void testIDPDescriptor() throws Exception {
         Client client = ClientBuilder.newClient();
         String text = client.target("http://localhost:8081/auth/realms/master/protocol/saml/descriptor").request().get(String.class);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTestStrategy.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTestStrategy.java
index f45255f..9589fe9 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTestStrategy.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/keycloaksaml/SamlAdapterTestStrategy.java
@@ -44,6 +44,7 @@ import org.keycloak.saml.common.constants.JBossSAMLURIConstants;
 import org.keycloak.saml.processing.core.saml.v2.constants.X500SAMLProfileConstants;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.testsuite.KeycloakServer;
+import org.keycloak.testsuite.Retry;
 import org.keycloak.testsuite.pages.LoginPage;
 import org.keycloak.testsuite.rule.AbstractKeycloakRule;
 import org.keycloak.testsuite.rule.ErrorServlet;
@@ -281,6 +282,16 @@ public class SamlAdapterTestStrategy  extends ExternalResource {
         checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post-sig/", true);
 
     }
+    public void testPostSignedResponseAndAssertionLoginLogout() {
+        driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-assertion-and-response-sig/");
+        assertAtLoginPagePostBinding();
+        loginPage.login("bburke", "password");
+        assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post-assertion-and-response-sig/");
+        Assert.assertTrue(driver.getPageSource().contains("bburke"));
+        driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-assertion-and-response-sig?GLO=true");
+        checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post-assertion-and-response-sig/", true);
+
+    }
     public void testPostSignedLoginLogoutTransientNameID() {
         driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-sig-transient/");
         assertAtLoginPagePostBinding();
@@ -493,7 +504,12 @@ public class SamlAdapterTestStrategy  extends ExternalResource {
         driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-enc/");
         assertAtLoginPagePostBinding();
         loginPage.login("bburke", "password");
-        assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post-enc/");
+        Retry.execute(new Runnable() {
+            @Override
+            public void run() {
+                assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/sales-post-enc/");
+            }
+        }, 10, 100);
         Assert.assertTrue(driver.getPageSource().contains("bburke"));
         driver.navigate().to(APP_SERVER_BASE_URL + "/sales-post-enc?GLO=true");
         checkLoggedOut(APP_SERVER_BASE_URL + "/sales-post-enc/", true);
@@ -523,6 +539,32 @@ public class SamlAdapterTestStrategy  extends ExternalResource {
         ErrorServlet.authError = null;
     }
 
+    public void testPostBadAssertionSignature() {
+        ErrorServlet.authError = null;
+        driver.navigate().to(APP_SERVER_BASE_URL + "/bad-assertion-sales-post-sig/");
+        assertAtLoginPagePostBinding();
+        loginPage.login("bburke", "password");
+        assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/bad-assertion-sales-post-sig/saml");
+        System.out.println(driver.getPageSource());
+        Assert.assertNotNull(ErrorServlet.authError);
+        SamlAuthenticationError error = (SamlAuthenticationError)ErrorServlet.authError;
+        Assert.assertEquals(SamlAuthenticationError.Reason.INVALID_SIGNATURE, error.getReason());
+        ErrorServlet.authError = null;
+    }
+
+    public void testMissingAssertionSignature() {
+        ErrorServlet.authError = null;
+        driver.navigate().to(APP_SERVER_BASE_URL + "/missing-assertion-sig/");
+        assertAtLoginPagePostBinding();
+        loginPage.login("bburke", "password");
+        assertEquals(driver.getCurrentUrl(), APP_SERVER_BASE_URL + "/missing-assertion-sig/saml");
+        System.out.println(driver.getPageSource());
+        Assert.assertNotNull(ErrorServlet.authError);
+        SamlAuthenticationError error = (SamlAuthenticationError)ErrorServlet.authError;
+        Assert.assertEquals(SamlAuthenticationError.Reason.INVALID_SIGNATURE, error.getReason());
+        ErrorServlet.authError = null;
+    }
+
     public void testMetadataPostSignedLoginLogout() throws Exception {
 
         driver.navigate().to(APP_SERVER_BASE_URL + "/sales-metadata/");
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/KeycloakServer.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/KeycloakServer.java
index 6cb3f7c..3b8d68b 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/KeycloakServer.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/KeycloakServer.java
@@ -22,7 +22,9 @@ import io.undertow.servlet.Servlets;
 import io.undertow.servlet.api.DefaultServletConfig;
 import io.undertow.servlet.api.DeploymentInfo;
 import io.undertow.servlet.api.FilterInfo;
+import io.undertow.servlet.api.ServletInfo;
 import org.jboss.logging.Logger;
+import org.jboss.resteasy.plugins.server.servlet.HttpServlet30Dispatcher;
 import org.jboss.resteasy.plugins.server.undertow.UndertowJaxrsServer;
 import org.jboss.resteasy.spi.ResteasyDeployment;
 import org.keycloak.models.KeycloakSession;
@@ -246,7 +248,7 @@ public class KeycloakServer {
 
     public void importRealm(RealmRepresentation rep) {
         KeycloakSession session = sessionFactory.create();;
-        session.getTransaction().begin();
+        session.getTransactionManager().begin();
 
         try {
             RealmManager manager = new RealmManager(session);
@@ -265,7 +267,7 @@ public class KeycloakServer {
 
             info("Imported realm " + realm.getName());
 
-            session.getTransaction().commit();
+            session.getTransactionManager().commit();
         } finally {
             session.close();
         }
@@ -275,11 +277,11 @@ public class KeycloakServer {
         if (System.getProperty("keycloak.createAdminUser", "true").equals("true")) {
             KeycloakSession session = sessionFactory.create();
             try {
-                session.getTransaction().begin();
+                session.getTransactionManager().begin();
                 if (new ApplianceBootstrap(session).isNoMasterUser()) {
                     new ApplianceBootstrap(session).createMasterRealmUser("admin", "admin");
                 }
-                session.getTransaction().commit();
+                session.getTransactionManager().commit();
             } finally {
                 session.close();
             }
@@ -309,7 +311,17 @@ public class KeycloakServer {
 
             di.setDefaultServletConfig(new DefaultServletConfig(true));
 
+            ServletInfo restEasyDispatcher = Servlets.servlet("Keycloak REST Interface", HttpServlet30Dispatcher.class);
+
+            restEasyDispatcher.addInitParam("resteasy.servlet.mapping.prefix", "/");
+            restEasyDispatcher.setAsyncSupported(true);
+
+            di.addServlet(restEasyDispatcher);
+
             FilterInfo filter = Servlets.filter("SessionFilter", KeycloakSessionServletFilter.class);
+
+            filter.setAsyncSupported(true);
+
             di.addFilter(filter);
             di.addFilterUrlMapping("SessionFilter", "/*", DispatcherType.REQUEST);
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/AbstractModelTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/AbstractModelTest.java
index 0befa7c..f1409f4 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/AbstractModelTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/AbstractModelTest.java
@@ -81,16 +81,16 @@ public class AbstractModelTest {
 
     protected void commit(boolean rollback) {
         if (rollback) {
-            session.getTransaction().rollback();
+            session.getTransactionManager().rollback();
         } else {
-            session.getTransaction().commit();
+            session.getTransactionManager().commit();
         }
         resetSession();
     }
 
     protected void resetSession() {
-        if (session.getTransaction().isActive()) {
-            session.getTransaction().rollback();
+        if (session.getTransactionManager().isActive()) {
+            session.getTransactionManager().rollback();
         }
         kc.stopSession(session, false);
         session = kc.startSession();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/AdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/AdapterTest.java
index 27b550a..42d190c 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/AdapterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/AdapterTest.java
@@ -22,6 +22,7 @@ import org.junit.FixMethodOrder;
 import org.junit.Test;
 import org.junit.runners.MethodSorters;
 import org.keycloak.Config;
+import org.keycloak.component.ComponentModel;
 import org.keycloak.models.ClientModel;
 import org.keycloak.models.FederatedIdentityModel;
 import org.keycloak.models.ModelDuplicateException;
@@ -36,6 +37,9 @@ import org.keycloak.models.UserModel;
 import org.keycloak.models.UserProvider;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.services.managers.RealmManager;
+import org.keycloak.storage.UserStorageProvider;
+import org.keycloak.storage.UserStorageProviderModel;
+import org.keycloak.testsuite.federation.storage.UserMapStorageFactory;
 
 import java.security.KeyPair;
 import java.security.KeyPairGenerator;
@@ -74,7 +78,7 @@ public class AdapterTest extends AbstractModelTest {
         realmModel.setAccessTokenLifespan(1000);
         realmModel.addDefaultRole("foo");
 
-        session.getTransaction().commit();
+        session.getTransactionManager().commit();
         resetSession();
 
         realmModel = realmManager.getRealm(realmModel.getId());
@@ -86,7 +90,7 @@ public class AdapterTest extends AbstractModelTest {
         Assert.assertEquals(realmModel.getName(), "JUGGLER");
         Assert.assertArrayEquals(realmModel.getPrivateKey().getEncoded(), keyPair.getPrivate().getEncoded());
         Assert.assertArrayEquals(realmModel.getPublicKey().getEncoded(), keyPair.getPublic().getEncoded());
-        Assert.assertEquals(2, realmModel.getDefaultRoles().size());
+        Assert.assertEquals(3, realmModel.getDefaultRoles().size());
         Assert.assertTrue(realmModel.getDefaultRoles().contains("foo"));
     }
 
@@ -112,7 +116,7 @@ public class AdapterTest extends AbstractModelTest {
         Assert.assertEquals(realmModel.getName(), "JUGGLER");
         Assert.assertArrayEquals(realmModel.getPrivateKey().getEncoded(), keyPair.getPrivate().getEncoded());
         Assert.assertArrayEquals(realmModel.getPublicKey().getEncoded(), keyPair.getPublic().getEncoded());
-        Assert.assertEquals(2, realmModel.getDefaultRoles().size());
+        Assert.assertEquals(3, realmModel.getDefaultRoles().size());
         Assert.assertTrue(realmModel.getDefaultRoles().contains("foo"));
 
         realmModel.getId();
@@ -164,11 +168,11 @@ public class AdapterTest extends AbstractModelTest {
         Assert.assertTrue(userProvider.validCredentials(session, realmModel, user, UserCredentialModel.password("geheim")));
         List<UserCredentialValueModel> creds = user.getCredentialsDirectly();
         Assert.assertEquals(creds.get(0).getHashIterations(), 20000);
-        realmModel.setPasswordPolicy(new PasswordPolicy("hashIterations(200)"));
+        realmModel.setPasswordPolicy(PasswordPolicy.parse(realmManager.getSession(), "hashIterations(200)"));
         Assert.assertTrue(userProvider.validCredentials(session, realmModel, user, UserCredentialModel.password("geheim")));
         creds = user.getCredentialsDirectly();
         Assert.assertEquals(creds.get(0).getHashIterations(), 200);
-        realmModel.setPasswordPolicy(new PasswordPolicy("hashIterations(1)"));
+        realmModel.setPasswordPolicy(PasswordPolicy.parse(realmManager.getSession(), "hashIterations(1)"));
     }
 
     @Test
@@ -462,7 +466,7 @@ public class AdapterTest extends AbstractModelTest {
         realmModel.addRole("admin");
         realmModel.addRole("user");
         Set<RoleModel> roles = realmModel.getRoles();
-        Assert.assertEquals(4, roles.size());
+        Assert.assertEquals(5, roles.size());
         UserModel user = realmManager.getSession().users().addUser(realmModel, "bburke");
         RoleModel realmUserRole = realmModel.getRole("user");
         user.grantRole(realmUserRole);
@@ -488,7 +492,7 @@ public class AdapterTest extends AbstractModelTest {
         user.grantRole(application.getRole("user"));
 
         roles = user.getRealmRoleMappings();
-        Assert.assertEquals(roles.size(), 3);
+        Assert.assertEquals(4, roles.size());
         assertRolesContains(realmUserRole, roles);
         Assert.assertTrue(user.hasRole(realmUserRole));
         // Role "foo" is default realm role
@@ -503,13 +507,13 @@ public class AdapterTest extends AbstractModelTest {
         // Test that application role 'user' don't clash with realm role 'user'
         Assert.assertNotEquals(realmModel.getRole("user").getId(), application.getRole("user").getId());
 
-        Assert.assertEquals(7, user.getRoleMappings().size());
+        Assert.assertEquals(8, user.getRoleMappings().size());
 
         // Revoke some roles
         user.deleteRoleMapping(realmModel.getRole("foo"));
         user.deleteRoleMapping(appBarRole);
         roles = user.getRoleMappings();
-        Assert.assertEquals(5, roles.size());
+        Assert.assertEquals(6, roles.size());
         assertRolesContains(realmUserRole, roles);
         assertRolesContains(application.getRole("user"), roles);
         Assert.assertFalse(user.hasRole(appBarRole));
@@ -831,6 +835,61 @@ public class AdapterTest extends AbstractModelTest {
         realmManager.removeRealm(realmModel);
     }
 
+    @Test
+    public void testComponentModelCRUD() {
+        // Add
+        realmModel = realmManager.createRealm("foo-realm");
+        UserStorageProviderModel model = new UserStorageProviderModel();
+        model.setName("memory");
+        model.setPriority(0);
+        model.setProviderId(UserMapStorageFactory.PROVIDER_ID);
+        model.setParentId(realmModel.getId());
+        ComponentModel createdModel = realmModel.addComponentModel(model);
+        String id = createdModel.getId();
+        Assert.assertNotNull(id);
+
+        commit();
+
+        realmModel = realmManager.getRealmByName("foo-realm");
+        ComponentModel foundModel = realmModel.getComponent(id);
+        assertComponentModel(foundModel, id, UserMapStorageFactory.PROVIDER_ID, realmModel.getId(), "memory");
+
+        List<ComponentModel> components = realmModel.getComponents();
+        Assert.assertEquals(components.size(), 1);
+        assertComponentModel(components.get(0), id, UserMapStorageFactory.PROVIDER_ID, realmModel.getId(), "memory");
+
+        components = realmModel.getComponents(realmModel.getId(), UserStorageProvider.class.getName());
+        Assert.assertEquals(components.size(), 1);
+        assertComponentModel(components.get(0), id, UserMapStorageFactory.PROVIDER_ID, realmModel.getId(), "memory");
+
+        // Update
+        foundModel.getConfig().putSingle("foo", "bar");
+        realmModel.updateComponent(foundModel);
+
+        commit();
+
+        realmModel = realmManager.getRealmByName("foo-realm");
+        foundModel = realmModel.getComponent(id);
+        assertComponentModel(foundModel, id, UserMapStorageFactory.PROVIDER_ID, realmModel.getId(), "memory");
+        Assert.assertEquals("bar", foundModel.getConfig().getFirst("foo"));
+
+        // Remove
+        realmModel.removeComponent(foundModel);
+
+        commit();
+
+        realmModel = realmManager.getRealmByName("foo-realm");
+        foundModel = realmModel.getComponent(id);
+        Assert.assertNull(foundModel);
+    }
+
+    private void assertComponentModel(ComponentModel componentModel, String expectedId, String expectedProviderId, String expectedParentId, String expectedName) {
+        Assert.assertEquals(expectedId, componentModel.getId());
+        Assert.assertEquals(expectedProviderId, componentModel.getProviderId());
+        Assert.assertEquals(expectedParentId, componentModel.getParentId());
+        Assert.assertEquals(expectedName, componentModel.getName());
+    }
+
     private KeyPair generateKeypair() throws NoSuchAlgorithmException {
         return KeyPairGenerator.getInstance("RSA").generateKeyPair();
     }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/CacheTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/CacheTest.java
index 0d7c9b0..c478375 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/CacheTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/CacheTest.java
@@ -105,7 +105,7 @@ public class CacheTest {
 
             assertNotNull(user2.getLastName());
         } finally {
-            session.getTransaction().commit();
+            session.getTransactionManager().commit();
             session.close();
         }
     }
@@ -121,7 +121,7 @@ public class CacheTest {
             RoleModel fooRole = client.addRole("foo-role");
             user.grantRole(fooRole);
         } finally {
-            session.getTransaction().commit();
+            session.getTransactionManager().commit();
             session.close();
         }
 
@@ -136,7 +136,7 @@ public class CacheTest {
             ClientModel client = realm.getClientByClientId("foo");
             realm.removeClient(client.getId());
         } finally {
-            session.getTransaction().commit();
+            session.getTransactionManager().commit();
             session.close();
         }
 
@@ -152,7 +152,7 @@ public class CacheTest {
 
             Assert.assertEquals(roles.size(), grantedRolesCount - 1);
         } finally {
-            session.getTransaction().commit();
+            session.getTransactionManager().commit();
             session.close();
         }
     }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ConcurrentTransactionsTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ConcurrentTransactionsTest.java
index 93b6458..b3ad0c4 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ConcurrentTransactionsTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ConcurrentTransactionsTest.java
@@ -18,7 +18,9 @@
 package org.keycloak.testsuite.model;
 
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
 
+import org.jboss.logging.Logger;
 import org.junit.Assert;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -28,6 +30,7 @@ import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.models.KeycloakSessionTask;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.RealmProvider;
+import org.keycloak.models.UserModel;
 import org.keycloak.models.utils.KeycloakModelUtils;
 
 /**
@@ -35,6 +38,8 @@ import org.keycloak.models.utils.KeycloakModelUtils;
  */
 public class ConcurrentTransactionsTest extends AbstractModelTest {
 
+    private static final Logger logger = Logger.getLogger(ConcurrentTransactionsTest.class);
+
     @Test
     public void persistClient() throws Exception {
         RealmModel realm = realmManager.createRealm("original");
@@ -63,21 +68,21 @@ public class ConcurrentTransactionsTest extends AbstractModelTest {
                         try {
                             // Wait until transaction in both threads started
                             transactionsCounter.countDown();
-                            System.out.println("transaction1 started");
+                            logger.info("transaction1 started");
                             transactionsCounter.await();
 
                             // Read client
                             RealmModel realm = session.realms().getRealmByName("original");
                             ClientModel client = session.realms().getClientByClientId("client", realm);
-                            System.out.println("transaction1: Read client finished");
+                            logger.info("transaction1: Read client finished");
                             readLatch.countDown();
 
                             // Wait until thread2 updates client and commits
                             updateLatch.await();
-                            System.out.println("transaction1: Going to read client again");
+                            logger.info("transaction1: Going to read client again");
 
                             client = session.realms().getClientByClientId("client", realm);
-                            System.out.println("transaction1: secret: " + client.getSecret());
+                            logger.info("transaction1: secret: " + client.getSecret());
                         } catch (Exception e) {
                             throw new RuntimeException(e);
                         }
@@ -99,12 +104,12 @@ public class ConcurrentTransactionsTest extends AbstractModelTest {
                         try {
                             // Wait until transaction in both threads started
                             transactionsCounter.countDown();
-                            System.out.println("transaction2 started");
+                            logger.info("transaction2 started");
                             transactionsCounter.await();
 
 
                             readLatch.await();
-                            System.out.println("transaction2: Going to update client secret");
+                            logger.info("transaction2: Going to update client secret");
 
                             RealmModel realm = session.realms().getRealmByName("original");
                             ClientModel client = session.realms().getClientByClientId("client", realm);
@@ -116,7 +121,7 @@ public class ConcurrentTransactionsTest extends AbstractModelTest {
 
                 });
 
-                System.out.println("transaction2: commited");
+                logger.info("transaction2: commited");
                 updateLatch.countDown();
             }
 
@@ -128,7 +133,7 @@ public class ConcurrentTransactionsTest extends AbstractModelTest {
         thread1.join();
         thread2.join();
 
-        System.out.println("after thread join");
+        logger.info("after thread join");
 
         commit();
 
@@ -138,11 +143,83 @@ public class ConcurrentTransactionsTest extends AbstractModelTest {
         ClientModel clientFromCache = session.realms().getClientById(clientDBId, realm);
         ClientModel clientFromDB = session.getProvider(RealmProvider.class).getClientById(clientDBId, realm);
 
-        System.out.println("SECRET FROM DB : " + clientFromDB.getSecret());
-        System.out.println("SECRET FROM CACHE : " + clientFromCache.getSecret());
+        logger.info("SECRET FROM DB : " + clientFromDB.getSecret());
+        logger.info("SECRET FROM CACHE : " + clientFromCache.getSecret());
 
         Assert.assertEquals("new", clientFromDB.getSecret());
         Assert.assertEquals("new", clientFromCache.getSecret());
     }
 
+
+    // KEYCLOAK-3296
+    @Test
+    public void removeUserAttribute() throws Exception {
+        RealmModel realm = realmManager.createRealm("original");
+        KeycloakSession session = realmManager.getSession();
+
+        UserModel user = session.users().addUser(realm, "john");
+        user.setSingleAttribute("foo", "val1");
+
+        final KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
+        commit();
+
+        AtomicReference<Exception> reference = new AtomicReference<>();
+
+        final CountDownLatch readAttrLatch = new CountDownLatch(2);
+
+        Runnable runnable = new Runnable() {
+
+            @Override
+            public void run() {
+                try {
+                    KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {
+
+                        @Override
+                        public void run(KeycloakSession session) {
+                            try {
+                                // Read user attribute
+                                RealmModel realm = session.realms().getRealmByName("original");
+                                UserModel john = session.users().getUserByUsername("john", realm);
+                                String attrVal = john.getFirstAttribute("foo");
+
+                                // Wait until it's read in both threads
+                                readAttrLatch.countDown();
+                                readAttrLatch.await();
+
+                                // Remove user attribute in both threads
+                                john.removeAttribute("foo");
+                            } catch (Exception e) {
+                                throw new RuntimeException(e);
+                            }
+                        }
+
+                    });
+                } catch (Exception e) {
+                    reference.set(e);
+                    throw new RuntimeException(e);
+                } finally {
+                    readAttrLatch.countDown();
+                }
+            }
+
+        };
+
+        Thread thread1 = new Thread(runnable);
+        Thread thread2 = new Thread(runnable);
+
+        thread1.start();
+        thread2.start();
+
+        thread1.join();
+        thread2.join();
+
+        logger.info("removeUserAttribute: after thread join");
+
+        commit();
+
+        if (reference.get() != null) {
+            Assert.fail("Exception happened in some of threads. Details: " + reference.get().getMessage());
+        }
+    }
+
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/DBLockTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/DBLockTest.java
index 14fde53..2537332 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/DBLockTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/DBLockTest.java
@@ -24,12 +24,11 @@ import java.util.concurrent.atomic.AtomicInteger;
 import org.jboss.logging.Logger;
 import org.junit.Assert;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.models.KeycloakSessionTask;
-import org.keycloak.services.managers.DBLockManager;
+import org.keycloak.models.dblock.DBLockManager;
 import org.keycloak.models.dblock.DBLockProvider;
 import org.keycloak.models.dblock.DBLockProviderFactory;
 import org.keycloak.models.utils.KeycloakModelUtils;
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
index 136fc69..dedc8d1 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ImportTest.java
@@ -90,6 +90,12 @@ public class ImportTest extends AbstractModelTest {
     }
 
     // Moved to static method, so it's possible to test this from other places too (for example export-import tests)
+    /*
+    BIG HELPFUL HINT!!!!
+    WHEN YOU MIGRATE THIS CLASS YOU DO NOT NEED TO MIGRATE THIS METHOD.
+    IT HAS ALREADY BEEN IMPLEMENTED IN THE NEW ARQUILLIAN TESTSUTE.
+    SEE org.keycloak.testsuite.exportimport.ExportImportUtil
+    */
     public static void assertDataImportedInRealm(KeycloakSession session, RealmModel realm) {
         Assert.assertTrue(realm.isVerifyEmail());
         Assert.assertEquals(3600000, realm.getOfflineSessionIdleTimeout());
@@ -99,7 +105,7 @@ public class ImportTest extends AbstractModelTest {
         Assert.assertEquals(1, creds.size());
         RequiredCredentialModel cred = creds.get(0);
         Assert.assertEquals("password", cred.getFormLabel());
-        Assert.assertEquals(3, realm.getDefaultRoles().size());
+        Assert.assertEquals(4, realm.getDefaultRoles().size());
 
         Assert.assertNotNull(realm.getRole("foo"));
         Assert.assertNotNull(realm.getRole("bar"));
@@ -351,15 +357,15 @@ public class ImportTest extends AbstractModelTest {
 
         // Test user consents
         admin =  session.users().getUserByUsername("admin", realm);
-        Assert.assertEquals(2, admin.getConsents().size());
+        Assert.assertEquals(2, session.users().getConsents(realm, admin).size());
 
-        UserConsentModel appAdminConsent = admin.getConsentByClient(application.getId());
+        UserConsentModel appAdminConsent = session.users().getConsentByClient(realm, admin, application.getId());
         Assert.assertEquals(2, appAdminConsent.getGrantedRoles().size());
         Assert.assertTrue(appAdminConsent.getGrantedProtocolMappers() == null || appAdminConsent.getGrantedProtocolMappers().isEmpty());
         Assert.assertTrue(appAdminConsent.isRoleGranted(realm.getRole("admin")));
         Assert.assertTrue(appAdminConsent.isRoleGranted(application.getRole("app-admin")));
 
-        UserConsentModel otherAppAdminConsent = admin.getConsentByClient(otherApp.getId());
+        UserConsentModel otherAppAdminConsent = session.users().getConsentByClient(realm, admin, otherApp.getId());
         Assert.assertEquals(1, otherAppAdminConsent.getGrantedRoles().size());
         Assert.assertEquals(1, otherAppAdminConsent.getGrantedProtocolMappers().size());
         Assert.assertTrue(otherAppAdminConsent.isRoleGranted(realm.getRole("admin")));
@@ -376,8 +382,8 @@ public class ImportTest extends AbstractModelTest {
         // Test service accounts
         Assert.assertFalse(application.isServiceAccountsEnabled());
         Assert.assertTrue(otherApp.isServiceAccountsEnabled());
-        Assert.assertNull(session.users().getUserByServiceAccountClient(application));
-        UserModel linked = session.users().getUserByServiceAccountClient(otherApp);
+        Assert.assertNull(session.users().getServiceAccount(application));
+        UserModel linked = session.users().getServiceAccount(otherApp);
         Assert.assertNotNull(linked);
         Assert.assertEquals("my-service-user", linked.getUsername());
     }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ModelTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ModelTest.java
index c356eb5..a34f460 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ModelTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/ModelTest.java
@@ -42,7 +42,7 @@ public class ModelTest extends AbstractModelTest {
         realm.setSslRequired(SslRequired.EXTERNAL);
         realm.setVerifyEmail(true);
         realm.setAccessTokenLifespan(1000);
-        realm.setPasswordPolicy(new PasswordPolicy("length"));
+        realm.setPasswordPolicy(PasswordPolicy.parse(realmManager.getSession(), "length"));
         realm.setAccessCodeLifespan(1001);
         realm.setAccessCodeLifespanUserAction(1002);
         KeycloakModelUtils.generateRealmKeys(realm);
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/PasswordPolicyTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/PasswordPolicyTest.java
new file mode 100755
index 0000000..e21fb0b
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/PasswordPolicyTest.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.model;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.models.PasswordPolicy;
+import org.keycloak.models.RealmModel;
+import org.keycloak.policy.PasswordPolicyManagerProvider;
+
+import java.util.regex.PatternSyntaxException;
+
+import static org.junit.Assert.fail;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class PasswordPolicyTest extends AbstractModelTest {
+
+    private RealmModel realmModel;
+    private PasswordPolicyManagerProvider policyManager;
+
+    @Before
+    public void before() throws Exception {
+        super.before();
+        realmModel = realmManager.createRealm("JUGGLER");
+        session.getContext().setRealm(realmModel);
+        policyManager = session.getProvider(PasswordPolicyManagerProvider.class);
+    }
+
+    @Test
+    public void testLength() {
+        realmModel.setPasswordPolicy(PasswordPolicy.parse(session, "length"));
+
+        Assert.assertEquals("invalidPasswordMinLengthMessage", policyManager.validate("jdoe", "1234567").getMessage());
+        Assert.assertArrayEquals(new Object[]{8}, policyManager.validate("jdoe", "1234567").getParameters());
+        Assert.assertNull(policyManager.validate("jdoe", "12345678"));
+
+        realmModel.setPasswordPolicy(PasswordPolicy.parse(session, "length(4)"));
+
+        Assert.assertEquals("invalidPasswordMinLengthMessage", policyManager.validate("jdoe", "123").getMessage());
+        Assert.assertArrayEquals(new Object[]{4}, policyManager.validate("jdoe", "123").getParameters());
+        Assert.assertNull(policyManager.validate("jdoe", "1234"));
+    }
+
+    @Test
+    public void testDigits() {
+        realmModel.setPasswordPolicy(PasswordPolicy.parse(session, "digits"));
+        Assert.assertEquals("invalidPasswordMinDigitsMessage", policyManager.validate("jdoe", "abcd").getMessage());
+        Assert.assertArrayEquals(new Object[]{1}, policyManager.validate("jdoe", "abcd").getParameters());
+        Assert.assertNull(policyManager.validate("jdoe", "abcd1"));
+
+        realmModel.setPasswordPolicy(PasswordPolicy.parse(session, "digits(2)"));
+        Assert.assertEquals("invalidPasswordMinDigitsMessage", policyManager.validate("jdoe", "abcd1").getMessage());
+        Assert.assertArrayEquals(new Object[]{2}, policyManager.validate("jdoe", "abcd1").getParameters());
+        Assert.assertNull(policyManager.validate("jdoe", "abcd12"));
+    }
+
+    @Test
+    public void testLowerCase() {
+        realmModel.setPasswordPolicy(PasswordPolicy.parse(session, "lowerCase"));
+        Assert.assertEquals("invalidPasswordMinLowerCaseCharsMessage", policyManager.validate("jdoe", "ABCD1234").getMessage());
+        Assert.assertArrayEquals(new Object[]{1}, policyManager.validate("jdoe", "ABCD1234").getParameters());
+        Assert.assertNull(policyManager.validate("jdoe", "ABcD1234"));
+
+        realmModel.setPasswordPolicy(PasswordPolicy.parse(session, "lowerCase(2)"));
+        Assert.assertEquals("invalidPasswordMinLowerCaseCharsMessage", policyManager.validate("jdoe", "ABcD1234").getMessage());
+        Assert.assertArrayEquals(new Object[]{2}, policyManager.validate("jdoe", "ABcD1234").getParameters());
+        Assert.assertNull(policyManager.validate("jdoe", "aBcD1234"));
+    }
+
+    @Test
+    public void testUpperCase() {
+        realmModel.setPasswordPolicy(PasswordPolicy.parse(session, "upperCase"));
+        Assert.assertEquals("invalidPasswordMinUpperCaseCharsMessage", policyManager.validate("jdoe", "abcd1234").getMessage());
+        Assert.assertArrayEquals(new Object[]{1}, policyManager.validate("jdoe", "abcd1234").getParameters());
+        Assert.assertNull(policyManager.validate("jdoe", "abCd1234"));
+
+        realmModel.setPasswordPolicy(PasswordPolicy.parse(session, "upperCase(2)"));
+        Assert.assertEquals("invalidPasswordMinUpperCaseCharsMessage", policyManager.validate("jdoe", "abCd1234").getMessage());
+        Assert.assertArrayEquals(new Object[]{2}, policyManager.validate("jdoe", "abCd1234").getParameters());
+        Assert.assertNull(policyManager.validate("jdoe", "AbCd1234"));
+    }
+
+    @Test
+    public void testSpecialChars() {
+        realmModel.setPasswordPolicy(PasswordPolicy.parse(session, "specialChars"));
+        Assert.assertEquals("invalidPasswordMinSpecialCharsMessage", policyManager.validate("jdoe", "abcd1234").getMessage());
+        Assert.assertArrayEquals(new Object[]{1}, policyManager.validate("jdoe", "abcd1234").getParameters());
+        Assert.assertNull(policyManager.validate("jdoe", "ab&d1234"));
+
+        realmModel.setPasswordPolicy(PasswordPolicy.parse(session, "specialChars(2)"));
+        Assert.assertEquals("invalidPasswordMinSpecialCharsMessage", policyManager.validate("jdoe", "ab&d1234").getMessage());
+        Assert.assertArrayEquals(new Object[]{2}, policyManager.validate("jdoe", "ab&d1234").getParameters());
+        Assert.assertNull(policyManager.validate("jdoe", "ab&d-234"));
+    }
+
+    @Test
+    public void testNotUsername() {
+        realmModel.setPasswordPolicy(PasswordPolicy.parse(session, "notUsername"));
+        Assert.assertEquals("invalidPasswordNotUsernameMessage", policyManager.validate("jdoe", "jdoe").getMessage());
+        Assert.assertNull(policyManager.validate("jdoe", "ab&d1234"));
+    }
+
+    @Test
+    public void testInvalidPolicyName() {
+        try {
+            realmModel.setPasswordPolicy(PasswordPolicy.parse(session, "noSuchPolicy"));
+            Assert.fail("Expected exception");
+        } catch (IllegalArgumentException e) {
+        }
+    }
+
+    @Test
+    public void testRegexPatterns() {
+        PasswordPolicy policy = null;
+        try {
+            realmModel.setPasswordPolicy(PasswordPolicy.parse(session, "regexPattern"));
+            fail("Expected NullPointerException: Regex Pattern cannot be null.");
+        } catch (IllegalArgumentException e) {
+            // Expected NPE as regex pattern is null.
+        }
+
+        try {
+            realmModel.setPasswordPolicy(PasswordPolicy.parse(session, "regexPattern(*)"));
+            fail("Expected PatternSyntaxException: Regex Pattern cannot be null.");
+        } catch (PatternSyntaxException e) {
+            // Expected PSE as regex pattern(or any of its token) is not quantifiable.
+        }
+
+        try {
+            realmModel.setPasswordPolicy(PasswordPolicy.parse(session, "regexPattern(*,**)"));
+            fail("Expected PatternSyntaxException: Regex Pattern cannot be null.");
+        } catch (PatternSyntaxException e) {
+            // Expected PSE as regex pattern(or any of its token) is not quantifiable.
+        }
+
+        //Fails to match one of the regex pattern
+        realmModel.setPasswordPolicy(PasswordPolicy.parse(session, "regexPattern(jdoe) and regexPattern(j*d)"));
+        Assert.assertEquals("invalidPasswordRegexPatternMessage", policyManager.validate("jdoe", "jdoe").getMessage());
+
+        ////Fails to match all of the regex patterns
+        realmModel.setPasswordPolicy(PasswordPolicy.parse(session, "regexPattern(j*p) and regexPattern(j*d) and regexPattern(adoe)"));
+        Assert.assertEquals("invalidPasswordRegexPatternMessage", policyManager.validate("jdoe", "jdoe").getMessage());
+
+        realmModel.setPasswordPolicy(PasswordPolicy.parse(session, "regexPattern([a-z][a-z][a-z][a-z][0-9])"));
+        Assert.assertEquals("invalidPasswordRegexPatternMessage", policyManager.validate("jdoe", "jdoe").getMessage());
+
+        realmModel.setPasswordPolicy(PasswordPolicy.parse(session, "regexPattern(jdoe)"));
+        Assert.assertNull(policyManager.validate("jdoe", "jdoe"));
+
+        realmModel.setPasswordPolicy(PasswordPolicy.parse(session, "regexPattern([a-z][a-z][a-z][a-z][0-9])"));
+        Assert.assertNull(policyManager.validate("jdoe", "jdoe0"));
+    }
+
+    @Test
+    public void testComplex() {
+        realmModel.setPasswordPolicy(PasswordPolicy.parse(session, "length(8) and digits(2) and lowerCase(2) and upperCase(2) and specialChars(2) and notUsername()"));
+        Assert.assertNotNull(policyManager.validate("jdoe", "12aaBB&"));
+        Assert.assertNotNull(policyManager.validate("jdoe", "aaaaBB&-"));
+        Assert.assertNotNull(policyManager.validate("jdoe", "12AABB&-"));
+        Assert.assertNotNull(policyManager.validate("jdoe", "12aabb&-"));
+        Assert.assertNotNull(policyManager.validate("jdoe", "12aaBBcc"));
+        Assert.assertNotNull(policyManager.validate("12aaBB&-", "12aaBB&-"));
+
+        Assert.assertNull(policyManager.validate("jdoe", "12aaBB&-"));
+    }
+
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/TransactionsTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/TransactionsTest.java
index 0d7e9e2..2edcfaa 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/TransactionsTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/TransactionsTest.java
@@ -35,14 +35,14 @@ public class TransactionsTest {
     public void testTransactionActive() {
         KeycloakSession session = kc.startSession();
 
-        Assert.assertTrue(session.getTransaction().isActive());
-        session.getTransaction().commit();
-        Assert.assertFalse(session.getTransaction().isActive());
-
-        session.getTransaction().begin();
-        Assert.assertTrue(session.getTransaction().isActive());
-        session.getTransaction().rollback();
-        Assert.assertFalse(session.getTransaction().isActive());
+        Assert.assertTrue(session.getTransactionManager().isActive());
+        session.getTransactionManager().commit();
+        Assert.assertFalse(session.getTransactionManager().isActive());
+
+        session.getTransactionManager().begin();
+        Assert.assertTrue(session.getTransactionManager().isActive());
+        session.getTransactionManager().rollback();
+        Assert.assertFalse(session.getTransactionManager().isActive());
 
         session.close();
     }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserConsentModelTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserConsentModelTest.java
index 0a03398..2f71b23 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserConsentModelTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserConsentModelTest.java
@@ -67,7 +67,7 @@ public class UserConsentModelTest extends AbstractModelTest {
         johnFooGrant.addGrantedRole(realmRole);
         johnFooGrant.addGrantedRole(barClientRole);
         johnFooGrant.addGrantedProtocolMapper(fooMapper);
-        john.addConsent(johnFooGrant);
+        realmManager.getSession().users().addConsent(realm, john, johnFooGrant);
 
         UserConsentModel johnBarGrant = new UserConsentModel(barClient);
         johnBarGrant.addGrantedProtocolMapper(barMapper);
@@ -75,17 +75,17 @@ public class UserConsentModelTest extends AbstractModelTest {
 
         // Update should fail as grant doesn't yet exists
         try {
-            john.updateConsent(johnBarGrant);
+            realmManager.getSession().users().updateConsent(realm, john, johnBarGrant);
             Assert.fail("Not expected to end here");
         } catch (ModelException expected) {
         }
 
-        john.addConsent(johnBarGrant);
+        realmManager.getSession().users().addConsent(realm, john, johnBarGrant);
 
         UserConsentModel maryFooGrant = new UserConsentModel(fooClient);
         maryFooGrant.addGrantedRole(realmRole);
         maryFooGrant.addGrantedProtocolMapper(fooMapper);
-        mary.addConsent(maryFooGrant);
+        realmManager.getSession().users().addConsent(realm, mary, maryFooGrant);
 
         commit();
     }
@@ -99,27 +99,27 @@ public class UserConsentModelTest extends AbstractModelTest {
         UserModel john = session.users().getUserByUsername("john", realm);
         UserModel mary = session.users().getUserByUsername("mary", realm);
 
-        UserConsentModel johnFooConsent = john.getConsentByClient(fooClient.getId());
+        UserConsentModel johnFooConsent = realmManager.getSession().users().getConsentByClient(realm, john, fooClient.getId());
         Assert.assertEquals(johnFooConsent.getGrantedRoles().size(), 2);
         Assert.assertEquals(johnFooConsent.getGrantedProtocolMappers().size(), 1);
         Assert.assertTrue(isRoleGranted(realm, "realm-role", johnFooConsent));
         Assert.assertTrue(isRoleGranted(barClient, "bar-client-role", johnFooConsent));
         Assert.assertTrue(isMapperGranted(fooClient, "foo", johnFooConsent));
 
-        UserConsentModel johnBarConsent = john.getConsentByClient(barClient.getId());
+        UserConsentModel johnBarConsent = realmManager.getSession().users().getConsentByClient(realm, john, barClient.getId());
         Assert.assertEquals(johnBarConsent.getGrantedRoles().size(), 1);
         Assert.assertEquals(johnBarConsent.getGrantedProtocolMappers().size(), 1);
         Assert.assertTrue(isRoleGranted(realm, "realm-role", johnBarConsent));
         Assert.assertTrue(isMapperGranted(barClient, "bar", johnBarConsent));
 
-        UserConsentModel maryConsent = mary.getConsentByClient(fooClient.getId());
+        UserConsentModel maryConsent = realmManager.getSession().users().getConsentByClient(realm, mary, fooClient.getId());
         Assert.assertEquals(maryConsent.getGrantedRoles().size(), 1);
         Assert.assertEquals(maryConsent.getGrantedProtocolMappers().size(), 1);
         Assert.assertTrue(isRoleGranted(realm, "realm-role", maryConsent));
         Assert.assertFalse(isRoleGranted(barClient, "bar-client-role", maryConsent));
         Assert.assertTrue(isMapperGranted(fooClient, "foo", maryConsent));
 
-        Assert.assertNull(mary.getConsentByClient(barClient.getId()));
+        Assert.assertNull(realmManager.getSession().users().getConsentByClient(realm, mary, barClient.getId()));
     }
 
     @Test
@@ -130,10 +130,10 @@ public class UserConsentModelTest extends AbstractModelTest {
         UserModel john = session.users().getUserByUsername("john", realm);
         UserModel mary = session.users().getUserByUsername("mary", realm);
 
-        List<UserConsentModel> johnConsents = john.getConsents();
+        List<UserConsentModel> johnConsents = realmManager.getSession().users().getConsents(realm, john);
         Assert.assertEquals(2, johnConsents.size());
 
-        List<UserConsentModel> maryConsents = mary.getConsents();
+        List<UserConsentModel> maryConsents = realmManager.getSession().users().getConsents(realm, mary);
         Assert.assertEquals(1, maryConsents.size());
         UserConsentModel maryConsent = maryConsents.get(0);
         Assert.assertEquals(maryConsent.getClient().getId(), fooClient.getId());
@@ -149,7 +149,7 @@ public class UserConsentModelTest extends AbstractModelTest {
         ClientModel fooClient = realm.getClientByClientId("foo-client");
         UserModel john = session.users().getUserByUsername("john", realm);
 
-        UserConsentModel johnConsent = john.getConsentByClient(fooClient.getId());
+        UserConsentModel johnConsent = realmManager.getSession().users().getConsentByClient(realm, john, fooClient.getId());
 
         // Remove foo protocol mapper from johnConsent
         ProtocolMapperModel protMapperModel = fooClient.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, "foo");
@@ -162,14 +162,14 @@ public class UserConsentModelTest extends AbstractModelTest {
         RoleModel newRealmRole = realm.addRole("new-realm-role");
         johnConsent.addGrantedRole(newRealmRole);
 
-        john.updateConsent(johnConsent);
+        realmManager.getSession().users().updateConsent(realm, john, johnConsent);
 
         commit();
 
         realm = realmManager.getRealm("original");
         fooClient = realm.getClientByClientId("foo-client");
         john = session.users().getUserByUsername("john", realm);
-        johnConsent = john.getConsentByClient(fooClient.getId());
+        johnConsent = realmManager.getSession().users().getConsentByClient(realm, john, fooClient.getId());
 
         Assert.assertEquals(johnConsent.getGrantedRoles().size(), 2);
         Assert.assertEquals(johnConsent.getGrantedProtocolMappers().size(), 0);
@@ -184,13 +184,13 @@ public class UserConsentModelTest extends AbstractModelTest {
         ClientModel fooClient = realm.getClientByClientId("foo-client");
         UserModel john = session.users().getUserByUsername("john", realm);
 
-        john.revokeConsentForClient(fooClient.getId());
+        realmManager.getSession().users().revokeConsentForClient(realm, john, fooClient.getId());
 
         commit();
 
         realm = realmManager.getRealm("original");
         john = session.users().getUserByUsername("john", realm);
-        Assert.assertNull(john.getConsentByClient(fooClient.getId()));
+        Assert.assertNull(realmManager.getSession().users().getConsentByClient(realm, john, fooClient.getId()));
     }
 
     @Test
@@ -213,7 +213,7 @@ public class UserConsentModelTest extends AbstractModelTest {
         realm = realmManager.getRealm("original");
         fooClient = realm.getClientByClientId("foo-client");
         UserModel john = session.users().getUserByUsername("john", realm);
-        UserConsentModel johnConsent = john.getConsentByClient(fooClient.getId());
+        UserConsentModel johnConsent = realmManager.getSession().users().getConsentByClient(realm, john, fooClient.getId());
 
         Assert.assertEquals(johnConsent.getGrantedRoles().size(), 2);
         Assert.assertEquals(johnConsent.getGrantedProtocolMappers().size(), 0);
@@ -232,7 +232,7 @@ public class UserConsentModelTest extends AbstractModelTest {
         ClientModel fooClient = realm.getClientByClientId("foo-client");
         ClientModel barClient = realm.getClientByClientId("bar-client");
         UserModel john = session.users().getUserByUsername("john", realm);
-        UserConsentModel johnConsent = john.getConsentByClient(fooClient.getId());
+        UserConsentModel johnConsent = realmManager.getSession().users().getConsentByClient(realm, john, fooClient.getId());
 
         Assert.assertEquals(johnConsent.getGrantedRoles().size(), 1);
         Assert.assertEquals(johnConsent.getGrantedProtocolMappers().size(), 1);
@@ -254,13 +254,13 @@ public class UserConsentModelTest extends AbstractModelTest {
 
         UserModel john = session.users().getUserByUsername("john", realm);
 
-        UserConsentModel johnFooConsent = john.getConsentByClient(fooClient.getId());
+        UserConsentModel johnFooConsent = realmManager.getSession().users().getConsentByClient(realm, john, fooClient.getId());
         Assert.assertEquals(johnFooConsent.getGrantedRoles().size(), 1);
         Assert.assertEquals(johnFooConsent.getGrantedProtocolMappers().size(), 1);
         Assert.assertTrue(isRoleGranted(realm, "realm-role", johnFooConsent));
         Assert.assertTrue(isMapperGranted(fooClient, "foo", johnFooConsent));
 
-        Assert.assertNull(john.getConsentByClient(barClient.getId()));
+        Assert.assertNull(realmManager.getSession().users().getConsentByClient(realm, john, barClient.getId()));
     }
 
     private boolean isRoleGranted(RoleContainerModel roleContainer, String roleName, UserConsentModel consentModel) {
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserModelTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserModelTest.java
index 0841c1f..4b3f78e 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserModelTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserModelTest.java
@@ -66,20 +66,20 @@ public class UserModelTest extends AbstractModelTest {
 
         Map<String, String> attributes = new HashMap<String, String>();
         attributes.put(UserModel.LAST_NAME, "last-name");
-        List<UserModel> search = session.users().searchForUserByAttributes(attributes, realm);
+        List<UserModel> search = session.users().searchForUser(attributes, realm);
         Assert.assertEquals(search.size(), 1);
         Assert.assertEquals(search.get(0).getUsername(), "user");
 
         attributes.clear();
         attributes.put(UserModel.EMAIL, "email");
-        search = session.users().searchForUserByAttributes(attributes, realm);
+        search = session.users().searchForUser(attributes, realm);
         Assert.assertEquals(search.size(), 1);
         Assert.assertEquals(search.get(0).getUsername(), "user");
 
         attributes.clear();
         attributes.put(UserModel.LAST_NAME, "last-name");
         attributes.put(UserModel.EMAIL, "email");
-        search = session.users().searchForUserByAttributes(attributes, realm);
+        search = session.users().searchForUser(attributes, realm);
         Assert.assertEquals(search.size(), 1);
         Assert.assertEquals(search.get(0).getUsername(), "user");
     }
@@ -217,7 +217,7 @@ public class UserModelTest extends AbstractModelTest {
         UserModel user1 = session.users().addUser(realm, "user1");
 
         commit();
-
+        realm = session.realms().getRealmByName("original");
         List<UserModel> users = session.users().searchForUser("user", realm, 0, 7);
         Assert.assertTrue(users.contains(user1));
     }
@@ -238,6 +238,7 @@ public class UserModelTest extends AbstractModelTest {
         user3.setSingleAttribute("key2", "value21");
 
         commit();
+        realm = session.realms().getRealmByName("original");
 
         List<UserModel> users = session.users().searchForUserByUserAttribute("key1", "value1", realm);
         Assert.assertEquals(2, users.size());
@@ -271,7 +272,7 @@ public class UserModelTest extends AbstractModelTest {
         user2.setLastName("Doe");
 
         // Search
-        Assert.assertNull(session.users().getUserByServiceAccountClient(client));
+        Assert.assertNull(session.users().getServiceAccount(client));
         List<UserModel> users = session.users().searchForUser("John Doe", realm);
         Assert.assertEquals(2, users.size());
         Assert.assertTrue(users.contains(user1));
@@ -284,7 +285,8 @@ public class UserModelTest extends AbstractModelTest {
 
         // Search and assert service account user not found
         realm = realmManager.getRealmByName("original");
-        UserModel searched = session.users().getUserByServiceAccountClient(client);
+        client = realm.getClientByClientId("foo");
+        UserModel searched = session.users().getServiceAccount(client);
         Assert.assertEquals(searched, user1);
         users = session.users().searchForUser("John Doe", realm);
         Assert.assertEquals(1, users.size());
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java
index 3da7d23..0a5842c 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java
@@ -28,7 +28,7 @@ import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
-import org.keycloak.models.UsernameLoginFailureModel;
+import org.keycloak.models.UserLoginFailureModel;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.services.managers.UserManager;
 import org.keycloak.testsuite.rule.KeycloakRule;
@@ -471,10 +471,10 @@ public class UserSessionProviderTest {
 
     @Test
     public void loginFailures() {
-        UsernameLoginFailureModel failure1 = session.sessions().addUserLoginFailure(realm, "user1");
+        UserLoginFailureModel failure1 = session.sessions().addUserLoginFailure(realm, "user1");
         failure1.incrementFailures();
 
-        UsernameLoginFailureModel failure2 = session.sessions().addUserLoginFailure(realm, "user2");
+        UserLoginFailureModel failure2 = session.sessions().addUserLoginFailure(realm, "user2");
         failure2.incrementFailures();
         failure2.incrementFailures();
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
index 7ccd8d7..12c1f30 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
@@ -39,6 +39,7 @@ import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.RefreshToken;
 import org.keycloak.util.BasicAuthHelper;
 import org.keycloak.common.util.PemUtils;
+import org.keycloak.util.TokenUtil;
 import org.openqa.selenium.By;
 import org.openqa.selenium.WebDriver;
 
@@ -442,9 +443,10 @@ public class OAuthClient {
         if(uiLocales != null){
             b.queryParam(OAuth2Constants.UI_LOCALES_PARAM, uiLocales);
         }
-        if (scope != null) {
-            b.queryParam(OAuth2Constants.SCOPE, scope);
-        }
+
+        String scopeParam = TokenUtil.attachOIDCScope(scope);
+        b.queryParam(OAuth2Constants.SCOPE, scopeParam);
+
         return b.build(realm).toString();
     }
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/Retry.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/Retry.java
index 441dcac..673d4fb 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/Retry.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/Retry.java
@@ -22,7 +22,7 @@ package org.keycloak.testsuite;
  */
 public class Retry {
 
-    public static void execute(Runnable runnable, int retry, long interval) throws InterruptedException {
+    public static void execute(Runnable runnable, int retry, long interval) {
         while (true) {
             try {
                 runnable.run();
@@ -30,7 +30,11 @@ public class Retry {
             } catch (RuntimeException e) {
                 retry--;
                 if (retry > 0) {
-                   Thread.sleep(interval);
+                    try {
+                        Thread.sleep(interval);
+                    } catch (InterruptedException ie) {
+                        throw new RuntimeException(ie);
+                    }
                 } else {
                     throw e;
                 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java
index 172c517..8315331 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/AbstractKeycloakRule.java
@@ -85,12 +85,12 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
 
     public UserRepresentation getUser(String realm, String name) {
         KeycloakSession session = server.getSessionFactory().create();
-        session.getTransaction().begin();
+        session.getTransactionManager().begin();
         try {
             RealmModel realmByName = session.realms().getRealmByName(realm);
             UserModel user = session.users().getUserByUsername(name, realmByName);
             UserRepresentation userRep = user != null ? ModelToRepresentation.toRepresentation(user) : null;
-            session.getTransaction().commit();
+            session.getTransactionManager().commit();
             return userRep;
         } finally {
             session.close();
@@ -99,11 +99,11 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
 
     public UserRepresentation getUserById(String realm, String id) {
         KeycloakSession session = server.getSessionFactory().create();
-        session.getTransaction().begin();
+        session.getTransactionManager().begin();
         try {
             RealmModel realmByName = session.realms().getRealmByName(realm);
             UserRepresentation userRep = ModelToRepresentation.toRepresentation(session.users().getUserById(id, realmByName));
-            session.getTransaction().commit();
+            session.getTransactionManager().commit();
             return userRep;
         } finally {
             session.close();
@@ -112,7 +112,7 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
 
     protected void setupKeycloak() {
         KeycloakSession session = server.getSessionFactory().create();
-        session.getTransaction().begin();
+        session.getTransactionManager().begin();
 
         try {
             RealmManager manager = new RealmManager(session);
@@ -121,7 +121,7 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
 
             configure(session, manager, adminstrationRealm);
 
-            session.getTransaction().commit();
+            session.getTransactionManager().commit();
         } finally {
             session.close();
         }
@@ -129,7 +129,7 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
 
     public void update(KeycloakRule.KeycloakSetup configurer, String realmId) {
         KeycloakSession session = server.getSessionFactory().create();
-        session.getTransaction().begin();
+        session.getTransactionManager().begin();
 
         try {
             RealmManager manager = new RealmManager(session);
@@ -141,7 +141,7 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
             configurer.session = session;
             configurer.config(manager, adminstrationRealm, appRealm);
 
-            session.getTransaction().commit();
+            session.getTransactionManager().commit();
         } finally {
             session.close();
         }
@@ -221,7 +221,7 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
     protected void removeTestRealms() {
         KeycloakSession session = server.getSessionFactory().create();
         try {
-            session.getTransaction().begin();
+            session.getTransactionManager().begin();
             RealmManager realmManager = new RealmManager(session);
             for (String realmName : getTestRealms()) {
                 RealmModel realm = realmManager.getRealmByName(realmName);
@@ -229,7 +229,7 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
                     realmManager.removeRealm(realm);
                 }
             }
-            session.getTransaction().commit();
+            session.getTransactionManager().commit();
         } finally {
             session.close();
         }
@@ -248,12 +248,12 @@ public abstract class AbstractKeycloakRule extends ExternalResource {
 
     public KeycloakSession startSession() {
         KeycloakSession session = server.getSessionFactory().create();
-        session.getTransaction().begin();
+        session.getTransactionManager().begin();
         return session;
     }
 
     public void stopSession(KeycloakSession session, boolean commit) {
-        KeycloakTransaction transaction = session.getTransaction();
+        KeycloakTransaction transaction = session.getTransactionManager();
         if (commit && !transaction.getRollbackOnly()) {
             transaction.commit();
         } else {
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KeycloakRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KeycloakRule.java
index 8e48177..050bcf3 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KeycloakRule.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/KeycloakRule.java
@@ -58,7 +58,7 @@ public class KeycloakRule extends AbstractKeycloakRule {
 
     public void configure(KeycloakSetup configurer) {
         KeycloakSession session = server.getSessionFactory().create();
-        session.getTransaction().begin();
+        session.getTransactionManager().begin();
 
         try {
             RealmManager manager = new RealmManager(session);
@@ -70,7 +70,7 @@ public class KeycloakRule extends AbstractKeycloakRule {
             configurer.session = session;
             configurer.config(manager, adminstrationRealm, appRealm);
 
-            session.getTransaction().commit();
+            session.getTransactionManager().commit();
         } finally {
             session.close();
         }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/ValidationTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/ValidationTest.java
new file mode 100644
index 0000000..43638e0
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/saml/ValidationTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.saml;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.keycloak.common.util.PemUtils;
+import org.keycloak.common.util.StreamUtil;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.protocol.saml.SamlProtocol;
+import org.keycloak.protocol.saml.SamlService;
+import org.keycloak.saml.SPMetadataDescriptor;
+import org.keycloak.services.resources.RealmsResource;
+import org.xml.sax.SAXException;
+
+import javax.ws.rs.core.UriInfo;
+import javax.xml.XMLConstants;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import javax.xml.validation.Validator;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ValidationTest {
+
+    public static String getIDPMetadataDescriptor() throws IOException {
+        InputStream is = SamlService.class.getResourceAsStream("/idp-metadata-template.xml");
+        String template = StreamUtil.readString(is);
+        template = template.replace("${idp.entityID}", "http://keycloak.org/auth/realms/test");
+        template = template.replace("${idp.sso.HTTP-POST}", "http://keycloak.org/auth/realms/test/saml");
+        template = template.replace("${idp.sso.HTTP-Redirect}", "http://keycloak.org/auth/realms/test/saml");
+        template = template.replace("${idp.sls.HTTP-POST}", "http://keycloak.org/auth/realms/test/saml");
+        template = template.replace("${idp.signing.certificate}", KeycloakModelUtils.generateKeyPairCertificate("test").getCertificate());
+        return template;
+    }
+
+
+    @Test
+    @Ignore // ignore because it goes out to web
+    public void testIDPDescriptor() throws Exception {
+        URL schemaFile = getClass().getResource("/schema/saml/v2/saml-schema-metadata-2.0.xsd");
+        Source xmlFile = new StreamSource(new ByteArrayInputStream(getIDPMetadataDescriptor().getBytes()), "IDPSSODescriptor");
+        SchemaFactory schemaFactory = SchemaFactory
+                .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+        Schema schema = schemaFactory.newSchema(schemaFile);
+        Validator validator = schema.newValidator();
+        try {
+            validator.validate(xmlFile);
+            System.out.println(xmlFile.getSystemId() + " is valid");
+        } catch (SAXException e) {
+            System.out.println(xmlFile.getSystemId() + " is NOT valid");
+            System.out.println("Reason: " + e.getLocalizedMessage());
+            Assert.fail();
+        }
+    }
+    @Test
+    @Ignore // ignore because it goes out to web
+    public void testBrokerExportDescriptor() throws Exception {
+        URL schemaFile = getClass().getResource("/schema/saml/v2/saml-schema-metadata-2.0.xsd");
+        Source xmlFile = new StreamSource(new ByteArrayInputStream(SPMetadataDescriptor.getSPDescriptor(
+                "POST", "http://realm/assertion", "http://realm/logout", true, "test", SamlProtocol.SAML_DEFAULT_NAMEID_FORMAT, KeycloakModelUtils.generateKeyPairCertificate("test").getCertificate()
+        ).getBytes()), "SP Descriptor");
+        SchemaFactory schemaFactory = SchemaFactory
+                .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+        Schema schema = schemaFactory.newSchema(schemaFile);
+        Validator validator = schema.newValidator();
+        try {
+            validator.validate(xmlFile);
+            System.out.println(xmlFile.getSystemId() + " is valid");
+        } catch (SAXException e) {
+            System.out.println(xmlFile.getSystemId() + " is NOT valid");
+            System.out.println("Reason: " + e.getLocalizedMessage());
+            Assert.fail();
+        }
+    }
+}
diff --git a/testsuite/integration/src/test/resources/adapter-test/demorealm.json b/testsuite/integration/src/test/resources/adapter-test/demorealm.json
index 70dc85a..aaac871 100755
--- a/testsuite/integration/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/integration/src/test/resources/adapter-test/demorealm.json
@@ -157,6 +157,12 @@
             ]
         },
         {
+            "name": "customer-portal-public",
+            "enabled": true,
+            "publicClient": true,
+            "directAccessGrantsEnabled": true
+        },
+        {
             "name": "product-portal",
             "enabled": true,
             "adminUrl": "http://localhost:8081/product-portal",
diff --git a/testsuite/integration/src/test/resources/authorization-test/test-photoz-realm.json b/testsuite/integration/src/test/resources/authorization-test/test-photoz-realm.json
new file mode 100644
index 0000000..340576c
--- /dev/null
+++ b/testsuite/integration/src/test/resources/authorization-test/test-photoz-realm.json
@@ -0,0 +1,158 @@
+{
+  "realm": "photoz",
+  "enabled": true,
+  "accessTokenLifespan": 60,
+  "accessCodeLifespan": 60,
+  "accessCodeLifespanUserAction": 300,
+  "ssoSessionIdleTimeout": 600,
+  "ssoSessionMaxLifespan": 36000,
+  "sslRequired": "external",
+  "registrationAllowed": false,
+  "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+  "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "requiredCredentials": [
+    "password"
+  ],
+  "users": [
+    {
+      "username": "alice",
+      "enabled": true,
+      "email": "alice@keycloak.org",
+      "firstName": "Alice",
+      "lastName": "In Chains",
+      "credentials": [
+        {
+          "type": "password",
+          "value": "alice"
+        }
+      ],
+      "realmRoles": [
+        "user"
+      ],
+      "clientRoles": {
+        "photoz-html5-client": [
+          "uma_authorization",
+          "kc_entitlement"
+        ]
+      }
+    },
+    {
+      "username": "jdoe",
+      "enabled": true,
+      "email": "jdoe@keycloak.org",
+      "firstName": "John",
+      "lastName": "Doe",
+      "credentials": [
+        {
+          "type": "password",
+          "value": "jdoe"
+        }
+      ],
+      "realmRoles": [
+        "user"
+      ],
+      "clientRoles": {
+        "photoz-html5-client": [
+          "uma_authorization",
+          "kc_entitlement"
+        ]
+      }
+    },
+    {
+      "username": "admin",
+      "enabled": true,
+      "email": "admin@admin.com",
+      "firstName": "Admin",
+      "lastName": "Istrator",
+      "credentials": [
+        {
+          "type": "password",
+          "value": "admin"
+        }
+      ],
+      "realmRoles": [
+        "user",
+        "admin"
+      ],
+      "clientRoles": {
+        "realm-management": [
+          "realm-admin"
+        ],
+        "photoz-html5-client": [
+          "uma_authorization",
+          "kc_entitlement"
+        ]
+      }
+    },
+    {
+      "username": "service-account-photoz-restful-api",
+      "enabled": true,
+      "email": "service-account-photoz-restful-api@placeholder.org",
+      "serviceAccountClientId": "photoz-restful-api",
+      "realmRoles": [
+        "uma_protection"
+      ]
+    }
+  ],
+  "roles": {
+    "realm": [
+      {
+        "name": "user",
+        "description": "User privileges"
+      },
+      {
+        "name": "admin",
+        "description": "Administrator privileges"
+      },
+      {
+        "name": "uma_protection",
+        "description": "Allows access to the Protection API"
+      }
+    ]
+  },
+  "clients": [
+    {
+      "clientId": "photoz-html5-client",
+      "enabled": true,
+      "adminUrl": "/photoz-html5-client",
+      "baseUrl": "/photoz-html5-client",
+      "publicClient": true,
+      "redirectUris": [
+        "/photoz-html5-client/*"
+      ]
+    },
+    {
+      "clientId": "photoz-restful-api",
+      "enabled": true,
+      "publicClient": false,
+      "baseUrl": "/photoz-restful-api",
+      "bearerOnly": false,
+      "serviceAccountsEnabled": true,
+      "redirectUris": [
+        "/photoz-restful-api/*"
+      ],
+      "secret": "secret"
+    },
+    {
+      "clientId": "public-client-01",
+      "enabled": true,
+      "publicClient": true,
+      "baseUrl": "public-client-01",
+      "redirectUris": [
+        "/public-client-01/*"
+      ]
+    },
+    {
+      "clientId": "confidential-no-service-account",
+      "enabled": true,
+      "publicClient": false,
+      "baseUrl": "/confidential-no-service-account",
+      "bearerOnly": false,
+      "serviceAccountsEnabled": false,
+      "redirectUris": [
+        "/confidential-no-service-account/*"
+      ],
+      "secret": "secret"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json
index 84bcaf8..99c0245 100755
--- a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json
+++ b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json
@@ -178,7 +178,6 @@
             "config": {
                 "clientId": "broker-app",
                 "clientSecret": "secret",
-                "prompt": "login",
                 "authorizationUrl": "http://localhost:8082/auth/realms/realm-with-oidc-identity-provider/protocol/openid-connect/auth",
                 "tokenUrl": "http://localhost:8082/auth/realms/realm-with-oidc-identity-provider/protocol/openid-connect/token",
                 "userInfoUrl": "http://localhost:8082/auth/realms/realm-with-oidc-identity-provider/protocol/openid-connect/userinfo",
@@ -196,7 +195,6 @@
             "config": {
                 "clientId": "broker-app",
                 "clientSecret": "secret",
-                "prompt": "login",
                 "authorizationUrl": "http://localhost:8082/auth/realms/realm-with-oidc-idp-property-mappers/protocol/openid-connect/auth",
                 "tokenUrl": "http://localhost:8082/auth/realms/realm-with-oidc-idp-property-mappers/protocol/openid-connect/token",
                 "userInfoUrl": "http://localhost:8082/auth/realms/realm-with-oidc-idp-property-mappers/protocol/openid-connect/userinfo",
diff --git a/testsuite/integration/src/test/resources/keycloak-saml/bad-assertion-signed-post/WEB-INF/keycloak-saml.xml b/testsuite/integration/src/test/resources/keycloak-saml/bad-assertion-signed-post/WEB-INF/keycloak-saml.xml
new file mode 100755
index 0000000..16f78d9
--- /dev/null
+++ b/testsuite/integration/src/test/resources/keycloak-saml/bad-assertion-signed-post/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,62 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<keycloak-saml-adapter>
+    <SP entityID="http://localhost:8081/bad-assertion-sales-post-sig/"
+        sslPolicy="EXTERNAL"
+        nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+        logoutPage="/logout.jsp"
+        forceAuthentication="false">
+        <Keys>
+            <Key signing="true" >
+                <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                    <PrivateKey alias="http://localhost:8081/bad-realm-sales-post-sig/" password="test123"/>
+                    <Certificate alias="http://localhost:8081/bad-realm-sales-post-sig/"/>
+                </KeyStore>
+            </Key>
+        </Keys>
+        <PrincipalNameMapping policy="FROM_NAME_ID"/>
+        <RoleIdentifiers>
+            <Attribute name="Role"/>
+        </RoleIdentifiers>
+        <IDP entityID="idp">
+            <SingleSignOnService signRequest="true"
+                                 validateAssertionSignature="true"
+                                 requestBinding="POST"
+                                 bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+
+            <SingleLogoutService
+                    validateRequestSignature="true"
+                    validateResponseSignature="true"
+                    signRequest="true"
+                    signResponse="true"
+                    requestBinding="POST"
+                    responseBinding="POST"
+                    postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+            <Keys>
+                <Key signing="true">
+                    <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                        <Certificate alias="demo"/>
+                    </KeyStore>
+                </Key>
+            </Keys>
+        </IDP>
+     </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/integration/src/test/resources/keycloak-saml/bad-assertion-signed-post/WEB-INF/keystore.jks b/testsuite/integration/src/test/resources/keycloak-saml/bad-assertion-signed-post/WEB-INF/keystore.jks
new file mode 100755
index 0000000..215384c
Binary files /dev/null and b/testsuite/integration/src/test/resources/keycloak-saml/bad-assertion-signed-post/WEB-INF/keystore.jks differ
diff --git a/testsuite/integration/src/test/resources/keycloak-saml/missing-assertion-sig/WEB-INF/keycloak-saml.xml b/testsuite/integration/src/test/resources/keycloak-saml/missing-assertion-sig/WEB-INF/keycloak-saml.xml
new file mode 100755
index 0000000..dc60fda
--- /dev/null
+++ b/testsuite/integration/src/test/resources/keycloak-saml/missing-assertion-sig/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,60 @@
+<!--
+  ~ JBoss, Home of Professional Open Source.
+  ~ Copyright 2016 Red Hat, Inc., and individual contributors
+  ~ as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<keycloak-saml-adapter>
+    <SP entityID="http://localhost:8081/missing-assertion-sig/"
+        sslPolicy="EXTERNAL"
+        nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+        logoutPage="/logout.jsp"
+        forceAuthentication="false">
+        <Keys>
+            <Key signing="true" >
+                <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                    <PrivateKey alias="http://localhost:8080/sales-post-sig/" password="test123"/>
+                    <Certificate alias="http://localhost:8080/sales-post-sig/"/>
+                </KeyStore>
+            </Key>
+        </Keys>
+        <PrincipalNameMapping policy="FROM_NAME_ID"/>
+        <RoleIdentifiers>
+            <Attribute name="Role"/>
+        </RoleIdentifiers>
+        <IDP entityID="idp"
+             signaturesRequired="true">
+        <SingleSignOnService requestBinding="POST"
+                             bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                             validateAssertionSignature="true"
+                             validateResponseSignature="false"
+                    />
+
+            <SingleLogoutService
+                    requestBinding="POST"
+                    responseBinding="POST"
+                    postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+            <Keys>
+                <Key signing="true">
+                    <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                        <Certificate alias="demo"/>
+                    </KeyStore>
+                </Key>
+            </Keys>
+        </IDP>
+     </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/integration/src/test/resources/keycloak-saml/missing-assertion-sig/WEB-INF/keystore.jks b/testsuite/integration/src/test/resources/keycloak-saml/missing-assertion-sig/WEB-INF/keystore.jks
new file mode 100755
index 0000000..144830b
Binary files /dev/null and b/testsuite/integration/src/test/resources/keycloak-saml/missing-assertion-sig/WEB-INF/keystore.jks differ
diff --git a/testsuite/integration/src/test/resources/keycloak-saml/sales-post-assertion-and-response-sig/WEB-INF/keycloak-saml.xml b/testsuite/integration/src/test/resources/keycloak-saml/sales-post-assertion-and-response-sig/WEB-INF/keycloak-saml.xml
new file mode 100755
index 0000000..1bd35d1
--- /dev/null
+++ b/testsuite/integration/src/test/resources/keycloak-saml/sales-post-assertion-and-response-sig/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,60 @@
+<!--
+  ~ JBoss, Home of Professional Open Source.
+  ~ Copyright 2016 Red Hat, Inc., and individual contributors
+  ~ as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<keycloak-saml-adapter>
+    <SP entityID="http://localhost:8081/sales-post-assertion-and-response-sig/"
+        sslPolicy="EXTERNAL"
+        nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+        logoutPage="/logout.jsp"
+        forceAuthentication="false">
+        <Keys>
+            <Key signing="true" >
+                <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                    <PrivateKey alias="http://localhost:8080/sales-post-sig/" password="test123"/>
+                    <Certificate alias="http://localhost:8080/sales-post-sig/"/>
+                </KeyStore>
+            </Key>
+        </Keys>
+        <PrincipalNameMapping policy="FROM_NAME_ID"/>
+        <RoleIdentifiers>
+            <Attribute name="Role"/>
+        </RoleIdentifiers>
+        <IDP entityID="idp"
+             signaturesRequired="true">
+        <SingleSignOnService requestBinding="POST"
+                             bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                             validateAssertionSignature="true"
+                             validateResponseSignature="true"
+                    />
+
+            <SingleLogoutService
+                    requestBinding="POST"
+                    responseBinding="POST"
+                    postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+            <Keys>
+                <Key signing="true">
+                    <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                        <Certificate alias="demo"/>
+                    </KeyStore>
+                </Key>
+            </Keys>
+        </IDP>
+     </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/integration/src/test/resources/keycloak-saml/sales-post-assertion-and-response-sig/WEB-INF/keystore.jks b/testsuite/integration/src/test/resources/keycloak-saml/sales-post-assertion-and-response-sig/WEB-INF/keystore.jks
new file mode 100755
index 0000000..144830b
Binary files /dev/null and b/testsuite/integration/src/test/resources/keycloak-saml/sales-post-assertion-and-response-sig/WEB-INF/keystore.jks differ
diff --git a/testsuite/integration/src/test/resources/keycloak-saml/testsaml.json b/testsuite/integration/src/test/resources/keycloak-saml/testsaml.json
index 92ddf1a..b184a58 100755
--- a/testsuite/integration/src/test/resources/keycloak-saml/testsaml.json
+++ b/testsuite/integration/src/test/resources/keycloak-saml/testsaml.json
@@ -159,6 +159,50 @@
             }
         },
         {
+            "name": "http://localhost:8081/sales-post-assertion-and-response-sig/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8081/sales-post-assertion-and-response-sig",
+            "redirectUris": [
+                "http://localhost:8081/sales-post-assertion-and-response-sig/*"
+            ],
+            "attributes": {
+                "saml_assertion_consumer_url_post": "http://localhost:8081/sales-post-assertion-and-response-sig/saml",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8081/sales-post-assertion-and-response-sig/saml",
+                "saml_single_logout_service_url_post": "http://localhost:8081/sales-post-assertion-and-response-sig/saml",
+                "saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-assertion-and-response-sig/saml",
+                "saml.server.signature": "true",
+                "saml.assertion.signature": "true",
+                "saml.signature.algorithm": "RSA_SHA256",
+                "saml.client.signature": "true",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
+            }
+        },
+        {
+            "name": "http://localhost:8081/missing-assertion-sig/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8081/missing-assertion-sig",
+            "redirectUris": [
+                "http://localhost:8081/missing-assertion-sig/*"
+            ],
+            "attributes": {
+                "saml_assertion_consumer_url_post": "http://localhost:8081/missing-assertion-sig/saml",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8081/missing-assertion-sig/saml",
+                "saml_single_logout_service_url_post": "http://localhost:8081/missing-assertion-sig/saml",
+                "saml_single_logout_service_url_redirect": "http://localhost:8081/missing-assertion-sig/saml",
+                "saml.server.signature": "true",
+                "saml.assertion.signature": "false",
+                "saml.signature.algorithm": "RSA_SHA256",
+                "saml.client.signature": "true",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
+            }
+        },
+        {
             "name": "http://localhost:8081/sales-post-sig-transient/",
             "enabled": true,
             "protocol": "saml",
@@ -243,6 +287,23 @@
             }
         },
         {
+            "name": "http://localhost:8081/bad-assertion-sales-post-sig/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8081/bad-assertion-sales-post-sig/",
+            "adminUrl": "http://localhost:8081/bad-assertion-sales-post-sig/saml",
+            "redirectUris": [
+                "http://localhost:8081/bad-assertion-sales-post-sig/*"
+            ],
+            "attributes": {
+                "saml.assertion.signature": "true",
+                "saml.client.signature": "true",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
+            }
+        },
+        {
             "name": "http://localhost:8081/bad-client-sales-post-sig/",
             "enabled": true,
             "protocol": "saml",
@@ -274,6 +335,7 @@
                 "saml_single_logout_service_url_post": "http://localhost:8081/sales-post-enc/saml",
                 "saml_single_logout_service_url_redirect": "http://localhost:8081/sales-post-enc/saml",
                 "saml.server.signature": "true",
+                "saml.assertion.signature": "true",
                 "saml.signature.algorithm": "RSA_SHA512",
                 "saml.client.signature": "true",
                 "saml.encrypt": "true",
diff --git a/testsuite/integration/src/test/resources/log4j.properties b/testsuite/integration/src/test/resources/log4j.properties
index f093692..5d5369c 100755
--- a/testsuite/integration/src/test/resources/log4j.properties
+++ b/testsuite/integration/src/test/resources/log4j.properties
@@ -23,6 +23,7 @@ log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p %t [%c] %m%
 
 log4j.logger.org.keycloak=info
 
+
 # Enable to view events
 # log4j.logger.org.keycloak.events=debug
 
@@ -49,12 +50,15 @@ log4j.logger.org.keycloak.connections.jpa.updater.liquibase=${keycloak.liquibase
 
 # Enable to view database updates
 # log4j.logger.org.keycloak.connections.mongo.updater.DefaultMongoUpdaterProvider=debug
-# log4j.logger.org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory=debug
+log4j.logger.org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory=${keycloak.liquibase.logging.level}
 # log4j.logger.org.keycloak.migration.MigrationModelManager=debug
 
 # Enable to view hibernate statistics
 log4j.logger.org.keycloak.connections.jpa.HibernateStatsReporter=debug
 
+# Enable to view ldap logging
+# log4j.logger.org.keycloak.federation.ldap=trace
+
 # Enable to view kerberos/spnego logging
 # log4j.logger.org.keycloak.federation.kerberos=trace
 
diff --git a/testsuite/integration/src/test/resources/META-INF/keycloak-server.json b/testsuite/integration/src/test/resources/META-INF/keycloak-server.json
index ec76904..d3f87c9 100755
--- a/testsuite/integration/src/test/resources/META-INF/keycloak-server.json
+++ b/testsuite/integration/src/test/resources/META-INF/keycloak-server.json
@@ -26,6 +26,10 @@
         "provider": "${keycloak.userSessionPersister.provider:jpa}"
     },
 
+    "authorizationPersister": {
+        "provider": "${keycloak.authorization.provider:jpa}"
+    },
+
     "userCache": {
         "default" : {
             "enabled": true
@@ -90,5 +94,16 @@
             "async": "${keycloak.connectionsInfinispan.async:false}",
             "sessionsOwners": "${keycloak.connectionsInfinispan.sessionsOwners:2}"
         }
+    },
+
+    "scripting": {
+    },
+
+    "jta-lookup": {
+        "provider": "${keycloak.jta.lookup.provider:jboss}",
+        "jboss" : {
+            "enabled": true
+        }
+
     }
 }
\ No newline at end of file
diff --git a/testsuite/integration/src/test/resources/META-INF/services/org.keycloak.hash.PasswordHashProviderFactory b/testsuite/integration/src/test/resources/META-INF/services/org.keycloak.hash.PasswordHashProviderFactory
new file mode 100644
index 0000000..9b9b525
--- /dev/null
+++ b/testsuite/integration/src/test/resources/META-INF/services/org.keycloak.hash.PasswordHashProviderFactory
@@ -0,0 +1 @@
+org.keycloak.testsuite.federation.storage.PlainTextPasswordProviderFactory
\ No newline at end of file
diff --git a/testsuite/integration/src/test/resources/META-INF/services/org.keycloak.storage.UserStorageProviderFactory b/testsuite/integration/src/test/resources/META-INF/services/org.keycloak.storage.UserStorageProviderFactory
new file mode 100644
index 0000000..efbed13
--- /dev/null
+++ b/testsuite/integration/src/test/resources/META-INF/services/org.keycloak.storage.UserStorageProviderFactory
@@ -0,0 +1,2 @@
+org.keycloak.testsuite.federation.storage.UserPropertyFileStorageFactory
+org.keycloak.testsuite.federation.storage.UserMapStorageFactory
\ No newline at end of file
diff --git a/testsuite/integration/src/test/resources/storage-test/read-only-user-password.properties b/testsuite/integration/src/test/resources/storage-test/read-only-user-password.properties
new file mode 100644
index 0000000..c0b76ab
--- /dev/null
+++ b/testsuite/integration/src/test/resources/storage-test/read-only-user-password.properties
@@ -0,0 +1,4 @@
+tbrady=goat
+rob=pw
+jules=pw
+danny=pw
diff --git a/testsuite/integration/src/test/resources/storage-test/user-password.properties b/testsuite/integration/src/test/resources/storage-test/user-password.properties
new file mode 100644
index 0000000..a6e28c1
--- /dev/null
+++ b/testsuite/integration/src/test/resources/storage-test/user-password.properties
@@ -0,0 +1,4 @@
+thor=hammer
+zeus=pw
+apollo=pw
+perseus=pw
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/pom.xml b/testsuite/integration-arquillian/pom.xml
index ed794f1..977fba8 100644
--- a/testsuite/integration-arquillian/pom.xml
+++ b/testsuite/integration-arquillian/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak</groupId>
         <artifactId>keycloak-testsuite-pom</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     
@@ -33,7 +33,7 @@
     <packaging>pom</packaging>
 
     <name>Keycloak Arquillian Integration TestSuite</name>
-    
+
     <properties>
 
         <containers.home>${project.build.directory}/containers</containers.home>
@@ -42,12 +42,15 @@
 
         <!--component versions-->
         <arquillian-core.version>1.1.11.Final</arquillian-core.version>
-        <selenium.version>2.52.0</selenium.version>
+        <selenium.version>2.53.0</selenium.version>
         <arquillian-drone.version>2.0.0.Beta1</arquillian-drone.version>
         <arquillian-graphene.version>2.1.0.Alpha3</arquillian-graphene.version>
         <arquillian-wildfly-container.version>2.0.0.Final</arquillian-wildfly-container.version>
         <version.shrinkwrap.resolvers>2.2.2</version.shrinkwrap.resolvers>
         <undertow-embedded.version>1.0.0.Alpha2</undertow-embedded.version>
+
+        <maven.compiler.target>1.8</maven.compiler.target>
+        <maven.compiler.source>1.8</maven.compiler.source>
     </properties>
 
     <dependencyManagement>
@@ -67,6 +70,11 @@
                 <scope>import</scope>
             </dependency>
             <dependency>
+                <groupId>org.jboss.shrinkwrap.resolver</groupId>
+                <artifactId>shrinkwrap-resolver-impl-maven</artifactId>
+                <scope>test</scope>
+            </dependency>
+            <dependency>
                 <groupId>org.jboss.arquillian.extension</groupId>
                 <artifactId>arquillian-drone-bom</artifactId>
                 <version>${arquillian-drone.version}</version>
diff --git a/testsuite/integration-arquillian/README.md b/testsuite/integration-arquillian/README.md
index 4a0cfa1..965dead 100644
--- a/testsuite/integration-arquillian/README.md
+++ b/testsuite/integration-arquillian/README.md
@@ -120,13 +120,6 @@ It automatically modifies imported test realms and deployments' adapter configs 
 | **Relative** | auth server == app server | client `baseUrl`, `adminUrl` and `redirect-uris` can be relative | `auth-server-url` can be relative |
 | **Non-relative** | auth server != app server  | client `baseUrl`, `adminUrl` and `redirect-uris` need to include FQDN of the app server | `auth-server-url` needs to include FQDN of the auth server|
 
-
-
-#### Adapter Libs Mode
-
-1. **Provided** - By container, e.g. as a subsystem. **Default.**
-2. **Bundled** - In the deployed war in `/WEB-INF/libs`. Enable with `-Dadapter.libs.bundled`. *Wildfly only*.
-
 #### Adapter Config Mode
 
 1. ~~**Provided** - In `standalone.xml` using `secure-deployment`. *Wildfly only.*~~ WIP
diff --git a/testsuite/integration-arquillian/servers/app-server/jboss/as7/pom.xml b/testsuite/integration-arquillian/servers/app-server/jboss/as7/pom.xml
index 71bf55a..5153f3c 100644
--- a/testsuite/integration-arquillian/servers/app-server/jboss/as7/pom.xml
+++ b/testsuite/integration-arquillian/servers/app-server/jboss/as7/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-app-server-jboss</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/app-server/jboss/common/security-eap6.xsl b/testsuite/integration-arquillian/servers/app-server/jboss/common/security-eap6.xsl
index b389cd1..a902fcb 100644
--- a/testsuite/integration-arquillian/servers/app-server/jboss/common/security-eap6.xsl
+++ b/testsuite/integration-arquillian/servers/app-server/jboss/common/security-eap6.xsl
@@ -17,7 +17,7 @@
 
 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                 xmlns:xalan="http://xml.apache.org/xalan"
-                xmlns:j="urn:jboss:domain:1.7"
+                xmlns:j="urn:jboss:domain:1.8"
                 xmlns:w="urn:jboss:domain:web:2.2"
                 version="2.0"
                 exclude-result-prefixes="xalan j ds k sec">
diff --git a/testsuite/integration-arquillian/servers/app-server/jboss/eap/pom.xml b/testsuite/integration-arquillian/servers/app-server/jboss/eap/pom.xml
index c3c02dd..13ff7f7 100644
--- a/testsuite/integration-arquillian/servers/app-server/jboss/eap/pom.xml
+++ b/testsuite/integration-arquillian/servers/app-server/jboss/eap/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-app-server-jboss</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/app-server/jboss/eap6/pom.xml b/testsuite/integration-arquillian/servers/app-server/jboss/eap6/pom.xml
index 3c3e52a..7dc2147 100644
--- a/testsuite/integration-arquillian/servers/app-server/jboss/eap6/pom.xml
+++ b/testsuite/integration-arquillian/servers/app-server/jboss/eap6/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-app-server-jboss</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/app-server/jboss/pom.xml b/testsuite/integration-arquillian/servers/app-server/jboss/pom.xml
index 702fb51..c4d8f6f 100644
--- a/testsuite/integration-arquillian/servers/app-server/jboss/pom.xml
+++ b/testsuite/integration-arquillian/servers/app-server/jboss/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-app-server</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -186,6 +186,24 @@
                     <plugin>
                         <groupId>org.codehaus.mojo</groupId>
                         <artifactId>exec-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>install-adapters</id>
+                                <phase>process-test-resources</phase>
+                                <goals>
+                                    <goal>exec</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                        <configuration>
+                            <executable>${common.resources}/install-adapters.${script.suffix}</executable>
+                            <workingDirectory>${app.server.jboss.home}/bin</workingDirectory>
+                            <environmentVariables>
+                                <JAVA_HOME>${app.server.java.home}</JAVA_HOME>
+                                <JBOSS_HOME>${app.server.jboss.home}</JBOSS_HOME>
+                                <SAML_SUPPORTED>${app.server.saml.adapter.supported}</SAML_SUPPORTED>
+                            </environmentVariables>
+                        </configuration>
                     </plugin>
 
                     <plugin>
@@ -268,45 +286,6 @@
         </profile>
         
         <profile>
-            <id>adapter-libs-provided</id>
-            <activation>    
-                <property>
-                    <name>!adapter.libs.bundled</name>
-                </property>
-            </activation>
-
-            <build>
-                <pluginManagement>
-                    <plugins>
-                        <plugin>
-                            <groupId>org.codehaus.mojo</groupId>
-                            <artifactId>exec-maven-plugin</artifactId>
-                            <executions>
-                                <execution>
-                                    <id>install-adapters</id>
-                                    <phase>process-test-resources</phase>
-                                    <goals>
-                                        <goal>exec</goal>
-                                    </goals>
-                                </execution>
-                            </executions>
-                            <configuration>
-                                <executable>${common.resources}/install-adapters.${script.suffix}</executable>
-                                <workingDirectory>${app.server.jboss.home}/bin</workingDirectory>
-                                <environmentVariables>
-                                    <JAVA_HOME>${app.server.java.home}</JAVA_HOME>
-                                    <JBOSS_HOME>${app.server.jboss.home}</JBOSS_HOME>
-                                    <SAML_SUPPORTED>${app.server.saml.adapter.supported}</SAML_SUPPORTED>
-                                </environmentVariables>
-                            </configuration>
-                        </plugin>
-                    </plugins>
-                </pluginManagement>
-            </build>
-        </profile>
-        
-                        
-        <profile>
             <id>ssl</id>
             <activation>
                 <property>
diff --git a/testsuite/integration-arquillian/servers/app-server/jboss/relative/eap/pom.xml b/testsuite/integration-arquillian/servers/app-server/jboss/relative/eap/pom.xml
index fc382ae..e4e7f97 100644
--- a/testsuite/integration-arquillian/servers/app-server/jboss/relative/eap/pom.xml
+++ b/testsuite/integration-arquillian/servers/app-server/jboss/relative/eap/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-app-server-jboss-relative</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/app-server/jboss/relative/pom.xml b/testsuite/integration-arquillian/servers/app-server/jboss/relative/pom.xml
index f6a54b7..6223139 100644
--- a/testsuite/integration-arquillian/servers/app-server/jboss/relative/pom.xml
+++ b/testsuite/integration-arquillian/servers/app-server/jboss/relative/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-app-server-jboss</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/app-server/jboss/relative/wildfly/pom.xml b/testsuite/integration-arquillian/servers/app-server/jboss/relative/wildfly/pom.xml
index 0bc97fe..fe2902d 100644
--- a/testsuite/integration-arquillian/servers/app-server/jboss/relative/wildfly/pom.xml
+++ b/testsuite/integration-arquillian/servers/app-server/jboss/relative/wildfly/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-app-server-jboss-relative</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/app-server/jboss/wildfly/pom.xml b/testsuite/integration-arquillian/servers/app-server/jboss/wildfly/pom.xml
index 0462a72..93395af 100644
--- a/testsuite/integration-arquillian/servers/app-server/jboss/wildfly/pom.xml
+++ b/testsuite/integration-arquillian/servers/app-server/jboss/wildfly/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-app-server-jboss</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/app-server/jboss/wildfly8/pom.xml b/testsuite/integration-arquillian/servers/app-server/jboss/wildfly8/pom.xml
index de19c9a..495236d 100644
--- a/testsuite/integration-arquillian/servers/app-server/jboss/wildfly8/pom.xml
+++ b/testsuite/integration-arquillian/servers/app-server/jboss/wildfly8/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-app-server-jboss</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/app-server/jboss/wildfly9/pom.xml b/testsuite/integration-arquillian/servers/app-server/jboss/wildfly9/pom.xml
index dd9e73f..25859a4 100644
--- a/testsuite/integration-arquillian/servers/app-server/jboss/wildfly9/pom.xml
+++ b/testsuite/integration-arquillian/servers/app-server/jboss/wildfly9/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-app-server-jboss</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/app-server/karaf/fuse61/pom.xml b/testsuite/integration-arquillian/servers/app-server/karaf/fuse61/pom.xml
index 93d666b..0bc3eaa 100644
--- a/testsuite/integration-arquillian/servers/app-server/karaf/fuse61/pom.xml
+++ b/testsuite/integration-arquillian/servers/app-server/karaf/fuse61/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-app-server-karaf</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/app-server/karaf/fuse62/pom.xml b/testsuite/integration-arquillian/servers/app-server/karaf/fuse62/pom.xml
index 6f607ce..f601c9f 100644
--- a/testsuite/integration-arquillian/servers/app-server/karaf/fuse62/pom.xml
+++ b/testsuite/integration-arquillian/servers/app-server/karaf/fuse62/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-app-server-karaf</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/pom.xml b/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/pom.xml
index 21d812f..b305dec 100644
--- a/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/pom.xml
+++ b/testsuite/integration-arquillian/servers/app-server/karaf/fuse63/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-app-server-karaf</artifactId>
-        <version>1.9.3.Final-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/app-server/karaf/karaf3/pom.xml b/testsuite/integration-arquillian/servers/app-server/karaf/karaf3/pom.xml
index 9b9a054..2c2039f 100644
--- a/testsuite/integration-arquillian/servers/app-server/karaf/karaf3/pom.xml
+++ b/testsuite/integration-arquillian/servers/app-server/karaf/karaf3/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-app-server-karaf</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/app-server/karaf/pom.xml b/testsuite/integration-arquillian/servers/app-server/karaf/pom.xml
index d573952..5baece5 100644
--- a/testsuite/integration-arquillian/servers/app-server/karaf/pom.xml
+++ b/testsuite/integration-arquillian/servers/app-server/karaf/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-app-server</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/app-server/pom.xml b/testsuite/integration-arquillian/servers/app-server/pom.xml
index 17d9a3d..70efbd0 100644
--- a/testsuite/integration-arquillian/servers/app-server/pom.xml
+++ b/testsuite/integration-arquillian/servers/app-server/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/app-server/README.md b/testsuite/integration-arquillian/servers/app-server/README.md
index 008e4f5..e6a3354 100644
--- a/testsuite/integration-arquillian/servers/app-server/README.md
+++ b/testsuite/integration-arquillian/servers/app-server/README.md
@@ -23,14 +23,9 @@ Submodules are enabled with profiles: `-Papp-server-MODULE`
  * __`wildfly` Relative Wildfly 10__ Based on [`auth-server/jboss/wildfly`](../auth-server/README.md). Activate with `-Pauth-server-wildfly`.
  * __`eap` Relative EAP 7__ Based on [`auth-server/jboss/eap`](../auth-server/README.md). Activate with `-Pauth-server-eap`.
 
-### Adapter Libs Location
-
-* __Provided__ (in container) - Default.
-* __Bundled__ (in war) `-Dadapter.libs.bundled=true`
-
 ### Adapter Configs Location
 
-* __Provided__ (in standalone.xml as secure-deployment) _Not implemented_
+* __Provided__ (in standalone.xml as secure-deployment) WIP
 * __Bundled__ (in war) - Default.
 
 ### SSL
diff --git a/testsuite/integration-arquillian/servers/app-server/tomcat/pom.xml b/testsuite/integration-arquillian/servers/app-server/tomcat/pom.xml
index 13ef0a8..d02a811 100644
--- a/testsuite/integration-arquillian/servers/app-server/tomcat/pom.xml
+++ b/testsuite/integration-arquillian/servers/app-server/tomcat/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-app-server</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/app-server/tomcat/tomcat7/pom.xml b/testsuite/integration-arquillian/servers/app-server/tomcat/tomcat7/pom.xml
index 24b1d71..66d235b 100644
--- a/testsuite/integration-arquillian/servers/app-server/tomcat/tomcat7/pom.xml
+++ b/testsuite/integration-arquillian/servers/app-server/tomcat/tomcat7/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-app-server-tomcat</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/app-server/tomcat/tomcat8/pom.xml b/testsuite/integration-arquillian/servers/app-server/tomcat/tomcat8/pom.xml
index 929c135..9766f3d 100644
--- a/testsuite/integration-arquillian/servers/app-server/tomcat/tomcat8/pom.xml
+++ b/testsuite/integration-arquillian/servers/app-server/tomcat/tomcat8/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-app-server-tomcat</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/app-server/tomcat/tomcat9/pom.xml b/testsuite/integration-arquillian/servers/app-server/tomcat/tomcat9/pom.xml
index 8b58b52..6041025 100644
--- a/testsuite/integration-arquillian/servers/app-server/tomcat/tomcat9/pom.xml
+++ b/testsuite/integration-arquillian/servers/app-server/tomcat/tomcat9/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-app-server-tomcat</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/install-patch.bat b/testsuite/integration-arquillian/servers/auth-server/jboss/common/install-patch.bat
new file mode 100644
index 0000000..d3a5cc4
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/install-patch.bat
@@ -0,0 +1,7 @@
+set NOPAUSE=true
+
+call %JBOSS_HOME%\bin\jboss-cli.bat --command="patch apply %PATCH_ZIP%"
+
+if %ERRORLEVEL% neq 0 set ERROR=%ERRORLEVEL%
+exit /b %ERROR%
+
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/install-patch.sh b/testsuite/integration-arquillian/servers/auth-server/jboss/common/install-patch.sh
new file mode 100755
index 0000000..4a44294
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/install-patch.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+echo "JBOSS_HOME=$JBOSS_HOME"
+
+if [ ! -d "$JBOSS_HOME/bin" ] ; then
+    >&2 echo "JBOSS_HOME/bin doesn't exist"
+    exit 1
+fi
+
+cd $JBOSS_HOME/bin
+
+RESULT=0
+./jboss-cli.sh --command="patch apply $PATCH_ZIP"
+if [ $? -ne 0 ]; then RESULT=1; fi
+   exit $RESULT
+fi
+
+exit 1
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/keycloak-add-user.json b/testsuite/integration-arquillian/servers/auth-server/jboss/common/keycloak-add-user.json
new file mode 100644
index 0000000..60c0f09
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/keycloak-add-user.json
@@ -0,0 +1,15 @@
+[ {
+  "realm" : "master",
+  "users" : [ {
+    "username" : "admin",
+    "enabled" : true,
+    "credentials" : [ {
+      "type" : "password",
+      "hashedSaltedValue" : "dqalJHLkWhUJZO/q6+z1fvXOohTcGCXcvoU8xCEyvTxGN4wmLx7DtyhKuefggh6Bkx1I2eBTEX4tiWggwyXMDw==",
+      "salt" : "3fBAt5GAGGxFrV9fznpZHQ==",
+      "hashIterations" : 100000,
+      "algorithm" : "pbkdf2"
+    } ],
+    "realmRoles" : [ "admin" ]
+  } ]
+} ]
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/common/mod_cluster.xsl b/testsuite/integration-arquillian/servers/auth-server/jboss/common/mod_cluster.xsl
index c5d983d..685211b 100644
--- a/testsuite/integration-arquillian/servers/auth-server/jboss/common/mod_cluster.xsl
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/common/mod_cluster.xsl
@@ -22,8 +22,26 @@
 
     <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" xalan:indent-amount="4" standalone="no"/>
     <xsl:strip-space elements="*"/>
-
-    <!--add socket binding-->
+    
+    <xsl:param name="load.metric" select="'simple'" />\
+    
+    <!-- mod-cluster-config -->
+    <xsl:template match="//*[local-name()='mod-cluster-config']">
+        <mod-cluster-config advertise-socket="modcluster" connector="ajp">
+            <xsl:choose>
+                <xsl:when test="$load.metric='simple'">
+                    <simple-load-provider factor="1"/>
+                </xsl:when>
+                <xsl:otherwise>
+                    <dynamic-load-provider>
+                        <load-metric type="{$load.metric}"/>
+                    </dynamic-load-provider>
+                </xsl:otherwise>
+            </xsl:choose>
+        </mod-cluster-config>
+    </xsl:template>
+    
+    <!--add socket-binding-->
     <xsl:template match="//*[local-name()='socket-binding-group' and @name='standard-sockets']/*[local-name()='socket-binding' and @name='modcluster']">
         <socket-binding name="modcluster" interface="private" port="0" multicast-address="${{jboss.default.multicast.address:230.0.0.4}}" multicast-port="23364"/>
     </xsl:template>
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/eap/pom.xml b/testsuite/integration-arquillian/servers/auth-server/jboss/eap/pom.xml
index 5c1c6e7..d5b663b 100644
--- a/testsuite/integration-arquillian/servers/auth-server/jboss/eap/pom.xml
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/eap/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-auth-server-jboss</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml b/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml
index 02f768d..4fab304 100644
--- a/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-auth-server</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -161,6 +161,20 @@
                                     </target>
                                 </configuration>
                             </execution>
+                            <execution>
+                                <id>inject-truststore-into-keycloak-server-json</id>
+                                <phase>process-resources</phase>
+                                <goals>
+                                    <goal>run</goal>
+                                </goals>
+                                <configuration>
+                                    <target>
+                                        <ant antfile="../build-truststore.xml" inheritRefs="true">
+                                            <target name="inject-truststore"/>
+                                        </ant>
+                                    </target>
+                                </configuration>
+                            </execution>
                         </executions>
                         <dependencies>
                             <dependency>
@@ -257,9 +271,32 @@
                                     <overwrite>true</overwrite>
                                 </configuration>
                             </execution>
+                            <execution>
+                                <id>copy-keystore</id>
+                                <phase>process-resources</phase>
+                                <goals>
+                                    <goal>copy-resources</goal>
+                                </goals>
+                                <configuration>
+                                    <outputDirectory>${auth.server.home}/standalone/configuration</outputDirectory>
+                                    <resources>
+                                        <resource>
+                                            <directory>${common.resources}/keystore</directory>
+                                            <includes>
+                                                <include>keycloak.jks</include>
+                                                <include>keycloak.truststore</include>
+                                            </includes>
+                                        </resource>
+                                    </resources>
+                                </configuration>
+                            </execution>
                         </executions>
                     </plugin>
                     <plugin>
+                        <groupId>org.codehaus.mojo</groupId>
+                        <artifactId>exec-maven-plugin</artifactId>
+                    </plugin>
+                    <plugin>
                         <artifactId>maven-assembly-plugin</artifactId>
                         <executions>
                             <execution>
@@ -406,60 +443,6 @@
                                 </execution>
                             </executions>
                         </plugin>
-                            <plugin>
-                                <groupId>org.apache.maven.plugins</groupId>
-                                <artifactId>maven-antrun-plugin</artifactId>
-                                <version>1.8</version>
-                                <executions>
-                                    <execution>
-                                        <id>inject-truststore-into-keycloak-server-json</id>
-                                        <phase>process-resources</phase>
-                                        <goals>
-                                            <goal>run</goal>
-                                        </goals>
-                                        <configuration>
-                                            <target>
-                                                <ant antfile="../build-truststore.xml" inheritRefs="true">
-                                                    <target name="inject-truststore"/>
-                                                </ant>
-                                            </target>
-                                        </configuration>
-                                    </execution>
-                                </executions>
-                                <dependencies>
-                                    <dependency>
-                                        <groupId>ant-contrib</groupId>
-                                        <artifactId>ant-contrib</artifactId>
-                                        <version>1.0b3</version>
-                                        <exclusions>
-                                            <exclusion>
-                                                <groupId>ant</groupId>
-                                                <artifactId>ant</artifactId>
-                                            </exclusion>
-                                        </exclusions>
-                                    </dependency>
-                                    <dependency>
-                                        <groupId>org.apache.ant</groupId>
-                                        <artifactId>ant-apache-bsf</artifactId>
-                                        <version>1.9.3</version>
-                                    </dependency>
-                                    <dependency>
-                                        <groupId>org.apache.bsf</groupId>
-                                        <artifactId>bsf-api</artifactId>
-                                        <version>3.1</version>
-                                    </dependency>
-                                    <dependency>
-                                        <groupId>rhino</groupId>
-                                        <artifactId>js</artifactId>
-                                        <version>1.7R2</version>
-                                    </dependency>
-                                    <dependency>
-                                        <groupId>org.keycloak</groupId>
-                                        <artifactId>keycloak-core</artifactId>
-                                        <version>${project.version}</version>
-                                    </dependency>
-                                </dependencies>
-                            </plugin>
                     </plugins>
                 </pluginManagement>
             </build>
@@ -608,13 +591,54 @@
                 </pluginManagement>
             </build>
         </profile>
-
+        <profile>
+            <id>auth-server-apply-patch</id>
+            <activation>
+                <property>
+                    <name>auth.server.patch.zip</name>
+                </property>
+            </activation>
+            <build>
+                <pluginManagement>
+                    <plugins>
+                        <plugin>
+                            <groupId>org.codehaus.mojo</groupId>
+                            <artifactId>exec-maven-plugin</artifactId>
+                            <executions>
+                                <execution>
+                                    <id>install-patch</id>
+                                    <phase>process-resources</phase>
+                                    <goals>
+                                        <goal>exec</goal>
+                                    </goals>
+                                </execution>
+                            </executions>
+                            <configuration>
+                                <executable>${common.resources}/install-patch.${script.suffix}</executable>
+                                <workingDirectory>${auth.server.home}/bin</workingDirectory>
+                                <environmentVariables>
+                                    <JAVA_HOME>${auth.server.java.home}</JAVA_HOME>
+                                    <JBOSS_HOME>${auth.server.home}</JBOSS_HOME>
+                                    <PATCH_ZIP>${auth.server.patch.zip}</PATCH_ZIP>
+                                </environmentVariables>
+                            </configuration>
+                        </plugin>
+                    </plugins>
+                </pluginManagement>
+            </build>
+        </profile>
         <profile>
             <id>auth-server-cluster</id>
             <properties>
                 <session.cache.owners>1</session.cache.owners>
                 <offline.session.cache.owners>1</offline.session.cache.owners>
                 <login.failure.cache.owners>1</login.failure.cache.owners>
+
+                <load.metric>simple</load.metric>
+                <!-- The default value 'simple' configures mod-cluster with simple-load-provider.
+                Any other value configures it with dynamic-load-provider using the particular `load.metric`.
+                Supported metrics: https://docs.jboss.org/mod_cluster/1.2.0/html/java.AS7config.html#LoadMetric -->
+
             </properties>
             <build>
                 <pluginManagement>
@@ -701,6 +725,12 @@
                                                 </includes>
                                                 <stylesheet>${common.resources}/mod_cluster.xsl</stylesheet>
                                                 <outputDir>${auth.server.home}/standalone/configuration</outputDir>
+                                                <parameters>
+                                                    <parameter>
+                                                        <name>load.metric</name>
+                                                        <value>${load.metric}</value>
+                                                    </parameter>
+                                                </parameters>
                                             </transformationSet>
                                         </transformationSets>
                                     </configuration>
@@ -713,6 +743,40 @@
         </profile>
 
         <profile>
+            <id>admin</id>
+            <build>
+                <pluginManagement>
+                    <plugins>
+                        <plugin>
+                            <artifactId>maven-resources-plugin</artifactId>
+                            <executions>
+                                <execution>
+                                    <id>copy-keycloak-add-user-json</id>
+                                    <phase>process-resources</phase>
+                                    <goals>
+                                        <goal>copy-resources</goal>
+                                    </goals>
+                                    <configuration>
+                                        <outputDirectory>${auth.server.home}/standalone/configuration</outputDirectory>
+                                        <resources>
+                                            <resource>
+                                                <directory>${common.resources}</directory>
+                                                <includes>
+                                                    <include>keycloak-add-user.json</include>
+                                                </includes>
+                                            </resource>
+                                        </resources>
+                                        <overwrite>true</overwrite>
+                                    </configuration>
+                                </execution>
+                            </executions>
+                        </plugin>
+                    </plugins>
+                </pluginManagement>
+            </build>
+        </profile>
+
+        <profile>
             <id>auth-server-wildfly</id>
             <properties>
                 <security.xsl>security-wildfly.xsl</security.xsl>
diff --git a/testsuite/integration-arquillian/servers/auth-server/jboss/wildfly/pom.xml b/testsuite/integration-arquillian/servers/auth-server/jboss/wildfly/pom.xml
index 700a519..6e9b224 100644
--- a/testsuite/integration-arquillian/servers/auth-server/jboss/wildfly/pom.xml
+++ b/testsuite/integration-arquillian/servers/auth-server/jboss/wildfly/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-auth-server-jboss</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/auth-server/pom.xml b/testsuite/integration-arquillian/servers/auth-server/pom.xml
index a10cee0..3ced124 100644
--- a/testsuite/integration-arquillian/servers/auth-server/pom.xml
+++ b/testsuite/integration-arquillian/servers/auth-server/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/pom.xml b/testsuite/integration-arquillian/servers/auth-server/services/pom.xml
index b875ec5..75abf9b 100644
--- a/testsuite/integration-arquillian/servers/auth-server/services/pom.xml
+++ b/testsuite/integration-arquillian/servers/auth-server/services/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-auth-server</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/pom.xml b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/pom.xml
index c7a3e5b..c47d8e6 100644
--- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/pom.xml
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-auth-server-services</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-testsuite-providers</artifactId>
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/authorization/TestPolicyProviderFactory.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/authorization/TestPolicyProviderFactory.java
new file mode 100644
index 0000000..9382f20
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/authorization/TestPolicyProviderFactory.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.authorization;
+
+import org.keycloak.Config;
+import org.keycloak.authorization.AuthorizationProvider;
+import org.keycloak.authorization.model.Policy;
+import org.keycloak.authorization.model.ResourceServer;
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+import org.keycloak.authorization.policy.provider.PolicyProvider;
+import org.keycloak.authorization.policy.provider.PolicyProviderAdminService;
+import org.keycloak.authorization.policy.provider.PolicyProviderFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+import static org.bouncycastle.asn1.x500.style.RFC4519Style.l;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class TestPolicyProviderFactory implements PolicyProviderFactory {
+
+    @Override
+    public String getName() {
+        return "Test";
+    }
+
+    @Override
+    public String getGroup() {
+        return "Test Suite";
+    }
+
+    @Override
+    public PolicyProvider create(Policy policy, AuthorizationProvider authorization) {
+        return new TestPolicyProvider(policy, authorization);
+    }
+
+    @Override
+    public PolicyProviderAdminService getAdminResource(ResourceServer resourceServer) {
+        return null;
+    }
+
+    @Override
+    public PolicyProvider create(KeycloakSession session) {
+        return null;
+    }
+
+    @Override
+    public void init(Config.Scope config) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "test";
+    }
+
+    private class TestPolicyProvider implements PolicyProvider {
+
+        private final Policy policy;
+        private final AuthorizationProvider authorization;
+
+        public TestPolicyProvider(Policy policy, AuthorizationProvider authorization) {
+            this.policy = policy;
+            this.authorization = authorization;
+        }
+
+        @Override
+        public void evaluate(Evaluation evaluation) {
+
+        }
+
+        @Override
+        public void close() {
+
+        }
+    }
+}
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/CompanyRepresentation.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/CompanyRepresentation.java
new file mode 100644
index 0000000..117b928
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/CompanyRepresentation.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.domainextension;
+
+
+import org.keycloak.testsuite.domainextension.jpa.Company;
+
+public class CompanyRepresentation {
+
+    private String id;
+    private String name;
+
+    public CompanyRepresentation() {
+    }
+
+    public CompanyRepresentation(Company company) {
+        id = company.getId();
+        name = company.getName();
+    }
+    
+    public String getId() {
+		return id;
+	}
+    
+    public String getName() {
+		return name;
+	}
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/jpa/Company.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/jpa/Company.java
new file mode 100644
index 0000000..d5f95ae
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/jpa/Company.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.domainextension.jpa;
+
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "EXAMPLE_COMPANY")
+@NamedQueries({ @NamedQuery(name = "findByRealm", query = "from Company where realmId = :realmId") })
+public class Company {
+
+    @Id
+    @Column(name = "ID")
+    private String id;
+
+    @Column(name = "NAME", nullable = false)
+    private String name;
+
+    @Column(name = "REALM_ID", nullable = false)
+    private String realmId;
+
+    public String getId() {
+		return id;
+	}
+    
+    public String getRealmId() {
+        return realmId;
+    }
+    
+    public String getName() {
+		return name;
+	}
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setRealmId(String realmId) {
+        this.realmId = realmId;
+    }
+}
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/jpa/ExampleJpaEntityProvider.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/jpa/ExampleJpaEntityProvider.java
new file mode 100644
index 0000000..2f87632
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/jpa/ExampleJpaEntityProvider.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.domainextension.jpa;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.keycloak.connections.jpa.entityprovider.JpaEntityProvider;
+
+/**
+ * @author <a href="mailto:erik.mulder@docdatapayments.com">Erik Mulder</a>
+ * 
+ * Example JpaEntityProvider.
+ */
+public class ExampleJpaEntityProvider implements JpaEntityProvider {
+
+    @Override
+    public List<Class<?>> getEntities() {
+        return Collections.<Class<?>>singletonList(Company.class);
+    }
+
+    @Override
+    public String getChangelogLocation() {
+    	return "META-INF/example-changelog.xml";
+    }
+    
+    @Override
+    public void close() {
+    }
+
+    @Override
+    public String getFactoryId() {
+        return ExampleJpaEntityProviderFactory.ID;
+    }
+}
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/jpa/ExampleJpaEntityProviderFactory.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/jpa/ExampleJpaEntityProviderFactory.java
new file mode 100644
index 0000000..83dc0a7
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/jpa/ExampleJpaEntityProviderFactory.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.domainextension.jpa;
+
+import org.keycloak.Config.Scope;
+import org.keycloak.connections.jpa.entityprovider.JpaEntityProvider;
+import org.keycloak.connections.jpa.entityprovider.JpaEntityProviderFactory;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+
+/**
+ * @author <a href="mailto:erik.mulder@docdatapayments.com">Erik Mulder</a>
+ * 
+ * Example JpaEntityProviderFactory.
+ */
+public class ExampleJpaEntityProviderFactory implements JpaEntityProviderFactory {
+
+	protected static final String ID = "example-entity-provider";
+	
+    @Override
+    public JpaEntityProvider create(KeycloakSession session) {
+        return new ExampleJpaEntityProvider();
+    }
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+    @Override
+    public void init(Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/rest/CompanyResource.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/rest/CompanyResource.java
new file mode 100644
index 0000000..197cbce
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/rest/CompanyResource.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.domainextension.rest;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.testsuite.domainextension.CompanyRepresentation;
+import org.keycloak.testsuite.domainextension.spi.ExampleService;
+
+public class CompanyResource {
+
+	private final KeycloakSession session;
+	
+	public CompanyResource(KeycloakSession session) {
+		this.session = session;
+	}
+
+    @GET
+    @Path("")
+    @NoCache
+    @Produces(MediaType.APPLICATION_JSON)
+    public List<CompanyRepresentation> getCompanies() {
+        return session.getProvider(ExampleService.class).listCompanies();
+    }
+
+    @DELETE
+    @Path("")
+    @NoCache
+    public void deleteAllCompanies() {
+        session.getProvider(ExampleService.class).deleteAllCompanies();
+    }
+
+    @POST
+    @Path("")
+    @NoCache
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response createCompany(CompanyRepresentation rep) {
+        session.getProvider(ExampleService.class).addCompany(rep);
+        return Response.created(session.getContext().getUri().getAbsolutePathBuilder().path(rep.getId()).build()).build();
+    }
+
+    @GET
+    @NoCache
+    @Path("{id}")
+    @Produces(MediaType.APPLICATION_JSON)
+    public CompanyRepresentation getCompany(@PathParam("id") final String id) {
+        return session.getProvider(ExampleService.class).findCompany(id);
+    }
+
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/rest/ExampleRealmResourceProvider.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/rest/ExampleRealmResourceProvider.java
new file mode 100644
index 0000000..ff9ad02
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/rest/ExampleRealmResourceProvider.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.domainextension.rest;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.services.resource.RealmResourceProvider;
+
+public class ExampleRealmResourceProvider implements RealmResourceProvider {
+
+    private KeycloakSession session;
+
+    public ExampleRealmResourceProvider(KeycloakSession session) {
+        this.session = session;
+    }
+
+    @Override
+    public Object getResource() {
+        return new ExampleRestResource(session);
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/rest/ExampleRealmResourceProviderFactory.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/rest/ExampleRealmResourceProviderFactory.java
new file mode 100644
index 0000000..ae016b6
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/rest/ExampleRealmResourceProviderFactory.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.domainextension.rest;
+
+import org.keycloak.Config.Scope;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.services.resource.RealmResourceProvider;
+import org.keycloak.services.resource.RealmResourceProviderFactory;
+
+public class ExampleRealmResourceProviderFactory implements RealmResourceProviderFactory {
+
+    public static final String ID = "example";
+
+    @Override
+    public String getId() {
+        return ID;
+    }
+
+    @Override
+    public RealmResourceProvider create(KeycloakSession session) {
+        return new ExampleRealmResourceProvider(session);
+    }
+
+    @Override
+    public void init(Scope config) {
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+    }
+
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/rest/ExampleRestResource.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/rest/ExampleRestResource.java
new file mode 100644
index 0000000..629acc8
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/rest/ExampleRestResource.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.domainextension.rest;
+
+import javax.ws.rs.ForbiddenException;
+import javax.ws.rs.NotAuthorizedException;
+import javax.ws.rs.Path;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.services.managers.AppAuthManager;
+import org.keycloak.services.managers.AuthenticationManager;
+
+public class ExampleRestResource {
+
+	private final KeycloakSession session;
+    private final AuthenticationManager.AuthResult auth;
+	
+	public ExampleRestResource(KeycloakSession session) {
+		this.session = session;
+        this.auth = new AppAuthManager().authenticateBearerToken(session, session.getContext().getRealm());
+	}
+	
+    @Path("companies")
+    public CompanyResource getCompanyResource() {
+        return new CompanyResource(session);
+    }
+
+    // Same like "companies" endpoint, but REST endpoint is authenticated with Bearer token and user must be in realm role "admin"
+    // Just for illustration purposes
+    @Path("companies-auth")
+    public CompanyResource getCompanyResourceAuthenticated() {
+        checkRealmAdmin();
+        return new CompanyResource(session);
+    }
+
+    private void checkRealmAdmin() {
+        if (auth == null) {
+            throw new NotAuthorizedException("Bearer");
+        } else if (auth.getToken().getRealmAccess() == null || !auth.getToken().getRealmAccess().isUserInRole("admin")) {
+            throw new ForbiddenException("Does not have realm admin role");
+        }
+    }
+
+}
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/spi/ExampleService.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/spi/ExampleService.java
new file mode 100644
index 0000000..dd47d96
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/spi/ExampleService.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.domainextension.spi;
+
+import java.util.List;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.testsuite.domainextension.CompanyRepresentation;
+
+public interface ExampleService extends Provider {
+
+    List<CompanyRepresentation> listCompanies();
+
+    CompanyRepresentation findCompany(String id);
+
+    CompanyRepresentation addCompany(CompanyRepresentation company);
+
+    void deleteAllCompanies();
+
+}
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/spi/ExampleServiceProviderFactory.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/spi/ExampleServiceProviderFactory.java
new file mode 100644
index 0000000..ee802b0
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/spi/ExampleServiceProviderFactory.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.domainextension.spi;
+
+import org.keycloak.provider.ProviderFactory;
+
+public interface ExampleServiceProviderFactory extends ProviderFactory<ExampleService> {
+
+}
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/spi/ExampleSpi.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/spi/ExampleSpi.java
new file mode 100644
index 0000000..d85f043
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/spi/ExampleSpi.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.domainextension.spi;
+
+import org.keycloak.provider.Provider;
+import org.keycloak.provider.ProviderFactory;
+import org.keycloak.provider.Spi;
+
+public class ExampleSpi implements Spi {
+
+    @Override
+    public boolean isInternal() {
+        return false;
+    }
+
+    @Override
+    public String getName() {
+        return "example";
+    }
+
+    @Override
+    public Class<? extends Provider> getProviderClass() {
+        return ExampleService.class;
+    }
+
+    @Override
+    @SuppressWarnings("rawtypes")
+    public Class<? extends ProviderFactory> getProviderFactoryClass() {
+        return ExampleServiceProviderFactory.class;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/spi/impl/ExampleServiceImpl.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/spi/impl/ExampleServiceImpl.java
new file mode 100644
index 0000000..213f7e5
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/spi/impl/ExampleServiceImpl.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.domainextension.spi.impl;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.persistence.EntityManager;
+
+import org.keycloak.connections.jpa.JpaConnectionProvider;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.testsuite.domainextension.CompanyRepresentation;
+import org.keycloak.testsuite.domainextension.jpa.Company;
+import org.keycloak.testsuite.domainextension.spi.ExampleService;
+
+public class ExampleServiceImpl implements ExampleService {
+
+    private final KeycloakSession session;
+
+    public ExampleServiceImpl(KeycloakSession session) {
+        this.session = session;
+        if (getRealm() == null) {
+            throw new IllegalStateException("The service cannot accept a session without a realm in it's context.");
+        }
+    }
+
+    private EntityManager getEntityManager() {
+        return session.getProvider(JpaConnectionProvider.class).getEntityManager();
+    }
+
+    protected RealmModel getRealm() {
+        return session.getContext().getRealm();
+    }
+    
+    @Override
+    public List<CompanyRepresentation> listCompanies() {
+    	List<Company> companyEntities = getEntityManager().createNamedQuery("findByRealm", Company.class)
+                .setParameter("realmId", getRealm().getId())
+                .getResultList();
+
+        List<CompanyRepresentation> result = new LinkedList<>();
+        for (Company entity : companyEntities) {
+            result.add(new CompanyRepresentation(entity));
+        }
+        return result;
+    }
+    
+    @Override
+    public CompanyRepresentation findCompany(String id) {
+    	Company entity = getEntityManager().find(Company.class, id);
+        return entity==null ? null : new CompanyRepresentation(entity);
+    }
+    
+    @Override
+    public CompanyRepresentation addCompany(CompanyRepresentation company) {
+        Company entity = new Company();
+        String id = company.getId()==null ?  KeycloakModelUtils.generateId() : company.getId();
+        entity.setId(id);
+        entity.setName(company.getName());
+        entity.setRealmId(getRealm().getId());
+        getEntityManager().persist(entity);
+
+        company.setId(id);
+        return company;
+    }
+
+    @Override
+    public void deleteAllCompanies() {
+        EntityManager em = getEntityManager();
+        List<Company> companyEntities = em.createNamedQuery("findByRealm", Company.class)
+                .setParameter("realmId", getRealm().getId())
+                .getResultList();
+
+        for (Company entity : companyEntities) {
+            em.remove(entity);
+        }
+    }
+
+    public void close() {
+        // Nothing to do.
+    }
+
+}
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/spi/impl/ExampleServiceProviderFactoryImpl.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/spi/impl/ExampleServiceProviderFactoryImpl.java
new file mode 100644
index 0000000..c772827
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/domainextension/spi/impl/ExampleServiceProviderFactoryImpl.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.domainextension.spi.impl;
+
+import org.keycloak.Config.Scope;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.testsuite.domainextension.spi.ExampleService;
+import org.keycloak.testsuite.domainextension.spi.ExampleServiceProviderFactory;
+
+public class ExampleServiceProviderFactoryImpl implements ExampleServiceProviderFactory {
+
+    @Override
+    public ExampleService create(KeycloakSession session) {
+        return new ExampleServiceImpl(session);
+    }
+
+    @Override
+    public void init(Scope config) {
+
+    }
+
+    @Override
+    public void postInit(KeycloakSessionFactory factory) {
+
+    }
+
+    @Override
+    public void close() {
+
+    }
+
+    @Override
+    public String getId() {
+        return "exampleServiceImpl";
+    }
+
+}
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/events/EventsListenerProvider.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/events/EventsListenerProvider.java
index 87606ca..b0ea56a 100644
--- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/events/EventsListenerProvider.java
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/events/EventsListenerProvider.java
@@ -69,6 +69,7 @@ public class EventsListenerProvider implements EventListenerProvider {
         newEvent.setAuthDetails(adminEvent.getAuthDetails());
         newEvent.setError(adminEvent.getError());
         newEvent.setOperationType(adminEvent.getOperationType());
+        newEvent.setResourceType(adminEvent.getResourceType());
         newEvent.setRealmId(adminEvent.getRealmId());
         newEvent.setRepresentation(adminEvent.getRepresentation());
         newEvent.setResourcePath(adminEvent.getResourcePath());
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/forms/PassThroughClientAuthenticator.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/forms/PassThroughClientAuthenticator.java
index 2f8824d..83ee504 100755
--- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/forms/PassThroughClientAuthenticator.java
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/forms/PassThroughClientAuthenticator.java
@@ -18,10 +18,12 @@
 package org.keycloak.testsuite.forms;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.keycloak.authentication.AuthenticationFlowError;
 import org.keycloak.authentication.ClientAuthenticationFlowContext;
@@ -119,4 +121,9 @@ public class PassThroughClientAuthenticator extends AbstractClientAuthenticator 
     public String getId() {
         return PROVIDER_ID;
     }
+
+    @Override
+    public Set<String> getProtocolAuthenticatorMethods(String loginProtocol) {
+        return Collections.emptySet();
+    }
 }
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestApplicationResourceProvider.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestApplicationResourceProvider.java
index f75d93c..bc63c99 100644
--- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestApplicationResourceProvider.java
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestApplicationResourceProvider.java
@@ -17,6 +17,8 @@
 
 package org.keycloak.testsuite.rest;
 
+import org.jboss.resteasy.spi.HttpRequest;
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.jose.jws.JWSInput;
 import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.models.KeycloakSession;
@@ -25,7 +27,6 @@ import org.keycloak.representations.adapters.action.PushNotBeforeAction;
 import org.keycloak.representations.adapters.action.TestAvailabilityAction;
 import org.keycloak.services.resource.RealmResourceProvider;
 import org.keycloak.services.resources.RealmsResource;
-import org.keycloak.testsuite.events.EventsListenerProvider;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
@@ -34,8 +35,10 @@ import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
+
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.TimeUnit;
 
@@ -110,6 +113,35 @@ public class TestApplicationResourceProvider implements RealmResourceProvider {
         return Response.noContent().build();
     }
 
+    @POST
+    @Produces(MediaType.TEXT_HTML)
+    @Path("/{action}")
+    public String post(@PathParam("action") String action) {
+        String title = "APP_REQUEST";
+        if (action.equals("auth")) {
+            title = "AUTH_RESPONSE";
+        } else if (action.equals("logout")) {
+            title = "LOGOUT_REQUEST";
+        }
+
+        StringBuilder sb = new StringBuilder();
+        sb.append("<html><head><title>" + title + "</title></head><body>");
+
+        sb.append("<b>Form parameters: </b><br>");
+        HttpRequest request = ResteasyProviderFactory.getContextData(HttpRequest.class);
+        MultivaluedMap<String, String> formParams = request.getDecodedFormParameters();
+        for (String paramName : formParams.keySet()) {
+            sb.append(paramName).append(": ").append("<span id=\"").append(paramName).append("\">").append(formParams.getFirst(paramName)).append("</span><br>");
+        }
+        sb.append("<br>");
+
+        UriBuilder base = UriBuilder.fromUri("http://localhost:8180/auth");
+        sb.append("<a href=\"" + RealmsResource.accountUrl(base).build("test").toString() + "\" id=\"account\">account</a>");
+
+        sb.append("</body></html>");
+        return sb.toString();
+    }
+
     @GET
     @Produces(MediaType.TEXT_HTML)
     @Path("/{action}")
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java
index 7fdd384..b658d35 100644
--- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java
@@ -17,11 +17,17 @@
 
 package org.keycloak.testsuite.rest;
 
+import java.io.File;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
 import org.infinispan.Cache;
 import org.keycloak.common.util.Time;
 import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
 import org.keycloak.events.Event;
 import org.keycloak.events.admin.AdminEvent;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserSessionModel;
@@ -47,7 +53,31 @@ import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.jboss.resteasy.spi.BadRequestException;
+import org.keycloak.events.EventQuery;
+import org.keycloak.events.EventStoreProvider;
+import org.keycloak.events.EventType;
+import org.keycloak.events.admin.AdminEventQuery;
+import org.keycloak.events.admin.AuthDetails;
+import org.keycloak.events.admin.OperationType;
+import org.keycloak.exportimport.ExportImportManager;
+import org.keycloak.models.AuthenticationFlowModel;
+import org.keycloak.models.ClientModel;
+import org.keycloak.models.FederatedIdentityModel;
+import org.keycloak.models.RealmProvider;
+import org.keycloak.models.UserCredentialModel;
+import org.keycloak.models.UserFederationProvider;
+import org.keycloak.models.UserFederationProviderFactory;
+import org.keycloak.models.UserModel;
+import org.keycloak.models.UserProvider;
+import org.keycloak.representations.idm.AuthDetailsRepresentation;
+import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+
+import static org.keycloak.exportimport.ExportImportConfig.*;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -192,6 +222,300 @@ public class TestingResourceProvider implements RealmResourceProvider {
     }
 
     @GET
+    @Path("/clear-event-store")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response clearEventStore() {
+        EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
+        eventStore.clear();
+        return Response.ok().build();
+    }
+
+    @GET
+    @Path("/clear-event-store-for-realm")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response clearEventStore(@QueryParam("realmId") String realmId) {
+        EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
+        eventStore.clear(realmId);
+        return Response.ok().build();
+    }
+
+    @GET
+    @Path("/clear-event-store-older-than")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response clearEventStore(@QueryParam("realmId") String realmId, @QueryParam("olderThan") long olderThan) {
+        EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
+        eventStore.clear(realmId, olderThan);
+        return Response.ok().build();
+    }
+
+    /**
+     * Query events
+     *
+     * Returns all events, or filters them based on URL query parameters listed here
+     *
+     * @param realmId The realm
+     * @param types The types of events to return
+     * @param client App or oauth client name
+     * @param user User id
+     * @param dateFrom From date
+     * @param dateTo To date
+     * @param ipAddress IP address
+     * @param firstResult Paging offset
+     * @param maxResults Paging size
+     * @return
+     */
+    @Path("query-events")
+    @GET
+    @NoCache
+    @Produces(MediaType.APPLICATION_JSON)
+    public List<EventRepresentation> queryEvents(@QueryParam("realmId") String realmId, @QueryParam("type") List<String> types, @QueryParam("client") String client,
+            @QueryParam("user") String user, @QueryParam("dateFrom") String dateFrom, @QueryParam("dateTo") String dateTo,
+            @QueryParam("ipAddress") String ipAddress, @QueryParam("first") Integer firstResult,
+            @QueryParam("max") Integer maxResults) {
+
+        EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
+
+        EventQuery query = eventStore.createQuery();
+
+        if (realmId != null) {
+            query.realm(realmId);
+        }
+
+        if (client != null) {
+            query.client(client);
+        }
+
+        if (types != null & !types.isEmpty()) {
+            EventType[] t = new EventType[types.size()];
+            for (int i = 0; i < t.length; i++) {
+                t[i] = EventType.valueOf(types.get(i));
+            }
+            query.type(t);
+        }
+
+        if (user != null) {
+            query.user(user);
+        }
+
+        if(dateFrom != null) {
+            Date from = formatDate(dateFrom, "Date(From)");
+            query.fromDate(from);
+        }
+
+        if(dateTo != null) {
+            Date to = formatDate(dateTo, "Date(To)");
+            query.toDate(to);
+        }
+
+        if (ipAddress != null) {
+            query.ipAddress(ipAddress);
+        }
+        if (firstResult != null) {
+            query.firstResult(firstResult);
+        }
+        if (maxResults != null) {
+            query.maxResults(maxResults);
+        }
+
+        return toEventListRep(query.getResultList());
+    }
+
+    private List<EventRepresentation> toEventListRep(List<Event> events) {
+        List<EventRepresentation> reps = new ArrayList<>();
+        for (Event event : events) {
+            reps.add(ModelToRepresentation.toRepresentation(event));
+        }
+        return reps;
+    }
+
+    @PUT
+    @Path("/on-event")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void onEvent(final EventRepresentation rep) {
+        EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
+
+        eventStore.onEvent(repToModel(rep));
+    }
+
+    private Event repToModel(EventRepresentation rep) {
+        Event event = new Event();
+        event.setClientId(rep.getClientId());
+        event.setDetails(rep.getDetails());
+        event.setError(rep.getError());
+        event.setIpAddress(rep.getIpAddress());
+        event.setRealmId(rep.getRealmId());
+        event.setSessionId(rep.getSessionId());
+        event.setTime(rep.getTime());
+        event.setType(EventType.valueOf(rep.getType()));
+        event.setUserId(rep.getUserId());
+        return event;
+    }
+
+    @GET
+    @Path("/clear-admin-event-store")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response clearAdminEventStore() {
+        EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
+        eventStore.clearAdmin();
+        return Response.ok().build();
+    }
+
+    @GET
+    @Path("/clear-admin-event-store-for-realm")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response clearAdminEventStore(@QueryParam("realmId") String realmId) {
+        EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
+        eventStore.clearAdmin(realmId);
+        return Response.ok().build();
+    }
+
+    @GET
+    @Path("/clear-admin-event-store-older-than")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response clearAdminEventStore(@QueryParam("realmId") String realmId, @QueryParam("olderThan") long olderThan) {
+        EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
+        eventStore.clearAdmin(realmId, olderThan);
+        return Response.ok().build();
+    }
+
+    /**
+     * Get admin events
+     *
+     * Returns all admin events, or filters events based on URL query parameters listed here
+     *
+     * @param realmId
+     * @param operationTypes
+     * @param authRealm
+     * @param authClient
+     * @param authUser user id
+     * @param authIpAddress
+     * @param resourcePath
+     * @param dateFrom
+     * @param dateTo
+     * @param firstResult
+     * @param maxResults
+     * @return
+     */
+    @Path("query-admin-events")
+    @GET
+    @NoCache
+    @Produces(MediaType.APPLICATION_JSON)
+    public List<AdminEventRepresentation> getAdminEvents(@QueryParam("realmId") String realmId, @QueryParam("operationTypes") List<String> operationTypes, @QueryParam("authRealm") String authRealm, @QueryParam("authClient") String authClient,
+            @QueryParam("authUser") String authUser, @QueryParam("authIpAddress") String authIpAddress,
+            @QueryParam("resourcePath") String resourcePath, @QueryParam("dateFrom") String dateFrom,
+            @QueryParam("dateTo") String dateTo, @QueryParam("first") Integer firstResult,
+            @QueryParam("max") Integer maxResults) {
+
+        EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
+        AdminEventQuery query = eventStore.createAdminQuery();
+
+        if (realmId != null) {
+            query.realm(realmId);
+        };
+
+        if (authRealm != null) {
+            query.authRealm(authRealm);
+        }
+
+        if (authClient != null) {
+            query.authClient(authClient);
+        }
+
+        if (authUser != null) {
+            query.authUser(authUser);
+        }
+
+        if (authIpAddress != null) {
+            query.authIpAddress(authIpAddress);
+        }
+
+        if (resourcePath != null) {
+            query.resourcePath(resourcePath);
+        }
+
+        if (operationTypes != null && !operationTypes.isEmpty()) {
+            OperationType[] t = new OperationType[operationTypes.size()];
+            for (int i = 0; i < t.length; i++) {
+                t[i] = OperationType.valueOf(operationTypes.get(i));
+            }
+            query.operation(t);
+        }
+
+        if(dateFrom != null) {
+            Date from = formatDate(dateFrom, "Date(From)");
+            query.fromTime(from);
+        }
+
+        if(dateTo != null) {
+            Date to = formatDate(dateTo, "Date(To)");
+            query.toTime(to);
+        }
+
+        if (firstResult != null || maxResults != null) {
+            if (firstResult == null) {
+                firstResult = 0;
+            }
+            if (maxResults == null) {
+                maxResults = 100;
+            }
+            query.firstResult(firstResult);
+            query.maxResults(maxResults);
+        }
+
+        return toAdminEventRep(query.getResultList());
+    }
+
+    private Date formatDate(String date, String paramName) {
+        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
+        try {
+            return df.parse(date);
+        } catch (ParseException e) {
+            throw new BadRequestException("Invalid value for '" + paramName + "', expected format is yyyy-MM-dd");
+        }
+    }
+
+    private List<AdminEventRepresentation> toAdminEventRep(List<AdminEvent> events) {
+        List<AdminEventRepresentation> reps = new ArrayList<>();
+        for (AdminEvent event : events) {
+            reps.add(ModelToRepresentation.toRepresentation(event));
+        }
+
+        return reps;
+    }
+
+    @POST
+    @Path("/on-admin-event")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void onAdminEvent(final AdminEventRepresentation rep, @QueryParam("includeRepresentation") boolean includeRepresentation) {
+        EventStoreProvider eventStore = session.getProvider(EventStoreProvider.class);
+        eventStore.onEvent(repToModel(rep), includeRepresentation);
+    }
+
+    private AdminEvent repToModel(AdminEventRepresentation rep) {
+        AdminEvent event = new AdminEvent();
+        event.setAuthDetails(repToModel(rep.getAuthDetails()));
+        event.setError(rep.getError());
+        event.setOperationType(OperationType.valueOf(rep.getOperationType()));
+        if (rep.getResourceType() != null) {
+            event.setResourceType(ResourceType.valueOf(rep.getResourceType()));
+        }
+        event.setRealmId(rep.getRealmId());
+        event.setRepresentation(rep.getRepresentation());
+        event.setResourcePath(rep.getResourcePath());
+        event.setTime(rep.getTime());
+        return event;
+    }
+
+    private AuthDetails repToModel(AuthDetailsRepresentation rep) {
+        AuthDetails details = new AuthDetails();
+        details.setClientId(rep.getClientId());
+        details.setIpAddress(rep.getIpAddress());
+        details.setRealmId(rep.getRealmId());
+        details.setUserId(rep.getUserId());
+        return details;
+    }
+
+    @GET
     @Path("/cache/{cache}/{id}")
     @Produces(MediaType.APPLICATION_JSON)
     public boolean isCached(@PathParam("cache") String cacheName, @PathParam("id") String id) {
@@ -239,4 +563,167 @@ public class TestingResourceProvider implements RealmResourceProvider {
         result.setUsername(PassThroughAuthenticator.username);
         return result;
     }
+
+    @GET
+    @Path("/run-import")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response runImport() {
+        new ExportImportManager(session).runImport();
+        return Response.ok().build();
+    }
+
+    @GET
+    @Path("/run-export")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response runExport() {
+        new ExportImportManager(session).runExport();
+        return Response.ok().build();
+    }
+
+    @GET
+    @Path("/valid-credentials")
+    @Produces(MediaType.APPLICATION_JSON)
+    public boolean validCredentials(@QueryParam("realmName") String realmName, @QueryParam("userName") String userName, @QueryParam("password") String password) {
+        RealmModel realm = session.realms().getRealm(realmName);
+        if (realm == null) return false;
+        UserProvider userProvider = session.getProvider(UserProvider.class);
+        UserModel user = userProvider.getUserByUsername(userName, realm);
+        return userProvider.validCredentials(session, realm, user, UserCredentialModel.password(password));
+    }
+
+    @GET
+    @Path("/user-by-federated-identity")
+    @Produces(MediaType.APPLICATION_JSON)
+    public UserRepresentation getUserByFederatedIdentity(@QueryParam("realmName") String realmName,
+                                                         @QueryParam("identityProvider") String identityProvider,
+                                                         @QueryParam("userId") String userId,
+                                                         @QueryParam("userName") String userName) {
+        RealmModel realm = getRealmByName(realmName);
+        UserModel foundFederatedUser = session.users().getUserByFederatedIdentity(new FederatedIdentityModel(identityProvider, userId, userName), realm);
+        if (foundFederatedUser == null) return null;
+        return ModelToRepresentation.toRepresentation(foundFederatedUser);
+    }
+
+    @GET
+    @Path("/user-by-username-from-fed-factory")
+    @Produces(MediaType.APPLICATION_JSON)
+    public UserRepresentation getUserByUsernameFromFedProviderFactory(@QueryParam("realmName") String realmName,
+                                                                      @QueryParam("userName") String userName) {
+        RealmModel realm = getRealmByName(realmName);
+        UserFederationProviderFactory factory = (UserFederationProviderFactory)session.getKeycloakSessionFactory().getProviderFactory(UserFederationProvider.class, "dummy");
+        UserModel user = factory.getInstance(session, null).getUserByUsername(realm, userName);
+        if (user == null) return null;
+        return ModelToRepresentation.toRepresentation(user);
+    }
+
+    @GET
+    @Path("/get-client-auth-flow")
+    @Produces(MediaType.APPLICATION_JSON)
+    public AuthenticationFlowRepresentation getClientAuthFlow(@QueryParam("realmName") String realmName) {
+        RealmModel realm = getRealmByName(realmName);
+        AuthenticationFlowModel flow = realm.getClientAuthenticationFlow();
+        if (flow == null) return null;
+        return ModelToRepresentation.toRepresentation(realm, flow);
+    }
+
+    @GET
+    @Path("/get-reset-cred-flow")
+    @Produces(MediaType.APPLICATION_JSON)
+    public AuthenticationFlowRepresentation getResetCredFlow(@QueryParam("realmName") String realmName) {
+        RealmModel realm = getRealmByName(realmName);
+        AuthenticationFlowModel flow = realm.getResetCredentialsFlow();
+        if (flow == null) return null;
+        return ModelToRepresentation.toRepresentation(realm, flow);
+    }
+
+    @GET
+    @Path("/get-user-by-service-account-client")
+    @Produces(MediaType.APPLICATION_JSON)
+    public UserRepresentation getUserByServiceAccountClient(@QueryParam("realmName") String realmName, @QueryParam("clientId") String clientId) {
+        RealmModel realm = getRealmByName(realmName);
+        ClientModel client =  realm.getClientByClientId(clientId);
+        UserModel user = session.users().getServiceAccount(client);
+        if (user == null) return null;
+        return ModelToRepresentation.toRepresentation(user);
+    }
+
+    private RealmModel getRealmByName(String realmName) {
+        RealmProvider realmProvider = session.getProvider(RealmProvider.class);
+        return realmProvider.getRealmByName(realmName);
+    }
+
+    @GET
+    @Path("/get-users-per-file")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Integer getUsersPerFile() {
+        String usersPerFile = System.getProperty(USERS_PER_FILE, String.valueOf(DEFAULT_USERS_PER_FILE));
+        return Integer.parseInt(usersPerFile.trim());
+    }
+
+    @PUT
+    @Path("/set-users-per-file")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void setUsersPerFile(@QueryParam("usersPerFile") Integer usersPerFile) {
+        System.setProperty(USERS_PER_FILE, String.valueOf(usersPerFile));
+    }
+
+    @GET
+    @Path("/get-dir")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public String getDir() {
+        return System.getProperty(DIR);
+    }
+
+    @PUT
+    @Path("/set-dir")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public String setDir(@QueryParam("dir") String dir) {
+        return System.setProperty(DIR, dir);
+    }
+
+    @PUT
+    @Path("/export-import-provider")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void setProvider(@QueryParam("exportImportProvider") String exportImportProvider) {
+        System.setProperty(PROVIDER, exportImportProvider);
+    }
+
+    @PUT
+    @Path("/export-import-file")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void setFile(@QueryParam("file") String file) {
+        System.setProperty(FILE, file);
+    }
+
+    @PUT
+    @Path("/export-import-action")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void setAction(@QueryParam("exportImportAction") String exportImportAction) {
+        System.setProperty(ACTION, exportImportAction);
+    }
+
+    @PUT
+    @Path("/set-realm-name")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void setRealmName(@QueryParam("realmName") String realmName) {
+        if (realmName != null && !realmName.isEmpty()) {
+            System.setProperty(REALM_NAME, realmName);
+        } else {
+            System.getProperties().remove(REALM_NAME);
+        }
+    }
+
+    @GET
+    @Path("/get-test-dir")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public String getExportImportTestDirectory() {
+        System.setProperty("project.build.directory", "target");
+        String absolutePath = new File(System.getProperty("project.build.directory", "target")).getAbsolutePath();
+        return absolutePath;
+    }
+
 }
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/example-changelog.xml b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/example-changelog.xml
new file mode 100644
index 0000000..5edd719
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/example-changelog.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
+    <changeSet author="erik.mulder@docdatapayments.com" id="example-1.0">
+
+        <createTable tableName="EXAMPLE_COMPANY">
+            <column name="ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="NAME" type="VARCHAR(255)">
+                <constraints nullable="false"/>
+            </column>
+            <column name="REALM_ID" type="VARCHAR(36)">
+                <constraints nullable="false"/>
+            </column>
+        </createTable>
+
+        <addPrimaryKey
+            constraintName="PK_COMPANY"
+            tableName="EXAMPLE_COMPANY"
+            columnNames="ID"
+        />
+
+    </changeSet>
+    
+</databaseChangeLog>
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/services/org.keycloak.authorization.policy.provider.PolicyProviderFactory b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/services/org.keycloak.authorization.policy.provider.PolicyProviderFactory
new file mode 100644
index 0000000..ae41cc1
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/services/org.keycloak.authorization.policy.provider.PolicyProviderFactory
@@ -0,0 +1,18 @@
+#
+#  Copyright 2016 Red Hat, Inc. and/or its affiliates
+#  and other contributors as indicated by the @author tags.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#
+org.keycloak.testsuite.authorization.TestPolicyProviderFactory
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/services/org.keycloak.connections.jpa.entityprovider.JpaEntityProviderFactory b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/services/org.keycloak.connections.jpa.entityprovider.JpaEntityProviderFactory
new file mode 100644
index 0000000..67464bd
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/services/org.keycloak.connections.jpa.entityprovider.JpaEntityProviderFactory
@@ -0,0 +1,18 @@
+#
+# Copyright 2016 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.keycloak.testsuite.domainextension.jpa.ExampleJpaEntityProviderFactory
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/services/org.keycloak.provider.Spi b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/services/org.keycloak.provider.Spi
new file mode 100644
index 0000000..1c31c00
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/services/org.keycloak.provider.Spi
@@ -0,0 +1,18 @@
+#
+# Copyright 2016 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.keycloak.testsuite.domainextension.spi.ExampleSpi
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory
index 8823682..1958ff0 100644
--- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory
@@ -16,4 +16,5 @@
 #
 
 org.keycloak.testsuite.rest.TestingResourceProviderFactory
-org.keycloak.testsuite.rest.TestApplicationResourceProviderFactory
\ No newline at end of file
+org.keycloak.testsuite.rest.TestApplicationResourceProviderFactory
+org.keycloak.testsuite.domainextension.rest.ExampleRealmResourceProviderFactory
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/services/org.keycloak.testsuite.domainextension.spi.ExampleServiceProviderFactory b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/services/org.keycloak.testsuite.domainextension.spi.ExampleServiceProviderFactory
new file mode 100644
index 0000000..d58236f
--- /dev/null
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/META-INF/services/org.keycloak.testsuite.domainextension.spi.ExampleServiceProviderFactory
@@ -0,0 +1,18 @@
+#
+# Copyright 2016 Red Hat, Inc. and/or its affiliates
+# and other contributors as indicated by the @author tags.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+org.keycloak.testsuite.domainextension.spi.impl.ExampleServiceProviderFactoryImpl
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/org/keycloak/testsuite/integration-arquillian-testsuite-providers/main/module.xml b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/org/keycloak/testsuite/integration-arquillian-testsuite-providers/main/module.xml
index 92b57f2..28e4789 100644
--- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/org/keycloak/testsuite/integration-arquillian-testsuite-providers/main/module.xml
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/resources/org/keycloak/testsuite/integration-arquillian-testsuite-providers/main/module.xml
@@ -30,7 +30,12 @@
         <module name="org.keycloak.keycloak-server-spi"/>
         <module name="org.keycloak.keycloak-services"/>
         <module name="org.keycloak.keycloak-model-infinispan"/>
+        <module name="org.keycloak.keycloak-model-jpa"/>
         <module name="org.infinispan"/>
         <module name="org.jboss.logging"/>
+        <module name="org.jboss.resteasy.resteasy-jaxrs"/>
+        <module name="javax.persistence.api"/>
+        <module name="org.hibernate"/>
+        <module name="org.javassist"/>
     </dependencies>
-</module>
\ No newline at end of file
+</module>
diff --git a/testsuite/integration-arquillian/servers/auth-server/undertow/pom.xml b/testsuite/integration-arquillian/servers/auth-server/undertow/pom.xml
index f0579f2..772f60e 100644
--- a/testsuite/integration-arquillian/servers/auth-server/undertow/pom.xml
+++ b/testsuite/integration-arquillian/servers/auth-server/undertow/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers-auth-server</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/migration/pom.xml b/testsuite/integration-arquillian/servers/migration/pom.xml
index 36d53a7..6f6301a 100644
--- a/testsuite/integration-arquillian/servers/migration/pom.xml
+++ b/testsuite/integration-arquillian/servers/migration/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/migration/wildfly_kc12/pom.xml b/testsuite/integration-arquillian/servers/migration/wildfly_kc12/pom.xml
index 507cd65..00407ca 100644
--- a/testsuite/integration-arquillian/servers/migration/wildfly_kc12/pom.xml
+++ b/testsuite/integration-arquillian/servers/migration/wildfly_kc12/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-migration-servers</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/migration/wildfly_kc13/pom.xml b/testsuite/integration-arquillian/servers/migration/wildfly_kc13/pom.xml
index 210225c..8512451 100644
--- a/testsuite/integration-arquillian/servers/migration/wildfly_kc13/pom.xml
+++ b/testsuite/integration-arquillian/servers/migration/wildfly_kc13/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-migration-servers</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/migration/wildfly_kc14/pom.xml b/testsuite/integration-arquillian/servers/migration/wildfly_kc14/pom.xml
index 91a6520..baa4b88 100644
--- a/testsuite/integration-arquillian/servers/migration/wildfly_kc14/pom.xml
+++ b/testsuite/integration-arquillian/servers/migration/wildfly_kc14/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-migration-servers</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/migration/wildfly_kc15/pom.xml b/testsuite/integration-arquillian/servers/migration/wildfly_kc15/pom.xml
index 85f9063..5928cd4 100644
--- a/testsuite/integration-arquillian/servers/migration/wildfly_kc15/pom.xml
+++ b/testsuite/integration-arquillian/servers/migration/wildfly_kc15/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-migration-servers</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/migration/wildfly_kc16/pom.xml b/testsuite/integration-arquillian/servers/migration/wildfly_kc16/pom.xml
index 2ca3311..a919f05 100644
--- a/testsuite/integration-arquillian/servers/migration/wildfly_kc16/pom.xml
+++ b/testsuite/integration-arquillian/servers/migration/wildfly_kc16/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-migration-servers</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/pom.xml b/testsuite/integration-arquillian/servers/pom.xml
index 8541b74..e04f4a3 100644
--- a/testsuite/integration-arquillian/servers/pom.xml
+++ b/testsuite/integration-arquillian/servers/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/servers/wildfly-balancer/pom.xml b/testsuite/integration-arquillian/servers/wildfly-balancer/pom.xml
index a84f20c..1d31c0a 100644
--- a/testsuite/integration-arquillian/servers/wildfly-balancer/pom.xml
+++ b/testsuite/integration-arquillian/servers/wildfly-balancer/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-servers</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/test-apps/hello-world-authz-service/hello-world-authz-realm.json b/testsuite/integration-arquillian/test-apps/hello-world-authz-service/hello-world-authz-realm.json
new file mode 100644
index 0000000..022ee6f
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/hello-world-authz-service/hello-world-authz-realm.json
@@ -0,0 +1,48 @@
+{
+  "realm" : "hello-world-authz",
+  "enabled" : true,
+  "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+  "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "requiredCredentials" : [ "password" ],
+  "users" :
+  [
+    {
+      "username" : "alice",
+      "enabled" : true,
+      "credentials" : [ {
+        "type" : "password",
+        "value" : "alice"
+      } ],
+      "realmRoles" : ["uma_authorization"]
+    },
+    {
+      "username" : "jdoe",
+      "enabled" : true,
+      "credentials" : [ {
+        "type" : "password",
+        "value" : "jdoe"
+      } ],
+      "realmRoles" : ["uma_authorization"]
+    },
+    {
+      "username" : "service-account-hello-world-authz-service",
+      "enabled" : true,
+      "serviceAccountClientId" : "hello-world-authz-service",
+      "clientRoles": {
+        "hello-world-authz-service" : ["uma_protection"]
+      }
+    }
+  ],
+  "clients" : [
+    {
+      "clientId" : "hello-world-authz-service",
+      "secret" : "secret",
+      "authorizationServicesEnabled" : true,
+      "enabled" : true,
+      "redirectUris" : [ "http://localhost:8080/hello-world-authz-service/*" ],
+      "baseUrl": "http://localhost:8080/hello-world-authz-service",
+      "adminUrl": "http://localhost:8080/hello-world-authz-service",
+      "directAccessGrantsEnabled" : true
+    }
+  ]
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/hello-world-authz-service/hello-world-authz-service.json b/testsuite/integration-arquillian/test-apps/hello-world-authz-service/hello-world-authz-service.json
new file mode 100644
index 0000000..ea56e62
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/hello-world-authz-service/hello-world-authz-service.json
@@ -0,0 +1,30 @@
+{
+  "resources": [
+    {
+      "name": "Default Resource",
+      "uri": "/*",
+      "type": "urn:hello-world-authz-service:resources:default"
+    }
+  ],
+  "policies": [
+    {
+      "name": "Only From Realm Policy",
+      "description": "A policy that grants access only for users within this realm",
+      "type": "js",
+      "config": {
+        "applyPolicies": "[]",
+        "code": "var context = $evaluation.getContext();\n\n// using attributes from the evaluation context to obtain the realm\nvar contextAttributes = context.getAttributes();\nvar realmName = contextAttributes.getValue('kc.realm.name').asString(0);\n\n// using attributes from the identity to obtain the issuer\nvar identity = context.getIdentity();\nvar identityAttributes = identity.getAttributes();\nvar issuer = identityAttributes.getValue('iss').asString(0);\n\n// only users from the realm have access granted \nif (issuer.endsWith(realmName)) {\n    $evaluation.grant();\n}"
+      }
+    },
+    {
+      "name": "Default Permission",
+      "description": "A permission that applies to the default resource type",
+      "type": "resource",
+      "config": {
+        "defaultResourceType": "urn:hello-world-authz-service:resources:default",
+        "default": "true",
+        "applyPolicies": "[\"Only From Realm Policy\"]"
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/hello-world-authz-service/pom.xml b/testsuite/integration-arquillian/test-apps/hello-world-authz-service/pom.xml
new file mode 100755
index 0000000..59cce47
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/hello-world-authz-service/pom.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~  Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~  and other contributors as indicated by the @author tags.
+  ~
+  ~  Licensed under the Apache License, Version 2.0 (the "License");
+  ~  you may not use this file except in compliance with the License.
+  ~  You may obtain a copy of the License at
+  ~
+  ~  http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing, software
+  ~  distributed under the License is distributed on an "AS IS" BASIS,
+  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  See the License for the specific language governing permissions and
+  ~  limitations under the License.
+  ~
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian-test-apps</artifactId>
+        <version>2.2.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>hello-world-authz-service</artifactId>
+    <packaging>war</packaging>
+
+    <name>Keycloak Authz Tests: Hello World Example</name>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.jboss.as.plugins</groupId>
+                <artifactId>jboss-as-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.wildfly.plugins</groupId>
+                <artifactId>wildfly-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/testsuite/integration-arquillian/test-apps/hello-world-authz-service/src/main/webapp/error.jsp b/testsuite/integration-arquillian/test-apps/hello-world-authz-service/src/main/webapp/error.jsp
new file mode 100644
index 0000000..00d25b3
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/hello-world-authz-service/src/main/webapp/error.jsp
@@ -0,0 +1,30 @@
+<%--
+  ~  Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~  and other contributors as indicated by the @author tags.
+  ~
+  ~  Licensed under the Apache License, Version 2.0 (the "License");
+  ~  you may not use this file except in compliance with the License.
+  ~  You may obtain a copy of the License at
+  ~
+  ~  http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing, software
+  ~  distributed under the License is distributed on an "AS IS" BASIS,
+  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  See the License for the specific language governing permissions and
+  ~  limitations under the License.
+  ~
+  --%>
+
+<%@ page import="org.keycloak.common.util.KeycloakUriBuilder" %>
+<%@ page import="org.keycloak.constants.ServiceUrlConstants" %>
+
+<html>
+<body>
+<h2><a href="<%= KeycloakUriBuilder.fromUri("/auth").path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH)
+            .queryParam("redirect_uri", "http://localhost:8080/hello-world-authz-service").build("hello-world-authz").toString()%>">Logout</a></h2>
+
+<h3>Access Denied !</h3>
+</body>
+</html>
+
diff --git a/testsuite/integration-arquillian/test-apps/hello-world-authz-service/src/main/webapp/index.jsp b/testsuite/integration-arquillian/test-apps/hello-world-authz-service/src/main/webapp/index.jsp
new file mode 100644
index 0000000..75f3d6f
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/hello-world-authz-service/src/main/webapp/index.jsp
@@ -0,0 +1,49 @@
+<%--
+  ~  Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~  and other contributors as indicated by the @author tags.
+  ~
+  ~  Licensed under the Apache License, Version 2.0 (the "License");
+  ~  you may not use this file except in compliance with the License.
+  ~  You may obtain a copy of the License at
+  ~
+  ~  http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing, software
+  ~  distributed under the License is distributed on an "AS IS" BASIS,
+  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  See the License for the specific language governing permissions and
+  ~  limitations under the License.
+  ~
+  --%>
+<%@page import="org.keycloak.AuthorizationContext" %>
+<%@ page import="org.keycloak.common.util.KeycloakUriBuilder" %>
+<%@ page import="org.keycloak.constants.ServiceUrlConstants" %>
+<%@ page import="org.keycloak.KeycloakSecurityContext" %>
+<%@ page import="org.keycloak.representations.idm.authorization.Permission" %>
+
+<%
+    KeycloakSecurityContext keycloakSecurityContext = (KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
+    AuthorizationContext authzContext = keycloakSecurityContext.getAuthorizationContext();
+%>
+<html>
+<body>
+<h2>Welcome !</h2>
+<h2><a href="<%= KeycloakUriBuilder.fromUri("/auth").path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH)
+            .queryParam("redirect_uri", "http://localhost:8080/hello-world-authz-service").build("hello-world-authz").toString()%>">Logout</a></h2>
+
+<h3>Your permissions are:</h3>
+
+<ul>
+    <%
+        for (Permission permission : authzContext.getPermissions()) {
+    %>
+    <li>
+        <p>Resource: <%= permission.getResourceSetName() %></p>
+        <p>ID: <%= permission.getResourceSetId() %></p>
+    </li>
+    <%
+        }
+    %>
+</ul>
+</body>
+</html>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/hello-world-authz-service/src/main/webapp/WEB-INF/keycloak.json b/testsuite/integration-arquillian/test-apps/hello-world-authz-service/src/main/webapp/WEB-INF/keycloak.json
new file mode 100644
index 0000000..a492837
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/hello-world-authz-service/src/main/webapp/WEB-INF/keycloak.json
@@ -0,0 +1,13 @@
+{
+  "realm": "hello-world-authz",
+  "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url": "http://localhost:8080/auth",
+  "ssl-required": "external",
+  "resource": "hello-world-authz-service",
+  "credentials": {
+    "secret": "secret"
+  },
+  "policy-enforcer": {
+    "on-deny-redirect-to" : "/hello-world-authz-service/error.jsp"
+  }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/hello-world-authz-service/src/main/webapp/WEB-INF/web.xml b/testsuite/integration-arquillian/test-apps/hello-world-authz-service/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..1ca06be
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/hello-world-authz-service/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~  Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~  and other contributors as indicated by the @author tags.
+  ~
+  ~  Licensed under the Apache License, Version 2.0 (the "License");
+  ~  you may not use this file except in compliance with the License.
+  ~  You may obtain a copy of the License at
+  ~
+  ~  http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing, software
+  ~  distributed under the License is distributed on an "AS IS" BASIS,
+  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  See the License for the specific language governing permissions and
+  ~  limitations under the License.
+  ~
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+		 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+		 version="3.0">
+
+	<module-name>hello-world-authz-service</module-name>
+
+	<security-constraint>
+		<web-resource-collection>
+			<web-resource-name>All Resources</web-resource-name>
+			<url-pattern>/*</url-pattern>
+		</web-resource-collection>
+		<auth-constraint>
+			<role-name>uma_authorization</role-name>
+		</auth-constraint>
+	</security-constraint>
+
+	<login-config>
+		<auth-method>KEYCLOAK</auth-method>
+		<realm-name>hello-world-authz</realm-name>
+	</login-config>
+
+	<security-role>
+		<role-name>uma_authorization</role-name>
+	</security-role>
+</web-app>
diff --git a/testsuite/integration-arquillian/test-apps/js-console/example-realm.json b/testsuite/integration-arquillian/test-apps/js-console/example-realm.json
index 3bc609e..4e3adca 100755
--- a/testsuite/integration-arquillian/test-apps/js-console/example-realm.json
+++ b/testsuite/integration-arquillian/test-apps/js-console/example-realm.json
@@ -21,6 +21,20 @@
             "clientRoles": {
                 "account": ["view-profile", "manage-account"]
             }
+        },{
+            "username" : "unauthorized",
+            "enabled": true,
+            "email" : "sample-user2@example",
+            "firstName": "Sample",
+            "lastName": "User",
+            "credentials" : [
+                { "type" : "password",
+                    "value" : "password" }
+            ],
+            "realmRoles": [],
+            "clientRoles": {
+                "account": ["view-profile", "manage-account"]
+            }
         }
     ],
     "roles" : {
@@ -54,6 +68,12 @@
                 "http://localhost:8280",
                 "https://localhost:8643"
             ]
+        },{
+            "clientId": "js-database",
+            "enabled": true,
+            "adminUrl": "/database",
+            "baseUrl": "/database",
+            "bearerOnly": true
         }
     ],
     "clientScopeMappings": {
diff --git a/testsuite/integration-arquillian/test-apps/js-console/pom.xml b/testsuite/integration-arquillian/test-apps/js-console/pom.xml
index fdf7d2f..e5690a8 100755
--- a/testsuite/integration-arquillian/test-apps/js-console/pom.xml
+++ b/testsuite/integration-arquillian/test-apps/js-console/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-test-apps</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <modelVersion>4.0.0</modelVersion>
diff --git a/testsuite/integration-arquillian/test-apps/js-console/src/main/webapp/index.html b/testsuite/integration-arquillian/test-apps/js-console/src/main/webapp/index.html
index 04d7a8e..468f98e 100755
--- a/testsuite/integration-arquillian/test-apps/js-console/src/main/webapp/index.html
+++ b/testsuite/integration-arquillian/test-apps/js-console/src/main/webapp/index.html
@@ -29,6 +29,7 @@
     <button onclick="keycloak.register()">Register</button>
     <button onclick="refreshToken(9999)">Refresh Token</button>
     <button onclick="refreshToken(30)">Refresh Token (if <30s validity)</button>
+    <button onclick="showError()">Show Error Response</button>
     <button onclick="loadProfile()">Get Profile</button>
     <button onclick="loadUserInfo()">Get User Info</button>
     <button onclick="output(keycloak.tokenParsed)">Show Token</button>
@@ -39,6 +40,7 @@
     <button onclick="output(keycloak.createLoginUrl())">Show Login URL</button>
     <button onclick="output(keycloak.createLogoutUrl())">Show Logout URL</button>
     <button onclick="output(keycloak.createRegisterUrl())">Show Register URL</button>
+    <button onclick="createBearerRequest()">Create Bearer Request</button>
     <select id="flowSelect">
         <option value="standard">standard</option>
         <option value="implicit">implicit</option>
@@ -48,6 +50,10 @@
         <option value="fragment">fragment</option>
         <option value="query">query</option>
     </select>
+    <select id="onLoad">
+        <option value="check-sso">check-sso</option>
+        <option value="login-required">login-required</option>
+    </select>
 </div>
 
 <h2>Result</h2>
@@ -103,6 +109,20 @@
         output(o);
     }
 
+    function showError() {
+        output("Error: " + getParameterByName("error") + "\n" + "Error description: " + getParameterByName("error_description"));
+    }
+
+    function getParameterByName(name, url) {
+        if (!url) url = window.location.href;
+        name = name.replace(/[\[\]]/g, "\\$&");
+        var regex = new RegExp("[?&#]" + name + "(=([^&#]*)|&|#|$)"),
+                results = regex.exec(url);
+        if (!results) return null;
+        if (!results[2]) return '';
+        return decodeURIComponent(results[2].replace(/\+/g, " "));
+    }
+
     function output(data) {
         if (typeof data === 'object') {
             data = JSON.stringify(data, null, '  ');
@@ -115,6 +135,38 @@
         document.getElementById('events').innerHTML = new Date().toLocaleString() + "\t" + event + "\n" + e;
     }
 
+    function createBearerRequest() {
+
+        var url = 'http://localhost:8280/js-database/customers';
+        if (window.location.href.indexOf("8643") > -1) {
+            url = url.replace("8280","8643");
+            url = url.replace("http","https");
+        }
+
+        if (window.location.href.indexOf("8180") > -1) {
+            url = url.replace("8280","8180");
+        }
+
+        var req = new XMLHttpRequest();
+        req.open('GET', url, true);
+        req.setRequestHeader('Accept', 'application/json');
+        req.setRequestHeader('Authorization', 'Bearer ' + keycloak.token);
+
+        req.onreadystatechange = function () {
+            if (req.readyState == 4) {
+                if (req.status == 200) {
+                    output(req.responseText);
+                } else if (req.status == 403) {
+                    output('Forbidden');
+                } else if (req.status == 401) {
+                    output('Unauthorized');
+                }
+            }
+        };
+
+        req.send();
+    }
+
     var keycloak;
 
     function keycloakInit() {
@@ -144,7 +196,7 @@
             event('Access token expired.');
         };
 
-        var initOptions = {flow: document.getElementById("flowSelect").value, responseMode:  document.getElementById("responseModeSelect").value}
+        var initOptions = {onLoad: document.getElementById("onLoad").value, flow: document.getElementById("flowSelect").value, responseMode:  document.getElementById("responseModeSelect").value};
         keycloak.init(initOptions).success(function (authenticated) {
             output('Init Success (' + (authenticated ? 'Authenticated' : 'Not Authenticated') + ')');
         }).error(function () {
diff --git a/testsuite/integration-arquillian/test-apps/js-database/pom.xml b/testsuite/integration-arquillian/test-apps/js-database/pom.xml
new file mode 100644
index 0000000..a6bee73
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/js-database/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>integration-arquillian-test-apps</artifactId>
+        <groupId>org.keycloak.testsuite</groupId>
+        <version>2.2.0-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>integration-arquillian-test-apps-js-database</artifactId>
+    <name>JAX-RS Database Service Using OAuth Bearer Tokens</name>
+    <packaging>war</packaging>
+
+    <repositories>
+        <repository>
+            <id>jboss</id>
+            <name>jboss repo</name>
+            <url>http://repository.jboss.org/nexus/content/groups/public/</url>
+        </repository>
+    </repositories>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>resteasy-jaxrs</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.spec.javax.servlet</groupId>
+            <artifactId>jboss-servlet-api_3.0_spec</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-adapter-core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>js-database</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.jboss.as.plugins</groupId>
+                <artifactId>jboss-as-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.wildfly.plugins</groupId>
+                <artifactId>wildfly-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/js-database/src/main/java/org/keycloak/example/oauth/CustomerService.java b/testsuite/integration-arquillian/test-apps/js-database/src/main/java/org/keycloak/example/oauth/CustomerService.java
new file mode 100755
index 0000000..d2b193e
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/js-database/src/main/java/org/keycloak/example/oauth/CustomerService.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.example.oauth;
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.jboss.resteasy.spi.HttpRequest;
+import org.keycloak.KeycloakSecurityContext;
+import org.keycloak.representations.AccessToken;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@Path("customers")
+public class CustomerService {
+
+    @Context
+    private HttpRequest httpRequest;
+
+    @GET
+    @Produces("application/json")
+    @NoCache
+    public List<String> getCustomers() {
+        // Just to show how to user info from access token in REST endpoint
+        KeycloakSecurityContext securityContext = (KeycloakSecurityContext) httpRequest.getAttribute(KeycloakSecurityContext.class.getName());
+        AccessToken accessToken = securityContext.getToken();
+        System.out.println(String.format("User '%s' with email '%s' made request to CustomerService REST endpoint", accessToken.getPreferredUsername(), accessToken.getEmail()));
+
+        ArrayList<String> rtn = new ArrayList<String>();
+        rtn.add("Bill Burke");
+        rtn.add("Stian Thorgersen");
+        rtn.add("Stan Silvert");
+        rtn.add("Gabriel Cardoso");
+        rtn.add("Viliam Rockai");
+        rtn.add("Marek Posolda");
+        rtn.add("Boleslaw Dawidowicz");
+        return rtn;
+    }
+}
diff --git a/testsuite/integration-arquillian/test-apps/js-database/src/main/java/org/keycloak/example/oauth/DataApplication.java b/testsuite/integration-arquillian/test-apps/js-database/src/main/java/org/keycloak/example/oauth/DataApplication.java
new file mode 100755
index 0000000..6456904
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/js-database/src/main/java/org/keycloak/example/oauth/DataApplication.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.example.oauth;
+
+import javax.ws.rs.ApplicationPath;
+import javax.ws.rs.core.Application;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@ApplicationPath("/")
+public class DataApplication extends Application
+{
+}
diff --git a/testsuite/integration-arquillian/test-apps/js-database/src/main/webapp/WEB-INF/keycloak.json b/testsuite/integration-arquillian/test-apps/js-database/src/main/webapp/WEB-INF/keycloak.json
new file mode 100755
index 0000000..9f94148
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/js-database/src/main/webapp/WEB-INF/keycloak.json
@@ -0,0 +1,8 @@
+{
+  "realm" : "example",
+  "resource" : "js-database",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url": "http://localhost:8180/auth",
+  "bearer-only" : true,
+  "ssl-required" : "external"
+}
diff --git a/testsuite/integration-arquillian/test-apps/js-database/src/main/webapp/WEB-INF/web.xml b/testsuite/integration-arquillian/test-apps/js-database/src/main/webapp/WEB-INF/web.xml
new file mode 100755
index 0000000..599f667
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/js-database/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>js-database</module-name>
+	
+    <security-constraint>
+        <web-resource-collection>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+<!--        <user-data-constraint>
+            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
+        </user-data-constraint>  -->
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>KEYCLOAK</auth-method>
+        <realm-name>example</realm-name>
+    </login-config>
+
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-authz-policy/pom.xml b/testsuite/integration-arquillian/test-apps/photoz/photoz-authz-policy/pom.xml
new file mode 100755
index 0000000..e6132d8
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-authz-policy/pom.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian-test-apps-photoz-parent</artifactId>
+        <version>2.2.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>photoz-authz-policy</artifactId>
+    <packaging>jar</packaging>
+
+    <name>Keycloak Authz Tests: Photoz Authz Rule-based Policy</name>
+
+    <description>
+        Photoz Authz Rule-based Policies using JBoss Drools
+    </description>
+
+</project>
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.admin/Main.drl b/testsuite/integration-arquillian/test-apps/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.admin/Main.drl
new file mode 100644
index 0000000..deb1c84
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.admin/Main.drl
@@ -0,0 +1,14 @@
+package com.photoz.authz.policy.admin
+
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+
+rule "Authorize Admin Resources"
+    dialect "mvel"
+        when
+           $evaluation : Evaluation(
+               $identity : context.identity,
+               $identity.hasRole("admin")
+           )
+        then
+           $evaluation.grant();
+end
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.resource.owner/Main.drl b/testsuite/integration-arquillian/test-apps/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.resource.owner/Main.drl
new file mode 100644
index 0000000..9378b94
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.resource.owner/Main.drl
@@ -0,0 +1,15 @@
+package com.photoz.authz.policy.admin
+
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+
+rule "Authorize Resource Owner"
+    dialect "mvel"
+    when
+       $evaluation : Evaluation(
+           $identity: context.identity,
+           $permission: permission,
+           $permission.resource != null && $permission.resource.owner.equals($identity.id)
+       )
+    then
+        $evaluation.grant();
+end
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.user/Main.drl b/testsuite/integration-arquillian/test-apps/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.user/Main.drl
new file mode 100644
index 0000000..9b1677e
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-authz-policy/src/main/resources/com.photoz.authz.policy.user/Main.drl
@@ -0,0 +1,14 @@
+package com.photoz.authz.policy.admin
+
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+
+rule "Authorize View User Album"
+    dialect "mvel"
+    when
+        $evaluation : Evaluation(
+            $identity : context.identity,
+            $identity.hasRole("user")
+       )
+    then
+       $evaluation.grant();
+end
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-authz-policy/src/main/resources/com/photoz/authz/policy/contextual/Main.drl b/testsuite/integration-arquillian/test-apps/photoz/photoz-authz-policy/src/main/resources/com/photoz/authz/policy/contextual/Main.drl
new file mode 100644
index 0000000..8a6a772
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-authz-policy/src/main/resources/com/photoz/authz/policy/contextual/Main.drl
@@ -0,0 +1,15 @@
+package com.photoz.authz.policy.admin
+
+import org.keycloak.authorization.policy.evaluation.Evaluation;
+
+rule "Authorize Using Context Information"
+    dialect "mvel"
+    when
+       $evaluation : Evaluation(
+           $attributes: context.attributes,
+           $attributes.containsValue("kc.identity.authc.method", "otp"),
+           $attributes.containsValue("someAttribute", "you_can_access")
+       )
+    then
+        $evaluation.grant();
+end
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-authz-policy/src/main/resources/META-INF/kmodule.xml b/testsuite/integration-arquillian/test-apps/photoz/photoz-authz-policy/src/main/resources/META-INF/kmodule.xml
new file mode 100644
index 0000000..84bacd5
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-authz-policy/src/main/resources/META-INF/kmodule.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kmodule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://jboss.org/kie/6.0.0/kmodule">
+
+    <kbase name="PhotozAuthzAdminPolicy" packages="com.photoz.authz.policy.admin">
+        <ksession name="MainAdminSession" default="true"/>
+    </kbase>
+
+    <kbase name="PhotozAuthzUserPolicy" packages="com.photoz.authz.policy.user">
+        <ksession name="MainUserSession"  default="true"/>
+    </kbase>
+
+    <kbase name="PhotozAuthzOwnerPolicy" packages="com.photoz.authz.policy.resource.owner">
+        <ksession name="MainOwnerSession" default="true"/>
+    </kbase>
+
+    <kbase name="PhotozAuthzContextualPolicy" packages="com.photoz.authz.policy.contextual">
+        <ksession name="MainContextualSession" default="true"/>
+    </kbase>
+
+</kmodule>
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/pom.xml b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/pom.xml
new file mode 100755
index 0000000..35d39e7
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/pom.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian-test-apps-photoz-parent</artifactId>
+        <version>2.2.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>photoz-html5-client</artifactId>
+    <packaging>war</packaging>
+
+    <name>Keycloak Authz Tests: Photoz HTML5 Client</name>
+    <description>Photoz Test HTML5 Client</description>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.jboss.as.plugins</groupId>
+                <artifactId>jboss-as-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.wildfly.plugins</groupId>
+                <artifactId>wildfly-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/index.html b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/index.html
new file mode 100755
index 0000000..bec9fae
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/index.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<html lang="en">
+
+<head>
+    <meta charset="utf-8">
+    <title>Photoz HTML5 Client</title>
+
+    <!-- Load AngularJS -->
+    <script src="lib/angular/angular.min.js"></script>
+    <script src="lib/angular/angular-resource.min.js"></script>
+    <script src="lib/angular/angular-route.min.js"></script>
+    <script src="lib/jwt-decode.min.js"></script>
+
+    <script src="http://localhost:8180/auth/js/keycloak.js"></script>
+    <script src="http://localhost:8180/auth/js/keycloak-authz.js"></script>
+    <script src="js/identity.js" type="text/javascript"></script>
+    <script src="js/app.js" type="text/javascript"></script>
+</head>
+
+<body data-ng-controller="TokenCtrl">
+
+<a href data-ng-click="showRpt()">Show Requesting Party Token </a> | <a href data-ng-click="showAccessToken()">Show Access Token </a> | <a href data-ng-click="requestEntitlements()">Request Entitlements</a> | <a href="" ng-click="Identity.logout()">Sign Out</a>
+
+<div id="content-area" class="col-md-9" role="main">
+    <div id="content" ng-view/>
+</div>
+
+<pre style="background-color: #ddd; border: 1px solid #ccc; padding: 10px;" id="output"></pre>
+
+</body>
+</html>
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/js/app.js b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/js/app.js
new file mode 100755
index 0000000..e58c5f5
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/js/app.js
@@ -0,0 +1,169 @@
+var module = angular.module('photoz', ['ngRoute', 'ngResource']);
+
+var resourceServerId = 'photoz-restful-api';
+var apiUrl = window.location.origin + '/' + resourceServerId;
+
+angular.element(document).ready(function ($http) {
+    var keycloak = new Keycloak('keycloak.json');
+    keycloak.init({onLoad: 'login-required'}).success(function () {
+        console.log('User is now authenticated.');
+
+        module.factory('Identity', function () {
+            return new Identity(keycloak);
+        });
+
+        angular.bootstrap(document, ["photoz"]);
+    }).error(function () {
+        window.location.reload();
+    });
+});
+
+module.config(function ($httpProvider, $routeProvider) {
+    $httpProvider.interceptors.push('authInterceptor');
+    $routeProvider.when('/', {
+        templateUrl: 'partials/home.html',
+        controller: 'GlobalCtrl'
+    }).when('/album/create', {
+        templateUrl: 'partials/album/create.html',
+        controller: 'AlbumCtrl',
+    }).when('/album/:id', {
+        templateUrl: 'partials/album/detail.html',
+        controller: 'AlbumCtrl',
+    }).when('/admin/album', {
+        templateUrl: 'partials/admin/albums.html',
+        controller: 'AdminAlbumCtrl',
+    }).when('/profile', {
+        templateUrl: 'partials/profile.html',
+        controller: 'ProfileCtrl',
+    });
+});
+
+module.controller('GlobalCtrl', function ($scope, $http, $route, $location, Album, Identity) {
+    Album.query(function (albums) {
+        $scope.albums = albums;
+    });
+
+    $scope.Identity = Identity;
+
+    $scope.deleteAlbum = function (album) {
+        new Album(album).$delete({id: album.id}, function () {
+            $route.reload();
+        });
+    }
+});
+
+module.controller('TokenCtrl', function ($scope, Identity) {
+    $scope.showRpt = function () {
+        document.getElementById("output").innerHTML = JSON.stringify(jwt_decode(Identity.authorization.rpt), null, '  ');
+    }
+
+    $scope.showAccessToken = function () {
+        document.getElementById("output").innerHTML = JSON.stringify(jwt_decode(Identity.authc.token), null, '  ');
+    }
+
+    $scope.requestEntitlements = function () {
+        Identity.authorization.entitlement('photoz-restful-api').then(function (rpt) {});
+    }
+
+    $scope.Identity = Identity;
+});
+
+module.controller('AlbumCtrl', function ($scope, $http, $routeParams, $location, Album) {
+    $scope.album = {};
+    if ($routeParams.id) {
+        $scope.album = Album.get({id: $routeParams.id});
+    }
+    $scope.create = function () {
+        var newAlbum = new Album($scope.album);
+        newAlbum.$save({}, function (data) {
+            $location.path('/');
+        });
+    };
+});
+
+module.controller('ProfileCtrl', function ($scope, $http, $routeParams, $location, Profile) {
+    $scope.profile = Profile.get();
+});
+
+module.controller('AdminAlbumCtrl', function ($scope, $http, $route, $location, AdminAlbum, Album) {
+    $scope.albums = {};
+    $http.get(apiUrl + '/admin/album').success(function (data) {
+        $scope.albums = data;
+    });
+    $scope.deleteAlbum = function (album) {
+        new Album(album).$delete({id: album.id}, function () {
+            $route.reload();
+        });
+    }
+});
+
+module.factory('Album', ['$resource', function ($resource) {
+    return $resource(apiUrl + '/album/:id');
+}]);
+
+module.factory('Profile', ['$resource', function ($resource) {
+    return $resource(apiUrl + '/profile');
+}]);
+
+module.factory('AdminAlbum', ['$resource', function ($resource) {
+    return $resource(apiUrl + '/admin/album/:id');
+}]);
+
+module.factory('authInterceptor', function ($q, $injector, $timeout, Identity) {
+    return {
+        request: function (request) {
+            document.getElementById("output").innerHTML = '';
+            if (Identity.authorization && Identity.authorization.rpt && request.url.indexOf('/authorize') == -1) {
+                retries = 0;
+                request.headers.Authorization = 'Bearer ' + Identity.authorization.rpt;
+            } else {
+                request.headers.Authorization = 'Bearer ' + Identity.authc.token;
+            }
+            return request;
+        },
+        responseError: function (rejection) {
+            var status = rejection.status;
+
+            if (status == 403 || status == 401) {
+                var retry = (!rejection.config.retry ||  rejection.config.retry < 1);
+
+                if (!retry) {
+                    document.getElementById("output").innerHTML = 'You can not access or perform the requested operation on this resource.';
+                    return $q.reject(rejection);
+                }
+
+                if (rejection.config.url.indexOf('/authorize') == -1 && retry) {
+                    var deferred = $q.defer();
+
+                    // here is the authorization logic, which tries to obtain an authorization token from the server in case the resource server
+                    // returns a 403 or 401.
+                    Identity.authorization.authorize(rejection.headers('WWW-Authenticate')).then(function (rpt) {
+                        deferred.resolve(rejection);
+                    }, function () {
+                        document.getElementById("output").innerHTML = 'You can not access or perform the requested operation on this resource.';
+                    }, function () {
+                        document.getElementById("output").innerHTML = 'Unexpected error from server.';
+                    });
+
+                    var promise = deferred.promise;
+
+                    return promise.then(function (res) {
+                        if (!res.config.retry) {
+                            res.config.retry = 1;
+                        } else {
+                            res.config.retry++;
+                        }
+
+                        var $http = $injector.get("$http");
+
+                        return $http(res.config).then(function (response) {
+                            return response;
+                        });
+                    });
+                }
+            }
+
+            return $q.reject(rejection);
+        }
+    };
+});
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/js/identity.js b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/js/identity.js
new file mode 100644
index 0000000..9a018e4
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/js/identity.js
@@ -0,0 +1,60 @@
+/*
+ *  Copyright 2016 Red Hat, Inc. and/or its affiliates
+ *  and other contributors as indicated by the @author tags.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/**
+ * Creates an Identity object holding the information obtained from the access token issued by Keycloak, after a successful authentication,
+ * and a few utility methods to manage it.
+ */
+(function (window, undefined) {
+    var Identity = function (keycloak) {
+        this.loggedIn = true;
+
+        this.claims = {};
+        this.claims.name = keycloak.idTokenParsed.name;
+
+        this.authc = {};
+        this.authc.token = keycloak.token;
+
+        this.logout = function () {
+            keycloak.logout();
+        };
+
+        this.hasRole = function (name) {
+            if (keycloak && keycloak.hasRealmRole(name)) {
+                return true;
+            }
+            return false;
+        };
+
+        this.isAdmin = function () {
+            return this.hasRole("admin");
+        };
+
+        this.authorization = new KeycloakAuthorization(keycloak);
+    }
+
+    if ( typeof module === "object" && module && typeof module.exports === "object" ) {
+        module.exports = Identity;
+    } else {
+        window.Identity = Identity;
+
+        if ( typeof define === "function" && define.amd ) {
+            define( "identity", [], function () { return Identity; } );
+        }
+    }
+})( window );
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/keycloak.json b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/keycloak.json
new file mode 100644
index 0000000..c1dee24
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/keycloak.json
@@ -0,0 +1,8 @@
+{
+  "realm": "photoz",
+  "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url" : "http://localhost:8080/auth",
+  "ssl-required" : "external",
+  "resource" : "photoz-html5-client",
+  "public-client" : true
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular.min.js b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular.min.js
new file mode 100644
index 0000000..569a9a2
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular.min.js
@@ -0,0 +1,214 @@
+/*
+ AngularJS v1.3.0-beta.5
+ (c) 2010-2014 Google, Inc. http://angularjs.org
+ License: MIT
+*/
+(function(O,U,s){'use strict';function v(b){return function(){var a=arguments[0],c,a="["+(b?b+":":"")+a+"] http://errors.angularjs.org/1.3.0-beta.5/"+(b?b+"/":"")+a;for(c=1;c<arguments.length;c++)a=a+(1==c?"?":"&")+"p"+(c-1)+"="+encodeURIComponent("function"==typeof arguments[c]?arguments[c].toString().replace(/ \{[\s\S]*$/,""):"undefined"==typeof arguments[c]?"undefined":"string"!=typeof arguments[c]?JSON.stringify(arguments[c]):arguments[c]);return Error(a)}}function db(b){if(null==b||Da(b))return!1;
+var a=b.length;return 1===b.nodeType&&a?!0:t(b)||M(b)||0===a||"number"===typeof a&&0<a&&a-1 in b}function q(b,a,c){var d;if(b)if(P(b))for(d in b)"prototype"==d||("length"==d||"name"==d||b.hasOwnProperty&&!b.hasOwnProperty(d))||a.call(c,b[d],d);else if(b.forEach&&b.forEach!==q)b.forEach(a,c);else if(db(b))for(d=0;d<b.length;d++)a.call(c,b[d],d);else for(d in b)b.hasOwnProperty(d)&&a.call(c,b[d],d);return b}function Tb(b){var a=[],c;for(c in b)b.hasOwnProperty(c)&&a.push(c);return a.sort()}function ad(b,
+a,c){for(var d=Tb(b),e=0;e<d.length;e++)a.call(c,b[d[e]],d[e]);return d}function Ub(b){return function(a,c){b(c,a)}}function eb(){for(var b=ka.length,a;b;){b--;a=ka[b].charCodeAt(0);if(57==a)return ka[b]="A",ka.join("");if(90==a)ka[b]="0";else return ka[b]=String.fromCharCode(a+1),ka.join("")}ka.unshift("0");return ka.join("")}function Vb(b,a){a?b.$$hashKey=a:delete b.$$hashKey}function A(b){var a=b.$$hashKey;q(arguments,function(a){a!==b&&q(a,function(a,c){b[c]=a})});Vb(b,a);return b}function Y(b){return parseInt(b,
+10)}function Wb(b,a){return A(new (A(function(){},{prototype:b})),a)}function C(){}function Ea(b){return b}function aa(b){return function(){return b}}function D(b){return"undefined"===typeof b}function B(b){return"undefined"!==typeof b}function X(b){return null!=b&&"object"===typeof b}function t(b){return"string"===typeof b}function Ab(b){return"number"===typeof b}function ra(b){return"[object Date]"===ya.call(b)}function M(b){return"[object Array]"===ya.call(b)}function P(b){return"function"===typeof b}
+function fb(b){return"[object RegExp]"===ya.call(b)}function Da(b){return b&&b.document&&b.location&&b.alert&&b.setInterval}function bd(b){return!(!b||!(b.nodeName||b.prop&&b.attr&&b.find))}function cd(b,a,c){var d=[];q(b,function(b,g,f){d.push(a.call(c,b,g,f))});return d}function gb(b,a){if(b.indexOf)return b.indexOf(a);for(var c=0;c<b.length;c++)if(a===b[c])return c;return-1}function Fa(b,a){var c=gb(b,a);0<=c&&b.splice(c,1);return a}function ba(b,a){if(Da(b)||b&&b.$evalAsync&&b.$watch)throw Oa("cpws");
+if(a){if(b===a)throw Oa("cpi");if(M(b))for(var c=a.length=0;c<b.length;c++)a.push(ba(b[c]));else{c=a.$$hashKey;q(a,function(b,c){delete a[c]});for(var d in b)a[d]=ba(b[d]);Vb(a,c)}}else(a=b)&&(M(b)?a=ba(b,[]):ra(b)?a=new Date(b.getTime()):fb(b)?a=RegExp(b.source):X(b)&&(a=ba(b,{})));return a}function Xb(b,a){a=a||{};for(var c in b)!b.hasOwnProperty(c)||"$"===c.charAt(0)&&"$"===c.charAt(1)||(a[c]=b[c]);return a}function za(b,a){if(b===a)return!0;if(null===b||null===a)return!1;if(b!==b&&a!==a)return!0;
+var c=typeof b,d;if(c==typeof a&&"object"==c)if(M(b)){if(!M(a))return!1;if((c=b.length)==a.length){for(d=0;d<c;d++)if(!za(b[d],a[d]))return!1;return!0}}else{if(ra(b))return ra(a)&&b.getTime()==a.getTime();if(fb(b)&&fb(a))return b.toString()==a.toString();if(b&&b.$evalAsync&&b.$watch||a&&a.$evalAsync&&a.$watch||Da(b)||Da(a)||M(a))return!1;c={};for(d in b)if("$"!==d.charAt(0)&&!P(b[d])){if(!za(b[d],a[d]))return!1;c[d]=!0}for(d in a)if(!c.hasOwnProperty(d)&&"$"!==d.charAt(0)&&a[d]!==s&&!P(a[d]))return!1;
+return!0}return!1}function Yb(){return U.securityPolicy&&U.securityPolicy.isActive||U.querySelector&&!(!U.querySelector("[ng-csp]")&&!U.querySelector("[data-ng-csp]"))}function hb(b,a){var c=2<arguments.length?sa.call(arguments,2):[];return!P(a)||a instanceof RegExp?a:c.length?function(){return arguments.length?a.apply(b,c.concat(sa.call(arguments,0))):a.apply(b,c)}:function(){return arguments.length?a.apply(b,arguments):a.call(b)}}function dd(b,a){var c=a;"string"===typeof b&&"$"===b.charAt(0)?c=
+s:Da(a)?c="$WINDOW":a&&U===a?c="$DOCUMENT":a&&(a.$evalAsync&&a.$watch)&&(c="$SCOPE");return c}function ta(b,a){return"undefined"===typeof b?s:JSON.stringify(b,dd,a?"  ":null)}function Zb(b){return t(b)?JSON.parse(b):b}function Pa(b){"function"===typeof b?b=!0:b&&0!==b.length?(b=I(""+b),b=!("f"==b||"0"==b||"false"==b||"no"==b||"n"==b||"[]"==b)):b=!1;return b}function ha(b){b=y(b).clone();try{b.empty()}catch(a){}var c=y("<div>").append(b).html();try{return 3===b[0].nodeType?I(c):c.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,
+function(a,b){return"<"+I(b)})}catch(d){return I(c)}}function $b(b){try{return decodeURIComponent(b)}catch(a){}}function ac(b){var a={},c,d;q((b||"").split("&"),function(b){b&&(c=b.split("="),d=$b(c[0]),B(d)&&(b=B(c[1])?$b(c[1]):!0,a[d]?M(a[d])?a[d].push(b):a[d]=[a[d],b]:a[d]=b))});return a}function bc(b){var a=[];q(b,function(b,d){M(b)?q(b,function(b){a.push(Aa(d,!0)+(!0===b?"":"="+Aa(b,!0)))}):a.push(Aa(d,!0)+(!0===b?"":"="+Aa(b,!0)))});return a.length?a.join("&"):""}function Bb(b){return Aa(b,
+!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function Aa(b,a){return encodeURIComponent(b).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,a?"%20":"+")}function ed(b,a){function c(a){a&&d.push(a)}var d=[b],e,g,f=["ng:app","ng-app","x-ng-app","data-ng-app"],h=/\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;q(f,function(a){f[a]=!0;c(U.getElementById(a));a=a.replace(":","\\:");b.querySelectorAll&&(q(b.querySelectorAll("."+a),c),q(b.querySelectorAll("."+
+a+"\\:"),c),q(b.querySelectorAll("["+a+"]"),c))});q(d,function(a){if(!e){var b=h.exec(" "+a.className+" ");b?(e=a,g=(b[2]||"").replace(/\s+/g,",")):q(a.attributes,function(b){!e&&f[b.name]&&(e=a,g=b.value)})}});e&&a(e,g?[g]:[])}function cc(b,a){var c=function(){b=y(b);if(b.injector()){var c=b[0]===U?"document":ha(b);throw Oa("btstrpd",c);}a=a||[];a.unshift(["$provide",function(a){a.value("$rootElement",b)}]);a.unshift("ng");c=dc(a);c.invoke(["$rootScope","$rootElement","$compile","$injector","$animate",
+function(a,b,c,d,e){a.$apply(function(){b.data("$injector",d);c(b)(a)})}]);return c},d=/^NG_DEFER_BOOTSTRAP!/;if(O&&!d.test(O.name))return c();O.name=O.name.replace(d,"");Qa.resumeBootstrap=function(b){q(b,function(b){a.push(b)});c()}}function ib(b,a){a=a||"_";return b.replace(fd,function(b,d){return(d?a:"")+b.toLowerCase()})}function Cb(b,a,c){if(!b)throw Oa("areq",a||"?",c||"required");return b}function Ra(b,a,c){c&&M(b)&&(b=b[b.length-1]);Cb(P(b),a,"not a function, got "+(b&&"object"==typeof b?
+b.constructor.name||"Object":typeof b));return b}function Ba(b,a){if("hasOwnProperty"===b)throw Oa("badname",a);}function ec(b,a,c){if(!a)return b;a=a.split(".");for(var d,e=b,g=a.length,f=0;f<g;f++)d=a[f],b&&(b=(e=b)[d]);return!c&&P(b)?hb(e,b):b}function Db(b){var a=b[0];b=b[b.length-1];if(a===b)return y(a);var c=[a];do{a=a.nextSibling;if(!a)break;c.push(a)}while(a!==b);return y(c)}function gd(b){var a=v("$injector"),c=v("ng");b=b.angular||(b.angular={});b.$$minErr=b.$$minErr||v;return b.module||
+(b.module=function(){var b={};return function(e,g,f){if("hasOwnProperty"===e)throw c("badname","module");g&&b.hasOwnProperty(e)&&(b[e]=null);return b[e]||(b[e]=function(){function b(a,d,e){return function(){c[e||"push"]([a,d,arguments]);return n}}if(!g)throw a("nomod",e);var c=[],d=[],l=b("$injector","invoke"),n={_invokeQueue:c,_runBlocks:d,requires:g,name:e,provider:b("$provide","provider"),factory:b("$provide","factory"),service:b("$provide","service"),value:b("$provide","value"),constant:b("$provide",
+"constant","unshift"),animation:b("$animateProvider","register"),filter:b("$filterProvider","register"),controller:b("$controllerProvider","register"),directive:b("$compileProvider","directive"),config:l,run:function(a){d.push(a);return this}};f&&l(f);return n}())}}())}function hd(b){A(b,{bootstrap:cc,copy:ba,extend:A,equals:za,element:y,forEach:q,injector:dc,noop:C,bind:hb,toJson:ta,fromJson:Zb,identity:Ea,isUndefined:D,isDefined:B,isString:t,isFunction:P,isObject:X,isNumber:Ab,isElement:bd,isArray:M,
+version:id,isDate:ra,lowercase:I,uppercase:Ga,callbacks:{counter:0},$$minErr:v,$$csp:Yb});Sa=gd(O);try{Sa("ngLocale")}catch(a){Sa("ngLocale",[]).provider("$locale",jd)}Sa("ng",["ngLocale"],["$provide",function(a){a.provider({$$sanitizeUri:kd});a.provider("$compile",fc).directive({a:ld,input:gc,textarea:gc,form:md,script:nd,select:od,style:pd,option:qd,ngBind:rd,ngBindHtml:sd,ngBindTemplate:td,ngClass:ud,ngClassEven:vd,ngClassOdd:wd,ngCloak:xd,ngController:yd,ngForm:zd,ngHide:Ad,ngIf:Bd,ngInclude:Cd,
+ngInit:Dd,ngNonBindable:Ed,ngPluralize:Fd,ngRepeat:Gd,ngShow:Hd,ngStyle:Id,ngSwitch:Jd,ngSwitchWhen:Kd,ngSwitchDefault:Ld,ngOptions:Md,ngTransclude:Nd,ngModel:Od,ngList:Pd,ngChange:Qd,required:hc,ngRequired:hc,ngValue:Rd}).directive({ngInclude:Sd}).directive(Eb).directive(ic);a.provider({$anchorScroll:Td,$animate:Ud,$browser:Vd,$cacheFactory:Wd,$controller:Xd,$document:Yd,$exceptionHandler:Zd,$filter:jc,$interpolate:$d,$interval:ae,$http:be,$httpBackend:ce,$location:de,$log:ee,$parse:fe,$rootScope:ge,
+$q:he,$sce:ie,$sceDelegate:je,$sniffer:ke,$templateCache:le,$timeout:me,$window:ne,$$rAF:oe,$$asyncCallback:pe})}])}function Ta(b){return b.replace(qe,function(a,b,d,e){return e?d.toUpperCase():d}).replace(re,"Moz$1")}function Fb(b,a,c,d){function e(b){var e=c&&b?[this.filter(b)]:[this],m=a,k,l,n,p,r,u;if(!d||null!=b)for(;e.length;)for(k=e.shift(),l=0,n=k.length;l<n;l++)for(p=y(k[l]),m?p.triggerHandler("$destroy"):m=!m,r=0,p=(u=p.children()).length;r<p;r++)e.push(Ha(u[r]));return g.apply(this,arguments)}
+var g=Ha.fn[b],g=g.$original||g;e.$original=g;Ha.fn[b]=e}function se(b,a){var c,d,e=a.createDocumentFragment(),g=[];if(Gb.test(b)){c=c||e.appendChild(a.createElement("div"));d=(te.exec(b)||["",""])[1].toLowerCase();d=ea[d]||ea._default;c.innerHTML=d[1]+b.replace(ue,"<$1></$2>")+d[2];for(d=d[0];d--;)c=c.lastChild;g=g.concat(sa.call(c.childNodes,void 0));c=e.firstChild;c.textContent=""}else g.push(a.createTextNode(b));e.textContent="";e.innerHTML="";q(g,function(a){e.appendChild(a)});return e}function N(b){if(b instanceof
+N)return b;t(b)&&(b=ca(b));if(!(this instanceof N)){if(t(b)&&"<"!=b.charAt(0))throw Hb("nosel");return new N(b)}if(t(b)){var a;a=U;var c;b=(c=ve.exec(b))?[a.createElement(c[1])]:(c=se(b,a))?c.childNodes:[]}kc(this,b)}function Ib(b){return b.cloneNode(!0)}function Ia(b){lc(b);var a=0;for(b=b.childNodes||[];a<b.length;a++)Ia(b[a])}function mc(b,a,c,d){if(B(d))throw Hb("offargs");var e=la(b,"events");la(b,"handle")&&(D(a)?q(e,function(a,c){Ua(b,c,a);delete e[c]}):q(a.split(" "),function(a){D(c)?(Ua(b,
+a,e[a]),delete e[a]):Fa(e[a]||[],c)}))}function lc(b,a){var c=b[jb],d=Va[c];d&&(a?delete Va[c].data[a]:(d.handle&&(d.events.$destroy&&d.handle({},"$destroy"),mc(b)),delete Va[c],b[jb]=s))}function la(b,a,c){var d=b[jb],d=Va[d||-1];if(B(c))d||(b[jb]=d=++we,d=Va[d]={}),d[a]=c;else return d&&d[a]}function nc(b,a,c){var d=la(b,"data"),e=B(c),g=!e&&B(a),f=g&&!X(a);d||f||la(b,"data",d={});if(e)d[a]=c;else if(g){if(f)return d&&d[a];A(d,a)}else return d}function Jb(b,a){return b.getAttribute?-1<(" "+(b.getAttribute("class")||
+"")+" ").replace(/[\n\t]/g," ").indexOf(" "+a+" "):!1}function kb(b,a){a&&b.setAttribute&&q(a.split(" "),function(a){b.setAttribute("class",ca((" "+(b.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ").replace(" "+ca(a)+" "," ")))})}function lb(b,a){if(a&&b.setAttribute){var c=(" "+(b.getAttribute("class")||"")+" ").replace(/[\n\t]/g," ");q(a.split(" "),function(a){a=ca(a);-1===c.indexOf(" "+a+" ")&&(c+=a+" ")});b.setAttribute("class",ca(c))}}function kc(b,a){if(a){a=a.nodeName||!B(a.length)||
+Da(a)?[a]:a;for(var c=0;c<a.length;c++)b.push(a[c])}}function oc(b,a){return mb(b,"$"+(a||"ngController")+"Controller")}function mb(b,a,c){b=y(b);9==b[0].nodeType&&(b=b.find("html"));for(a=M(a)?a:[a];b.length;){for(var d=b[0],e=0,g=a.length;e<g;e++)if((c=b.data(a[e]))!==s)return c;b=y(d.parentNode||11===d.nodeType&&d.host)}}function pc(b){for(var a=0,c=b.childNodes;a<c.length;a++)Ia(c[a]);for(;b.firstChild;)b.removeChild(b.firstChild)}function qc(b,a){var c=nb[a.toLowerCase()];return c&&rc[b.nodeName]&&
+c}function xe(b,a){var c=function(c,e){c.preventDefault||(c.preventDefault=function(){c.returnValue=!1});c.stopPropagation||(c.stopPropagation=function(){c.cancelBubble=!0});c.target||(c.target=c.srcElement||U);if(D(c.defaultPrevented)){var g=c.preventDefault;c.preventDefault=function(){c.defaultPrevented=!0;g.call(c)};c.defaultPrevented=!1}c.isDefaultPrevented=function(){return c.defaultPrevented||!1===c.returnValue};var f=Xb(a[e||c.type]||[]);q(f,function(a){a.call(b,c)});8>=T?(c.preventDefault=
+null,c.stopPropagation=null,c.isDefaultPrevented=null):(delete c.preventDefault,delete c.stopPropagation,delete c.isDefaultPrevented)};c.elem=b;return c}function Ja(b){var a=typeof b,c;"object"==a&&null!==b?"function"==typeof(c=b.$$hashKey)?c=b.$$hashKey():c===s&&(c=b.$$hashKey=eb()):c=b;return a+":"+c}function Wa(b){q(b,this.put,this)}function sc(b){var a,c;"function"==typeof b?(a=b.$inject)||(a=[],b.length&&(c=b.toString().replace(ye,""),c=c.match(ze),q(c[1].split(Ae),function(b){b.replace(Be,function(b,
+c,d){a.push(d)})})),b.$inject=a):M(b)?(c=b.length-1,Ra(b[c],"fn"),a=b.slice(0,c)):Ra(b,"fn",!0);return a}function dc(b){function a(a){return function(b,c){if(X(b))q(b,Ub(a));else return a(b,c)}}function c(a,b){Ba(a,"service");if(P(b)||M(b))b=n.instantiate(b);if(!b.$get)throw Xa("pget",a);return l[a+h]=b}function d(a,b){return c(a,{$get:b})}function e(a){var b=[],c,d,g,h;q(a,function(a){if(!k.get(a)){k.put(a,!0);try{if(t(a))for(c=Sa(a),b=b.concat(e(c.requires)).concat(c._runBlocks),d=c._invokeQueue,
+g=0,h=d.length;g<h;g++){var f=d[g],m=n.get(f[0]);m[f[1]].apply(m,f[2])}else P(a)?b.push(n.invoke(a)):M(a)?b.push(n.invoke(a)):Ra(a,"module")}catch(l){throw M(a)&&(a=a[a.length-1]),l.message&&(l.stack&&-1==l.stack.indexOf(l.message))&&(l=l.message+"\n"+l.stack),Xa("modulerr",a,l.stack||l.message||l);}}});return b}function g(a,b){function c(d){if(a.hasOwnProperty(d)){if(a[d]===f)throw Xa("cdep",m.join(" <- "));return a[d]}try{return m.unshift(d),a[d]=f,a[d]=b(d)}catch(e){throw a[d]===f&&delete a[d],
+e;}finally{m.shift()}}function d(a,b,e){var g=[],h=sc(a),f,m,k;m=0;for(f=h.length;m<f;m++){k=h[m];if("string"!==typeof k)throw Xa("itkn",k);g.push(e&&e.hasOwnProperty(k)?e[k]:c(k))}a.$inject||(a=a[f]);return a.apply(b,g)}return{invoke:d,instantiate:function(a,b){var c=function(){},e;c.prototype=(M(a)?a[a.length-1]:a).prototype;c=new c;e=d(a,c,b);return X(e)||P(e)?e:c},get:c,annotate:sc,has:function(b){return l.hasOwnProperty(b+h)||a.hasOwnProperty(b)}}}var f={},h="Provider",m=[],k=new Wa,l={$provide:{provider:a(c),
+factory:a(d),service:a(function(a,b){return d(a,["$injector",function(a){return a.instantiate(b)}])}),value:a(function(a,b){return d(a,aa(b))}),constant:a(function(a,b){Ba(a,"constant");l[a]=b;p[a]=b}),decorator:function(a,b){var c=n.get(a+h),d=c.$get;c.$get=function(){var a=r.invoke(d,c);return r.invoke(b,null,{$delegate:a})}}}},n=l.$injector=g(l,function(){throw Xa("unpr",m.join(" <- "));}),p={},r=p.$injector=g(p,function(a){a=n.get(a+h);return r.invoke(a.$get,a)});q(e(b),function(a){r.invoke(a||
+C)});return r}function Td(){var b=!0;this.disableAutoScrolling=function(){b=!1};this.$get=["$window","$location","$rootScope",function(a,c,d){function e(a){var b=null;q(a,function(a){b||"a"!==I(a.nodeName)||(b=a)});return b}function g(){var b=c.hash(),d;b?(d=f.getElementById(b))?d.scrollIntoView():(d=e(f.getElementsByName(b)))?d.scrollIntoView():"top"===b&&a.scrollTo(0,0):a.scrollTo(0,0)}var f=a.document;b&&d.$watch(function(){return c.hash()},function(){d.$evalAsync(g)});return g}]}function pe(){this.$get=
+["$$rAF","$timeout",function(b,a){return b.supported?function(a){return b(a)}:function(b){return a(b,0,!1)}}]}function Ce(b,a,c,d){function e(a){try{a.apply(null,sa.call(arguments,1))}finally{if(u--,0===u)for(;z.length;)try{z.pop()()}catch(b){c.error(b)}}}function g(a,b){(function S(){q(K,function(a){a()});w=b(S,a)})()}function f(){x=null;H!=h.url()&&(H=h.url(),q(ma,function(a){a(h.url())}))}var h=this,m=a[0],k=b.location,l=b.history,n=b.setTimeout,p=b.clearTimeout,r={};h.isMock=!1;var u=0,z=[];h.$$completeOutstandingRequest=
+e;h.$$incOutstandingRequestCount=function(){u++};h.notifyWhenNoOutstandingRequests=function(a){q(K,function(a){a()});0===u?a():z.push(a)};var K=[],w;h.addPollFn=function(a){D(w)&&g(100,n);K.push(a);return a};var H=k.href,G=a.find("base"),x=null;h.url=function(a,c){k!==b.location&&(k=b.location);l!==b.history&&(l=b.history);if(a){if(H!=a)return H=a,d.history?c?l.replaceState(null,"",a):(l.pushState(null,"",a),G.attr("href",G.attr("href"))):(x=a,c?k.replace(a):k.href=a),h}else return x||k.href.replace(/%27/g,
+"'")};var ma=[],L=!1;h.onUrlChange=function(a){if(!L){if(d.history)y(b).on("popstate",f);if(d.hashchange)y(b).on("hashchange",f);else h.addPollFn(f);L=!0}ma.push(a);return a};h.baseHref=function(){var a=G.attr("href");return a?a.replace(/^(https?\:)?\/\/[^\/]*/,""):""};var Q={},da="",E=h.baseHref();h.cookies=function(a,b){var d,e,g,h;if(a)b===s?m.cookie=escape(a)+"=;path="+E+";expires=Thu, 01 Jan 1970 00:00:00 GMT":t(b)&&(d=(m.cookie=escape(a)+"="+escape(b)+";path="+E).length+1,4096<d&&c.warn("Cookie '"+
+a+"' possibly not set or overflowed because it was too large ("+d+" > 4096 bytes)!"));else{if(m.cookie!==da)for(da=m.cookie,d=da.split("; "),Q={},g=0;g<d.length;g++)e=d[g],h=e.indexOf("="),0<h&&(a=unescape(e.substring(0,h)),Q[a]===s&&(Q[a]=unescape(e.substring(h+1))));return Q}};h.defer=function(a,b){var c;u++;c=n(function(){delete r[c];e(a)},b||0);r[c]=!0;return c};h.defer.cancel=function(a){return r[a]?(delete r[a],p(a),e(C),!0):!1}}function Vd(){this.$get=["$window","$log","$sniffer","$document",
+function(b,a,c,d){return new Ce(b,d,a,c)}]}function Wd(){this.$get=function(){function b(b,d){function e(a){a!=n&&(p?p==a&&(p=a.n):p=a,g(a.n,a.p),g(a,n),n=a,n.n=null)}function g(a,b){a!=b&&(a&&(a.p=b),b&&(b.n=a))}if(b in a)throw v("$cacheFactory")("iid",b);var f=0,h=A({},d,{id:b}),m={},k=d&&d.capacity||Number.MAX_VALUE,l={},n=null,p=null;return a[b]={put:function(a,b){if(k<Number.MAX_VALUE){var c=l[a]||(l[a]={key:a});e(c)}if(!D(b))return a in m||f++,m[a]=b,f>k&&this.remove(p.key),b},get:function(a){if(k<
+Number.MAX_VALUE){var b=l[a];if(!b)return;e(b)}return m[a]},remove:function(a){if(k<Number.MAX_VALUE){var b=l[a];if(!b)return;b==n&&(n=b.p);b==p&&(p=b.n);g(b.n,b.p);delete l[a]}delete m[a];f--},removeAll:function(){m={};f=0;l={};n=p=null},destroy:function(){l=h=m=null;delete a[b]},info:function(){return A({},h,{size:f})}}}var a={};b.info=function(){var b={};q(a,function(a,e){b[e]=a.info()});return b};b.get=function(b){return a[b]};return b}}function le(){this.$get=["$cacheFactory",function(b){return b("templates")}]}
+function fc(b,a){var c={},d="Directive",e=/^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,g=/(([\d\w\-_]+)(?:\:([^;]+))?;?)/,f=/^(on[a-z]+|formaction)$/;this.directive=function m(a,e){Ba(a,"directive");t(a)?(Cb(e,"directiveFactory"),c.hasOwnProperty(a)||(c[a]=[],b.factory(a+d,["$injector","$exceptionHandler",function(b,d){var e=[];q(c[a],function(c,g){try{var f=b.invoke(c);P(f)?f={compile:aa(f)}:!f.compile&&f.link&&(f.compile=aa(f.link));f.priority=f.priority||0;f.index=g;f.name=f.name||a;f.require=f.require||
+f.controller&&f.name;f.restrict=f.restrict||"A";e.push(f)}catch(m){d(m)}});return e}])),c[a].push(e)):q(a,Ub(m));return this};this.aHrefSanitizationWhitelist=function(b){return B(b)?(a.aHrefSanitizationWhitelist(b),this):a.aHrefSanitizationWhitelist()};this.imgSrcSanitizationWhitelist=function(b){return B(b)?(a.imgSrcSanitizationWhitelist(b),this):a.imgSrcSanitizationWhitelist()};this.$get=["$injector","$interpolate","$exceptionHandler","$http","$templateCache","$parse","$controller","$rootScope",
+"$document","$sce","$animate","$$sanitizeUri",function(a,b,l,n,p,r,u,z,K,w,H,G){function x(a,b,c,d,e){a instanceof y||(a=y(a));q(a,function(b,c){3==b.nodeType&&b.nodeValue.match(/\S+/)&&(a[c]=y(b).wrap("<span></span>").parent()[0])});var g=L(a,b,a,c,d,e);ma(a,"ng-scope");return function(b,c,d){Cb(b,"scope");var e=c?Ka.clone.call(a):a;q(d,function(a,b){e.data("$"+b+"Controller",a)});d=0;for(var f=e.length;d<f;d++){var m=e[d].nodeType;1!==m&&9!==m||e.eq(d).data("$scope",b)}c&&c(e,b);g&&g(b,e,e);return e}}
+function ma(a,b){try{a.addClass(b)}catch(c){}}function L(a,b,c,d,e,g){function f(a,c,d,e){var g,k,l,n,r,p,u;g=c.length;var J=Array(g);for(r=0;r<g;r++)J[r]=c[r];u=r=0;for(p=m.length;r<p;u++)k=J[u],c=m[r++],g=m[r++],l=y(k),c?(c.scope?(n=a.$new(),l.data("$scope",n)):n=a,(l=c.transclude)||!e&&b?c(g,n,k,d,Q(a,l||b)):c(g,n,k,d,e)):g&&g(a,k.childNodes,s,e)}for(var m=[],k,l,n,r,p=0;p<a.length;p++)k=new Kb,l=da(a[p],[],k,0===p?d:s,e),(g=l.length?ia(l,a[p],k,b,c,null,[],[],g):null)&&g.scope&&ma(y(a[p]),"ng-scope"),
+k=g&&g.terminal||!(n=a[p].childNodes)||!n.length?null:L(n,g?g.transclude:b),m.push(g,k),r=r||g||k,g=null;return r?f:null}function Q(a,b){return function(c,d,e){var g=!1;c||(c=a.$new(),g=c.$$transcluded=!0);d=b(c,d,e);if(g)d.on("$destroy",hb(c,c.$destroy));return d}}function da(a,b,c,d,f){var m=c.$attr,k;switch(a.nodeType){case 1:S(b,na(La(a).toLowerCase()),"E",d,f);var l,n,r;k=a.attributes;for(var p=0,u=k&&k.length;p<u;p++){var z=!1,K=!1;l=k[p];if(!T||8<=T||l.specified){n=l.name;r=na(n);W.test(r)&&
+(n=ib(r.substr(6),"-"));var H=r.replace(/(Start|End)$/,"");r===H+"Start"&&(z=n,K=n.substr(0,n.length-5)+"end",n=n.substr(0,n.length-6));r=na(n.toLowerCase());m[r]=n;c[r]=l=ca(l.value);qc(a,r)&&(c[r]=!0);N(a,b,l,r);S(b,r,"A",d,f,z,K)}}a=a.className;if(t(a)&&""!==a)for(;k=g.exec(a);)r=na(k[2]),S(b,r,"C",d,f)&&(c[r]=ca(k[3])),a=a.substr(k.index+k[0].length);break;case 3:v(b,a.nodeValue);break;case 8:try{if(k=e.exec(a.nodeValue))r=na(k[1]),S(b,r,"M",d,f)&&(c[r]=ca(k[2]))}catch(x){}}b.sort(D);return b}
+function E(a,b,c){var d=[],e=0;if(b&&a.hasAttribute&&a.hasAttribute(b)){do{if(!a)throw ja("uterdir",b,c);1==a.nodeType&&(a.hasAttribute(b)&&e++,a.hasAttribute(c)&&e--);d.push(a);a=a.nextSibling}while(0<e)}else d.push(a);return y(d)}function R(a,b,c){return function(d,e,g,f,k){e=E(e[0],b,c);return a(d,e,g,f,k)}}function ia(a,c,d,e,g,f,m,n,p){function z(a,b,c,d){if(a){c&&(a=R(a,c,d));a.require=F.require;if(Q===F||F.$$isolateScope)a=uc(a,{isolateScope:!0});m.push(a)}if(b){c&&(b=R(b,c,d));b.require=F.require;
+if(Q===F||F.$$isolateScope)b=uc(b,{isolateScope:!0});n.push(b)}}function K(a,b,c){var d,e="data",g=!1;if(t(a)){for(;"^"==(d=a.charAt(0))||"?"==d;)a=a.substr(1),"^"==d&&(e="inheritedData"),g=g||"?"==d;d=null;c&&"data"===e&&(d=c[a]);d=d||b[e]("$"+a+"Controller");if(!d&&!g)throw ja("ctreq",a,v);}else M(a)&&(d=[],q(a,function(a){d.push(K(a,b,c))}));return d}function H(a,e,g,f,p){function z(a,b){var c;2>arguments.length&&(b=a,a=s);A&&(c=da);return p(a,b,c)}var J,x,w,G,R,E,da={},ob;J=c===g?d:Xb(d,new Kb(y(g),
+d.$attr));x=J.$$element;if(Q){var S=/^\s*([@=&])(\??)\s*(\w*)\s*$/;f=y(g);E=e.$new(!0);ia&&ia===Q.$$originalDirective?f.data("$isolateScope",E):f.data("$isolateScopeNoTemplate",E);ma(f,"ng-isolate-scope");q(Q.scope,function(a,c){var d=a.match(S)||[],g=d[3]||c,f="?"==d[2],d=d[1],m,l,n,p;E.$$isolateBindings[c]=d+g;switch(d){case "@":J.$observe(g,function(a){E[c]=a});J.$$observers[g].$$scope=e;J[g]&&(E[c]=b(J[g])(e));break;case "=":if(f&&!J[g])break;l=r(J[g]);p=l.literal?za:function(a,b){return a===
+b};n=l.assign||function(){m=E[c]=l(e);throw ja("nonassign",J[g],Q.name);};m=E[c]=l(e);E.$watch(function(){var a=l(e);p(a,E[c])||(p(a,m)?n(e,a=E[c]):E[c]=a);return m=a},null,l.literal);break;case "&":l=r(J[g]);E[c]=function(a){return l(e,a)};break;default:throw ja("iscp",Q.name,c,a);}})}ob=p&&z;L&&q(L,function(a){var b={$scope:a===Q||a.$$isolateScope?E:e,$element:x,$attrs:J,$transclude:ob},c;R=a.controller;"@"==R&&(R=J[a.name]);c=u(R,b);da[a.name]=c;A||x.data("$"+a.name+"Controller",c);a.controllerAs&&
+(b.$scope[a.controllerAs]=c)});f=0;for(w=m.length;f<w;f++)try{G=m[f],G(G.isolateScope?E:e,x,J,G.require&&K(G.require,x,da),ob)}catch(F){l(F,ha(x))}f=e;Q&&(Q.template||null===Q.templateUrl)&&(f=E);a&&a(f,g.childNodes,s,p);for(f=n.length-1;0<=f;f--)try{G=n[f],G(G.isolateScope?E:e,x,J,G.require&&K(G.require,x,da),ob)}catch(B){l(B,ha(x))}}p=p||{};for(var w=-Number.MAX_VALUE,G,L=p.controllerDirectives,Q=p.newIsolateScopeDirective,ia=p.templateDirective,S=p.nonTlbTranscludeDirective,D=!1,A=p.hasElementTranscludeDirective,
+Z=d.$$element=y(c),F,v,V,Ya=e,O,N=0,oa=a.length;N<oa;N++){F=a[N];var T=F.$$start,W=F.$$end;T&&(Z=E(c,T,W));V=s;if(w>F.priority)break;if(V=F.scope)G=G||F,F.templateUrl||(I("new/isolated scope",Q,F,Z),X(V)&&(Q=F));v=F.name;!F.templateUrl&&F.controller&&(V=F.controller,L=L||{},I("'"+v+"' controller",L[v],F,Z),L[v]=F);if(V=F.transclude)D=!0,F.$$tlb||(I("transclusion",S,F,Z),S=F),"element"==V?(A=!0,w=F.priority,V=E(c,T,W),Z=d.$$element=y(U.createComment(" "+v+": "+d[v]+" ")),c=Z[0],pb(g,y(sa.call(V,0)),
+c),Ya=x(V,e,w,f&&f.name,{nonTlbTranscludeDirective:S})):(V=y(Ib(c)).contents(),Z.empty(),Ya=x(V,e));if(F.template)if(I("template",ia,F,Z),ia=F,V=P(F.template)?F.template(Z,d):F.template,V=Y(V),F.replace){f=F;V=Gb.test(V)?y(V):[];c=V[0];if(1!=V.length||1!==c.nodeType)throw ja("tplrt",v,"");pb(g,Z,c);oa={$attr:{}};V=da(c,[],oa);var $=a.splice(N+1,a.length-(N+1));Q&&tc(V);a=a.concat(V).concat($);B(d,oa);oa=a.length}else Z.html(V);if(F.templateUrl)I("template",ia,F,Z),ia=F,F.replace&&(f=F),H=C(a.splice(N,
+a.length-N),Z,d,g,Ya,m,n,{controllerDirectives:L,newIsolateScopeDirective:Q,templateDirective:ia,nonTlbTranscludeDirective:S}),oa=a.length;else if(F.compile)try{O=F.compile(Z,d,Ya),P(O)?z(null,O,T,W):O&&z(O.pre,O.post,T,W)}catch(aa){l(aa,ha(Z))}F.terminal&&(H.terminal=!0,w=Math.max(w,F.priority))}H.scope=G&&!0===G.scope;H.transclude=D&&Ya;p.hasElementTranscludeDirective=A;return H}function tc(a){for(var b=0,c=a.length;b<c;b++)a[b]=Wb(a[b],{$$isolateScope:!0})}function S(b,e,g,f,k,n,r){if(e===k)return null;
+k=null;if(c.hasOwnProperty(e)){var p;e=a.get(e+d);for(var u=0,z=e.length;u<z;u++)try{p=e[u],(f===s||f>p.priority)&&-1!=p.restrict.indexOf(g)&&(n&&(p=Wb(p,{$$start:n,$$end:r})),b.push(p),k=p)}catch(K){l(K)}}return k}function B(a,b){var c=b.$attr,d=a.$attr,e=a.$$element;q(a,function(d,e){"$"!=e.charAt(0)&&(b[e]&&(d+=("style"===e?";":" ")+b[e]),a.$set(e,d,!0,c[e]))});q(b,function(b,g){"class"==g?(ma(e,b),a["class"]=(a["class"]?a["class"]+" ":"")+b):"style"==g?(e.attr("style",e.attr("style")+";"+b),a.style=
+(a.style?a.style+";":"")+b):"$"==g.charAt(0)||a.hasOwnProperty(g)||(a[g]=b,d[g]=c[g])})}function C(a,b,c,d,e,g,f,k){var m=[],l,r,u=b[0],z=a.shift(),K=A({},z,{templateUrl:null,transclude:null,replace:null,$$originalDirective:z}),x=P(z.templateUrl)?z.templateUrl(b,c):z.templateUrl;b.empty();n.get(w.getTrustedResourceUrl(x),{cache:p}).success(function(n){var p,H;n=Y(n);if(z.replace){n=Gb.test(n)?y(n):[];p=n[0];if(1!=n.length||1!==p.nodeType)throw ja("tplrt",z.name,x);n={$attr:{}};pb(d,b,p);var w=da(p,
+[],n);X(z.scope)&&tc(w);a=w.concat(a);B(c,n)}else p=u,b.html(n);a.unshift(K);l=ia(a,p,c,e,b,z,g,f,k);q(d,function(a,c){a==p&&(d[c]=b[0])});for(r=L(b[0].childNodes,e);m.length;){n=m.shift();H=m.shift();var G=m.shift(),R=m.shift(),w=b[0];if(H!==u){var E=H.className;k.hasElementTranscludeDirective&&z.replace||(w=Ib(p));pb(G,y(H),w);ma(y(w),E)}H=l.transclude?Q(n,l.transclude):R;l(r,n,w,d,H)}m=null}).error(function(a,b,c,d){throw ja("tpload",d.url);});return function(a,b,c,d,e){m?(m.push(b),m.push(c),
+m.push(d),m.push(e)):l(r,b,c,d,e)}}function D(a,b){var c=b.priority-a.priority;return 0!==c?c:a.name!==b.name?a.name<b.name?-1:1:a.index-b.index}function I(a,b,c,d){if(b)throw ja("multidir",b.name,c.name,a,ha(d));}function v(a,c){var d=b(c,!0);d&&a.push({priority:0,compile:aa(function(a,b){var c=b.parent(),e=c.data("$binding")||[];e.push(d);ma(c.data("$binding",e),"ng-binding");a.$watch(d,function(a){b[0].nodeValue=a})})})}function O(a,b){if("srcdoc"==b)return w.HTML;var c=La(a);if("xlinkHref"==b||
+"FORM"==c&&"action"==b||"IMG"!=c&&("src"==b||"ngSrc"==b))return w.RESOURCE_URL}function N(a,c,d,e){var g=b(d,!0);if(g){if("multiple"===e&&"SELECT"===La(a))throw ja("selmulti",ha(a));c.push({priority:100,compile:function(){return{pre:function(c,d,m){d=m.$$observers||(m.$$observers={});if(f.test(e))throw ja("nodomevents");if(g=b(m[e],!0,O(a,e)))m[e]=g(c),(d[e]||(d[e]=[])).$$inter=!0,(m.$$observers&&m.$$observers[e].$$scope||c).$watch(g,function(a,b){"class"===e&&a!=b?m.$updateClass(a,b):m.$set(e,a)})}}}})}}
+function pb(a,b,c){var d=b[0],e=b.length,g=d.parentNode,f,m;if(a)for(f=0,m=a.length;f<m;f++)if(a[f]==d){a[f++]=c;m=f+e-1;for(var k=a.length;f<k;f++,m++)m<k?a[f]=a[m]:delete a[f];a.length-=e-1;break}g&&g.replaceChild(c,d);a=U.createDocumentFragment();a.appendChild(d);c[y.expando]=d[y.expando];d=1;for(e=b.length;d<e;d++)g=b[d],y(g).remove(),a.appendChild(g),delete b[d];b[0]=c;b.length=1}function uc(a,b){return A(function(){return a.apply(null,arguments)},a,b)}var Kb=function(a,b){this.$$element=a;this.$attr=
+b||{}};Kb.prototype={$normalize:na,$addClass:function(a){a&&0<a.length&&H.addClass(this.$$element,a)},$removeClass:function(a){a&&0<a.length&&H.removeClass(this.$$element,a)},$updateClass:function(a,b){var c=vc(a,b),d=vc(b,a);0===c.length?H.removeClass(this.$$element,d):0===d.length?H.addClass(this.$$element,c):H.setClass(this.$$element,c,d)},$set:function(a,b,c,d){var e=qc(this.$$element[0],a);e&&(this.$$element.prop(a,b),d=e);this[a]=b;d?this.$attr[a]=d:(d=this.$attr[a])||(this.$attr[a]=d=ib(a,
+"-"));e=La(this.$$element);if("A"===e&&"href"===a||"IMG"===e&&"src"===a)this[a]=b=G(b,"src"===a);!1!==c&&(null===b||b===s?this.$$element.removeAttr(d):this.$$element.attr(d,b));(c=this.$$observers)&&q(c[a],function(a){try{a(b)}catch(c){l(c)}})},$observe:function(a,b){var c=this,d=c.$$observers||(c.$$observers={}),e=d[a]||(d[a]=[]);e.push(b);z.$evalAsync(function(){e.$$inter||b(c[a])});return function(){Fa(e,b)}}};var Z=b.startSymbol(),oa=b.endSymbol(),Y="{{"==Z||"}}"==oa?Ea:function(a){return a.replace(/\{\{/g,
+Z).replace(/}}/g,oa)},W=/^ngAttr[A-Z]/;return x}]}function na(b){return Ta(b.replace(De,""))}function vc(b,a){var c="",d=b.split(/\s+/),e=a.split(/\s+/),g=0;a:for(;g<d.length;g++){for(var f=d[g],h=0;h<e.length;h++)if(f==e[h])continue a;c+=(0<c.length?" ":"")+f}return c}function Xd(){var b={},a=/^(\S+)(\s+as\s+(\w+))?$/;this.register=function(a,d){Ba(a,"controller");X(a)?A(b,a):b[a]=d};this.$get=["$injector","$window",function(c,d){return function(e,g){var f,h,m;t(e)&&(f=e.match(a),h=f[1],m=f[3],e=
+b.hasOwnProperty(h)?b[h]:ec(g.$scope,h,!0)||ec(d,h,!0),Ra(e,h,!0));f=c.instantiate(e,g);if(m){if(!g||"object"!=typeof g.$scope)throw v("$controller")("noscp",h||e.name,m);g.$scope[m]=f}return f}}]}function Yd(){this.$get=["$window",function(b){return y(b.document)}]}function Zd(){this.$get=["$log",function(b){return function(a,c){b.error.apply(b,arguments)}}]}function wc(b){var a={},c,d,e;if(!b)return a;q(b.split("\n"),function(b){e=b.indexOf(":");c=I(ca(b.substr(0,e)));d=ca(b.substr(e+1));c&&(a[c]=
+a[c]?a[c]+(", "+d):d)});return a}function xc(b){var a=X(b)?b:s;return function(c){a||(a=wc(b));return c?a[I(c)]||null:a}}function yc(b,a,c){if(P(c))return c(b,a);q(c,function(c){b=c(b,a)});return b}function be(){var b=/^\s*(\[|\{[^\{])/,a=/[\}\]]\s*$/,c=/^\)\]\}',?\n/,d={"Content-Type":"application/json;charset=utf-8"},e=this.defaults={transformResponse:[function(d){t(d)&&(d=d.replace(c,""),b.test(d)&&a.test(d)&&(d=Zb(d)));return d}],transformRequest:[function(a){return X(a)&&"[object File]"!==ya.call(a)&&
+"[object Blob]"!==ya.call(a)?ta(a):a}],headers:{common:{Accept:"application/json, text/plain, */*"},post:ba(d),put:ba(d),patch:ba(d)},xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN"},g=this.interceptors=[],f=this.responseInterceptors=[];this.$get=["$httpBackend","$browser","$cacheFactory","$rootScope","$q","$injector",function(a,b,c,d,n,p){function r(a){function c(a){var b=A({},a,{data:yc(a.data,a.headers,d.transformResponse)});return 200<=a.status&&300>a.status?b:n.reject(b)}var d={method:"get",
+transformRequest:e.transformRequest,transformResponse:e.transformResponse},g=function(a){function b(a){var c;q(a,function(b,d){P(b)&&(c=b(),null!=c?a[d]=c:delete a[d])})}var c=e.headers,d=A({},a.headers),g,f,c=A({},c.common,c[I(a.method)]);b(c);b(d);a:for(g in c){a=I(g);for(f in d)if(I(f)===a)continue a;d[g]=c[g]}return d}(a);A(d,a);d.headers=g;d.method=Ga(d.method);(a=Lb(d.url)?b.cookies()[d.xsrfCookieName||e.xsrfCookieName]:s)&&(g[d.xsrfHeaderName||e.xsrfHeaderName]=a);var f=[function(a){g=a.headers;
+var b=yc(a.data,xc(g),a.transformRequest);D(a.data)&&q(g,function(a,b){"content-type"===I(b)&&delete g[b]});D(a.withCredentials)&&!D(e.withCredentials)&&(a.withCredentials=e.withCredentials);return u(a,b,g).then(c,c)},s],h=n.when(d);for(q(w,function(a){(a.request||a.requestError)&&f.unshift(a.request,a.requestError);(a.response||a.responseError)&&f.push(a.response,a.responseError)});f.length;){a=f.shift();var k=f.shift(),h=h.then(a,k)}h.success=function(a){h.then(function(b){a(b.data,b.status,b.headers,
+d)});return h};h.error=function(a){h.then(null,function(b){a(b.data,b.status,b.headers,d)});return h};return h}function u(b,c,g){function f(a,b,c,e){w&&(200<=a&&300>a?w.put(s,[a,b,wc(c),e]):w.remove(s));m(b,a,c,e);d.$$phase||d.$apply()}function m(a,c,d,e){c=Math.max(c,0);(200<=c&&300>c?p.resolve:p.reject)({data:a,status:c,headers:xc(d),config:b,statusText:e})}function k(){var a=gb(r.pendingRequests,b);-1!==a&&r.pendingRequests.splice(a,1)}var p=n.defer(),u=p.promise,w,q,s=z(b.url,b.params);r.pendingRequests.push(b);
+u.then(k,k);(b.cache||e.cache)&&(!1!==b.cache&&"GET"==b.method)&&(w=X(b.cache)?b.cache:X(e.cache)?e.cache:K);if(w)if(q=w.get(s),B(q)){if(q.then)return q.then(k,k),q;M(q)?m(q[1],q[0],ba(q[2]),q[3]):m(q,200,{},"OK")}else w.put(s,u);D(q)&&a(b.method,s,c,f,g,b.timeout,b.withCredentials,b.responseType);return u}function z(a,b){if(!b)return a;var c=[];ad(b,function(a,b){null===a||D(a)||(M(a)||(a=[a]),q(a,function(a){X(a)&&(a=ta(a));c.push(Aa(b)+"="+Aa(a))}))});0<c.length&&(a+=(-1==a.indexOf("?")?"?":"&")+
+c.join("&"));return a}var K=c("$http"),w=[];q(g,function(a){w.unshift(t(a)?p.get(a):p.invoke(a))});q(f,function(a,b){var c=t(a)?p.get(a):p.invoke(a);w.splice(b,0,{response:function(a){return c(n.when(a))},responseError:function(a){return c(n.reject(a))}})});r.pendingRequests=[];(function(a){q(arguments,function(a){r[a]=function(b,c){return r(A(c||{},{method:a,url:b}))}})})("get","delete","head","jsonp");(function(a){q(arguments,function(a){r[a]=function(b,c,d){return r(A(d||{},{method:a,url:b,data:c}))}})})("post",
+"put");r.defaults=e;return r}]}function Ee(b){if(8>=T&&(!b.match(/^(get|post|head|put|delete|options)$/i)||!O.XMLHttpRequest))return new O.ActiveXObject("Microsoft.XMLHTTP");if(O.XMLHttpRequest)return new O.XMLHttpRequest;throw v("$httpBackend")("noxhr");}function ce(){this.$get=["$browser","$window","$document",function(b,a,c){return Fe(b,Ee,b.defer,a.angular.callbacks,c[0])}]}function Fe(b,a,c,d,e){function g(a,b,c){var g=e.createElement("script"),f=null;g.type="text/javascript";g.src=a;g.async=
+!0;f=function(a){Ua(g,"load",f);Ua(g,"error",f);e.body.removeChild(g);g=null;var h=-1,u="unknown";a&&("load"!==a.type||d[b].called||(a={type:"error"}),u=a.type,h="error"===a.type?404:200);c&&c(h,u)};qb(g,"load",f);qb(g,"error",f);e.body.appendChild(g);return f}var f=-1;return function(e,m,k,l,n,p,r,u){function z(){w=f;G&&G();x&&x.abort()}function K(a,d,e,g,f){L&&c.cancel(L);G=x=null;0===d&&(d=e?200:"file"==ua(m).protocol?404:0);a(1223===d?204:d,e,g,f||"");b.$$completeOutstandingRequest(C)}var w;b.$$incOutstandingRequestCount();
+m=m||b.url();if("jsonp"==I(e)){var H="_"+(d.counter++).toString(36);d[H]=function(a){d[H].data=a;d[H].called=!0};var G=g(m.replace("JSON_CALLBACK","angular.callbacks."+H),H,function(a,b){K(l,a,d[H].data,"",b);d[H]=C})}else{var x=a(e);x.open(e,m,!0);q(n,function(a,b){B(a)&&x.setRequestHeader(b,a)});x.onreadystatechange=function(){if(x&&4==x.readyState){var a=null,b=null;w!==f&&(a=x.getAllResponseHeaders(),b="response"in x?x.response:x.responseText);K(l,w||x.status,b,a,x.statusText||"")}};r&&(x.withCredentials=
+!0);if(u)try{x.responseType=u}catch(s){if("json"!==u)throw s;}x.send(k||null)}if(0<p)var L=c(z,p);else p&&p.then&&p.then(z)}}function $d(){var b="{{",a="}}";this.startSymbol=function(a){return a?(b=a,this):b};this.endSymbol=function(b){return b?(a=b,this):a};this.$get=["$parse","$exceptionHandler","$sce",function(c,d,e){function g(g,k,l){for(var n,p,r=0,u=[],z=g.length,K=!1,w=[];r<z;)-1!=(n=g.indexOf(b,r))&&-1!=(p=g.indexOf(a,n+f))?(r!=n&&u.push(g.substring(r,n)),u.push(r=c(K=g.substring(n+f,p))),
+r.exp=K,r=p+h,K=!0):(r!=z&&u.push(g.substring(r)),r=z);(z=u.length)||(u.push(""),z=1);if(l&&1<u.length)throw zc("noconcat",g);if(!k||K)return w.length=z,r=function(a){try{for(var b=0,c=z,f;b<c;b++)"function"==typeof(f=u[b])&&(f=f(a),f=l?e.getTrusted(l,f):e.valueOf(f),null===f||D(f)?f="":"string"!=typeof f&&(f=ta(f))),w[b]=f;return w.join("")}catch(h){a=zc("interr",g,h.toString()),d(a)}},r.exp=g,r.parts=u,r}var f=b.length,h=a.length;g.startSymbol=function(){return b};g.endSymbol=function(){return a};
+return g}]}function ae(){this.$get=["$rootScope","$window","$q",function(b,a,c){function d(d,f,h,m){var k=a.setInterval,l=a.clearInterval,n=c.defer(),p=n.promise,r=0,u=B(m)&&!m;h=B(h)?h:0;p.then(null,null,d);p.$$intervalId=k(function(){n.notify(r++);0<h&&r>=h&&(n.resolve(r),l(p.$$intervalId),delete e[p.$$intervalId]);u||b.$apply()},f);e[p.$$intervalId]=n;return p}var e={};d.cancel=function(a){return a&&a.$$intervalId in e?(e[a.$$intervalId].reject("canceled"),clearInterval(a.$$intervalId),delete e[a.$$intervalId],
+!0):!1};return d}]}function jd(){this.$get=function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3,lgSize:3},{minInt:1,minFrac:2,maxFrac:2,posPre:"\u00a4",posSuf:"",negPre:"(\u00a4",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"},DATETIME_FORMATS:{MONTH:"January February March April May June July August September October November December".split(" "),SHORTMONTH:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),
+DAY:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),SHORTDAY:"Sun Mon Tue Wed Thu Fri Sat".split(" "),AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a","short":"M/d/yy h:mm a",fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a",shortTime:"h:mm a"},pluralCat:function(b){return 1===b?"one":"other"}}}}function Ac(b){b=b.split("/");for(var a=b.length;a--;)b[a]=Bb(b[a]);return b.join("/")}function Bc(b,a,c){b=ua(b,c);a.$$protocol=
+b.protocol;a.$$host=b.hostname;a.$$port=Y(b.port)||Ge[b.protocol]||null}function Cc(b,a,c){var d="/"!==b.charAt(0);d&&(b="/"+b);b=ua(b,c);a.$$path=decodeURIComponent(d&&"/"===b.pathname.charAt(0)?b.pathname.substring(1):b.pathname);a.$$search=ac(b.search);a.$$hash=decodeURIComponent(b.hash);a.$$path&&"/"!=a.$$path.charAt(0)&&(a.$$path="/"+a.$$path)}function pa(b,a){if(0===a.indexOf(b))return a.substr(b.length)}function Za(b){var a=b.indexOf("#");return-1==a?b:b.substr(0,a)}function Mb(b){return b.substr(0,
+Za(b).lastIndexOf("/")+1)}function Dc(b,a){this.$$html5=!0;a=a||"";var c=Mb(b);Bc(b,this,b);this.$$parse=function(a){var e=pa(c,a);if(!t(e))throw Nb("ipthprfx",a,c);Cc(e,this,b);this.$$path||(this.$$path="/");this.$$compose()};this.$$compose=function(){var a=bc(this.$$search),b=this.$$hash?"#"+Bb(this.$$hash):"";this.$$url=Ac(this.$$path)+(a?"?"+a:"")+b;this.$$absUrl=c+this.$$url.substr(1)};this.$$rewrite=function(d){var e;if((e=pa(b,d))!==s)return d=e,(e=pa(a,e))!==s?c+(pa("/",e)||e):b+d;if((e=pa(c,
+d))!==s)return c+e;if(c==d+"/")return c}}function Ob(b,a){var c=Mb(b);Bc(b,this,b);this.$$parse=function(d){var e=pa(b,d)||pa(c,d),e="#"==e.charAt(0)?pa(a,e):this.$$html5?e:"";if(!t(e))throw Nb("ihshprfx",d,a);Cc(e,this,b);d=this.$$path;var g=/^\/?.*?:(\/.*)/;0===e.indexOf(b)&&(e=e.replace(b,""));g.exec(e)||(d=(e=g.exec(d))?e[1]:d);this.$$path=d;this.$$compose()};this.$$compose=function(){var c=bc(this.$$search),e=this.$$hash?"#"+Bb(this.$$hash):"";this.$$url=Ac(this.$$path)+(c?"?"+c:"")+e;this.$$absUrl=
+b+(this.$$url?a+this.$$url:"")};this.$$rewrite=function(a){if(Za(b)==Za(a))return a}}function Ec(b,a){this.$$html5=!0;Ob.apply(this,arguments);var c=Mb(b);this.$$rewrite=function(d){var e;if(b==Za(d))return d;if(e=pa(c,d))return b+a+e;if(c===d+"/")return c}}function rb(b){return function(){return this[b]}}function Fc(b,a){return function(c){if(D(c))return this[b];this[b]=a(c);this.$$compose();return this}}function de(){var b="",a=!1;this.hashPrefix=function(a){return B(a)?(b=a,this):b};this.html5Mode=
+function(b){return B(b)?(a=b,this):a};this.$get=["$rootScope","$browser","$sniffer","$rootElement",function(c,d,e,g){function f(a){c.$broadcast("$locationChangeSuccess",h.absUrl(),a)}var h,m=d.baseHref(),k=d.url();a?(m=k.substring(0,k.indexOf("/",k.indexOf("//")+2))+(m||"/"),e=e.history?Dc:Ec):(m=Za(k),e=Ob);h=new e(m,"#"+b);h.$$parse(h.$$rewrite(k));g.on("click",function(a){if(!a.ctrlKey&&!a.metaKey&&2!=a.which){for(var b=y(a.target);"a"!==I(b[0].nodeName);)if(b[0]===g[0]||!(b=b.parent())[0])return;
+var e=b.prop("href");X(e)&&"[object SVGAnimatedString]"===e.toString()&&(e=ua(e.animVal).href);var f=h.$$rewrite(e);e&&(!b.attr("target")&&f&&!a.isDefaultPrevented())&&(a.preventDefault(),f!=d.url()&&(h.$$parse(f),c.$apply(),O.angular["ff-684208-preventDefault"]=!0))}});h.absUrl()!=k&&d.url(h.absUrl(),!0);d.onUrlChange(function(a){h.absUrl()!=a&&(c.$evalAsync(function(){var b=h.absUrl();h.$$parse(a);c.$broadcast("$locationChangeStart",a,b).defaultPrevented?(h.$$parse(b),d.url(b)):f(b)}),c.$$phase||
+c.$digest())});var l=0;c.$watch(function(){var a=d.url(),b=h.$$replace;l&&a==h.absUrl()||(l++,c.$evalAsync(function(){c.$broadcast("$locationChangeStart",h.absUrl(),a).defaultPrevented?h.$$parse(a):(d.url(h.absUrl(),b),f(a))}));h.$$replace=!1;return l});return h}]}function ee(){var b=!0,a=this;this.debugEnabled=function(a){return B(a)?(b=a,this):b};this.$get=["$window",function(c){function d(a){a instanceof Error&&(a.stack?a=a.message&&-1===a.stack.indexOf(a.message)?"Error: "+a.message+"\n"+a.stack:
+a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function e(a){var b=c.console||{},e=b[a]||b.log||C;a=!1;try{a=!!e.apply}catch(m){}return a?function(){var a=[];q(arguments,function(b){a.push(d(b))});return e.apply(b,a)}:function(a,b){e(a,null==b?"":b)}}return{log:e("log"),info:e("info"),warn:e("warn"),error:e("error"),debug:function(){var c=e("debug");return function(){b&&c.apply(a,arguments)}}()}}]}function fa(b,a){if("constructor"===b)throw Ca("isecfld",a);return b}function $a(b,
+a){if(b){if(b.constructor===b)throw Ca("isecfn",a);if(b.document&&b.location&&b.alert&&b.setInterval)throw Ca("isecwindow",a);if(b.children&&(b.nodeName||b.prop&&b.attr&&b.find))throw Ca("isecdom",a);}return b}function sb(b,a,c,d,e){e=e||{};a=a.split(".");for(var g,f=0;1<a.length;f++){g=fa(a.shift(),d);var h=b[g];h||(h={},b[g]=h);b=h;b.then&&e.unwrapPromises&&(va(d),"$$v"in b||function(a){a.then(function(b){a.$$v=b})}(b),b.$$v===s&&(b.$$v={}),b=b.$$v)}g=fa(a.shift(),d);return b[g]=c}function Gc(b,
+a,c,d,e,g,f){fa(b,g);fa(a,g);fa(c,g);fa(d,g);fa(e,g);return f.unwrapPromises?function(f,m){var k=m&&m.hasOwnProperty(b)?m:f,l;if(null==k)return k;(k=k[b])&&k.then&&(va(g),"$$v"in k||(l=k,l.$$v=s,l.then(function(a){l.$$v=a})),k=k.$$v);if(!a)return k;if(null==k)return s;(k=k[a])&&k.then&&(va(g),"$$v"in k||(l=k,l.$$v=s,l.then(function(a){l.$$v=a})),k=k.$$v);if(!c)return k;if(null==k)return s;(k=k[c])&&k.then&&(va(g),"$$v"in k||(l=k,l.$$v=s,l.then(function(a){l.$$v=a})),k=k.$$v);if(!d)return k;if(null==
+k)return s;(k=k[d])&&k.then&&(va(g),"$$v"in k||(l=k,l.$$v=s,l.then(function(a){l.$$v=a})),k=k.$$v);if(!e)return k;if(null==k)return s;(k=k[e])&&k.then&&(va(g),"$$v"in k||(l=k,l.$$v=s,l.then(function(a){l.$$v=a})),k=k.$$v);return k}:function(g,f){var k=f&&f.hasOwnProperty(b)?f:g;if(null==k)return k;k=k[b];if(!a)return k;if(null==k)return s;k=k[a];if(!c)return k;if(null==k)return s;k=k[c];if(!d)return k;if(null==k)return s;k=k[d];return e?null==k?s:k=k[e]:k}}function He(b,a){fa(b,a);return function(a,
+d){return null==a?s:(d&&d.hasOwnProperty(b)?d:a)[b]}}function Ie(b,a,c){fa(b,c);fa(a,c);return function(c,e){if(null==c)return s;c=(e&&e.hasOwnProperty(b)?e:c)[b];return null==c?s:c[a]}}function Hc(b,a,c){if(Pb.hasOwnProperty(b))return Pb[b];var d=b.split("."),e=d.length,g;if(a.unwrapPromises||1!==e)if(a.unwrapPromises||2!==e)if(a.csp)g=6>e?Gc(d[0],d[1],d[2],d[3],d[4],c,a):function(b,g){var f=0,h;do h=Gc(d[f++],d[f++],d[f++],d[f++],d[f++],c,a)(b,g),g=s,b=h;while(f<e);return h};else{var f="var p;\n";
+q(d,function(b,d){fa(b,c);f+="if(s == null) return undefined;\ns="+(d?"s":'((k&&k.hasOwnProperty("'+b+'"))?k:s)')+'["'+b+'"];\n'+(a.unwrapPromises?'if (s && s.then) {\n pw("'+c.replace(/(["\r\n])/g,"\\$1")+'");\n if (!("$$v" in s)) {\n p=s;\n p.$$v = undefined;\n p.then(function(v) {p.$$v=v;});\n}\n s=s.$$v\n}\n':"")});var f=f+"return s;",h=new Function("s","k","pw",f);h.toString=aa(f);g=a.unwrapPromises?function(a,b){return h(a,b,va)}:h}else g=Ie(d[0],d[1],c);else g=He(d[0],c);"hasOwnProperty"!==
+b&&(Pb[b]=g);return g}function fe(){var b={},a={csp:!1,unwrapPromises:!1,logPromiseWarnings:!0};this.unwrapPromises=function(b){return B(b)?(a.unwrapPromises=!!b,this):a.unwrapPromises};this.logPromiseWarnings=function(b){return B(b)?(a.logPromiseWarnings=b,this):a.logPromiseWarnings};this.$get=["$filter","$sniffer","$log",function(c,d,e){a.csp=d.csp;va=function(b){a.logPromiseWarnings&&!Ic.hasOwnProperty(b)&&(Ic[b]=!0,e.warn("[$parse] Promise found in the expression `"+b+"`. Automatic unwrapping of promises in Angular expressions is deprecated."))};
+return function(d){var e;switch(typeof d){case "string":if(b.hasOwnProperty(d))return b[d];e=new Qb(a);e=(new ab(e,c,a)).parse(d,!1);"hasOwnProperty"!==d&&(b[d]=e);return e;case "function":return d;default:return C}}}]}function he(){this.$get=["$rootScope","$exceptionHandler",function(b,a){return Je(function(a){b.$evalAsync(a)},a)}]}function Je(b,a){function c(a){return a}function d(a){return f(a)}var e=function(){var f=[],k,l;return l={resolve:function(a){if(f){var c=f;f=s;k=g(a);c.length&&b(function(){for(var a,
+b=0,d=c.length;b<d;b++)a=c[b],k.then(a[0],a[1],a[2])})}},reject:function(a){l.resolve(h(a))},notify:function(a){if(f){var c=f;f.length&&b(function(){for(var b,d=0,e=c.length;d<e;d++)b=c[d],b[2](a)})}},promise:{then:function(b,g,h){var l=e(),z=function(d){try{l.resolve((P(b)?b:c)(d))}catch(e){l.reject(e),a(e)}},K=function(b){try{l.resolve((P(g)?g:d)(b))}catch(c){l.reject(c),a(c)}},w=function(b){try{l.notify((P(h)?h:c)(b))}catch(d){a(d)}};f?f.push([z,K,w]):k.then(z,K,w);return l.promise},"catch":function(a){return this.then(null,
+a)},"finally":function(a){function b(a,c){var d=e();c?d.resolve(a):d.reject(a);return d.promise}function d(e,g){var f=null;try{f=(a||c)()}catch(h){return b(h,!1)}return f&&P(f.then)?f.then(function(){return b(e,g)},function(a){return b(a,!1)}):b(e,g)}return this.then(function(a){return d(a,!0)},function(a){return d(a,!1)})}}}},g=function(a){return a&&P(a.then)?a:{then:function(c){var d=e();b(function(){d.resolve(c(a))});return d.promise}}},f=function(a){var b=e();b.reject(a);return b.promise},h=function(c){return{then:function(g,
+f){var h=e();b(function(){try{h.resolve((P(f)?f:d)(c))}catch(b){h.reject(b),a(b)}});return h.promise}}};return{defer:e,reject:f,when:function(h,k,l,n){var p=e(),r,u=function(b){try{return(P(k)?k:c)(b)}catch(d){return a(d),f(d)}},z=function(b){try{return(P(l)?l:d)(b)}catch(c){return a(c),f(c)}},K=function(b){try{return(P(n)?n:c)(b)}catch(d){a(d)}};b(function(){g(h).then(function(a){r||(r=!0,p.resolve(g(a).then(u,z,K)))},function(a){r||(r=!0,p.resolve(z(a)))},function(a){r||p.notify(K(a))})});return p.promise},
+all:function(a){var b=e(),c=0,d=M(a)?[]:{};q(a,function(a,e){c++;g(a).then(function(a){d.hasOwnProperty(e)||(d[e]=a,--c||b.resolve(d))},function(a){d.hasOwnProperty(e)||b.reject(a)})});0===c&&b.resolve(d);return b.promise}}}function oe(){this.$get=["$window","$timeout",function(b,a){var c=b.requestAnimationFrame||b.webkitRequestAnimationFrame||b.mozRequestAnimationFrame,d=b.cancelAnimationFrame||b.webkitCancelAnimationFrame||b.mozCancelAnimationFrame||b.webkitCancelRequestAnimationFrame,e=!!c,g=e?
+function(a){var b=c(a);return function(){d(b)}}:function(b){var c=a(b,16.66,!1);return function(){a.cancel(c)}};g.supported=e;return g}]}function ge(){var b=10,a=v("$rootScope"),c=null;this.digestTtl=function(a){arguments.length&&(b=a);return b};this.$get=["$injector","$exceptionHandler","$parse","$browser",function(d,e,g,f){function h(){this.$id=eb();this.$$phase=this.$parent=this.$$watchers=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null;this["this"]=this.$root=this;
+this.$$destroyed=!1;this.$$asyncQueue=[];this.$$postDigestQueue=[];this.$$listeners={};this.$$listenerCount={};this.$$isolateBindings={}}function m(b){if(p.$$phase)throw a("inprog",p.$$phase);p.$$phase=b}function k(a,b){var c=g(a);Ra(c,b);return c}function l(a,b,c){do a.$$listenerCount[c]-=b,0===a.$$listenerCount[c]&&delete a.$$listenerCount[c];while(a=a.$parent)}function n(){}h.prototype={constructor:h,$new:function(a){a?(a=new h,a.$root=this.$root,a.$$asyncQueue=this.$$asyncQueue,a.$$postDigestQueue=
+this.$$postDigestQueue):(a=function(){},a.prototype=this,a=new a,a.$id=eb());a["this"]=a;a.$$listeners={};a.$$listenerCount={};a.$parent=this;a.$$watchers=a.$$nextSibling=a.$$childHead=a.$$childTail=null;a.$$prevSibling=this.$$childTail;this.$$childHead?this.$$childTail=this.$$childTail.$$nextSibling=a:this.$$childHead=this.$$childTail=a;return a},$watch:function(a,b,d){var e=k(a,"watch"),g=this.$$watchers,f={fn:b,last:n,get:e,exp:a,eq:!!d};c=null;if(!P(b)){var h=k(b||C,"listener");f.fn=function(a,
+b,c){h(c)}}if("string"==typeof a&&e.constant){var m=f.fn;f.fn=function(a,b,c){m.call(this,a,b,c);Fa(g,f)}}g||(g=this.$$watchers=[]);g.unshift(f);return function(){Fa(g,f);c=null}},$watchCollection:function(a,b){var c=this,d,e,f,h=1<b.length,k=0,m=g(a),l=[],n={},p=!0,q=0;return this.$watch(function(){d=m(c);var a,b;if(X(d))if(db(d))for(e!==l&&(e=l,q=e.length=0,k++),a=d.length,q!==a&&(k++,e.length=q=a),b=0;b<a;b++)e[b]!==e[b]&&d[b]!==d[b]||e[b]===d[b]||(k++,e[b]=d[b]);else{e!==n&&(e=n={},q=0,k++);a=
+0;for(b in d)d.hasOwnProperty(b)&&(a++,e.hasOwnProperty(b)?e[b]!==d[b]&&(k++,e[b]=d[b]):(q++,e[b]=d[b],k++));if(q>a)for(b in k++,e)e.hasOwnProperty(b)&&!d.hasOwnProperty(b)&&(q--,delete e[b])}else e!==d&&(e=d,k++);return k},function(){p?(p=!1,b(d,d,c)):b(d,f,c);if(h)if(X(d))if(db(d)){f=Array(d.length);for(var a=0;a<d.length;a++)f[a]=d[a]}else for(a in f={},d)Jc.call(d,a)&&(f[a]=d[a]);else f=d})},$digest:function(){var d,g,f,h,k=this.$$asyncQueue,l=this.$$postDigestQueue,q,x,s=b,L,Q=[],y,E,R;m("$digest");
+c=null;do{x=!1;for(L=this;k.length;){try{R=k.shift(),R.scope.$eval(R.expression)}catch(B){p.$$phase=null,e(B)}c=null}a:do{if(h=L.$$watchers)for(q=h.length;q--;)try{if(d=h[q])if((g=d.get(L))!==(f=d.last)&&!(d.eq?za(g,f):"number"==typeof g&&"number"==typeof f&&isNaN(g)&&isNaN(f)))x=!0,c=d,d.last=d.eq?ba(g):g,d.fn(g,f===n?g:f,L),5>s&&(y=4-s,Q[y]||(Q[y]=[]),E=P(d.exp)?"fn: "+(d.exp.name||d.exp.toString()):d.exp,E+="; newVal: "+ta(g)+"; oldVal: "+ta(f),Q[y].push(E));else if(d===c){x=!1;break a}}catch(t){p.$$phase=
+null,e(t)}if(!(h=L.$$childHead||L!==this&&L.$$nextSibling))for(;L!==this&&!(h=L.$$nextSibling);)L=L.$parent}while(L=h);if((x||k.length)&&!s--)throw p.$$phase=null,a("infdig",b,ta(Q));}while(x||k.length);for(p.$$phase=null;l.length;)try{l.shift()()}catch(S){e(S)}},$destroy:function(){if(!this.$$destroyed){var a=this.$parent;this.$broadcast("$destroy");this.$$destroyed=!0;this!==p&&(q(this.$$listenerCount,hb(null,l,this)),a.$$childHead==this&&(a.$$childHead=this.$$nextSibling),a.$$childTail==this&&
+(a.$$childTail=this.$$prevSibling),this.$$prevSibling&&(this.$$prevSibling.$$nextSibling=this.$$nextSibling),this.$$nextSibling&&(this.$$nextSibling.$$prevSibling=this.$$prevSibling),this.$parent=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=this.$root=null,this.$$listeners={},this.$$watchers=this.$$asyncQueue=this.$$postDigestQueue=[],this.$destroy=this.$digest=this.$apply=C,this.$on=this.$watch=function(){return C})}},$eval:function(a,b){return g(a)(this,b)},$evalAsync:function(a){p.$$phase||
+p.$$asyncQueue.length||f.defer(function(){p.$$asyncQueue.length&&p.$digest()});this.$$asyncQueue.push({scope:this,expression:a})},$$postDigest:function(a){this.$$postDigestQueue.push(a)},$apply:function(a){try{return m("$apply"),this.$eval(a)}catch(b){e(b)}finally{p.$$phase=null;try{p.$digest()}catch(c){throw e(c),c;}}},$on:function(a,b){var c=this.$$listeners[a];c||(this.$$listeners[a]=c=[]);c.push(b);var d=this;do d.$$listenerCount[a]||(d.$$listenerCount[a]=0),d.$$listenerCount[a]++;while(d=d.$parent);
+var e=this;return function(){c[gb(c,b)]=null;l(e,1,a)}},$emit:function(a,b){var c=[],d,g=this,f=!1,h={name:a,targetScope:g,stopPropagation:function(){f=!0},preventDefault:function(){h.defaultPrevented=!0},defaultPrevented:!1},k=[h].concat(sa.call(arguments,1)),m,l;do{d=g.$$listeners[a]||c;h.currentScope=g;m=0;for(l=d.length;m<l;m++)if(d[m])try{d[m].apply(null,k)}catch(n){e(n)}else d.splice(m,1),m--,l--;if(f)break;g=g.$parent}while(g);return h},$broadcast:function(a,b){for(var c=this,d=this,g={name:a,
+targetScope:this,preventDefault:function(){g.defaultPrevented=!0},defaultPrevented:!1},f=[g].concat(sa.call(arguments,1)),h,k;c=d;){g.currentScope=c;d=c.$$listeners[a]||[];h=0;for(k=d.length;h<k;h++)if(d[h])try{d[h].apply(null,f)}catch(m){e(m)}else d.splice(h,1),h--,k--;if(!(d=c.$$listenerCount[a]&&c.$$childHead||c!==this&&c.$$nextSibling))for(;c!==this&&!(d=c.$$nextSibling);)c=c.$parent}return g}};var p=new h;return p}]}function kd(){var b=/^\s*(https?|ftp|mailto|tel|file):/,a=/^\s*(https?|ftp|file|blob):|data:image\//;
+this.aHrefSanitizationWhitelist=function(a){return B(a)?(b=a,this):b};this.imgSrcSanitizationWhitelist=function(b){return B(b)?(a=b,this):a};this.$get=function(){return function(c,d){var e=d?a:b,g;if(!T||8<=T)if(g=ua(c).href,""!==g&&!g.match(e))return"unsafe:"+g;return c}}}function Ke(b){if("self"===b)return b;if(t(b)){if(-1<b.indexOf("***"))throw wa("iwcard",b);b=b.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g,"\\$1").replace(/\x08/g,"\\x08").replace("\\*\\*",".*").replace("\\*","[^:/.?&;]*");return RegExp("^"+
+b+"$")}if(fb(b))return RegExp("^"+b.source+"$");throw wa("imatcher");}function Kc(b){var a=[];B(b)&&q(b,function(b){a.push(Ke(b))});return a}function je(){this.SCE_CONTEXTS=ga;var b=["self"],a=[];this.resourceUrlWhitelist=function(a){arguments.length&&(b=Kc(a));return b};this.resourceUrlBlacklist=function(b){arguments.length&&(a=Kc(b));return a};this.$get=["$injector",function(c){function d(a){var b=function(a){this.$$unwrapTrustedValue=function(){return a}};a&&(b.prototype=new a);b.prototype.valueOf=
+function(){return this.$$unwrapTrustedValue()};b.prototype.toString=function(){return this.$$unwrapTrustedValue().toString()};return b}var e=function(a){throw wa("unsafe");};c.has("$sanitize")&&(e=c.get("$sanitize"));var g=d(),f={};f[ga.HTML]=d(g);f[ga.CSS]=d(g);f[ga.URL]=d(g);f[ga.JS]=d(g);f[ga.RESOURCE_URL]=d(f[ga.URL]);return{trustAs:function(a,b){var c=f.hasOwnProperty(a)?f[a]:null;if(!c)throw wa("icontext",a,b);if(null===b||b===s||""===b)return b;if("string"!==typeof b)throw wa("itype",a);return new c(b)},
+getTrusted:function(c,d){if(null===d||d===s||""===d)return d;var g=f.hasOwnProperty(c)?f[c]:null;if(g&&d instanceof g)return d.$$unwrapTrustedValue();if(c===ga.RESOURCE_URL){var g=ua(d.toString()),l,n,p=!1;l=0;for(n=b.length;l<n;l++)if("self"===b[l]?Lb(g):b[l].exec(g.href)){p=!0;break}if(p)for(l=0,n=a.length;l<n;l++)if("self"===a[l]?Lb(g):a[l].exec(g.href)){p=!1;break}if(p)return d;throw wa("insecurl",d.toString());}if(c===ga.HTML)return e(d);throw wa("unsafe");},valueOf:function(a){return a instanceof
+g?a.$$unwrapTrustedValue():a}}}]}function ie(){var b=!0;this.enabled=function(a){arguments.length&&(b=!!a);return b};this.$get=["$parse","$sniffer","$sceDelegate",function(a,c,d){if(b&&c.msie&&8>c.msieDocumentMode)throw wa("iequirks");var e=ba(ga);e.isEnabled=function(){return b};e.trustAs=d.trustAs;e.getTrusted=d.getTrusted;e.valueOf=d.valueOf;b||(e.trustAs=e.getTrusted=function(a,b){return b},e.valueOf=Ea);e.parseAs=function(b,c){var d=a(c);return d.literal&&d.constant?d:function(a,c){return e.getTrusted(b,
+d(a,c))}};var g=e.parseAs,f=e.getTrusted,h=e.trustAs;q(ga,function(a,b){var c=I(b);e[Ta("parse_as_"+c)]=function(b){return g(a,b)};e[Ta("get_trusted_"+c)]=function(b){return f(a,b)};e[Ta("trust_as_"+c)]=function(b){return h(a,b)}});return e}]}function ke(){this.$get=["$window","$document",function(b,a){var c={},d=Y((/android (\d+)/.exec(I((b.navigator||{}).userAgent))||[])[1]),e=/Boxee/i.test((b.navigator||{}).userAgent),g=a[0]||{},f=g.documentMode,h,m=/^(Moz|webkit|O|ms)(?=[A-Z])/,k=g.body&&g.body.style,
+l=!1,n=!1;if(k){for(var p in k)if(l=m.exec(p)){h=l[0];h=h.substr(0,1).toUpperCase()+h.substr(1);break}h||(h="WebkitOpacity"in k&&"webkit");l=!!("transition"in k||h+"Transition"in k);n=!!("animation"in k||h+"Animation"in k);!d||l&&n||(l=t(g.body.style.webkitTransition),n=t(g.body.style.webkitAnimation))}return{history:!(!b.history||!b.history.pushState||4>d||e),hashchange:"onhashchange"in b&&(!f||7<f),hasEvent:function(a){if("input"==a&&9==T)return!1;if(D(c[a])){var b=g.createElement("div");c[a]="on"+
+a in b}return c[a]},csp:Yb(),vendorPrefix:h,transitions:l,animations:n,android:d,msie:T,msieDocumentMode:f}}]}function me(){this.$get=["$rootScope","$browser","$q","$exceptionHandler",function(b,a,c,d){function e(e,h,m){var k=c.defer(),l=k.promise,n=B(m)&&!m;h=a.defer(function(){try{k.resolve(e())}catch(a){k.reject(a),d(a)}finally{delete g[l.$$timeoutId]}n||b.$apply()},h);l.$$timeoutId=h;g[h]=k;return l}var g={};e.cancel=function(b){return b&&b.$$timeoutId in g?(g[b.$$timeoutId].reject("canceled"),
+delete g[b.$$timeoutId],a.defer.cancel(b.$$timeoutId)):!1};return e}]}function ua(b,a){var c=b;T&&(W.setAttribute("href",c),c=W.href);W.setAttribute("href",c);return{href:W.href,protocol:W.protocol?W.protocol.replace(/:$/,""):"",host:W.host,search:W.search?W.search.replace(/^\?/,""):"",hash:W.hash?W.hash.replace(/^#/,""):"",hostname:W.hostname,port:W.port,pathname:"/"===W.pathname.charAt(0)?W.pathname:"/"+W.pathname}}function Lb(b){b=t(b)?ua(b):b;return b.protocol===Lc.protocol&&b.host===Lc.host}
+function ne(){this.$get=aa(O)}function jc(b){function a(d,e){if(X(d)){var g={};q(d,function(b,c){g[c]=a(c,b)});return g}return b.factory(d+c,e)}var c="Filter";this.register=a;this.$get=["$injector",function(a){return function(b){return a.get(b+c)}}];a("currency",Mc);a("date",Nc);a("filter",Le);a("json",Me);a("limitTo",Ne);a("lowercase",Oe);a("number",Oc);a("orderBy",Pc);a("uppercase",Pe)}function Le(){return function(b,a,c){if(!M(b))return b;var d=typeof c,e=[];e.check=function(a){for(var b=0;b<e.length;b++)if(!e[b](a))return!1;
+return!0};"function"!==d&&(c="boolean"===d&&c?function(a,b){return Qa.equals(a,b)}:function(a,b){if(a&&b&&"object"===typeof a&&"object"===typeof b){for(var d in a)if("$"!==d.charAt(0)&&Jc.call(a,d)&&c(a[d],b[d]))return!0;return!1}b=(""+b).toLowerCase();return-1<(""+a).toLowerCase().indexOf(b)});var g=function(a,b){if("string"==typeof b&&"!"===b.charAt(0))return!g(a,b.substr(1));switch(typeof a){case "boolean":case "number":case "string":return c(a,b);case "object":switch(typeof b){case "object":return c(a,
+b);default:for(var d in a)if("$"!==d.charAt(0)&&g(a[d],b))return!0}return!1;case "array":for(d=0;d<a.length;d++)if(g(a[d],b))return!0;return!1;default:return!1}};switch(typeof a){case "boolean":case "number":case "string":a={$:a};case "object":for(var f in a)(function(b){"undefined"!=typeof a[b]&&e.push(function(c){return g("$"==b?c:c&&c[b],a[b])})})(f);break;case "function":e.push(a);break;default:return b}d=[];for(f=0;f<b.length;f++){var h=b[f];e.check(h)&&d.push(h)}return d}}function Mc(b){var a=
+b.NUMBER_FORMATS;return function(b,d){D(d)&&(d=a.CURRENCY_SYM);return Qc(b,a.PATTERNS[1],a.GROUP_SEP,a.DECIMAL_SEP,2).replace(/\u00A4/g,d)}}function Oc(b){var a=b.NUMBER_FORMATS;return function(b,d){return Qc(b,a.PATTERNS[0],a.GROUP_SEP,a.DECIMAL_SEP,d)}}function Qc(b,a,c,d,e){if(null==b||!isFinite(b)||X(b))return"";var g=0>b;b=Math.abs(b);var f=b+"",h="",m=[],k=!1;if(-1!==f.indexOf("e")){var l=f.match(/([\d\.]+)e(-?)(\d+)/);l&&"-"==l[2]&&l[3]>e+1?f="0":(h=f,k=!0)}if(k)0<e&&(-1<b&&1>b)&&(h=b.toFixed(e));
+else{f=(f.split(Rc)[1]||"").length;D(e)&&(e=Math.min(Math.max(a.minFrac,f),a.maxFrac));f=Math.pow(10,e);b=Math.round(b*f)/f;b=(""+b).split(Rc);f=b[0];b=b[1]||"";var l=0,n=a.lgSize,p=a.gSize;if(f.length>=n+p)for(l=f.length-n,k=0;k<l;k++)0===(l-k)%p&&0!==k&&(h+=c),h+=f.charAt(k);for(k=l;k<f.length;k++)0===(f.length-k)%n&&0!==k&&(h+=c),h+=f.charAt(k);for(;b.length<e;)b+="0";e&&"0"!==e&&(h+=d+b.substr(0,e))}m.push(g?a.negPre:a.posPre);m.push(h);m.push(g?a.negSuf:a.posSuf);return m.join("")}function tb(b,
+a,c){var d="";0>b&&(d="-",b=-b);for(b=""+b;b.length<a;)b="0"+b;c&&(b=b.substr(b.length-a));return d+b}function $(b,a,c,d){c=c||0;return function(e){e=e["get"+b]();if(0<c||e>-c)e+=c;0===e&&-12==c&&(e=12);return tb(e,a,d)}}function ub(b,a){return function(c,d){var e=c["get"+b](),g=Ga(a?"SHORT"+b:b);return d[g][e]}}function Sc(b){var a=(new Date(b,0,1)).getDay();return new Date(b,0,(4>=a?5:12)-a)}function Tc(b){return function(a){var c=Sc(a.getFullYear());a=+new Date(a.getFullYear(),a.getMonth(),a.getDate()+
+(4-a.getDay()))-+c;a=1+Math.round(a/6048E5);return tb(a,b)}}function Nc(b){function a(a){var b;if(b=a.match(c)){a=new Date(0);var g=0,f=0,h=b[8]?a.setUTCFullYear:a.setFullYear,m=b[8]?a.setUTCHours:a.setHours;b[9]&&(g=Y(b[9]+b[10]),f=Y(b[9]+b[11]));h.call(a,Y(b[1]),Y(b[2])-1,Y(b[3]));g=Y(b[4]||0)-g;f=Y(b[5]||0)-f;h=Y(b[6]||0);b=Math.round(1E3*parseFloat("0."+(b[7]||0)));m.call(a,g,f,h,b)}return a}var c=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
+return function(c,e){var g="",f=[],h,m;e=e||"mediumDate";e=b.DATETIME_FORMATS[e]||e;t(c)&&(c=Qe.test(c)?Y(c):a(c));Ab(c)&&(c=new Date(c));if(!ra(c))return c;for(;e;)(m=Re.exec(e))?(f=f.concat(sa.call(m,1)),e=f.pop()):(f.push(e),e=null);q(f,function(a){h=Se[a];g+=h?h(c,b.DATETIME_FORMATS):a.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return g}}function Me(){return function(b){return ta(b,!0)}}function Ne(){return function(b,a){if(!M(b)&&!t(b))return b;a=Y(a);if(t(b))return a?0<=a?b.slice(0,a):b.slice(a,
+b.length):"";var c=[],d,e;a>b.length?a=b.length:a<-b.length&&(a=-b.length);0<a?(d=0,e=a):(d=b.length+a,e=b.length);for(;d<e;d++)c.push(b[d]);return c}}function Pc(b){return function(a,c,d){function e(a,b){return Pa(b)?function(b,c){return a(c,b)}:a}function g(a,b){var c=typeof a,d=typeof b;return c==d?("string"==c&&(a=a.toLowerCase(),b=b.toLowerCase()),a===b?0:a<b?-1:1):c<d?-1:1}if(!M(a)||!c)return a;c=M(c)?c:[c];c=cd(c,function(a){var c=!1,d=a||Ea;if(t(a)){if("+"==a.charAt(0)||"-"==a.charAt(0))c=
+"-"==a.charAt(0),a=a.substring(1);d=b(a);if(d.constant){var f=d();return e(function(a,b){return g(a[f],b[f])},c)}}return e(function(a,b){return g(d(a),d(b))},c)});for(var f=[],h=0;h<a.length;h++)f.push(a[h]);return f.sort(e(function(a,b){for(var d=0;d<c.length;d++){var e=c[d](a,b);if(0!==e)return e}return 0},d))}}function xa(b){P(b)&&(b={link:b});b.restrict=b.restrict||"AC";return aa(b)}function Uc(b,a,c,d){function e(a,c){c=c?"-"+ib(c,"-"):"";d.removeClass(b,(a?vb:wb)+c);d.addClass(b,(a?wb:vb)+c)}
+var g=this,f=b.parent().controller("form")||xb,h=0,m=g.$error={},k=[];g.$name=a.name||a.ngForm;g.$dirty=!1;g.$pristine=!0;g.$valid=!0;g.$invalid=!1;f.$addControl(g);b.addClass(Ma);e(!0);g.$addControl=function(a){Ba(a.$name,"input");k.push(a);a.$name&&(g[a.$name]=a)};g.$removeControl=function(a){a.$name&&g[a.$name]===a&&delete g[a.$name];q(m,function(b,c){g.$setValidity(c,!0,a)});Fa(k,a)};g.$setValidity=function(a,b,c){var d=m[a];if(b)d&&(Fa(d,c),d.length||(h--,h||(e(b),g.$valid=!0,g.$invalid=!1),
+m[a]=!1,e(!0,a),f.$setValidity(a,!0,g)));else{h||e(b);if(d){if(-1!=gb(d,c))return}else m[a]=d=[],h++,e(!1,a),f.$setValidity(a,!1,g);d.push(c);g.$valid=!1;g.$invalid=!0}};g.$setDirty=function(){d.removeClass(b,Ma);d.addClass(b,yb);g.$dirty=!0;g.$pristine=!1;f.$setDirty()};g.$setPristine=function(){d.removeClass(b,yb);d.addClass(b,Ma);g.$dirty=!1;g.$pristine=!0;q(k,function(a){a.$setPristine()})}}function qa(b,a,c,d){b.$setValidity(a,c);return c?d:s}function Te(b,a,c){var d=c.prop("validity");X(d)&&
+b.$parsers.push(function(c){if(b.$error[a]||!(d.badInput||d.customError||d.typeMismatch)||d.valueMissing)return c;b.$setValidity(a,!1)})}function bb(b,a,c,d,e,g){var f=a.prop("validity");if(!e.android){var h=!1;a.on("compositionstart",function(a){h=!0});a.on("compositionend",function(){h=!1;m()})}var m=function(){if(!h){var e=a.val();Pa(c.ngTrim||"T")&&(e=ca(e));if(d.$viewValue!==e||f&&""===e&&!f.valueMissing)b.$$phase?d.$setViewValue(e):b.$apply(function(){d.$setViewValue(e)})}};if(e.hasEvent("input"))a.on("input",
+m);else{var k,l=function(){k||(k=g.defer(function(){m();k=null}))};a.on("keydown",function(a){a=a.keyCode;91===a||(15<a&&19>a||37<=a&&40>=a)||l()});if(e.hasEvent("paste"))a.on("paste cut",l)}a.on("change",m);d.$render=function(){a.val(d.$isEmpty(d.$viewValue)?"":d.$viewValue)};var n=c.ngPattern;n&&((e=n.match(/^\/(.*)\/([gim]*)$/))?(n=RegExp(e[1],e[2]),e=function(a){return qa(d,"pattern",d.$isEmpty(a)||n.test(a),a)}):e=function(c){var e=b.$eval(n);if(!e||!e.test)throw v("ngPattern")("noregexp",n,
+e,ha(a));return qa(d,"pattern",d.$isEmpty(c)||e.test(c),c)},d.$formatters.push(e),d.$parsers.push(e));if(c.ngMinlength){var p=Y(c.ngMinlength);e=function(a){return qa(d,"minlength",d.$isEmpty(a)||a.length>=p,a)};d.$parsers.push(e);d.$formatters.push(e)}if(c.ngMaxlength){var r=Y(c.ngMaxlength);e=function(a){return qa(d,"maxlength",d.$isEmpty(a)||a.length<=r,a)};d.$parsers.push(e);d.$formatters.push(e)}}function zb(b,a){return function(c){var d;return ra(c)?c:t(c)&&(b.lastIndex=0,c=b.exec(c))?(c.shift(),
+d={yyyy:0,MM:1,dd:1,HH:0,mm:0},q(c,function(b,c){c<a.length&&(d[a[c]]=+b)}),new Date(d.yyyy,d.MM-1,d.dd,d.HH,d.mm)):NaN}}function cb(b,a,c,d){return function(e,g,f,h,m,k,l){bb(e,g,f,h,m,k);h.$parsers.push(function(d){if(h.$isEmpty(d))return h.$setValidity(b,!0),null;if(a.test(d))return h.$setValidity(b,!0),c(d);h.$setValidity(b,!1);return s});h.$formatters.push(function(a){return ra(a)?l("date")(a,d):""});f.min&&(e=function(a){var b=h.$isEmpty(a)||c(a)>=c(f.min);h.$setValidity("min",b);return b?a:
+s},h.$parsers.push(e),h.$formatters.push(e));f.max&&(e=function(a){var b=h.$isEmpty(a)||c(a)<=c(f.max);h.$setValidity("max",b);return b?a:s},h.$parsers.push(e),h.$formatters.push(e))}}function Rb(b,a){b="ngClass"+b;return["$animate",function(c){function d(a,b){var c=[],d=0;a:for(;d<a.length;d++){for(var e=a[d],l=0;l<b.length;l++)if(e==b[l])continue a;c.push(e)}return c}function e(a){if(!M(a)){if(t(a))return a.split(" ");if(X(a)){var b=[];q(a,function(a,c){a&&b.push(c)});return b}}return a}return{restrict:"AC",
+link:function(g,f,h){function m(a,b){var c=f.data("$classCounts")||{},d=[];q(a,function(a){if(0<b||c[a])c[a]=(c[a]||0)+b,c[a]===+(0<b)&&d.push(a)});f.data("$classCounts",c);return d.join(" ")}function k(b){if(!0===a||g.$index%2===a){var k=e(b||[]);if(!l){var r=m(k,1);h.$addClass(r)}else if(!za(b,l)){var q=e(l),r=d(k,q),k=d(q,k),k=m(k,-1),r=m(r,1);0===r.length?c.removeClass(f,k):0===k.length?c.addClass(f,r):c.setClass(f,r,k)}}l=ba(b)}var l;g.$watch(h[b],k,!0);h.$observe("class",function(a){k(g.$eval(h[b]))});
+"ngClass"!==b&&g.$watch("$index",function(c,d){var f=c&1;if(f!==d&1){var k=e(g.$eval(h[b]));f===a?(f=m(k,1),h.$addClass(f)):(f=m(k,-1),h.$removeClass(f))}})}}}]}var I=function(b){return t(b)?b.toLowerCase():b},Jc=Object.prototype.hasOwnProperty,Ga=function(b){return t(b)?b.toUpperCase():b},T,y,Ha,sa=[].slice,Ue=[].push,ya=Object.prototype.toString,Oa=v("ng"),Qa=O.angular||(O.angular={}),Sa,La,ka=["0","0","0"];T=Y((/msie (\d+)/.exec(I(navigator.userAgent))||[])[1]);isNaN(T)&&(T=Y((/trident\/.*; rv:(\d+)/.exec(I(navigator.userAgent))||
+[])[1]));C.$inject=[];Ea.$inject=[];var ca=function(){return String.prototype.trim?function(b){return t(b)?b.trim():b}:function(b){return t(b)?b.replace(/^\s\s*/,"").replace(/\s\s*$/,""):b}}();La=9>T?function(b){b=b.nodeName?b:b[0];return b.scopeName&&"HTML"!=b.scopeName?Ga(b.scopeName+":"+b.nodeName):b.nodeName}:function(b){return b.nodeName?b.nodeName:b[0].nodeName};var fd=/[A-Z]/g,id={full:"1.3.0-beta.5",major:1,minor:3,dot:0,codeName:"chimeric-glitterfication"},Va=N.cache={},jb=N.expando="ng-"+
+(new Date).getTime(),we=1,qb=O.document.addEventListener?function(b,a,c){b.addEventListener(a,c,!1)}:function(b,a,c){b.attachEvent("on"+a,c)},Ua=O.document.removeEventListener?function(b,a,c){b.removeEventListener(a,c,!1)}:function(b,a,c){b.detachEvent("on"+a,c)};N._data=function(b){return this.cache[b[this.expando]]||{}};var qe=/([\:\-\_]+(.))/g,re=/^moz([A-Z])/,Hb=v("jqLite"),ve=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,Gb=/<|&#?\w+;/,te=/<([\w:]+)/,ue=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
+ea={option:[1,'<select multiple="multiple">',"</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ea.optgroup=ea.option;ea.tbody=ea.tfoot=ea.colgroup=ea.caption=ea.thead;ea.th=ea.td;var Ka=N.prototype={ready:function(b){function a(){c||(c=!0,b())}var c=!1;"complete"===U.readyState?setTimeout(a):(this.on("DOMContentLoaded",a),N(O).on("load",a))},
+toString:function(){var b=[];q(this,function(a){b.push(""+a)});return"["+b.join(", ")+"]"},eq:function(b){return 0<=b?y(this[b]):y(this[this.length+b])},length:0,push:Ue,sort:[].sort,splice:[].splice},nb={};q("multiple selected checked disabled readOnly required open".split(" "),function(b){nb[I(b)]=b});var rc={};q("input select option textarea button form details".split(" "),function(b){rc[Ga(b)]=!0});q({data:nc,inheritedData:mb,scope:function(b){return y(b).data("$scope")||mb(b.parentNode||b,["$isolateScope",
+"$scope"])},isolateScope:function(b){return y(b).data("$isolateScope")||y(b).data("$isolateScopeNoTemplate")},controller:oc,injector:function(b){return mb(b,"$injector")},removeAttr:function(b,a){b.removeAttribute(a)},hasClass:Jb,css:function(b,a,c){a=Ta(a);if(B(c))b.style[a]=c;else{var d;8>=T&&(d=b.currentStyle&&b.currentStyle[a],""===d&&(d="auto"));d=d||b.style[a];8>=T&&(d=""===d?s:d);return d}},attr:function(b,a,c){var d=I(a);if(nb[d])if(B(c))c?(b[a]=!0,b.setAttribute(a,d)):(b[a]=!1,b.removeAttribute(d));
+else return b[a]||(b.attributes.getNamedItem(a)||C).specified?d:s;else if(B(c))b.setAttribute(a,c);else if(b.getAttribute)return b=b.getAttribute(a,2),null===b?s:b},prop:function(b,a,c){if(B(c))b[a]=c;else return b[a]},text:function(){function b(b,d){var e=a[b.nodeType];if(D(d))return e?b[e]:"";b[e]=d}var a=[];9>T?(a[1]="innerText",a[3]="nodeValue"):a[1]=a[3]="textContent";b.$dv="";return b}(),val:function(b,a){if(D(a)){if("SELECT"===La(b)&&b.multiple){var c=[];q(b.options,function(a){a.selected&&
+c.push(a.value||a.text)});return 0===c.length?null:c}return b.value}b.value=a},html:function(b,a){if(D(a))return b.innerHTML;for(var c=0,d=b.childNodes;c<d.length;c++)Ia(d[c]);b.innerHTML=a},empty:pc},function(b,a){N.prototype[a]=function(a,d){var e,g;if(b!==pc&&(2==b.length&&b!==Jb&&b!==oc?a:d)===s){if(X(a)){for(e=0;e<this.length;e++)if(b===nc)b(this[e],a);else for(g in a)b(this[e],g,a[g]);return this}e=b.$dv;g=e===s?Math.min(this.length,1):this.length;for(var f=0;f<g;f++){var h=b(this[f],a,d);e=
+e?e+h:h}return e}for(e=0;e<this.length;e++)b(this[e],a,d);return this}});q({removeData:lc,dealoc:Ia,on:function a(c,d,e,g){if(B(g))throw Hb("onargs");var f=la(c,"events"),h=la(c,"handle");f||la(c,"events",f={});h||la(c,"handle",h=xe(c,f));q(d.split(" "),function(d){var g=f[d];if(!g){if("mouseenter"==d||"mouseleave"==d){var l=U.body.contains||U.body.compareDocumentPosition?function(a,c){var d=9===a.nodeType?a.documentElement:a,e=c&&c.parentNode;return a===e||!!(e&&1===e.nodeType&&(d.contains?d.contains(e):
+a.compareDocumentPosition&&a.compareDocumentPosition(e)&16))}:function(a,c){if(c)for(;c=c.parentNode;)if(c===a)return!0;return!1};f[d]=[];a(c,{mouseleave:"mouseout",mouseenter:"mouseover"}[d],function(a){var c=a.relatedTarget;c&&(c===this||l(this,c))||h(a,d)})}else qb(c,d,h),f[d]=[];g=f[d]}g.push(e)})},off:mc,one:function(a,c,d){a=y(a);a.on(c,function g(){a.off(c,d);a.off(c,g)});a.on(c,d)},replaceWith:function(a,c){var d,e=a.parentNode;Ia(a);q(new N(c),function(c){d?e.insertBefore(c,d.nextSibling):
+e.replaceChild(c,a);d=c})},children:function(a){var c=[];q(a.childNodes,function(a){1===a.nodeType&&c.push(a)});return c},contents:function(a){return a.contentDocument||a.childNodes||[]},append:function(a,c){q(new N(c),function(c){1!==a.nodeType&&11!==a.nodeType||a.appendChild(c)})},prepend:function(a,c){if(1===a.nodeType){var d=a.firstChild;q(new N(c),function(c){a.insertBefore(c,d)})}},wrap:function(a,c){c=y(c)[0];var d=a.parentNode;d&&d.replaceChild(c,a);c.appendChild(a)},remove:function(a){Ia(a);
+var c=a.parentNode;c&&c.removeChild(a)},after:function(a,c){var d=a,e=a.parentNode;q(new N(c),function(a){e.insertBefore(a,d.nextSibling);d=a})},addClass:lb,removeClass:kb,toggleClass:function(a,c,d){c&&q(c.split(" "),function(c){var g=d;D(g)&&(g=!Jb(a,c));(g?lb:kb)(a,c)})},parent:function(a){return(a=a.parentNode)&&11!==a.nodeType?a:null},next:function(a){if(a.nextElementSibling)return a.nextElementSibling;for(a=a.nextSibling;null!=a&&1!==a.nodeType;)a=a.nextSibling;return a},find:function(a,c){return a.getElementsByTagName?
+a.getElementsByTagName(c):[]},clone:Ib,triggerHandler:function(a,c,d){c=(la(a,"events")||{})[c];d=d||[];var e=[{preventDefault:C,stopPropagation:C}];q(c,function(c){c.apply(a,e.concat(d))})}},function(a,c){N.prototype[c]=function(c,e,g){for(var f,h=0;h<this.length;h++)D(f)?(f=a(this[h],c,e,g),B(f)&&(f=y(f))):kc(f,a(this[h],c,e,g));return B(f)?f:this};N.prototype.bind=N.prototype.on;N.prototype.unbind=N.prototype.off});Wa.prototype={put:function(a,c){this[Ja(a)]=c},get:function(a){return this[Ja(a)]},
+remove:function(a){var c=this[a=Ja(a)];delete this[a];return c}};var ze=/^function\s*[^\(]*\(\s*([^\)]*)\)/m,Ae=/,/,Be=/^\s*(_?)(\S+?)\1\s*$/,ye=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,Xa=v("$injector"),Ve=v("$animate"),Ud=["$provide",function(a){this.$$selectors={};this.register=function(c,d){var e=c+"-animation";if(c&&"."!=c.charAt(0))throw Ve("notcsel",c);this.$$selectors[c.substr(1)]=e;a.factory(e,d)};this.classNameFilter=function(a){1===arguments.length&&(this.$$classNameFilter=a instanceof RegExp?
+a:null);return this.$$classNameFilter};this.$get=["$timeout","$$asyncCallback",function(a,d){return{enter:function(a,c,f,h){f?f.after(a):c.prepend(a);h&&d(h)},leave:function(a,c){a.remove();c&&d(c)},move:function(a,c,d,h){this.enter(a,c,d,h)},addClass:function(a,c,f){c=t(c)?c:M(c)?c.join(" "):"";q(a,function(a){lb(a,c)});f&&d(f)},removeClass:function(a,c,f){c=t(c)?c:M(c)?c.join(" "):"";q(a,function(a){kb(a,c)});f&&d(f)},setClass:function(a,c,f,h){q(a,function(a){lb(a,c);kb(a,f)});h&&d(h)},enabled:C}}]}],
+ja=v("$compile");fc.$inject=["$provide","$$sanitizeUriProvider"];var De=/^(x[\:\-_]|data[\:\-_])/i,zc=v("$interpolate"),We=/^([^\?#]*)(\?([^#]*))?(#(.*))?$/,Ge={http:80,https:443,ftp:21},Nb=v("$location");Ec.prototype=Ob.prototype=Dc.prototype={$$html5:!1,$$replace:!1,absUrl:rb("$$absUrl"),url:function(a,c){if(D(a))return this.$$url;var d=We.exec(a);d[1]&&this.path(decodeURIComponent(d[1]));(d[2]||d[1])&&this.search(d[3]||"");this.hash(d[5]||"",c);return this},protocol:rb("$$protocol"),host:rb("$$host"),
+port:rb("$$port"),path:Fc("$$path",function(a){return"/"==a.charAt(0)?a:"/"+a}),search:function(a,c){switch(arguments.length){case 0:return this.$$search;case 1:if(t(a))this.$$search=ac(a);else if(X(a))this.$$search=a;else throw Nb("isrcharg");break;default:D(c)||null===c?delete this.$$search[a]:this.$$search[a]=c}this.$$compose();return this},hash:Fc("$$hash",Ea),replace:function(){this.$$replace=!0;return this}};var Ca=v("$parse"),Ic={},va,Na={"null":function(){return null},"true":function(){return!0},
+"false":function(){return!1},undefined:C,"+":function(a,c,d,e){d=d(a,c);e=e(a,c);return B(d)?B(e)?d+e:d:B(e)?e:s},"-":function(a,c,d,e){d=d(a,c);e=e(a,c);return(B(d)?d:0)-(B(e)?e:0)},"*":function(a,c,d,e){return d(a,c)*e(a,c)},"/":function(a,c,d,e){return d(a,c)/e(a,c)},"%":function(a,c,d,e){return d(a,c)%e(a,c)},"^":function(a,c,d,e){return d(a,c)^e(a,c)},"=":C,"===":function(a,c,d,e){return d(a,c)===e(a,c)},"!==":function(a,c,d,e){return d(a,c)!==e(a,c)},"==":function(a,c,d,e){return d(a,c)==e(a,
+c)},"!=":function(a,c,d,e){return d(a,c)!=e(a,c)},"<":function(a,c,d,e){return d(a,c)<e(a,c)},">":function(a,c,d,e){return d(a,c)>e(a,c)},"<=":function(a,c,d,e){return d(a,c)<=e(a,c)},">=":function(a,c,d,e){return d(a,c)>=e(a,c)},"&&":function(a,c,d,e){return d(a,c)&&e(a,c)},"||":function(a,c,d,e){return d(a,c)||e(a,c)},"&":function(a,c,d,e){return d(a,c)&e(a,c)},"|":function(a,c,d,e){return e(a,c)(a,c,d(a,c))},"!":function(a,c,d){return!d(a,c)}},Xe={n:"\n",f:"\f",r:"\r",t:"\t",v:"\v","'":"'",'"':'"'},
+Qb=function(a){this.options=a};Qb.prototype={constructor:Qb,lex:function(a){this.text=a;this.index=0;this.ch=s;this.lastCh=":";this.tokens=[];var c;for(a=[];this.index<this.text.length;){this.ch=this.text.charAt(this.index);if(this.is("\"'"))this.readString(this.ch);else if(this.isNumber(this.ch)||this.is(".")&&this.isNumber(this.peek()))this.readNumber();else if(this.isIdent(this.ch))this.readIdent(),this.was("{,")&&("{"===a[0]&&(c=this.tokens[this.tokens.length-1]))&&(c.json=-1===c.text.indexOf("."));
+else if(this.is("(){}[].,;:?"))this.tokens.push({index:this.index,text:this.ch,json:this.was(":[,")&&this.is("{[")||this.is("}]:,")}),this.is("{[")&&a.unshift(this.ch),this.is("}]")&&a.shift(),this.index++;else if(this.isWhitespace(this.ch)){this.index++;continue}else{var d=this.ch+this.peek(),e=d+this.peek(2),g=Na[this.ch],f=Na[d],h=Na[e];h?(this.tokens.push({index:this.index,text:e,fn:h}),this.index+=3):f?(this.tokens.push({index:this.index,text:d,fn:f}),this.index+=2):g?(this.tokens.push({index:this.index,
+text:this.ch,fn:g,json:this.was("[,:")&&this.is("+-")}),this.index+=1):this.throwError("Unexpected next character ",this.index,this.index+1)}this.lastCh=this.ch}return this.tokens},is:function(a){return-1!==a.indexOf(this.ch)},was:function(a){return-1!==a.indexOf(this.lastCh)},peek:function(a){a=a||1;return this.index+a<this.text.length?this.text.charAt(this.index+a):!1},isNumber:function(a){return"0"<=a&&"9">=a},isWhitespace:function(a){return" "===a||"\r"===a||"\t"===a||"\n"===a||"\v"===a||"\u00a0"===
+a},isIdent:function(a){return"a"<=a&&"z">=a||"A"<=a&&"Z">=a||"_"===a||"$"===a},isExpOperator:function(a){return"-"===a||"+"===a||this.isNumber(a)},throwError:function(a,c,d){d=d||this.index;c=B(c)?"s "+c+"-"+this.index+" ["+this.text.substring(c,d)+"]":" "+d;throw Ca("lexerr",a,c,this.text);},readNumber:function(){for(var a="",c=this.index;this.index<this.text.length;){var d=I(this.text.charAt(this.index));if("."==d||this.isNumber(d))a+=d;else{var e=this.peek();if("e"==d&&this.isExpOperator(e))a+=
+d;else if(this.isExpOperator(d)&&e&&this.isNumber(e)&&"e"==a.charAt(a.length-1))a+=d;else if(!this.isExpOperator(d)||e&&this.isNumber(e)||"e"!=a.charAt(a.length-1))break;else this.throwError("Invalid exponent")}this.index++}a*=1;this.tokens.push({index:c,text:a,json:!0,fn:function(){return a}})},readIdent:function(){for(var a=this,c="",d=this.index,e,g,f,h;this.index<this.text.length;){h=this.text.charAt(this.index);if("."===h||this.isIdent(h)||this.isNumber(h))"."===h&&(e=this.index),c+=h;else break;
+this.index++}if(e)for(g=this.index;g<this.text.length;){h=this.text.charAt(g);if("("===h){f=c.substr(e-d+1);c=c.substr(0,e-d);this.index=g;break}if(this.isWhitespace(h))g++;else break}d={index:d,text:c};if(Na.hasOwnProperty(c))d.fn=Na[c],d.json=Na[c];else{var m=Hc(c,this.options,this.text);d.fn=A(function(a,c){return m(a,c)},{assign:function(d,e){return sb(d,c,e,a.text,a.options)}})}this.tokens.push(d);f&&(this.tokens.push({index:e,text:".",json:!1}),this.tokens.push({index:e+1,text:f,json:!1}))},
+readString:function(a){var c=this.index;this.index++;for(var d="",e=a,g=!1;this.index<this.text.length;){var f=this.text.charAt(this.index),e=e+f;if(g)"u"===f?(f=this.text.substring(this.index+1,this.index+5),f.match(/[\da-f]{4}/i)||this.throwError("Invalid unicode escape [\\u"+f+"]"),this.index+=4,d+=String.fromCharCode(parseInt(f,16))):d=(g=Xe[f])?d+g:d+f,g=!1;else if("\\"===f)g=!0;else{if(f===a){this.index++;this.tokens.push({index:c,text:e,string:d,json:!0,fn:function(){return d}});return}d+=
+f}this.index++}this.throwError("Unterminated quote",c)}};var ab=function(a,c,d){this.lexer=a;this.$filter=c;this.options=d};ab.ZERO=A(function(){return 0},{constant:!0});ab.prototype={constructor:ab,parse:function(a,c){this.text=a;this.json=c;this.tokens=this.lexer.lex(a);c&&(this.assignment=this.logicalOR,this.functionCall=this.fieldAccess=this.objectIndex=this.filterChain=function(){this.throwError("is not valid json",{text:a,index:0})});var d=c?this.primary():this.statements();0!==this.tokens.length&&
+this.throwError("is an unexpected token",this.tokens[0]);d.literal=!!d.literal;d.constant=!!d.constant;return d},primary:function(){var a;if(this.expect("("))a=this.filterChain(),this.consume(")");else if(this.expect("["))a=this.arrayDeclaration();else if(this.expect("{"))a=this.object();else{var c=this.expect();(a=c.fn)||this.throwError("not a primary expression",c);c.json&&(a.constant=!0,a.literal=!0)}for(var d;c=this.expect("(","[",".");)"("===c.text?(a=this.functionCall(a,d),d=null):"["===c.text?
+(d=a,a=this.objectIndex(a)):"."===c.text?(d=a,a=this.fieldAccess(a)):this.throwError("IMPOSSIBLE");return a},throwError:function(a,c){throw Ca("syntax",c.text,a,c.index+1,this.text,this.text.substring(c.index));},peekToken:function(){if(0===this.tokens.length)throw Ca("ueoe",this.text);return this.tokens[0]},peek:function(a,c,d,e){if(0<this.tokens.length){var g=this.tokens[0],f=g.text;if(f===a||f===c||f===d||f===e||!(a||c||d||e))return g}return!1},expect:function(a,c,d,e){return(a=this.peek(a,c,d,
+e))?(this.json&&!a.json&&this.throwError("is not valid json",a),this.tokens.shift(),a):!1},consume:function(a){this.expect(a)||this.throwError("is unexpected, expecting ["+a+"]",this.peek())},unaryFn:function(a,c){return A(function(d,e){return a(d,e,c)},{constant:c.constant})},ternaryFn:function(a,c,d){return A(function(e,g){return a(e,g)?c(e,g):d(e,g)},{constant:a.constant&&c.constant&&d.constant})},binaryFn:function(a,c,d){return A(function(e,g){return c(e,g,a,d)},{constant:a.constant&&d.constant})},
+statements:function(){for(var a=[];;)if(0<this.tokens.length&&!this.peek("}",")",";","]")&&a.push(this.filterChain()),!this.expect(";"))return 1===a.length?a[0]:function(c,d){for(var e,g=0;g<a.length;g++){var f=a[g];f&&(e=f(c,d))}return e}},filterChain:function(){for(var a=this.expression(),c;;)if(c=this.expect("|"))a=this.binaryFn(a,c.fn,this.filter());else return a},filter:function(){for(var a=this.expect(),c=this.$filter(a.text),d=[];;)if(a=this.expect(":"))d.push(this.expression());else{var e=
+function(a,e,h){h=[h];for(var m=0;m<d.length;m++)h.push(d[m](a,e));return c.apply(a,h)};return function(){return e}}},expression:function(){return this.assignment()},assignment:function(){var a=this.ternary(),c,d;return(d=this.expect("="))?(a.assign||this.throwError("implies assignment but ["+this.text.substring(0,d.index)+"] can not be assigned to",d),c=this.ternary(),function(d,g){return a.assign(d,c(d,g),g)}):a},ternary:function(){var a=this.logicalOR(),c,d;if(this.expect("?")){c=this.ternary();
+if(d=this.expect(":"))return this.ternaryFn(a,c,this.ternary());this.throwError("expected :",d)}else return a},logicalOR:function(){for(var a=this.logicalAND(),c;;)if(c=this.expect("||"))a=this.binaryFn(a,c.fn,this.logicalAND());else return a},logicalAND:function(){var a=this.equality(),c;if(c=this.expect("&&"))a=this.binaryFn(a,c.fn,this.logicalAND());return a},equality:function(){var a=this.relational(),c;if(c=this.expect("==","!=","===","!=="))a=this.binaryFn(a,c.fn,this.equality());return a},
+relational:function(){var a=this.additive(),c;if(c=this.expect("<",">","<=",">="))a=this.binaryFn(a,c.fn,this.relational());return a},additive:function(){for(var a=this.multiplicative(),c;c=this.expect("+","-");)a=this.binaryFn(a,c.fn,this.multiplicative());return a},multiplicative:function(){for(var a=this.unary(),c;c=this.expect("*","/","%");)a=this.binaryFn(a,c.fn,this.unary());return a},unary:function(){var a;return this.expect("+")?this.primary():(a=this.expect("-"))?this.binaryFn(ab.ZERO,a.fn,
+this.unary()):(a=this.expect("!"))?this.unaryFn(a.fn,this.unary()):this.primary()},fieldAccess:function(a){var c=this,d=this.expect().text,e=Hc(d,this.options,this.text);return A(function(c,d,h){return e(h||a(c,d))},{assign:function(e,f,h){return sb(a(e,h),d,f,c.text,c.options)}})},objectIndex:function(a){var c=this,d=this.expression();this.consume("]");return A(function(e,g){var f=a(e,g),h=d(e,g),m;if(!f)return s;(f=$a(f[h],c.text))&&(f.then&&c.options.unwrapPromises)&&(m=f,"$$v"in f||(m.$$v=s,m.then(function(a){m.$$v=
+a})),f=f.$$v);return f},{assign:function(e,g,f){var h=d(e,f);return $a(a(e,f),c.text)[h]=g}})},functionCall:function(a,c){var d=[];if(")"!==this.peekToken().text){do d.push(this.expression());while(this.expect(","))}this.consume(")");var e=this;return function(g,f){for(var h=[],m=c?c(g,f):g,k=0;k<d.length;k++)h.push(d[k](g,f));k=a(g,f,m)||C;$a(m,e.text);$a(k,e.text);h=k.apply?k.apply(m,h):k(h[0],h[1],h[2],h[3],h[4]);return $a(h,e.text)}},arrayDeclaration:function(){var a=[],c=!0;if("]"!==this.peekToken().text){do{if(this.peek("]"))break;
+var d=this.expression();a.push(d);d.constant||(c=!1)}while(this.expect(","))}this.consume("]");return A(function(c,d){for(var f=[],h=0;h<a.length;h++)f.push(a[h](c,d));return f},{literal:!0,constant:c})},object:function(){var a=[],c=!0;if("}"!==this.peekToken().text){do{if(this.peek("}"))break;var d=this.expect(),d=d.string||d.text;this.consume(":");var e=this.expression();a.push({key:d,value:e});e.constant||(c=!1)}while(this.expect(","))}this.consume("}");return A(function(c,d){for(var e={},m=0;m<
+a.length;m++){var k=a[m];e[k.key]=k.value(c,d)}return e},{literal:!0,constant:c})}};var Pb={},wa=v("$sce"),ga={HTML:"html",CSS:"css",URL:"url",RESOURCE_URL:"resourceUrl",JS:"js"},W=U.createElement("a"),Lc=ua(O.location.href,!0);jc.$inject=["$provide"];Mc.$inject=["$locale"];Oc.$inject=["$locale"];var Rc=".",Se={yyyy:$("FullYear",4),yy:$("FullYear",2,0,!0),y:$("FullYear",1),MMMM:ub("Month"),MMM:ub("Month",!0),MM:$("Month",2,1),M:$("Month",1,1),dd:$("Date",2),d:$("Date",1),HH:$("Hours",2),H:$("Hours",
+1),hh:$("Hours",2,-12),h:$("Hours",1,-12),mm:$("Minutes",2),m:$("Minutes",1),ss:$("Seconds",2),s:$("Seconds",1),sss:$("Milliseconds",3),EEEE:ub("Day"),EEE:ub("Day",!0),a:function(a,c){return 12>a.getHours()?c.AMPMS[0]:c.AMPMS[1]},Z:function(a){a=-1*a.getTimezoneOffset();return a=(0<=a?"+":"")+(tb(Math[0<a?"floor":"ceil"](a/60),2)+tb(Math.abs(a%60),2))},ww:Tc(2),w:Tc(1)},Re=/((?:[^yMdHhmsaZEw']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|w+))(.*)/,Qe=/^\-?\d+$/;Nc.$inject=["$locale"];var Oe=
+aa(I),Pe=aa(Ga);Pc.$inject=["$parse"];var ld=aa({restrict:"E",compile:function(a,c){8>=T&&(c.href||c.name||c.$set("href",""),a.append(U.createComment("IE fix")));if(!c.href&&!c.xlinkHref&&!c.name)return function(a,c){var g="[object SVGAnimatedString]"===ya.call(c.prop("href"))?"xlink:href":"href";c.on("click",function(a){c.attr(g)||a.preventDefault()})}}}),Eb={};q(nb,function(a,c){if("multiple"!=a){var d=na("ng-"+c);Eb[d]=function(){return{priority:100,link:function(a,g,f){a.$watch(f[d],function(a){f.$set(c,
+!!a)})}}}}});q(["src","srcset","href"],function(a){var c=na("ng-"+a);Eb[c]=function(){return{priority:99,link:function(d,e,g){var f=a,h=a;"href"===a&&"[object SVGAnimatedString]"===ya.call(e.prop("href"))&&(h="xlinkHref",g.$attr[h]="xlink:href",f=null);g.$observe(c,function(a){a&&(g.$set(h,a),T&&f&&e.prop(f,g[h]))})}}}});var xb={$addControl:C,$removeControl:C,$setValidity:C,$setDirty:C,$setPristine:C};Uc.$inject=["$element","$attrs","$scope","$animate"];var Vc=function(a){return["$timeout",function(c){return{name:"form",
+restrict:a?"EAC":"E",controller:Uc,compile:function(){return{pre:function(a,e,g,f){if(!g.action){var h=function(a){a.preventDefault?a.preventDefault():a.returnValue=!1};qb(e[0],"submit",h);e.on("$destroy",function(){c(function(){Ua(e[0],"submit",h)},0,!1)})}var m=e.parent().controller("form"),k=g.name||g.ngForm;k&&sb(a,k,f,k);if(m)e.on("$destroy",function(){m.$removeControl(f);k&&sb(a,k,s,k);A(f,xb)})}}}}}]},md=Vc(),zd=Vc(!0),Ye=/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/,
+Ze=/^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*$/i,$e=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/,Wc=/^(\d{4})-(\d{2})-(\d{2})$/,Xc=/^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)$/,Sb=/^(\d{4})-W(\d\d)$/,Yc=/^(\d{4})-(\d\d)$/,Zc=/^(\d\d):(\d\d)$/,$c={text:bb,date:cb("date",Wc,zb(Wc,["yyyy","MM","dd"]),"yyyy-MM-dd"),"datetime-local":cb("datetimelocal",Xc,zb(Xc,["yyyy","MM","dd","HH","mm"]),"yyyy-MM-ddTHH:mm"),time:cb("time",Zc,zb(Zc,["HH","mm"]),"HH:mm"),week:cb("week",Sb,function(a){if(ra(a))return a;
+if(t(a)){Sb.lastIndex=0;var c=Sb.exec(a);if(c){a=+c[1];var d=+c[2],c=Sc(a),d=7*(d-1);return new Date(a,0,c.getDate()+d)}}return NaN},"yyyy-Www"),month:cb("month",Yc,zb(Yc,["yyyy","MM"]),"yyyy-MM"),number:function(a,c,d,e,g,f){bb(a,c,d,e,g,f);e.$parsers.push(function(a){var c=e.$isEmpty(a);if(c||$e.test(a))return e.$setValidity("number",!0),""===a?null:c?a:parseFloat(a);e.$setValidity("number",!1);return s});Te(e,"number",c);e.$formatters.push(function(a){return e.$isEmpty(a)?"":""+a});d.min&&(a=function(a){var c=
+parseFloat(d.min);return qa(e,"min",e.$isEmpty(a)||a>=c,a)},e.$parsers.push(a),e.$formatters.push(a));d.max&&(a=function(a){var c=parseFloat(d.max);return qa(e,"max",e.$isEmpty(a)||a<=c,a)},e.$parsers.push(a),e.$formatters.push(a));e.$formatters.push(function(a){return qa(e,"number",e.$isEmpty(a)||Ab(a),a)})},url:function(a,c,d,e,g,f){bb(a,c,d,e,g,f);a=function(a){return qa(e,"url",e.$isEmpty(a)||Ye.test(a),a)};e.$formatters.push(a);e.$parsers.push(a)},email:function(a,c,d,e,g,f){bb(a,c,d,e,g,f);
+a=function(a){return qa(e,"email",e.$isEmpty(a)||Ze.test(a),a)};e.$formatters.push(a);e.$parsers.push(a)},radio:function(a,c,d,e){D(d.name)&&c.attr("name",eb());c.on("click",function(){c[0].checked&&a.$apply(function(){e.$setViewValue(d.value)})});e.$render=function(){c[0].checked=d.value==e.$viewValue};d.$observe("value",e.$render)},checkbox:function(a,c,d,e){var g=d.ngTrueValue,f=d.ngFalseValue;t(g)||(g=!0);t(f)||(f=!1);c.on("click",function(){a.$apply(function(){e.$setViewValue(c[0].checked)})});
+e.$render=function(){c[0].checked=e.$viewValue};e.$isEmpty=function(a){return a!==g};e.$formatters.push(function(a){return a===g});e.$parsers.push(function(a){return a?g:f})},hidden:C,button:C,submit:C,reset:C,file:C},gc=["$browser","$sniffer","$filter",function(a,c,d){return{restrict:"E",require:"?ngModel",link:function(e,g,f,h){h&&($c[I(f.type)]||$c.text)(e,g,f,h,c,a,d)}}}],wb="ng-valid",vb="ng-invalid",Ma="ng-pristine",yb="ng-dirty",af=["$scope","$exceptionHandler","$attrs","$element","$parse",
+"$animate",function(a,c,d,e,g,f){function h(a,c){c=c?"-"+ib(c,"-"):"";f.removeClass(e,(a?vb:wb)+c);f.addClass(e,(a?wb:vb)+c)}this.$modelValue=this.$viewValue=Number.NaN;this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$pristine=!0;this.$dirty=!1;this.$valid=!0;this.$invalid=!1;this.$name=d.name;var m=g(d.ngModel),k=m.assign;if(!k)throw v("ngModel")("nonassign",d.ngModel,ha(e));this.$render=C;this.$isEmpty=function(a){return D(a)||""===a||null===a||a!==a};var l=e.inheritedData("$formController")||
+xb,n=0,p=this.$error={};e.addClass(Ma);h(!0);this.$setValidity=function(a,c){p[a]!==!c&&(c?(p[a]&&n--,n||(h(!0),this.$valid=!0,this.$invalid=!1)):(h(!1),this.$invalid=!0,this.$valid=!1,n++),p[a]=!c,h(c,a),l.$setValidity(a,c,this))};this.$setPristine=function(){this.$dirty=!1;this.$pristine=!0;f.removeClass(e,yb);f.addClass(e,Ma)};this.$setViewValue=function(d){this.$viewValue=d;this.$pristine&&(this.$dirty=!0,this.$pristine=!1,f.removeClass(e,Ma),f.addClass(e,yb),l.$setDirty());q(this.$parsers,function(a){d=
+a(d)});this.$modelValue!==d&&(this.$modelValue=d,k(a,d),q(this.$viewChangeListeners,function(a){try{a()}catch(d){c(d)}}))};var r=this;a.$watch(function(){var c=m(a);if(r.$modelValue!==c){var d=r.$formatters,e=d.length;for(r.$modelValue=c;e--;)c=d[e](c);r.$viewValue!==c&&(r.$viewValue=c,r.$render())}return c})}],Od=function(){return{require:["ngModel","^?form"],controller:af,link:function(a,c,d,e){var g=e[0],f=e[1]||xb;f.$addControl(g);a.$on("$destroy",function(){f.$removeControl(g)})}}},Qd=aa({require:"ngModel",
+link:function(a,c,d,e){e.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}),hc=function(){return{require:"?ngModel",link:function(a,c,d,e){if(e){d.required=!0;var g=function(a){if(d.required&&e.$isEmpty(a))e.$setValidity("required",!1);else return e.$setValidity("required",!0),a};e.$formatters.push(g);e.$parsers.unshift(g);d.$observe("required",function(){g(e.$viewValue)})}}}},Pd=function(){return{require:"ngModel",link:function(a,c,d,e){var g=(a=/\/(.*)\//.exec(d.ngList))&&RegExp(a[1])||
+d.ngList||",";e.$parsers.push(function(a){if(!D(a)){var c=[];a&&q(a.split(g),function(a){a&&c.push(ca(a))});return c}});e.$formatters.push(function(a){return M(a)?a.join(", "):s});e.$isEmpty=function(a){return!a||!a.length}}}},bf=/^(true|false|\d+)$/,Rd=function(){return{priority:100,compile:function(a,c){return bf.test(c.ngValue)?function(a,c,g){g.$set("value",a.$eval(g.ngValue))}:function(a,c,g){a.$watch(g.ngValue,function(a){g.$set("value",a)})}}}},rd=xa(function(a,c,d){c.addClass("ng-binding").data("$binding",
+d.ngBind);a.$watch(d.ngBind,function(a){c.text(a==s?"":a)})}),td=["$interpolate",function(a){return function(c,d,e){c=a(d.attr(e.$attr.ngBindTemplate));d.addClass("ng-binding").data("$binding",c);e.$observe("ngBindTemplate",function(a){d.text(a)})}}],sd=["$sce","$parse",function(a,c){return function(d,e,g){e.addClass("ng-binding").data("$binding",g.ngBindHtml);var f=c(g.ngBindHtml);d.$watch(function(){return(f(d)||"").toString()},function(c){e.html(a.getTrustedHtml(f(d))||"")})}}],ud=Rb("",!0),wd=
+Rb("Odd",0),vd=Rb("Even",1),xd=xa({compile:function(a,c){c.$set("ngCloak",s);a.removeClass("ng-cloak")}}),yd=[function(){return{scope:!0,controller:"@",priority:500}}],ic={};q("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste".split(" "),function(a){var c=na("ng-"+a);ic[c]=["$parse",function(d){return{compile:function(e,g){var f=d(g[c]);return function(c,d,e){d.on(I(a),function(a){c.$apply(function(){f(c,{$event:a})})})}}}}]});
+var Bd=["$animate",function(a){return{transclude:"element",priority:600,terminal:!0,restrict:"A",$$tlb:!0,link:function(c,d,e,g,f){var h,m,k;c.$watch(e.ngIf,function(g){Pa(g)?m||(m=c.$new(),f(m,function(c){c[c.length++]=U.createComment(" end ngIf: "+e.ngIf+" ");h={clone:c};a.enter(c,d.parent(),d)})):(k&&(k.remove(),k=null),m&&(m.$destroy(),m=null),h&&(k=Db(h.clone),a.leave(k,function(){k=null}),h=null))})}}}],Cd=["$http","$templateCache","$anchorScroll","$animate","$sce",function(a,c,d,e,g){return{restrict:"ECA",
+priority:400,terminal:!0,transclude:"element",controller:Qa.noop,compile:function(f,h){var m=h.ngInclude||h.src,k=h.onload||"",l=h.autoscroll;return function(f,h,r,q,z){var s=0,w,y,G,x=function(){y&&(y.remove(),y=null);w&&(w.$destroy(),w=null);G&&(e.leave(G,function(){y=null}),y=G,G=null)};f.$watch(g.parseAsResourceUrl(m),function(g){var m=function(){!B(l)||l&&!f.$eval(l)||d()},r=++s;g?(a.get(g,{cache:c}).success(function(a){if(r===s){var c=f.$new();q.template=a;a=z(c,function(a){x();e.enter(a,null,
+h,m)});w=c;G=a;w.$emit("$includeContentLoaded");f.$eval(k)}}).error(function(){r===s&&x()}),f.$emit("$includeContentRequested")):(x(),q.template=null)})}}}}],Sd=["$compile",function(a){return{restrict:"ECA",priority:-400,require:"ngInclude",link:function(c,d,e,g){d.html(g.template);a(d.contents())(c)}}}],Dd=xa({priority:450,compile:function(){return{pre:function(a,c,d){a.$eval(d.ngInit)}}}}),Ed=xa({terminal:!0,priority:1E3}),Fd=["$locale","$interpolate",function(a,c){var d=/{}/g;return{restrict:"EA",
+link:function(e,g,f){var h=f.count,m=f.$attr.when&&g.attr(f.$attr.when),k=f.offset||0,l=e.$eval(m)||{},n={},p=c.startSymbol(),r=c.endSymbol(),s=/^when(Minus)?(.+)$/;q(f,function(a,c){s.test(c)&&(l[I(c.replace("when","").replace("Minus","-"))]=g.attr(f.$attr[c]))});q(l,function(a,e){n[e]=c(a.replace(d,p+h+"-"+k+r))});e.$watch(function(){var c=parseFloat(e.$eval(h));if(isNaN(c))return"";c in l||(c=a.pluralCat(c-k));return n[c](e,g,!0)},function(a){g.text(a)})}}}],Gd=["$parse","$animate",function(a,
+c){var d=v("ngRepeat");return{transclude:"element",priority:1E3,terminal:!0,$$tlb:!0,link:function(e,g,f,h,m){var k=f.ngRepeat,l=k.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),n,p,r,s,z,B,w={$id:Ja};if(!l)throw d("iexp",k);f=l[1];h=l[2];(l=l[3])?(n=a(l),p=function(a,c,d){B&&(w[B]=a);w[z]=c;w.$index=d;return n(e,w)}):(r=function(a,c){return Ja(c)},s=function(a){return a});l=f.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);if(!l)throw d("iidexp",f);z=l[3]||l[1];
+B=l[2];var H={};e.$watchCollection(h,function(a){var f,h,l=g[0],n,w={},E,R,t,C,S,v,D=[];if(db(a))S=a,n=p||r;else{n=p||s;S=[];for(t in a)a.hasOwnProperty(t)&&"$"!=t.charAt(0)&&S.push(t);S.sort()}E=S.length;h=D.length=S.length;for(f=0;f<h;f++)if(t=a===S?f:S[f],C=a[t],C=n(t,C,f),Ba(C,"`track by` id"),H.hasOwnProperty(C))v=H[C],delete H[C],w[C]=v,D[f]=v;else{if(w.hasOwnProperty(C))throw q(D,function(a){a&&a.scope&&(H[a.id]=a)}),d("dupes",k,C);D[f]={id:C};w[C]=!1}for(t in H)H.hasOwnProperty(t)&&(v=H[t],
+f=Db(v.clone),c.leave(f),q(f,function(a){a.$$NG_REMOVED=!0}),v.scope.$destroy());f=0;for(h=S.length;f<h;f++){t=a===S?f:S[f];C=a[t];v=D[f];D[f-1]&&(l=D[f-1].clone[D[f-1].clone.length-1]);if(v.scope){R=v.scope;n=l;do n=n.nextSibling;while(n&&n.$$NG_REMOVED);v.clone[0]!=n&&c.move(Db(v.clone),null,y(l));l=v.clone[v.clone.length-1]}else R=e.$new();R[z]=C;B&&(R[B]=t);R.$index=f;R.$first=0===f;R.$last=f===E-1;R.$middle=!(R.$first||R.$last);R.$odd=!(R.$even=0===(f&1));v.scope||m(R,function(a){a[a.length++]=
+U.createComment(" end ngRepeat: "+k+" ");c.enter(a,null,y(l));l=a;v.scope=R;v.clone=a;w[v.id]=v})}H=w})}}}],Hd=["$animate",function(a){return function(c,d,e){c.$watch(e.ngShow,function(c){a[Pa(c)?"removeClass":"addClass"](d,"ng-hide")})}}],Ad=["$animate",function(a){return function(c,d,e){c.$watch(e.ngHide,function(c){a[Pa(c)?"addClass":"removeClass"](d,"ng-hide")})}}],Id=xa(function(a,c,d){a.$watch(d.ngStyle,function(a,d){d&&a!==d&&q(d,function(a,d){c.css(d,"")});a&&c.css(a)},!0)}),Jd=["$animate",
+function(a){return{restrict:"EA",require:"ngSwitch",controller:["$scope",function(){this.cases={}}],link:function(c,d,e,g){var f,h,m,k=[];c.$watch(e.ngSwitch||e.on,function(d){var n,p=k.length;if(0<p){if(m){for(n=0;n<p;n++)m[n].remove();m=null}m=[];for(n=0;n<p;n++){var r=h[n];k[n].$destroy();m[n]=r;a.leave(r,function(){m.splice(n,1);0===m.length&&(m=null)})}}h=[];k=[];if(f=g.cases["!"+d]||g.cases["?"])c.$eval(e.change),q(f,function(d){var e=c.$new();k.push(e);d.transclude(e,function(c){var e=d.element;
+h.push(c);a.enter(c,e.parent(),e)})})})}}}],Kd=xa({transclude:"element",priority:800,require:"^ngSwitch",link:function(a,c,d,e,g){e.cases["!"+d.ngSwitchWhen]=e.cases["!"+d.ngSwitchWhen]||[];e.cases["!"+d.ngSwitchWhen].push({transclude:g,element:c})}}),Ld=xa({transclude:"element",priority:800,require:"^ngSwitch",link:function(a,c,d,e,g){e.cases["?"]=e.cases["?"]||[];e.cases["?"].push({transclude:g,element:c})}}),Nd=xa({link:function(a,c,d,e,g){if(!g)throw v("ngTransclude")("orphan",ha(c));g(function(a){c.empty();
+c.append(a)})}}),nd=["$templateCache",function(a){return{restrict:"E",terminal:!0,compile:function(c,d){"text/ng-template"==d.type&&a.put(d.id,c[0].text)}}}],cf=v("ngOptions"),Md=aa({terminal:!0}),od=["$compile","$parse",function(a,c){var d=/^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/,e={$setViewValue:C};return{restrict:"E",require:["select","?ngModel"],
+controller:["$element","$scope","$attrs",function(a,c,d){var m=this,k={},l=e,n;m.databound=d.ngModel;m.init=function(a,c,d){l=a;n=d};m.addOption=function(c){Ba(c,'"option value"');k[c]=!0;l.$viewValue==c&&(a.val(c),n.parent()&&n.remove())};m.removeOption=function(a){this.hasOption(a)&&(delete k[a],l.$viewValue==a&&this.renderUnknownOption(a))};m.renderUnknownOption=function(c){c="? "+Ja(c)+" ?";n.val(c);a.prepend(n);a.val(c);n.prop("selected",!0)};m.hasOption=function(a){return k.hasOwnProperty(a)};
+c.$on("$destroy",function(){m.renderUnknownOption=C})}],link:function(e,f,h,m){function k(a,c,d,e){d.$render=function(){var a=d.$viewValue;e.hasOption(a)?(G.parent()&&G.remove(),c.val(a),""===a&&v.prop("selected",!0)):D(a)&&v?c.val(""):e.renderUnknownOption(a)};c.on("change",function(){a.$apply(function(){G.parent()&&G.remove();d.$setViewValue(c.val())})})}function l(a,c,d){var e;d.$render=function(){var a=new Wa(d.$viewValue);q(c.find("option"),function(c){c.selected=B(a.get(c.value))})};a.$watch(function(){za(e,
+d.$viewValue)||(e=ba(d.$viewValue),d.$render())});c.on("change",function(){a.$apply(function(){var a=[];q(c.find("option"),function(c){c.selected&&a.push(c.value)});d.$setViewValue(a)})})}function n(e,f,g){function h(){var a={"":[]},c=[""],d,k,s,t,u;t=g.$modelValue;u=y(e)||[];var D=n?Tb(u):u,G,J,A;J={};s=!1;var E,I;if(r)if(v&&M(t))for(s=new Wa([]),A=0;A<t.length;A++)J[l]=t[A],s.put(v(e,J),t[A]);else s=new Wa(t);for(A=0;G=D.length,A<G;A++){k=A;if(n){k=D[A];if("$"===k.charAt(0))continue;J[n]=k}J[l]=
+u[k];d=p(e,J)||"";(k=a[d])||(k=a[d]=[],c.push(d));r?d=B(s.remove(v?v(e,J):q(e,J))):(v?(d={},d[l]=t,d=v(e,d)===v(e,J)):d=t===q(e,J),s=s||d);E=m(e,J);E=B(E)?E:"";k.push({id:v?v(e,J):n?D[A]:A,label:E,selected:d})}r||(z||null===t?a[""].unshift({id:"",label:"",selected:!s}):s||a[""].unshift({id:"?",label:"",selected:!0}));J=0;for(D=c.length;J<D;J++){d=c[J];k=a[d];x.length<=J?(t={element:C.clone().attr("label",d),label:k.label},u=[t],x.push(u),f.append(t.element)):(u=x[J],t=u[0],t.label!=d&&t.element.attr("label",
+t.label=d));E=null;A=0;for(G=k.length;A<G;A++)s=k[A],(d=u[A+1])?(E=d.element,d.label!==s.label&&E.text(d.label=s.label),d.id!==s.id&&E.val(d.id=s.id),d.selected!==s.selected&&E.prop("selected",d.selected=s.selected)):(""===s.id&&z?I=z:(I=w.clone()).val(s.id).attr("selected",s.selected).text(s.label),u.push({element:I,label:s.label,id:s.id,selected:s.selected}),E?E.after(I):t.element.append(I),E=I);for(A++;u.length>A;)u.pop().element.remove()}for(;x.length>J;)x.pop()[0].element.remove()}var k;if(!(k=
+t.match(d)))throw cf("iexp",t,ha(f));var m=c(k[2]||k[1]),l=k[4]||k[6],n=k[5],p=c(k[3]||""),q=c(k[2]?k[1]:l),y=c(k[7]),v=k[8]?c(k[8]):null,x=[[{element:f,label:""}]];z&&(a(z)(e),z.removeClass("ng-scope"),z.remove());f.empty();f.on("change",function(){e.$apply(function(){var a,c=y(e)||[],d={},h,k,m,p,t,w,u;if(r)for(k=[],p=0,w=x.length;p<w;p++)for(a=x[p],m=1,t=a.length;m<t;m++){if((h=a[m].element)[0].selected){h=h.val();n&&(d[n]=h);if(v)for(u=0;u<c.length&&(d[l]=c[u],v(e,d)!=h);u++);else d[l]=c[h];k.push(q(e,
+d))}}else{h=f.val();if("?"==h)k=s;else if(""===h)k=null;else if(v)for(u=0;u<c.length;u++){if(d[l]=c[u],v(e,d)==h){k=q(e,d);break}}else d[l]=c[h],n&&(d[n]=h),k=q(e,d);1<x[0].length&&x[0][1].id!==h&&(x[0][1].selected=!1)}g.$setViewValue(k)})});g.$render=h;e.$watch(h)}if(m[1]){var p=m[0];m=m[1];var r=h.multiple,t=h.ngOptions,z=!1,v,w=y(U.createElement("option")),C=y(U.createElement("optgroup")),G=w.clone();h=0;for(var x=f.children(),A=x.length;h<A;h++)if(""===x[h].value){v=z=x.eq(h);break}p.init(m,z,
+G);r&&(m.$isEmpty=function(a){return!a||0===a.length});t?n(e,f,m):r?l(e,f,m):k(e,f,m,p)}}}}],qd=["$interpolate",function(a){var c={addOption:C,removeOption:C};return{restrict:"E",priority:100,compile:function(d,e){if(D(e.value)){var g=a(d.text(),!0);g||e.$set("value",d.text())}return function(a,d,e){var k=d.parent(),l=k.data("$selectController")||k.parent().data("$selectController");l&&l.databound?d.prop("selected",!1):l=c;g?a.$watch(g,function(a,c){e.$set("value",a);a!==c&&l.removeOption(c);l.addOption(a)}):
+l.addOption(e.value);d.on("$destroy",function(){l.removeOption(e.value)})}}}}],pd=aa({restrict:"E",terminal:!1});O.angular.bootstrap?console.log("WARNING: Tried to load angular more than once."):((Ha=O.jQuery)?(y=Ha,A(Ha.fn,{scope:Ka.scope,isolateScope:Ka.isolateScope,controller:Ka.controller,injector:Ka.injector,inheritedData:Ka.inheritedData}),Fb("remove",!0,!0,!1),Fb("empty",!1,!1,!1),Fb("html",!1,!1,!0)):y=N,Qa.element=y,hd(Qa),y(U).ready(function(){ed(U,cc)}))})(window,document);
+!angular.$$csp()&&angular.element(document).find("head").prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}</style>');
+//# sourceMappingURL=angular.min.js.map
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular-resource.min.js b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular-resource.min.js
new file mode 100644
index 0000000..3f196c3
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular-resource.min.js
@@ -0,0 +1,13 @@
+/*
+ AngularJS v1.3.0-beta.5
+ (c) 2010-2014 Google, Inc. http://angularjs.org
+ License: MIT
+*/
+(function(H,a,A){'use strict';function D(p,g){g=g||{};a.forEach(g,function(a,c){delete g[c]});for(var c in p)!p.hasOwnProperty(c)||"$"===c.charAt(0)&&"$"===c.charAt(1)||(g[c]=p[c]);return g}var v=a.$$minErr("$resource"),C=/^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/;a.module("ngResource",["ng"]).factory("$resource",["$http","$q",function(p,g){function c(a,c){this.template=a;this.defaults=c||{};this.urlParams={}}function t(n,w,l){function r(h,d){var e={};d=x({},w,d);s(d,function(b,d){u(b)&&(b=b());var k;if(b&&
+b.charAt&&"@"==b.charAt(0)){k=h;var a=b.substr(1);if(null==a||""===a||"hasOwnProperty"===a||!C.test("."+a))throw v("badmember",a);for(var a=a.split("."),f=0,c=a.length;f<c&&k!==A;f++){var g=a[f];k=null!==k?k[g]:A}}else k=b;e[d]=k});return e}function e(a){return a.resource}function f(a){D(a||{},this)}var F=new c(n);l=x({},B,l);s(l,function(h,d){var c=/^(POST|PUT|PATCH)$/i.test(h.method);f[d]=function(b,d,k,w){var q={},n,l,y;switch(arguments.length){case 4:y=w,l=k;case 3:case 2:if(u(d)){if(u(b)){l=
+b;y=d;break}l=d;y=k}else{q=b;n=d;l=k;break}case 1:u(b)?l=b:c?n=b:q=b;break;case 0:break;default:throw v("badargs",arguments.length);}var t=this instanceof f,m=t?n:h.isArray?[]:new f(n),z={},B=h.interceptor&&h.interceptor.response||e,C=h.interceptor&&h.interceptor.responseError||A;s(h,function(a,b){"params"!=b&&("isArray"!=b&&"interceptor"!=b)&&(z[b]=G(a))});c&&(z.data=n);F.setUrlParams(z,x({},r(n,h.params||{}),q),h.url);q=p(z).then(function(b){var d=b.data,k=m.$promise;if(d){if(a.isArray(d)!==!!h.isArray)throw v("badcfg",
+h.isArray?"array":"object",a.isArray(d)?"array":"object");h.isArray?(m.length=0,s(d,function(b){m.push(new f(b))})):(D(d,m),m.$promise=k)}m.$resolved=!0;b.resource=m;return b},function(b){m.$resolved=!0;(y||E)(b);return g.reject(b)});q=q.then(function(b){var a=B(b);(l||E)(a,b.headers);return a},C);return t?q:(m.$promise=q,m.$resolved=!1,m)};f.prototype["$"+d]=function(b,a,k){u(b)&&(k=a,a=b,b={});b=f[d].call(this,b,this,a,k);return b.$promise||b}});f.bind=function(a){return t(n,x({},w,a),l)};return f}
+var B={get:{method:"GET"},save:{method:"POST"},query:{method:"GET",isArray:!0},remove:{method:"DELETE"},"delete":{method:"DELETE"}},E=a.noop,s=a.forEach,x=a.extend,G=a.copy,u=a.isFunction;c.prototype={setUrlParams:function(c,g,l){var r=this,e=l||r.template,f,p,h=r.urlParams={};s(e.split(/\W/),function(a){if("hasOwnProperty"===a)throw v("badname");!/^\d+$/.test(a)&&(a&&RegExp("(^|[^\\\\]):"+a+"(\\W|$)").test(e))&&(h[a]=!0)});e=e.replace(/\\:/g,":");g=g||{};s(r.urlParams,function(d,c){f=g.hasOwnProperty(c)?
+g[c]:r.defaults[c];a.isDefined(f)&&null!==f?(p=encodeURIComponent(f).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"%20").replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+"),e=e.replace(RegExp(":"+c+"(\\W|$)","g"),function(a,c){return p+c})):e=e.replace(RegExp("(/?):"+c+"(\\W|$)","g"),function(a,c,d){return"/"==d.charAt(0)?d:c+d})});e=e.replace(/\/+$/,"")||"/";e=e.replace(/\/\.(?=\w+($|\?))/,".");c.url=e.replace(/\/\\\./,"/.");s(g,function(a,
+e){r.urlParams[e]||(c.params=c.params||{},c.params[e]=a)})}};return t}])})(window,window.angular);
+//# sourceMappingURL=angular-resource.min.js.map
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular-route.min.js b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular-route.min.js
new file mode 100644
index 0000000..9e161e2
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/lib/angular/angular-route.min.js
@@ -0,0 +1,14 @@
+/*
+ AngularJS v1.3.0-beta.5
+ (c) 2010-2014 Google, Inc. http://angularjs.org
+ License: MIT
+*/
+(function(n,e,A){'use strict';function x(s,g,k){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(a,c,b,f,w){function y(){p&&(p.remove(),p=null);h&&(h.$destroy(),h=null);l&&(k.leave(l,function(){p=null}),p=l,l=null)}function v(){var b=s.current&&s.current.locals;if(e.isDefined(b&&b.$template)){var b=a.$new(),d=s.current;l=w(b,function(d){k.enter(d,null,l||c,function(){!e.isDefined(t)||t&&!a.$eval(t)||g()});y()});h=d.scope=b;h.$emit("$viewContentLoaded");h.$eval(u)}else y()}
+var h,l,p,t=b.autoscroll,u=b.onload||"";a.$on("$routeChangeSuccess",v);v()}}}function z(e,g,k){return{restrict:"ECA",priority:-400,link:function(a,c){var b=k.current,f=b.locals;c.html(f.$template);var w=e(c.contents());b.controller&&(f.$scope=a,f=g(b.controller,f),b.controllerAs&&(a[b.controllerAs]=f),c.data("$ngControllerController",f),c.children().data("$ngControllerController",f));w(a)}}}n=e.module("ngRoute",["ng"]).provider("$route",function(){function s(a,c){return e.extend(new (e.extend(function(){},
+{prototype:a})),c)}function g(a,e){var b=e.caseInsensitiveMatch,f={originalPath:a,regexp:a},k=f.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)([\?\*])?/g,function(a,e,b,c){a="?"===c?c:null;c="*"===c?c:null;k.push({name:b,optional:!!a});e=e||"";return""+(a?"":e)+"(?:"+(a?e:"")+(c&&"(.+?)"||"([^/]+)")+(a||"")+")"+(a||"")}).replace(/([\/$\*])/g,"\\$1");f.regexp=RegExp("^"+a+"$",b?"i":"");return f}var k={};this.when=function(a,c){k[a]=e.extend({reloadOnSearch:!0},c,a&&g(a,c));if(a){var b=
+"/"==a[a.length-1]?a.substr(0,a.length-1):a+"/";k[b]=e.extend({redirectTo:a},g(b,c))}return this};this.otherwise=function(a){this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache","$sce",function(a,c,b,f,g,n,v,h){function l(){var d=p(),m=r.current;if(d&&m&&d.$$route===m.$$route&&e.equals(d.pathParams,m.pathParams)&&!d.reloadOnSearch&&!u)m.params=d.params,e.copy(m.params,b),a.$broadcast("$routeUpdate",m);else if(d||m)u=!1,a.$broadcast("$routeChangeStart",
+d,m),(r.current=d)&&d.redirectTo&&(e.isString(d.redirectTo)?c.path(t(d.redirectTo,d.params)).search(d.params).replace():c.url(d.redirectTo(d.pathParams,c.path(),c.search())).replace()),f.when(d).then(function(){if(d){var a=e.extend({},d.resolve),c,b;e.forEach(a,function(d,c){a[c]=e.isString(d)?g.get(d):g.invoke(d)});e.isDefined(c=d.template)?e.isFunction(c)&&(c=c(d.params)):e.isDefined(b=d.templateUrl)&&(e.isFunction(b)&&(b=b(d.params)),b=h.getTrustedResourceUrl(b),e.isDefined(b)&&(d.loadedTemplateUrl=
+b,c=n.get(b,{cache:v}).then(function(a){return a.data})));e.isDefined(c)&&(a.$template=c);return f.all(a)}}).then(function(c){d==r.current&&(d&&(d.locals=c,e.copy(d.params,b)),a.$broadcast("$routeChangeSuccess",d,m))},function(c){d==r.current&&a.$broadcast("$routeChangeError",d,m,c)})}function p(){var a,b;e.forEach(k,function(f,k){var q;if(q=!b){var g=c.path();q=f.keys;var l={};if(f.regexp)if(g=f.regexp.exec(g)){for(var h=1,p=g.length;h<p;++h){var n=q[h-1],r="string"==typeof g[h]?decodeURIComponent(g[h]):
+g[h];n&&r&&(l[n.name]=r)}q=l}else q=null;else q=null;q=a=q}q&&(b=s(f,{params:e.extend({},c.search(),a),pathParams:a}),b.$$route=f)});return b||k[null]&&s(k[null],{params:{},pathParams:{}})}function t(a,c){var b=[];e.forEach((a||"").split(":"),function(a,d){if(0===d)b.push(a);else{var e=a.match(/(\w+)(.*)/),f=e[1];b.push(c[f]);b.push(e[2]||"");delete c[f]}});return b.join("")}var u=!1,r={routes:k,reload:function(){u=!0;a.$evalAsync(l)}};a.$on("$locationChangeSuccess",l);return r}]});n.provider("$routeParams",
+function(){this.$get=function(){return{}}});n.directive("ngView",x);n.directive("ngView",z);x.$inject=["$route","$anchorScroll","$animate"];z.$inject=["$compile","$controller","$route"]})(window,window.angular);
+//# sourceMappingURL=angular-route.min.js.map
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/lib/jwt-decode.min.js b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/lib/jwt-decode.min.js
new file mode 100644
index 0000000..f56f967
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/lib/jwt-decode.min.js
@@ -0,0 +1 @@
+!function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);throw new Error("Cannot find module '"+g+"'")}var j=c[g]={exports:{}};b[g][0].call(j.exports,function(a){var c=b[g][1][a];return e(c?c:a)},j,j.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g<d.length;g++)e(d[g]);return e}({1:[function(a,b){function c(a){return decodeURIComponent(atob(a).replace(/(.)/g,function(a,b){var c=b.charCodeAt(0).toString(16).toUpperCase();return c.length<2&&(c="0"+c),"%"+c}))}var d=a("Base64");b.exports=function(a){var b=a.replace(/-/g,"+").replace(/_/g,"/");switch(b.length%4){case 0:break;case 2:b+="==";break;case 3:b+="=";break;default:throw"Illegal base64url string!"}try{return c(b)}catch(e){return d.atob(b)}}},{Base64:4}],2:[function(a,b){"use strict";var c=a("./base64_url_decode"),d=a("./json_parse");b.exports=function(a){if(!a)throw new Error("Invalid token specified");return d(c(a.split(".")[1]))}},{"./base64_url_decode":1,"./json_parse":3}],3:[function(require,module,exports){module.exports=function(str){var parsed;return parsed="object"==typeof JSON?JSON.parse(str):eval("("+str+")")}},{}],4:[function(a,b,c){!function(){var a="undefined"!=typeof c?c:this,b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",d=function(){try{document.createElement("$")}catch(a){return a}}();a.btoa||(a.btoa=function(a){for(var c,e,f=0,g=b,h="";a.charAt(0|f)||(g="=",f%1);h+=g.charAt(63&c>>8-f%1*8)){if(e=a.charCodeAt(f+=.75),e>255)throw d;c=c<<8|e}return h}),a.atob||(a.atob=function(a){if(a=a.replace(/=+$/,""),a.length%4==1)throw d;for(var c,e,f=0,g=0,h="";e=a.charAt(g++);~e&&(c=f%4?64*c+e:e,f++%4)?h+=String.fromCharCode(255&c>>(-2*f&6)):0)e=b.indexOf(e);return h})}()},{}],5:[function(a){var b="undefined"!=typeof self?self:"undefined"!=typeof window?window:{},c=a("./lib/index");"function"==typeof b.window.define&&b.window.define.amd?b.window.define("jwt_decode",function(){return c}):b.window&&(b.window.jwt_decode=c)},{"./lib/index":2}]},{},[5]);
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/partials/admin/albums.html b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/partials/admin/albums.html
new file mode 100644
index 0000000..00f52d7
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/partials/admin/albums.html
@@ -0,0 +1,19 @@
+<h1>All Albums</h1>
+<table class="table" data-ng-repeat="(key, value) in albums">
+    <thead>
+    <tr>
+        <th>{{key}}</th>
+    </tr>
+    </thead>
+    <tbody>
+    <tr>
+        <td>
+            <ul>
+                <li data-ng-repeat="p in value">
+                    <a id="view-{{p.name}}" href="#/album/{{p.id}}">{{p.name}}</a> - [<a href="#/admin/album" id="delete-{{p.name}}" ng-click="deleteAlbum(p)">X</a>]
+                </li>
+            </ul>
+        </td>
+    </tr>
+    </tbody>
+</table>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/partials/album/create.html b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/partials/album/create.html
new file mode 100644
index 0000000..d9ddd25
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/partials/album/create.html
@@ -0,0 +1,7 @@
+<h1>Create an Album</h1>
+
+<form>
+    Name: <input type="text" id="album.name" ng-model="album.name"/>
+
+    <button ng-click="create()" id="save-album">Save</button>
+</form>
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/partials/album/detail.html b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/partials/album/detail.html
new file mode 100644
index 0000000..cf32df1
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/partials/album/detail.html
@@ -0,0 +1 @@
+<h1>{{album.name}}</h1>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/partials/home.html b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/partials/home.html
new file mode 100644
index 0000000..e144d1b
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/partials/home.html
@@ -0,0 +1,22 @@
+<h2><span>Welcome To Photoz, {{Identity.claims.name}}</span></h2>
+<div data-ng-show="Identity.isAdmin()"><b>Administration: </b> [<a href="#/admin/album" id="admin-albums">All Albums</a>]</div>
+<hr/>
+<br/>
+<div data-ng-show="!Identity.isAdmin()">
+<a href="#/album/create" id="create-album">Create Album</a> | <a href="#/profile">My Profile</a>
+<br/>
+<br/>
+<span data-ng-show="albums.length == 0" id="resource-list-empty">You don't have any albums, yet.</span>
+<table class="table" data-ng-show="albums.length > 0">
+    <thead>
+    <tr>
+        <th>Your Albums</th>
+    </tr>
+    </thead>
+    <tbody>
+    <tr data-ng-repeat="p in albums">
+        <td><a id="view-{{p.name}}" href="#/album/{{p.id}}">{{p.name}}</a> - [<a href="#" id="delete-{{p.name}}" ng-click="deleteAlbum(p)">X</a>]</td>
+    </tr>
+    </tbody>
+</table>
+</div>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/partials/profile.html b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/partials/profile.html
new file mode 100644
index 0000000..c6f6750
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/partials/profile.html
@@ -0,0 +1,6 @@
+<h1>My Profile</h1>
+
+<form>
+    <p>Name: {{profile.userName}}</p>
+    <p>Total of albums: {{profile.totalAlbums}}</p>
+</form>
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/WEB-INF/web.xml b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..a370557
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-html5-client/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>photoz-html5-client</module-name>
+
+</web-app>
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-realm.json b/testsuite/integration-arquillian/test-apps/photoz/photoz-realm.json
new file mode 100644
index 0000000..b0aeb5d
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-realm.json
@@ -0,0 +1,125 @@
+{
+  "realm": "photoz",
+  "enabled": true,
+  "sslRequired": "external",
+  "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+  "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "requiredCredentials": [
+    "password"
+  ],
+  "users": [
+    {
+      "username": "alice",
+      "enabled": true,
+      "email": "alice@keycloak.org",
+      "firstName": "Alice",
+      "lastName": "In Chains",
+      "credentials": [
+        {
+          "type": "password",
+          "value": "alice"
+        }
+      ],
+      "realmRoles": [
+        "user", "uma_authorization"
+      ],
+      "clientRoles": {
+        "photoz-restful-api": [
+          "manage-albums"
+        ]
+      }
+    },
+    {
+      "username": "jdoe",
+      "enabled": true,
+      "email": "jdoe@keycloak.org",
+      "firstName": "John",
+      "lastName": "Doe",
+      "credentials": [
+        {
+          "type": "password",
+          "value": "jdoe"
+        }
+      ],
+      "realmRoles": [
+        "user", "uma_authorization"
+      ],
+      "clientRoles": {
+        "photoz-restful-api": [
+          "manage-albums"
+        ]
+      }
+    },
+    {
+      "username": "admin",
+      "enabled": true,
+      "email": "admin@admin.com",
+      "firstName": "Admin",
+      "lastName": "Istrator",
+      "credentials": [
+        {
+          "type": "password",
+          "value": "admin"
+        }
+      ],
+      "realmRoles": [
+        "admin", "uma_authorization"
+      ],
+      "clientRoles": {
+        "realm-management": [
+          "realm-admin"
+        ],
+        "photoz-restful-api": [
+          "manage-albums"
+        ]
+      }
+    },
+    {
+      "username": "service-account-photoz-restful-api",
+      "enabled": true,
+      "email": "service-account-photoz-restful-api@placeholder.org",
+      "serviceAccountClientId": "photoz-restful-api",
+      "clientRoles": {
+        "photoz-restful-api" : ["uma_protection"]
+      }
+    }
+  ],
+  "roles": {
+    "realm": [
+      {
+        "name": "user",
+        "description": "User privileges"
+      },
+      {
+        "name": "admin",
+        "description": "Administrator privileges"
+      }
+    ]
+  },
+  "clients": [
+    {
+      "clientId": "photoz-html5-client",
+      "enabled": true,
+      "adminUrl": "/photoz-html5-client",
+      "baseUrl": "/photoz-html5-client",
+      "publicClient": true,
+      "consentRequired" : true,
+      "fullScopeAllowed" : true,
+      "redirectUris": [
+        "/photoz-html5-client/*"
+      ],
+      "webOrigins": ["*"]
+    },
+    {
+      "clientId": "photoz-restful-api",
+      "secret": "secret",
+      "enabled": true,
+      "baseUrl": "/photoz-restful-api",
+      "authorizationServicesEnabled" : true,
+      "redirectUris": [
+        "/photoz-restful-api/*"
+      ],
+      "webOrigins" : ["*"]
+    }
+  ]
+}
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/pom.xml b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/pom.xml
new file mode 100755
index 0000000..7885857
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/pom.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian-test-apps-photoz-parent</artifactId>
+        <version>2.2.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>photoz-restful-api</artifactId>
+    <packaging>war</packaging>
+
+    <name>Keycloak Authz Test: Photoz RESTful API</name>
+    <description>Photoz RESTful API</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.jboss.spec.javax.ws.rs</groupId>
+            <artifactId>jboss-jaxrs-api_2.0_spec</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.spec.javax.servlet</groupId>
+            <artifactId>jboss-servlet-api_3.0_spec</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>javax.persistence</groupId>
+            <artifactId>persistence-api</artifactId>
+            <version>1.0.2</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.spec.javax.ejb</groupId>
+            <artifactId>jboss-ejb-api_3.2_spec</artifactId>
+            <version>1.0.0.Final</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-authz-client</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.jboss.as.plugins</groupId>
+                <artifactId>jboss-as-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.wildfly.plugins</groupId>
+                <artifactId>wildfly-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/admin/AdminAlbumService.java b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/admin/AdminAlbumService.java
new file mode 100644
index 0000000..b349e02
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/admin/AdminAlbumService.java
@@ -0,0 +1,62 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.example.photoz.admin;
+
+import org.keycloak.example.photoz.entity.Album;
+
+import javax.ejb.Stateless;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@Path("/admin/album")
+@Stateless
+public class AdminAlbumService {
+
+    public static final String SCOPE_ADMIN_ALBUM_MANAGE = "urn:photoz.com:scopes:album:admin:manage";
+
+    @PersistenceContext
+    private EntityManager entityManager;
+
+    @Context
+    private HttpHeaders headers;
+
+    @GET
+    @Produces("application/json")
+    public Response findAll() {
+        HashMap<String, List<Album>> albums = new HashMap<>();
+        List<Album> result = this.entityManager.createQuery("from Album").getResultList();
+
+        for (Album album : result) {
+            albums.computeIfAbsent(album.getUserId(), key -> new ArrayList<>()).add(album);
+        }
+
+        return Response.ok(albums).build();
+    }
+}
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/AlbumService.java b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/AlbumService.java
new file mode 100644
index 0000000..a5d7f16
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/AlbumService.java
@@ -0,0 +1,158 @@
+package org.keycloak.example.photoz.album;
+
+import org.keycloak.authorization.client.AuthzClient;
+import org.keycloak.authorization.client.Configuration;
+import org.keycloak.authorization.client.representation.ResourceRepresentation;
+import org.keycloak.authorization.client.representation.ScopeRepresentation;
+import org.keycloak.authorization.client.resource.ProtectionResource;
+import org.keycloak.example.photoz.ErrorResponse;
+import org.keycloak.example.photoz.entity.Album;
+import org.keycloak.representations.adapters.config.AdapterConfig;
+import org.keycloak.util.JsonSerialization;
+
+import javax.ejb.Stateless;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import java.security.Principal;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Path("/album")
+@Stateless
+public class AlbumService {
+
+    public static final String SCOPE_ALBUM_VIEW = "urn:photoz.com:scopes:album:view";
+    public static final String SCOPE_ALBUM_CREATE = "urn:photoz.com:scopes:album:create";
+    public static final String SCOPE_ALBUM_DELETE = "urn:photoz.com:scopes:album:delete";
+
+    @PersistenceContext
+    private EntityManager entityManager;
+
+    @Context
+    private HttpServletRequest request;
+
+    private AuthzClient authzClient;
+
+    public AlbumService() {
+
+    }
+
+    @POST
+    @Consumes("application/json")
+    public Response create(Album newAlbum) {
+        Principal userPrincipal = request.getUserPrincipal();
+
+        newAlbum.setUserId(userPrincipal.getName());
+
+        Query queryDuplicatedAlbum = this.entityManager.createQuery("from Album where name = :name and userId = :userId");
+
+        queryDuplicatedAlbum.setParameter("name", newAlbum.getName());
+        queryDuplicatedAlbum.setParameter("userId", userPrincipal.getName());
+
+        if (!queryDuplicatedAlbum.getResultList().isEmpty()) {
+            throw new ErrorResponse("Name [" + newAlbum.getName() + "] already taken. Choose another one.", Status.CONFLICT);
+        }
+
+        this.entityManager.persist(newAlbum);
+
+        createProtectedResource(newAlbum);
+
+        return Response.ok(newAlbum).build();
+    }
+
+    @Path("{id}")
+    @DELETE
+    public Response delete(@PathParam("id") String id) {
+        Album album = this.entityManager.find(Album.class, Long.valueOf(id));
+
+        try {
+            deleteProtectedResource(album);
+            this.entityManager.remove(album);
+        } catch (Exception e) {
+            throw new RuntimeException("Could not delete album.", e);
+        }
+
+        return Response.ok().build();
+    }
+
+    @GET
+    @Produces("application/json")
+    public Response findAll() {
+        return Response.ok(this.entityManager.createQuery("from Album where userId = '" + request.getUserPrincipal().getName() + "'").getResultList()).build();
+    }
+
+    @GET
+    @Path("{id}")
+    @Produces("application/json")
+    public Response findById(@PathParam("id") String id) {
+        List result = this.entityManager.createQuery("from Album where id = " + id).getResultList();
+
+        if (result.isEmpty()) {
+            return Response.status(Status.NOT_FOUND).build();
+        }
+
+        return Response.ok(result.get(0)).build();
+    }
+
+    private void createProtectedResource(Album album) {
+        try {
+            HashSet<ScopeRepresentation> scopes = new HashSet<>();
+
+            scopes.add(new ScopeRepresentation(SCOPE_ALBUM_VIEW));
+            scopes.add(new ScopeRepresentation(SCOPE_ALBUM_DELETE));
+
+            ResourceRepresentation albumResource = new ResourceRepresentation(album.getName(), scopes, "/album/" + album.getId(), "http://photoz.com/album");
+
+            albumResource.setOwner(album.getUserId());
+
+            getAuthzClient().protection().resource().create(albumResource);
+        } catch (Exception e) {
+            throw new RuntimeException("Could not register protected resource.", e);
+        }
+    }
+
+    private void deleteProtectedResource(Album album) {
+        String uri = "/album/" + album.getId();
+
+        try {
+            ProtectionResource protection = getAuthzClient().protection();
+            Set<String> search = protection.resource().findByFilter("uri=" + uri);
+
+            if (search.isEmpty()) {
+                throw new RuntimeException("Could not find protected resource with URI [" + uri + "]");
+            }
+
+            protection.resource().delete(search.iterator().next());
+        } catch (Exception e) {
+            throw new RuntimeException("Could not search protected resource.", e);
+        }
+    }
+
+    private AuthzClient getAuthzClient() {
+        if (this.authzClient == null) {
+            try {
+                AdapterConfig adapterConfig = JsonSerialization.readValue(this.request.getServletContext().getResourceAsStream("/WEB-INF/keycloak.json"), AdapterConfig.class);
+                Configuration configuration = new Configuration(adapterConfig.getAuthServerUrl(), adapterConfig.getRealm(), adapterConfig.getResource(), adapterConfig.getCredentials(), null);
+
+                this.authzClient = AuthzClient.create(configuration);
+            } catch (Exception e) {
+                throw new RuntimeException("Could not create authorization client.", e);
+            }
+        }
+
+        return this.authzClient;
+    }
+}
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/ProfileService.java b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/ProfileService.java
new file mode 100644
index 0000000..be638b6
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/album/ProfileService.java
@@ -0,0 +1,70 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.example.photoz.album;
+
+import javax.ejb.Stateless;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import java.security.Principal;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@Path("/profile")
+@Stateless
+public class ProfileService {
+
+    private static final String PROFILE_VIEW = "urn:photoz.com:scopes:profile:view";
+
+    @PersistenceContext
+    private EntityManager entityManager;
+
+    @GET
+    @Produces("application/json")
+    public Response view(@Context HttpServletRequest request) {
+        Principal userPrincipal = request.getUserPrincipal();
+        List albums = this.entityManager.createQuery("from Album where userId = '" + userPrincipal.getName() + "'").getResultList();
+        return Response.ok(new Profile(userPrincipal.getName(), albums.size())).build();
+    }
+
+    public static class Profile {
+        private String userName;
+        private int totalAlbums;
+
+        public Profile(String name, int totalAlbums) {
+            this.userName = name;
+            this.totalAlbums = totalAlbums;
+        }
+
+        public String getUserName() {
+            return userName;
+        }
+
+        public int getTotalAlbums() {
+            return totalAlbums;
+        }
+    }
+}
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Album.java b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Album.java
new file mode 100644
index 0000000..978bdea
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Album.java
@@ -0,0 +1,79 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.example.photoz.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@Entity
+public class Album {
+
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    @Column(nullable = false)
+    private String name;
+
+    @OneToMany(mappedBy = "album", fetch = FetchType.EAGER)
+    private List<Photo> photos = new ArrayList<>();
+
+    @Column(nullable = false)
+    private String userId;
+
+    public Long getId() {
+        return this.id;
+    }
+
+    public void setId(final Long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    public List<Photo> getPhotos() {
+        return this.photos;
+    }
+
+    public void setPhotos(final List<Photo> photos) {
+        this.photos = photos;
+    }
+
+    public void setUserId(final String userId) {
+        this.userId = userId;
+    }
+
+    public String getUserId() {
+        return this.userId;
+    }
+}
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Photo.java b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Photo.java
new file mode 100644
index 0000000..08b7495
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/entity/Photo.java
@@ -0,0 +1,81 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 Red Hat, Inc. and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.example.photoz.entity;
+
+import javax.persistence.Basic;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Lob;
+import javax.persistence.ManyToOne;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+@Entity
+public class Photo {
+
+    @Id
+    @GeneratedValue
+    private Long id;
+
+    @Column
+    private String name;
+
+    @ManyToOne
+    private Album album;
+
+    @Lob
+    @Column
+    @Basic(fetch = FetchType.LAZY)
+    private byte[] image;
+
+    public Long getId() {
+        return this.id;
+    }
+
+    public void setId(final Long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    public Album getAlbum() {
+        return this.album;
+    }
+
+    public void setAlbum(final Album album) {
+        this.album = album;
+    }
+
+    public byte[] getImage() {
+        return this.image;
+    }
+
+    public void setImage(final byte[] image) {
+        this.image = image;
+    }
+}
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/ErrorResponse.java b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/ErrorResponse.java
new file mode 100644
index 0000000..51755d8
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/ErrorResponse.java
@@ -0,0 +1,32 @@
+package org.keycloak.example.photoz;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ErrorResponse extends WebApplicationException {
+
+    private final Response.Status status;
+
+    public ErrorResponse(String message) {
+        this(message, Response.Status.INTERNAL_SERVER_ERROR);
+    }
+
+    public ErrorResponse(String message, Response.Status status) {
+        super(message, status);
+        this.status = status;
+    }
+
+    @Override
+    public Response getResponse() {
+        Map<String, String> errorResponse = new HashMap<>();
+
+        errorResponse.put("message", getMessage());
+
+        return Response.status(status).entity(errorResponse).build();
+    }
+}
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/PhotozApplication.java b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/PhotozApplication.java
new file mode 100644
index 0000000..5b8377c
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/java/org/keycloak/example/photoz/PhotozApplication.java
@@ -0,0 +1,12 @@
+package org.keycloak.example.photoz;
+
+import javax.ws.rs.ApplicationPath;
+import javax.ws.rs.core.Application;
+
+/**
+ * Basic auth app.
+ */
+@ApplicationPath("/")
+public class PhotozApplication extends Application {
+
+}
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/resources/META-INF/beans.xml b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/resources/META-INF/beans.xml
new file mode 100644
index 0000000..957dc8a
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/resources/META-INF/beans.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+   xsi:schemaLocation="
+        http://java.sun.com/xml/ns/javaee 
+        http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
+        
+</beans>
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/resources/META-INF/persistence.xml b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/resources/META-INF/persistence.xml
new file mode 100644
index 0000000..9323182
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/resources/META-INF/persistence.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<persistence version="2.0"
+	xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="
+        http://java.sun.com/xml/ns/persistence
+        http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
+	<persistence-unit name="primary">
+		<non-jta-data-source>java:jboss/datasources/PhotozDS</non-jta-data-source>
+
+		<class>org.keycloak.example.photoz.entity.Album</class>
+		<class>org.keycloak.example.photoz.entity.Photo</class>
+
+		<properties>
+			<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
+			<property name="hibernate.hbm2ddl.auto" value="update" />
+			<property name="hibernate.show_sql" value="false" />
+		</properties>
+	</persistence-unit>
+</persistence>
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/META-INF/jboss-deployment-structure.xml b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/META-INF/jboss-deployment-structure.xml
new file mode 100644
index 0000000..4b23be6
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/META-INF/jboss-deployment-structure.xml
@@ -0,0 +1,26 @@
+<!--
+  ~  Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~  and other contributors as indicated by the @author tags.
+  ~
+  ~  Licensed under the Apache License, Version 2.0 (the "License");
+  ~  you may not use this file except in compliance with the License.
+  ~  You may obtain a copy of the License at
+  ~
+  ~  http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing, software
+  ~  distributed under the License is distributed on an "AS IS" BASIS,
+  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  See the License for the specific language governing permissions and
+  ~  limitations under the License.
+  ~
+  -->
+
+<jboss-deployment-structure>
+    <deployment>
+        <dependencies>
+            <module name="org.keycloak.keycloak-authz-client" services="import"/>
+        </dependencies>
+    </deployment>
+</jboss-deployment-structure>
+
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/WEB-INF/keycloak.json b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/WEB-INF/keycloak.json
new file mode 100644
index 0000000..a3ac697
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/WEB-INF/keycloak.json
@@ -0,0 +1,50 @@
+{
+  "realm": "photoz",
+  "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url": "http://localhost:8180/auth",
+  "ssl-required": "external",
+  "resource": "photoz-restful-api",
+  "bearer-only" : true,
+  "credentials": {
+    "secret": "secret"
+  },
+  "policy-enforcer": {
+    "user-managed-access" : {},
+    "paths": [
+      {
+        "path" : "/album/*",
+        "methods" : [
+          {
+            "method": "POST",
+            "scopes" : ["urn:photoz.com:scopes:album:create"]
+          },
+          {
+            "method": "GET",
+            "scopes" : ["urn:photoz.com:scopes:album:view"]
+          }
+        ]
+      },
+      {
+        "name" : "Album Resource",
+        "path" : "/album/{id}",
+        "methods" : [
+          {
+            "method": "DELETE",
+            "scopes" : ["urn:photoz.com:scopes:album:delete"]
+          },
+          {
+            "method": "GET",
+            "scopes" : ["urn:photoz.com:scopes:album:view"]
+          }
+        ]
+      },
+      {
+        "path" : "/profile"
+      },
+      {
+        "name" : "Admin Resources",
+        "path" : "/admin/*"
+      }
+    ]
+  }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/WEB-INF/photoz-ds.xml b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/WEB-INF/photoz-ds.xml
new file mode 100644
index 0000000..247448f
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/WEB-INF/photoz-ds.xml
@@ -0,0 +1,12 @@
+<datasources xmlns="http://www.jboss.org/ironjacamar/schema"
+             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+             xsi:schemaLocation="http://www.jboss.org/ironjacamar/schema http://docs.jboss.org/ironjacamar/schema/datasources_1_0.xsd">
+    <datasource jndi-name="java:jboss/datasources/PhotozDS" pool-name="PhotozDS" enabled="true" use-java-context="true">
+        <connection-url>jdbc:h2:${jboss.server.data.dir}/kc-authz-photo;AUTO_SERVER=TRUE</connection-url>
+        <driver>h2</driver>
+        <security>
+            <user-name>sa</user-name>
+            <password>sa</password>
+        </security>
+    </datasource>
+</datasources>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/WEB-INF/web.xml b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..34cf6bd
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>photoz-restful-api</module-name>
+
+	<security-constraint>
+		<web-resource-collection>
+			<web-resource-name>All Resources</web-resource-name>
+			<url-pattern>/*</url-pattern>
+		</web-resource-collection>
+		<auth-constraint>
+			<role-name>user</role-name>
+		</auth-constraint>
+	</security-constraint>
+
+	<security-constraint>
+		<web-resource-collection>
+			<web-resource-name>All Resources</web-resource-name>
+			<url-pattern>/*</url-pattern>
+		</web-resource-collection>
+		<auth-constraint>
+			<role-name>admin</role-name>
+		</auth-constraint>
+	</security-constraint>
+
+	<login-config>
+		<auth-method>KEYCLOAK</auth-method>
+		<realm-name>photoz</realm-name>
+	</login-config>
+
+	<security-role>
+		<role-name>admin</role-name>
+	</security-role>
+
+	<security-role>
+		<role-name>user</role-name>
+	</security-role>
+</web-app>
diff --git a/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api-authz-service.json b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api-authz-service.json
new file mode 100644
index 0000000..6547d2f
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/photoz-restful-api-authz-service.json
@@ -0,0 +1,188 @@
+{
+  "allowRemoteResourceManagement": true,
+  "policyEnforcementMode": "ENFORCING",
+  "resources": [
+    {
+      "name": "User Profile Resource",
+      "uri": "/profile",
+      "type": "http://photoz.com/profile",
+      "scopes": [
+        {
+          "name": "urn:photoz.com:scopes:profile:view"
+        }
+      ]
+    },
+    {
+      "name": "Album Resource",
+      "uri": "/album/*",
+      "type": "http://photoz.com/album",
+      "scopes": [
+        {
+          "name": "urn:photoz.com:scopes:album:view"
+        },
+        {
+          "name": "urn:photoz.com:scopes:album:delete"
+        },
+        {
+          "name": "urn:photoz.com:scopes:album:create"
+        }
+      ]
+    },
+    {
+      "name": "Admin Resources",
+      "uri": "/admin/*",
+      "type": "http://photoz.com/admin",
+      "scopes": [
+        {
+          "name": "urn:photoz.com:scopes:album:admin:manage"
+        }
+      ]
+    }
+  ],
+  "policies": [
+    {
+      "name": "Only Owner Policy",
+      "description": "Defines that only the resource owner is allowed to do something",
+      "type": "drools",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "mavenArtifactVersion": "2.1.0-SNAPSHOT",
+        "mavenArtifactId": "photoz-authz-policy",
+        "sessionName": "MainOwnerSession",
+        "mavenArtifactGroupId": "org.keycloak",
+        "moduleName": "PhotozAuthzOwnerPolicy",
+        "applyPolicies": "[]",
+        "scannerPeriod": "1",
+        "scannerPeriodUnit": "Hours"
+      }
+    },
+    {
+      "name": "Any Admin Policy",
+      "description": "Defines that adminsitrators can do something",
+      "type": "role",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "applyPolicies": "[]",
+        "roles": "[{\"id\":\"admin\",\"required\":true}]"
+      }
+    },
+    {
+      "name": "Any User Policy",
+      "description": "Defines that only users from well known clients are allowed to access",
+      "type": "role",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "applyPolicies": "[]",
+        "roles": "[{\"id\":\"user\"},{\"id\":\"manage-albums\",\"required\":true}]"
+      }
+    },
+    {
+      "name": "Only From a Specific Client Address",
+      "description": "Defines that only clients from a specific address can do something",
+      "type": "js",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "applyPolicies": "[]",
+        "code": "var contextAttributes = $evaluation.getContext().getAttributes();\n\nif (contextAttributes.containsValue('kc.client.network.ip_address', '127.0.0.1')) {\n    $evaluation.grant();\n}"
+      }
+    },
+    {
+      "name": "Administration Policy",
+      "description": "Defines that only administrators from a specific network address can do something.",
+      "type": "aggregate",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "applyPolicies": "[\"Only From a Specific Client Address\",\"Any Admin Policy\"]"
+      }
+    },
+    {
+      "name": "Only Owner and Administrators Policy",
+      "description": "Defines that only the resource owner and administrators can do something",
+      "type": "aggregate",
+      "logic": "POSITIVE",
+      "decisionStrategy": "AFFIRMATIVE",
+      "config": {
+        "applyPolicies": "[\"Administration Policy\",\"Only Owner Policy\"]"
+      }
+    },
+    {
+      "name": "Only From @keycloak.org or Admin",
+      "description": "Defines that only users from @keycloak.org",
+      "type": "js",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "applyPolicies": "[]",
+        "code": "var context = $evaluation.getContext();\nvar identity = context.getIdentity();\nvar attributes = identity.getAttributes();\nvar email = attributes.getValue('email').asString(0);\n\nif (identity.hasRole('admin') || email.endsWith('@keycloak.org')) {\n    $evaluation.grant();\n}"
+      }
+    },
+    {
+      "name": "Album Resource Permission",
+      "description": "General policies that apply to all album resources.",
+      "type": "resource",
+      "logic": "POSITIVE",
+      "decisionStrategy": "AFFIRMATIVE",
+      "config": {
+        "defaultResourceType": "http://photoz.com/album",
+        "default": "true",
+        "applyPolicies": "[\"Any User Policy\",\"Administration Policy\"]"
+      }
+    },
+    {
+      "name": "Admin Resource Permission",
+      "description": "General policy for any administrative resource.",
+      "type": "resource",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "defaultResourceType": "http://photoz.com/admin",
+        "default": "true",
+        "applyPolicies": "[\"Administration Policy\"]"
+      }
+    },
+    {
+      "name": "View User Permission",
+      "description": "Defines who is allowed to view an user profile",
+      "type": "scope",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "applyPolicies": "[\"Only From @keycloak.org or Admin\"]",
+        "scopes": "[\"urn:photoz.com:scopes:profile:view\"]"
+      }
+    },
+    {
+      "name": "Delete Album Permission",
+      "description": "A policy that only allows the owner to delete his albums.",
+      "type": "scope",
+      "logic": "POSITIVE",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "applyPolicies": "[\"Only Owner and Administrators Policy\"]",
+        "scopes": "[\"urn:photoz.com:scopes:album:delete\"]"
+      }
+    }
+  ],
+  "scopes": [
+    {
+      "name": "urn:photoz.com:scopes:profile:view"
+    },
+    {
+      "name": "urn:photoz.com:scopes:album:view"
+    },
+    {
+      "name": "urn:photoz.com:scopes:album:create"
+    },
+    {
+      "name": "urn:photoz.com:scopes:album:delete"
+    },
+    {
+      "name": "urn:photoz.com:scopes:album:admin:manage"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/photoz/pom.xml b/testsuite/integration-arquillian/test-apps/photoz/pom.xml
new file mode 100755
index 0000000..7aaae74
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/photoz/pom.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian-test-apps</artifactId>
+        <version>2.2.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>integration-arquillian-test-apps-photoz-parent</artifactId>
+    <packaging>pom</packaging>
+
+    <name>Keycloak Authz: PhotoZ  Test Parent</name>
+    <description>PhotoZ Test Application</description>
+
+    <modules>
+        <module>photoz-restful-api</module>
+        <module>photoz-html5-client</module>
+        <module>photoz-authz-policy</module>
+    </modules>
+</project>
diff --git a/testsuite/integration-arquillian/test-apps/pom.xml b/testsuite/integration-arquillian/test-apps/pom.xml
index 12c89a0..d2746f6 100644
--- a/testsuite/integration-arquillian/test-apps/pom.xml
+++ b/testsuite/integration-arquillian/test-apps/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>integration-arquillian</artifactId>
         <groupId>org.keycloak.testsuite</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -17,5 +17,9 @@
     <modules>
         <module>js-console</module>
         <module>test-apps-dist</module>
+        <module>js-database</module>
+        <module>photoz</module>
+        <module>hello-world-authz-service</module>
+        <module>servlet-authz</module>
     </modules>
 </project>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/servlet-authz/pom.xml b/testsuite/integration-arquillian/test-apps/servlet-authz/pom.xml
new file mode 100755
index 0000000..6c51d71
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/servlet-authz/pom.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.keycloak.testsuite</groupId>
+        <artifactId>integration-arquillian-test-apps</artifactId>
+        <version>2.2.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>servlet-authz-app</artifactId>
+    <packaging>war</packaging>
+
+    <name>Keycloak Authz: Servlet Authorization Test</name>
+    <description>Servlet Authorization Test</description>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-authz-client</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-core</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.jboss.as.plugins</groupId>
+                <artifactId>jboss-as-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.wildfly.plugins</groupId>
+                <artifactId>wildfly-maven-plugin</artifactId>
+                <configuration>
+                    <skip>false</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/testsuite/integration-arquillian/test-apps/servlet-authz/README.md b/testsuite/integration-arquillian/test-apps/servlet-authz/README.md
new file mode 100644
index 0000000..f93acb5
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/servlet-authz/README.md
@@ -0,0 +1,54 @@
+# About the Example Application
+
+This is a simple Servlet-based application that will introduce you to some of the main concepts around Keycloak Authorization Services.
+
+For this application, users can be regular users, premium users or administrators, where:
+
+* Regular users have very limited access.
+* Premium users have access to the *premium area*
+* Administrators have access to the *administration area*
+
+In Keycloak, all the paths being protected are resources on the server.
+
+This application will also show you how to create a dynamic menu with the permissions granted to an user.
+
+## Create the Example Realm and a Resource Server
+
+Considering that your Keycloak Server is up and running, log in to the Keycloak Administration Console.
+
+Now, create a new realm based on the following configuration file:
+
+    examples/authz/servlet-authz/servlet-authz-realm.json
+    
+That will import a pre-configured realm with everything you need to run this example. For more details about how to import a realm 
+into Keycloak, check the Keycloak's reference documentation.
+
+After importing that file, you'll have a new realm called ``servlet-authz``. 
+
+Now, let's import another configuration using the Administration Console in order to configure the client application ``servlet-authz-app`` as a resource server with all resources, scopes, permissions and policies.
+
+Click on ``Clients`` on the left side menu. Click on the ``servlet-authz-app`` on the client listing page. This will
+open the ``Client Details`` page. Once there, click on the `Authorization` tab. 
+
+Click on the ``Select file`` button, which means you want to import a resource server configuration. Now select the file that is located at:
+
+    examples/authz/servlet-authz/servlet-authz-app-config.json
+    
+Now click ``Upload`` and the resource server will be updated accordingly.
+
+## Deploy and Run the Example Applications
+
+To deploy the example application, follow these steps:
+
+    cd examples/authz/servlet-authz
+    mvn clean package wildfly:deploy
+    
+Now, try to access the client application using the following URL:
+
+    http://localhost:8080/servlet-authz-app
+
+If everything is correct, you will be redirect to Keycloak login page. You can login to the application with the following credentials:
+
+* username: jdoe / password: jdoe
+* username: alice / password: alice
+* username: admin / password: admin
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/servlet-authz/servlet-authz-app-authz-service.json b/testsuite/integration-arquillian/test-apps/servlet-authz/servlet-authz-app-authz-service.json
new file mode 100644
index 0000000..43ebde4
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/servlet-authz/servlet-authz-app-authz-service.json
@@ -0,0 +1,147 @@
+{
+  "allowRemoteResourceManagement": true,
+  "policyEnforcementMode": "ENFORCING",
+  "resources": [
+    {
+      "name": "Admin Resource",
+      "uri": "/protected/admin/*",
+      "type": "http://servlet-authz/protected/admin",
+      "scopes": [
+        {
+          "name": "urn:servlet-authz:protected:admin:access"
+        }
+      ]
+    },
+    {
+      "name": "Protected Resource",
+      "uri": "/*",
+      "type": "http://servlet-authz/protected/resource",
+      "scopes": [
+        {
+          "name": "urn:servlet-authz:protected:resource:access"
+        }
+      ]
+    },
+    {
+      "name": "Premium Resource",
+      "uri": "/protected/premium/*",
+      "type": "urn:servlet-authz:protected:resource",
+      "scopes": [
+        {
+          "name": "urn:servlet-authz:protected:premium:access"
+        }
+      ]
+    },
+    {
+      "name": "Main Page",
+      "type": "urn:servlet-authz:protected:resource",
+      "scopes": [
+        {
+          "name": "urn:servlet-authz:page:main:actionForAdmin"
+        },
+        {
+          "name": "urn:servlet-authz:page:main:actionForUser"
+        },
+        {
+          "name": "urn:servlet-authz:page:main:actionForPremiumUser"
+        }
+      ]
+    }
+  ],
+  "policies": [
+    {
+      "name": "Any Admin Policy",
+      "description": "Defines that adminsitrators can do something",
+      "type": "role",
+      "config": {
+        "roles": "[{\"id\":\"admin\"}]"
+      }
+    },
+    {
+      "name": "Any User Policy",
+      "description": "Defines that any user can do something",
+      "type": "role",
+      "config": {
+        "roles": "[{\"id\":\"user\"}]"
+      }
+    },
+    {
+      "name": "Only Premium User Policy",
+      "description": "Defines that only premium users can do something",
+      "type": "role",
+      "logic": "POSITIVE",
+      "config": {
+        "roles": "[{\"id\":\"user_premium\"}]"
+      }
+    },
+    {
+      "name": "All Users Policy",
+      "description": "Defines that all users can do something",
+      "type": "aggregate",
+      "decisionStrategy": "AFFIRMATIVE",
+      "config": {
+        "applyPolicies": "[\"Any User Policy\",\"Any Admin Policy\",\"Only Premium User Policy\"]"
+      }
+    },
+    {
+      "name": "Premium Resource Permission",
+      "description": "A policy that defines access to premium resources",
+      "type": "resource",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "resources": "[\"Premium Resource\"]",
+        "applyPolicies": "[\"Only Premium User Policy\"]"
+      }
+    },
+    {
+      "name": "Administrative Resource Permission",
+      "description": "A policy that defines access to administrative resources",
+      "type": "resource",
+      "decisionStrategy": "UNANIMOUS",
+      "config": {
+        "resources": "[\"Admin Resource\"]",
+        "applyPolicies": "[\"Any Admin Policy\"]"
+      }
+    },
+    {
+      "name": "Protected Resource Permission",
+      "description": "A policy that defines access to any protected resource",
+      "type": "resource",
+      "decisionStrategy": "AFFIRMATIVE",
+      "config": {
+        "resources": "[\"Protected Resource\"]",
+        "applyPolicies": "[\"All Users Policy\"]"
+      }
+    },
+    {
+      "name": "Action 1 on Main Page Resource Permission",
+      "description": "A policy that defines access to action 1 on the main page",
+      "type": "scope",
+      "decisionStrategy": "AFFIRMATIVE",
+      "config": {
+        "scopes": "[\"urn:servlet-authz:page:main:actionForAdmin\"]",
+        "applyPolicies": "[\"Any Admin Policy\"]"
+      }
+    },
+    {
+      "name": "Action 2 on Main Page Resource Permission",
+      "description": "A policy that defines access to action 2 on the main page",
+      "type": "scope",
+      "decisionStrategy": "AFFIRMATIVE",
+      "config": {
+        "scopes": "[\"urn:servlet-authz:page:main:actionForUser\"]",
+        "applyPolicies": "[\"Any User Policy\"]"
+      }
+    },
+    {
+      "name": "Action 3 on Main Page Resource Permission",
+      "description": "A policy that defines access to action 3 on the main page",
+      "type": "scope",
+      "decisionStrategy": "AFFIRMATIVE",
+      "config": {
+        "scopes": "[\"urn:servlet-authz:page:main:actionForPremiumUser\"]",
+        "applyPolicies": "[\"Only Premium User Policy\"]"
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/servlet-authz/servlet-authz-realm.json b/testsuite/integration-arquillian/test-apps/servlet-authz/servlet-authz-realm.json
new file mode 100644
index 0000000..371e451
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/servlet-authz/servlet-authz-realm.json
@@ -0,0 +1,95 @@
+{
+  "realm": "servlet-authz",
+  "enabled": true,
+  "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+  "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "requiredCredentials": [
+    "password"
+  ],
+  "users": [
+    {
+      "username": "alice",
+      "enabled": true,
+      "credentials": [
+        {
+          "type": "password",
+          "value": "alice"
+        }
+      ],
+      "realmRoles": [
+        "user"
+      ]
+    },
+    {
+      "username": "jdoe",
+      "enabled": true,
+      "credentials": [
+        {
+          "type": "password",
+          "value": "jdoe"
+        }
+      ],
+      "realmRoles": [
+        "user",
+        "user_premium"
+      ]
+    },
+    {
+      "username": "admin",
+      "enabled": true,
+      "credentials": [
+        {
+          "type": "password",
+          "value": "admin"
+        }
+      ],
+      "realmRoles": [
+        "user",
+        "admin"
+      ],
+      "clientRoles": {
+        "realm-management": [
+          "realm-admin"
+        ]
+      }
+    },
+    {
+      "username": "service-account-servlet-authz-app",
+      "enabled": true,
+      "serviceAccountClientId": "servlet-authz-app",
+      "clientRoles": {
+        "servlet-authz-app" : ["uma_protection"]
+      }
+    }
+  ],
+  "roles": {
+    "realm": [
+      {
+        "name": "user",
+        "description": "User privileges"
+      },
+      {
+        "name": "admin",
+        "description": "Administrator privileges"
+      },
+      {
+        "name": "user_premium",
+        "description": "User Premium privileges"
+      }
+    ]
+  },
+  "clients": [
+    {
+      "clientId": "servlet-authz-app",
+      "enabled": true,
+      "baseUrl": "/servlet-authz-app",
+      "adminUrl": "/servlet-authz-app",
+      "bearerOnly": false,
+      "authorizationServicesEnabled": true,
+      "redirectUris": [
+        "/servlet-authz-app/*"
+      ],
+      "secret": "secret"
+    }
+  ]
+}
diff --git a/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/accessDenied.jsp b/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/accessDenied.jsp
new file mode 100644
index 0000000..6f25023
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/accessDenied.jsp
@@ -0,0 +1,6 @@
+<html>
+    <body>
+        <h2 style="color: red">You can not access this resource.</h2>
+        <%@include file="logout-include.jsp"%>
+    </body>
+</html>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/index.jsp b/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/index.jsp
new file mode 100755
index 0000000..3fbfca2
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/index.jsp
@@ -0,0 +1,35 @@
+<%@page import="org.keycloak.AuthorizationContext" %>
+<%@ page import="org.keycloak.KeycloakSecurityContext" %>
+<%@ page import="org.keycloak.representations.idm.authorization.Permission" %>
+
+<%
+    KeycloakSecurityContext keycloakSecurityContext = (KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
+    AuthorizationContext authzContext = keycloakSecurityContext.getAuthorizationContext();
+%>
+
+<html>
+<body>
+    <%@include file="logout-include.jsp"%>
+    <h2>This is a public resource. Try to access one of these <i>protected</i> resources:</h2>
+
+    <p><a href="protected/dynamicMenu.jsp">Dynamic Menu</a></p>
+    <p><a href="protected/premium/onlyPremium.jsp">User Premium</a></p>
+    <p><a href="protected/admin/onlyAdmin.jsp">Administration</a></p>
+
+    <h3>Your permissions are:</h3>
+
+    <ul>
+        <%
+            for (Permission permission : authzContext.getPermissions()) {
+        %>
+        <li>
+            <p>Resource: <%= permission.getResourceSetName() %></p>
+            <p>ID: <%= permission.getResourceSetId() %></p>
+            <p>Scopes: <%= permission.getScopes() %></p>
+        </li>
+        <%
+            }
+        %>
+    </ul>
+</body>
+</html>
diff --git a/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/logout-include.jsp b/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/logout-include.jsp
new file mode 100644
index 0000000..21ef2ed
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/logout-include.jsp
@@ -0,0 +1,11 @@
+<%@ page import="org.keycloak.common.util.KeycloakUriBuilder" %>
+<%@ page import="org.keycloak.constants.ServiceUrlConstants" %>
+<%
+    String scheme = request.getScheme();
+    String host = request.getServerName();
+    int port = request.getServerPort();
+    String contextPath = request.getContextPath();
+    String redirectUri = scheme + "://" + host + ":" + port + contextPath;
+%>
+<h2>Click here <a href="<%= KeycloakUriBuilder.fromUri("http://localhost:8180/auth").path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH)
+            .queryParam("redirect_uri", redirectUri).build("servlet-authz").toString()%>">Sign Out</a></h2>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/META-INF/jboss-deployment-structure.xml b/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/META-INF/jboss-deployment-structure.xml
new file mode 100644
index 0000000..515ffa5
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/META-INF/jboss-deployment-structure.xml
@@ -0,0 +1,25 @@
+<!--
+  ~  Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~  and other contributors as indicated by the @author tags.
+  ~
+  ~  Licensed under the Apache License, Version 2.0 (the "License");
+  ~  you may not use this file except in compliance with the License.
+  ~  You may obtain a copy of the License at
+  ~
+  ~  http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing, software
+  ~  distributed under the License is distributed on an "AS IS" BASIS,
+  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  See the License for the specific language governing permissions and
+  ~  limitations under the License.
+  ~
+  -->
+
+<jboss-deployment-structure>
+    <deployment>
+        <dependencies>
+            <module name="org.keycloak.keycloak-authz-client" services="import"/>
+        </dependencies>
+    </deployment>
+</jboss-deployment-structure>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/protected/admin/onlyAdmin.jsp b/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/protected/admin/onlyAdmin.jsp
new file mode 100644
index 0000000..5946cd6
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/protected/admin/onlyAdmin.jsp
@@ -0,0 +1,6 @@
+<html>
+<body>
+    <h2>Only Administrators can access this page.</h2>
+    <%@include file="../../logout-include.jsp"%>
+</body>
+</html>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/protected/dynamicMenu.jsp b/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/protected/dynamicMenu.jsp
new file mode 100644
index 0000000..1473d22
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/protected/dynamicMenu.jsp
@@ -0,0 +1,48 @@
+<%@page import="org.keycloak.AuthorizationContext" %>
+<%@ page import="org.keycloak.KeycloakSecurityContext" %>
+
+<%
+    KeycloakSecurityContext keycloakSecurityContext = (KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
+    AuthorizationContext authzContext = keycloakSecurityContext.getAuthorizationContext();
+%>
+
+<html>
+<body>
+<h2>Any authenticated user can access this page.</h2>
+<%@include file="../logout-include.jsp"%>
+
+<p>Here is a dynamic menu built from the permissions returned by the server:</p>
+
+<ul>
+    <%
+        if (authzContext.hasResourcePermission("Protected Resource")) {
+    %>
+    <li>
+        Do user thing
+    </li>
+    <%
+        }
+    %>
+
+    <%
+        if (authzContext.hasResourcePermission("Premium Resource")) {
+    %>
+    <li>
+        Do  user premium thing
+    </li>
+    <%
+        }
+    %>
+
+    <%
+        if (authzContext.hasPermission("Admin Resource", "urn:servlet-authz:protected:admin:access")) {
+    %>
+    <li>
+        Do administration thing
+    </li>
+    <%
+        }
+    %>
+</ul>
+</body>
+</html>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/protected/premium/onlyPremium.jsp b/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/protected/premium/onlyPremium.jsp
new file mode 100644
index 0000000..9244f9c
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/protected/premium/onlyPremium.jsp
@@ -0,0 +1,6 @@
+<html>
+<body>
+<h2>Only for premium users.</h2>
+<%@include file="../../logout-include.jsp"%>
+</body>
+</html>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/WEB-INF/keycloak.json b/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/WEB-INF/keycloak.json
new file mode 100644
index 0000000..7b362a7
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/WEB-INF/keycloak.json
@@ -0,0 +1,14 @@
+{
+  "realm": "servlet-authz",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url" : "http://localhost:8180/auth",
+  "ssl-required" : "external",
+  "resource" : "servlet-authz-app",
+  "public-client" : false,
+  "credentials": {
+    "secret": "secret"
+  },
+  "policy-enforcer": {
+    "on-deny-redirect-to" : "/servlet-authz-app/accessDenied.jsp"
+  }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/WEB-INF/web.xml b/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..14d0615
--- /dev/null
+++ b/testsuite/integration-arquillian/test-apps/servlet-authz/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+		 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+		 version="3.0">
+
+	<module-name>servlet-authz-app</module-name>
+
+	<security-constraint>
+		<web-resource-collection>
+			<web-resource-name>All Resources</web-resource-name>
+			<url-pattern>/*</url-pattern>
+		</web-resource-collection>
+		<auth-constraint>
+			<role-name>user</role-name>
+		</auth-constraint>
+	</security-constraint>
+
+	<security-constraint>
+		<web-resource-collection>
+			<web-resource-name>All Resources</web-resource-name>
+			<url-pattern>/*</url-pattern>
+		</web-resource-collection>
+		<auth-constraint>
+			<role-name>admin</role-name>
+		</auth-constraint>
+	</security-constraint>
+
+	<login-config>
+		<auth-method>KEYCLOAK</auth-method>
+		<realm-name>servlet-authz</realm-name>
+	</login-config>
+
+	<security-role>
+		<role-name>admin</role-name>
+	</security-role>
+
+	<security-role>
+		<role-name>user</role-name>
+	</security-role>
+
+	<error-page>
+		<error-code>403</error-code>
+		<location>/accessDenied.jsp</location>
+	</error-page>
+
+</web-app>
diff --git a/testsuite/integration-arquillian/test-apps/test-apps-dist/build.xml b/testsuite/integration-arquillian/test-apps/test-apps-dist/build.xml
index e48e088..3e90544 100755
--- a/testsuite/integration-arquillian/test-apps/test-apps-dist/build.xml
+++ b/testsuite/integration-arquillian/test-apps/test-apps-dist/build.xml
@@ -27,5 +27,29 @@
                 <exclude name="**/subsystem-config.xml"/>
             </fileset>
         </copy>
+        <copy todir="target/test-apps/photoz" overwrite="true">
+            <fileset dir="../photoz">
+                <exclude name="**/target/**"/>
+                <exclude name="**/*.iml"/>
+                <exclude name="**/*.unconfigured"/>
+                <exclude name="**/subsystem-config.xml"/>
+            </fileset>
+        </copy>
+        <copy todir="target/test-apps/hello-world-authz-service" overwrite="true">
+            <fileset dir="../hello-world-authz-service">
+                <exclude name="**/target/**"/>
+                <exclude name="**/*.iml"/>
+                <exclude name="**/*.unconfigured"/>
+                <exclude name="**/subsystem-config.xml"/>
+            </fileset>
+        </copy>
+        <copy todir="target/test-apps/servlet-authz-app" overwrite="true">
+            <fileset dir="../servlet-authz">
+                <exclude name="**/target/**"/>
+                <exclude name="**/*.iml"/>
+                <exclude name="**/*.unconfigured"/>
+                <exclude name="**/subsystem-config.xml"/>
+            </fileset>
+        </copy>
     </target>
 </project>
diff --git a/testsuite/integration-arquillian/test-apps/test-apps-dist/pom.xml b/testsuite/integration-arquillian/test-apps/test-apps-dist/pom.xml
index 38ce732..30e5cc6 100644
--- a/testsuite/integration-arquillian/test-apps/test-apps-dist/pom.xml
+++ b/testsuite/integration-arquillian/test-apps/test-apps-dist/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>integration-arquillian-test-apps</artifactId>
         <groupId>org.keycloak.testsuite</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/testsuite/integration-arquillian/tests/base/pom.xml b/testsuite/integration-arquillian/tests/base/pom.xml
index ee6ad1b..ac85ebd 100644
--- a/testsuite/integration-arquillian/tests/base/pom.xml
+++ b/testsuite/integration-arquillian/tests/base/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -32,6 +32,7 @@
     <description></description>
 
     <properties>
+        <exclude.test>-</exclude.test>
         <exclude.console>-</exclude.console>
         <exclude.account>-</exclude.account>
         <exclude.client>-</exclude.client>
@@ -68,6 +69,11 @@
             <scope>compile</scope>
         </dependency>
         <dependency>
+            <groupId>org.subethamail</groupId>
+            <artifactId>subethasmtp</artifactId>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
             <groupId>com.icegreen</groupId>
             <artifactId>greenmail</artifactId>
             <scope>compile</scope>
@@ -92,6 +98,7 @@
                 <artifactId>maven-surefire-plugin</artifactId>
                 <configuration>
                     <excludes>
+                        <exclude>${exclude.test}</exclude>
                         <exclude>${exclude.console}</exclude>
                         <exclude>${exclude.account}</exclude>
                         <exclude>${exclude.client}</exclude>
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/filter/AdapterActionsFilter.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/filter/AdapterActionsFilter.java
new file mode 100644
index 0000000..c282dff
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/filter/AdapterActionsFilter.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.adapter.filter;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+
+import org.keycloak.common.util.Time;
+
+/**
+ * Filter to handle "special" requests to perform actions on adapter side (for example setting time offset )
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class AdapterActionsFilter implements Filter {
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+        HttpServletResponse servletResp = (HttpServletResponse) response;
+
+        //Accept timeOffset as argument to enforce timeouts
+        String timeOffsetParam = request.getParameter("timeOffset");
+        if (timeOffsetParam != null && !timeOffsetParam.isEmpty()) {
+            Time.setOffset(Integer.parseInt(timeOffsetParam));
+        }
+
+        // Continue request
+        chain.doFilter(request, response);
+
+    }
+
+    @Override
+    public void destroy() {
+
+    }
+
+    private void writeResponse(HttpServletResponse response, String responseText) throws IOException {
+        PrintWriter writer = response.getWriter();
+        writer.println(responseText);
+        writer.flush();
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AbstractShowTokensPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AbstractShowTokensPage.java
new file mode 100644
index 0000000..d370dd0
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/AbstractShowTokensPage.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.adapter.page;
+
+import java.io.IOException;
+
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.RefreshToken;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+import org.keycloak.util.JsonSerialization;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public abstract class AbstractShowTokensPage extends AbstractPageWithInjectedUrl {
+
+    @FindBy(id = "accessToken")
+    private WebElement accessToken;
+
+    @FindBy(id = "refreshToken")
+    private WebElement refreshToken;
+
+
+    public AccessToken getAccessToken() {
+        try {
+            return JsonSerialization.readValue(accessToken.getText(), AccessToken.class);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        return null;
+    }
+
+    public RefreshToken getRefreshToken() {
+        try {
+            return JsonSerialization.readValue(refreshToken.getText(), RefreshToken.class);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/BadClientSalesPostSigServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/BadClientSalesPostSigServlet.java
index e85d43e..163d3f1 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/BadClientSalesPostSigServlet.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/BadClientSalesPostSigServlet.java
@@ -25,7 +25,7 @@ import java.net.URL;
 /**
  * @author mhajas
  */
-public class BadClientSalesPostSigServlet extends SAMLServletWithLogout {
+public class BadClientSalesPostSigServlet extends SAMLServlet {
     public static final String DEPLOYMENT_NAME = "bad-client-sales-post-sig";
 
     @ArquillianResource
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/BadRealmSalesPostSigServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/BadRealmSalesPostSigServlet.java
index 08fd844..f4dcc0c 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/BadRealmSalesPostSigServlet.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/BadRealmSalesPostSigServlet.java
@@ -25,7 +25,7 @@ import java.net.URL;
 /**
  * @author mhajas
  */
-public class BadRealmSalesPostSigServlet extends SAMLServletWithLogout {
+public class BadRealmSalesPostSigServlet extends SAMLServlet {
     public static final String DEPLOYMENT_NAME = "bad-realm-sales-post-sig";
 
     @ArquillianResource
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/Employee2Servlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/Employee2Servlet.java
index 391c122..4257c2f 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/Employee2Servlet.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/Employee2Servlet.java
@@ -25,7 +25,7 @@ import java.net.URL;
 /**
  * @author mhajas
  */
-public class Employee2Servlet extends SAMLServletWithLogout {
+public class Employee2Servlet extends SAMLServlet {
     public static final String DEPLOYMENT_NAME = "employee2";
 
     @ArquillianResource
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/EmployeeSigFrontServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/EmployeeSigFrontServlet.java
index ec21b58..0e7886c 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/EmployeeSigFrontServlet.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/EmployeeSigFrontServlet.java
@@ -25,7 +25,7 @@ import java.net.URL;
 /**
  * @author mhajas
  */
-public class EmployeeSigFrontServlet extends SAMLServletWithLogout {
+public class EmployeeSigFrontServlet extends SAMLServlet {
     public static final String DEPLOYMENT_NAME = "employee-sig-front";
 
     @ArquillianResource
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/EmployeeSigServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/EmployeeSigServlet.java
index 24d92d0..910ef46 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/EmployeeSigServlet.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/EmployeeSigServlet.java
@@ -25,7 +25,7 @@ import java.net.URL;
 /**
  * @author mhajas
  */
-public class EmployeeSigServlet extends SAMLServletWithLogout {
+public class EmployeeSigServlet extends SAMLServlet {
     public static final String DEPLOYMENT_NAME = "employee-sig";
 
     @ArquillianResource
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/JSDatabaseTestApp.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/JSDatabaseTestApp.java
new file mode 100644
index 0000000..83afdb2
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/JSDatabaseTestApp.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.adapter.page;
+
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+
+import java.net.URL;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class JSDatabaseTestApp extends AbstractPageWithInjectedUrl {
+
+    public static final String DEPLOYMENT_NAME = "js-database-example";
+    public static final String CLIENT_ID = "integration-arquillian-test-apps-js-database";
+
+    @ArquillianResource
+    @OperateOnDeployment(DEPLOYMENT_NAME)
+    private URL url;
+
+    @Override
+    public URL getInjectedUrl() {
+        //EAP6 URL fix
+        URL fixedUrl = createInjectedURL("js-database");
+        return fixedUrl != null ? fixedUrl : url;
+    }
+
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/OfflineToken.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/OfflineToken.java
index 9df0ab9..248225e 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/OfflineToken.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/OfflineToken.java
@@ -19,7 +19,7 @@ import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
 /**
  * @author <a href="mailto:bruno@abstractj.org">Bruno Oliveira</a>.
  */
-public class OfflineToken extends AbstractPageWithInjectedUrl {
+public class OfflineToken extends AbstractShowTokensPage {
 
     public static final String DEPLOYMENT_NAME = "offline-client";
 
@@ -32,35 +32,6 @@ public class OfflineToken extends AbstractPageWithInjectedUrl {
         return url;
     }
 
-    @FindBy(id = "accessToken")
-    private WebElement accessToken;
-
-    @FindBy(id = "refreshToken")
-    private WebElement refreshToken;
-
-    @FindBy(id = "prettyToken")
-    private WebElement prettyToken;
-
-
-    public AccessToken getAccessToken() {
-        try {
-            return JsonSerialization.readValue(accessToken.getText(), AccessToken.class);
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-
-        return null;
-    }
-
-    public RefreshToken getRefreshToken() {
-        try {
-            return JsonSerialization.readValue(refreshToken.getText(), RefreshToken.class);
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-        return null;
-    }
-
     public void logout() {
         log.info("Logging out, navigating to: " + getUriBuilder().path("/logout").build().toASCIIString());
         driver.navigate().to(getUriBuilder().path("/logout").build().toASCIIString());
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/PhotozClientAuthzTestApp.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/PhotozClientAuthzTestApp.java
new file mode 100644
index 0000000..c76747a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/PhotozClientAuthzTestApp.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.adapter.page;
+
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.keycloak.testsuite.auth.page.login.OIDCLogin;
+import org.keycloak.testsuite.page.AbstractPageWithInjectedUrl;
+import org.keycloak.testsuite.page.Form;
+import org.keycloak.testsuite.pages.ConsentPage;
+import org.keycloak.testsuite.util.URLUtils;
+import org.keycloak.testsuite.util.WaitUtils;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+import java.net.URL;
+import java.util.List;
+
+import static org.keycloak.testsuite.util.WaitUtils.IMPLICIT_ELEMENT_WAIT_MILLIS;
+import static org.keycloak.testsuite.util.WaitUtils.pause;
+import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ * @author Vaclav Muzikar <vmuzikar@redhat.com>
+ */
+public class PhotozClientAuthzTestApp extends AbstractPageWithInjectedUrl {
+
+    public static final String DEPLOYMENT_NAME = "photoz-html5-client";
+    public static final int WAIT_AFTER_OPERATION = 2000;
+
+    @ArquillianResource
+    @OperateOnDeployment(DEPLOYMENT_NAME)
+    private URL url;
+
+    @Page
+    protected OIDCLogin loginPage;
+
+    @Page
+    protected ConsentPage consentPage;
+
+    @FindBy(xpath = "//a[@ng-click = 'Identity.logout()']")
+    WebElement signOutButton;
+
+    public void createAlbum(String name) {
+        navigateTo();
+        this.driver.findElement(By.id("create-album")).click();
+        Form.setInputValue(this.driver.findElement(By.id("album.name")), name);
+        pause(200); // We need to wait a bit for the form to "accept" the input (otherwise it registers the input as empty)
+        this.driver.findElement(By.id("save-album")).click();
+        pause(WAIT_AFTER_OPERATION);
+    }
+
+    @Override
+    public URL getInjectedUrl() {
+        return this.url;
+    }
+
+    public void deleteAlbum(String name) {
+        driver.findElements(By.xpath("//a[text()='" + name + "']/following-sibling::a[text()='X']")).forEach(WebElement::click);
+        pause(WAIT_AFTER_OPERATION);
+    }
+
+    public void navigateToAdminAlbum() {
+        URLUtils.navigateToUri(driver, toString() + "/#/admin/album", true);
+        driver.navigate().refresh(); // This is sometimes necessary for loading the new policy settings
+        waitForPageToLoad(driver);
+        pause(WAIT_AFTER_OPERATION);
+    }
+
+    public void logOut() {
+        signOutButton.click(); // Sometimes doesn't work in PhantomJS!
+        pause(WAIT_AFTER_OPERATION);
+    }
+
+    public void login(String username, String password, String... scopes) {
+        if (scopes.length > 0) {
+            StringBuilder scopesValue = new StringBuilder();
+
+            for (String scope : scopes) {
+                if (scopesValue.length() != 0) {
+                    scopesValue.append(" ");
+                }
+                scopesValue.append(scope);
+            }
+
+            URLUtils.navigateToUri(driver, this.driver.getCurrentUrl() + " " + scopesValue, true);
+        }
+
+        this.loginPage.form().login(username, password);
+
+        // simple check if we are at the consent page, if so just click 'Yes'
+        if (this.consentPage.isCurrent()) {
+            consentPage.confirm();
+        }
+
+        pause(WAIT_AFTER_OPERATION);
+    }
+
+    public boolean wasDenied() {
+        return this.driver.findElement(By.id("output")).getText().contains("You can not access");
+    }
+
+    public void viewAlbum(String name) throws InterruptedException {
+        this.driver.findElement(By.xpath("//a[text() = '" + name + "']")).click();
+        waitForPageToLoad(driver);
+        driver.navigate().refresh(); // This is sometimes necessary for loading the new policy settings
+        pause(WAIT_AFTER_OPERATION);
+    }
+
+    @Override
+    public void navigateTo(boolean waitForMatch) {
+        super.navigateTo(waitForMatch);
+        pause(WAIT_AFTER_OPERATION);
+    }
+
+    @Override
+    public boolean isCurrent() {
+        return URLUtils.currentUrlStartWith(driver, toString());
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesMetadataServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesMetadataServlet.java
index 730ed2e..93f2043 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesMetadataServlet.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesMetadataServlet.java
@@ -25,7 +25,7 @@ import java.net.URL;
 /**
  * @author mhajas
  */
-public class SalesMetadataServlet extends SAMLServletWithLogout {
+public class SalesMetadataServlet extends SAMLServlet {
     public static final String DEPLOYMENT_NAME = "sales-metadata";
 
     @ArquillianResource
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostEncServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostEncServlet.java
index 892848a..874b1e8 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostEncServlet.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostEncServlet.java
@@ -25,7 +25,7 @@ import java.net.URL;
 /**
  * @author mhajas
  */
-public class SalesPostEncServlet extends SAMLServletWithLogout {
+public class SalesPostEncServlet extends SAMLServlet {
     public static final String DEPLOYMENT_NAME = "sales-post-enc";
 
     @ArquillianResource
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostPassiveServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostPassiveServlet.java
index 47afaae..a5879c0 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostPassiveServlet.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostPassiveServlet.java
@@ -25,7 +25,7 @@ import java.net.URL;
 /**
  * @author mhajas
  */
-public class SalesPostPassiveServlet extends SAMLServletWithLogout {
+public class SalesPostPassiveServlet extends SAMLServlet {
     public static final String DEPLOYMENT_NAME = "sales-post-passive";
 
     @ArquillianResource
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostServlet.java
index e14acd4..cd9ea11 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostServlet.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostServlet.java
@@ -25,7 +25,7 @@ import java.net.URL;
 /**
  * @author mhajas
  */
-public class SalesPostServlet extends SAMLServletWithLogout {
+public class SalesPostServlet extends SAMLServlet {
     public static final String DEPLOYMENT_NAME = "sales-post";
 
     @ArquillianResource
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostSigEmailServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostSigEmailServlet.java
index 789469e..77c68f1 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostSigEmailServlet.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostSigEmailServlet.java
@@ -25,7 +25,7 @@ import java.net.URL;
 /**
  * @author mhajas
  */
-public class SalesPostSigEmailServlet extends SAMLServletWithLogout {
+public class SalesPostSigEmailServlet extends SAMLServlet {
     public static final String DEPLOYMENT_NAME = "sales-post-sig-email";
 
     @ArquillianResource
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostSigPersistentServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostSigPersistentServlet.java
index 059202f..5ccb96f 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostSigPersistentServlet.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostSigPersistentServlet.java
@@ -25,7 +25,7 @@ import java.net.URL;
 /**
  * @author mhajas
  */
-public class SalesPostSigPersistentServlet extends SAMLServletWithLogout {
+public class SalesPostSigPersistentServlet extends SAMLServlet {
     public static final String DEPLOYMENT_NAME = "sales-post-sig-persistent";
 
     @ArquillianResource
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostSigServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostSigServlet.java
index 77c57f1..b4ab9bb 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostSigServlet.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostSigServlet.java
@@ -25,7 +25,7 @@ import java.net.URL;
 /**
  * @author mhajas
  */
-public class SalesPostSigServlet extends SAMLServletWithLogout {
+public class SalesPostSigServlet extends SAMLServlet {
     public static final String DEPLOYMENT_NAME = "sales-post-sig";
 
     @ArquillianResource
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostSigTransientServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostSigTransientServlet.java
index 17ca8a8..697ac83 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostSigTransientServlet.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/SalesPostSigTransientServlet.java
@@ -25,7 +25,7 @@ import java.net.URL;
 /**
  * @author mhajas
  */
-public class SalesPostSigTransientServlet extends SAMLServletWithLogout {
+public class SalesPostSigTransientServlet extends SAMLServlet {
     public static final String DEPLOYMENT_NAME = "sales-post-sig-transient";
 
     @ArquillianResource
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/TokenMinTTLPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/TokenMinTTLPage.java
new file mode 100644
index 0000000..797ab6c
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/page/TokenMinTTLPage.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.adapter.page;
+
+import java.net.URL;
+
+import org.jboss.arquillian.container.test.api.OperateOnDeployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class TokenMinTTLPage extends AbstractShowTokensPage {
+
+    public static final String DEPLOYMENT_NAME = "token-min-ttl";
+
+    @ArquillianResource
+    @OperateOnDeployment(DEPLOYMENT_NAME)
+    private URL url;
+
+    @Override
+    public URL getInjectedUrl() {
+        return url;
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/AbstractShowTokensServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/AbstractShowTokensServlet.java
new file mode 100644
index 0000000..403c70e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/AbstractShowTokensServlet.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.adapter.servlet;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+
+import org.keycloak.KeycloakSecurityContext;
+import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
+import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.jose.jws.JWSInputException;
+import org.keycloak.representations.RefreshToken;
+import org.keycloak.util.JsonSerialization;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public abstract class AbstractShowTokensServlet extends HttpServlet {
+
+    private static final String LINK = "<a href=\"%s\" id=\"%s\">%s</a>";
+
+    protected String renderTokens(HttpServletRequest req)  throws ServletException, IOException {
+        RefreshableKeycloakSecurityContext ctx = (RefreshableKeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
+        String accessTokenPretty = JsonSerialization.writeValueAsPrettyString(ctx.getToken());
+        RefreshToken refreshToken;
+        try {
+            refreshToken = new JWSInput(ctx.getRefreshToken()).readJsonContent(RefreshToken.class);
+        } catch (JWSInputException e) {
+            throw new IOException(e);
+        }
+        String refreshTokenPretty = JsonSerialization.writeValueAsPrettyString(refreshToken);
+
+        return new StringBuilder("<span id=\"accessToken\">" + accessTokenPretty + "</span>")
+                .append("<span id=\"refreshToken\">" + refreshTokenPretty + "</span>")
+                .toString();
+    }
+
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/OfflineTokenServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/OfflineTokenServlet.java
index 030bee3..c36b30e 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/OfflineTokenServlet.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/OfflineTokenServlet.java
@@ -3,14 +3,12 @@ package org.keycloak.testsuite.adapter.servlet;
 import org.keycloak.KeycloakSecurityContext;
 import org.keycloak.OAuth2Constants;
 import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
-import org.keycloak.common.util.Time;
 import org.keycloak.jose.jws.JWSInput;
 import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.representations.RefreshToken;
 import org.keycloak.util.JsonSerialization;
 
 import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.ws.rs.core.UriBuilder;
@@ -19,7 +17,7 @@ import java.io.IOException;
 /**
  * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
  */
-public class OfflineTokenServlet extends HttpServlet {
+public class OfflineTokenServlet extends AbstractShowTokensServlet {
 
     private static final String OFFLINE_CLIENT_APP_URI = (System.getProperty("app.server.ssl.required", "false").equals("true")) ?
             System.getProperty("app.server.ssl.base.url", "https://localhost:8643") + "/offline-client" :
@@ -31,12 +29,6 @@ public class OfflineTokenServlet extends HttpServlet {
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 
-        //Accept timeOffset as argument to enforce timeouts
-        String timeOffsetParam = req.getParameter("timeOffset");
-        if (timeOffsetParam != null && !timeOffsetParam.isEmpty()) {
-            Time.setOffset(Integer.parseInt(timeOffsetParam));
-        }
-
         if (req.getRequestURI().endsWith("logout")) {
 
             UriBuilder redirectUriBuilder = UriBuilder.fromUri(OFFLINE_CLIENT_APP_URI);
@@ -54,19 +46,11 @@ public class OfflineTokenServlet extends HttpServlet {
         }
 
         StringBuilder response = new StringBuilder("<html><head><title>Offline token servlet</title></head><body><pre>");
-        RefreshableKeycloakSecurityContext ctx = (RefreshableKeycloakSecurityContext) req.getAttribute(KeycloakSecurityContext.class.getName());
-        String accessTokenPretty = JsonSerialization.writeValueAsPrettyString(ctx.getToken());
-        RefreshToken refreshToken;
-        try {
-            refreshToken = new JWSInput(ctx.getRefreshToken()).readJsonContent(RefreshToken.class);
-        } catch (JWSInputException e) {
-            throw new IOException(e);
-        }
-        String refreshTokenPretty = JsonSerialization.writeValueAsPrettyString(refreshToken);
 
-        response = response.append("<span id=\"accessToken\">" + accessTokenPretty + "</span>")
-                .append("<span id=\"refreshToken\">" + refreshTokenPretty + "</span>")
-                .append("</pre></body></html>");
+        String tokens = renderTokens(req);
+        response = response.append(tokens);
+
+        response.append("</pre></body></html>");
         resp.getWriter().println(response.toString());
     }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/SendUsernameServlet.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/SendUsernameServlet.java
index 6a07594..58feae3 100755
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/SendUsernameServlet.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/adapter/servlet/SendUsernameServlet.java
@@ -17,78 +17,91 @@
 
 package org.keycloak.testsuite.adapter.servlet;
 
+
+import org.jboss.resteasy.annotations.cache.NoCache;
+
 import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
 import java.io.IOException;
-import java.io.OutputStream;
 import java.security.Principal;
-import java.util.List;
 
 /**
-* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
-* @version $Revision: 1 $
-*/
-public class SendUsernameServlet extends HttpServlet {
-
-    public static Principal sentPrincipal;
-    public static List<String> checkRoles;
-
-    @Override
-    protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
-        System.out.println("In SendUsername Servlet doGet()");
-        if (checkRoles != null) {
-            for (String role : checkRoles) {
-                System.out.println("check role: " + role);
-                //Assert.assertTrue(req.isUserInRole(role));
-                if (!req.isUserInRole(role)) {
-                    resp.sendError(403);
-                    return;
-                }
-            }
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @author mhajas
+ * @version $Revision: 1 $
+ */
+@Path("/")
+public class SendUsernameServlet {
 
+    private static boolean checkRoles = false;
+
+    @Context
+    private HttpServletRequest httpServletRequest;
+
+    @GET
+    @NoCache
+    public Response doGet(@QueryParam("checkRoles") boolean checkRolesFlag) throws ServletException, IOException {
+        System.out.println("In SendUsername Servlet doGet() check roles is " + (checkRolesFlag || checkRoles));
+        if (httpServletRequest.getUserPrincipal() != null && (checkRolesFlag || checkRoles) && !checkRoles()) {
+            return Response.status(Response.Status.FORBIDDEN).entity("Forbidden").build();
         }
-        resp.setContentType("text/plain");
-        OutputStream stream = resp.getOutputStream();
-        Principal principal = req.getUserPrincipal();
-        stream.write("request-path: ".getBytes());
-        stream.write(req.getServletPath().getBytes());
-        stream.write("\n".getBytes());
-        stream.write("principal=".getBytes());
-        if (principal == null) {
-            stream.write("null".getBytes());
-            return;
-        }
-        String name = principal.getName();
-        stream.write(name.getBytes());
-        sentPrincipal = principal;
 
+        return Response.ok(getOutput(), MediaType.TEXT_PLAIN).build();
     }
-    @Override
-    protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
-        System.out.println("In SendUsername Servlet doPost()");
-        if (checkRoles != null) {
-            for (String role : checkRoles) {
-                System.out.println("check role: " + role);
-                if (!req.isUserInRole(role)) {
-                    throw new RuntimeException("User: " + req.getUserPrincipal() + " is not in Role: " + role);
-                }
-            }
+
+    @POST
+    @NoCache
+    public Response doPost(@QueryParam("checkRoles") boolean checkRolesFlag) throws ServletException, IOException {
+        System.out.println("In SendUsername Servlet doPost() check roles is " + (checkRolesFlag || checkRoles));
+
+        if (httpServletRequest.getUserPrincipal() != null && (checkRolesFlag || checkRoles) && !checkRoles()) {
+            throw new RuntimeException("User: " + httpServletRequest.getUserPrincipal() + " do not have required role");
         }
-        resp.setContentType("text/plain");
-        OutputStream stream = resp.getOutputStream();
-        Principal principal = req.getUserPrincipal();
-        stream.write("request-path: ".getBytes());
-        stream.write(req.getServletPath().getBytes());
-        stream.write("\n".getBytes());
-        stream.write("principal=".getBytes());
+
+        return Response.ok(getOutput(), MediaType.TEXT_PLAIN).build();
+    }
+
+    @GET
+    @Path("{path}")
+    public Response doGetElseWhere(@PathParam("path") String path, @QueryParam("checkRoles") boolean checkRolesFlag) throws ServletException, IOException {
+        System.out.println("In SendUsername Servlet doGetElseWhere() - path: " + path);
+        return doGet(checkRolesFlag);
+    }
+
+    @POST
+    @Path("{path}")
+    public Response doPostElseWhere(@PathParam("path") String path, @QueryParam("checkRoles") boolean checkRolesFlag) throws ServletException, IOException {
+        System.out.println("In SendUsername Servlet doPostElseWhere() - path: " + path);
+        return doPost(checkRolesFlag);
+    }
+
+    @GET
+    @Path("checkRoles")
+    public String checkRolesEndPoint() {
+        checkRoles = true;
+        System.out.println("Setting checkRoles to true");
+        return "Roles will be checked";
+    }
+
+    private boolean checkRoles() {
+        return httpServletRequest.isUserInRole("manager");
+    }
+
+    private String getOutput() {
+        String output = "request-path: ";
+        output += httpServletRequest.getServletPath();
+        output += "\n";
+        output += "principal=";
+        Principal principal = httpServletRequest.getUserPrincipal();
+
         if (principal == null) {
-            stream.write("null".getBytes());
-            return;
+            return output + "null";
         }
-        String name = principal.getName();
-        stream.write(name.getBytes());
-        sentPrincipal = principal;
+
+        return output + principal.getName();
     }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContainer.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContainer.java
index d2e2fa7..c284d9a 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContainer.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/AppServerContainer.java
@@ -33,5 +33,4 @@ import java.lang.annotation.Target;
 public @interface AppServerContainer 
 {
    String value() default "";
-   String adapterLibsLocationProperty() default "";
 }
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/UseServletFilter.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/UseServletFilter.java
new file mode 100644
index 0000000..dc0b3f4
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/annotation/UseServletFilter.java
@@ -0,0 +1,20 @@
+package org.keycloak.testsuite.arquillian.annotation;
+
+import java.lang.annotation.*;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * @author mhajas
+ */
+@Documented
+@Retention(RUNTIME)
+@Target({ElementType.TYPE})
+@Inherited
+public @interface UseServletFilter {
+
+    String filterName();
+    String filterClass();
+    String filterPattern() default "/*";
+    String dispatcherType() default "";
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AppServerTestEnricher.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AppServerTestEnricher.java
index 75d5510..11e5fc6 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AppServerTestEnricher.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/AppServerTestEnricher.java
@@ -8,17 +8,11 @@ import org.jboss.arquillian.core.api.annotation.Observes;
 import org.jboss.arquillian.test.spi.annotation.ClassScoped;
 import org.jboss.arquillian.test.spi.event.suite.BeforeClass;
 import org.jboss.logging.Logger;
-import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
 import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
-import org.keycloak.testsuite.util.LogChecker;
-
-import java.io.File;
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
 
-import static org.keycloak.testsuite.util.IOUtil.execCommand;
-import static org.keycloak.testsuite.util.WaitUtils.pause;
 import static org.keycloak.testsuite.arquillian.AuthServerTestEnricher.getAuthServerContextRoot;
 
 /**
@@ -109,66 +103,6 @@ public class AppServerTestEnricher {
         }
     }
 
-//    public void installAdapterLibs(@Observes BeforeDeploy event) {
-//        log.debug("BEFORE DEPLOY - INSTALL ADAPTER LIBS");
-//        if (testContext.isAdapterTest()) {
-//            // install adapter libs on JBoss-based container via CLI
-//            if (testContext.getAppServerInfo().isJBossBased()) {
-//                try {
-//                    installAdapterLibsUsingJBossCLIClient(testContext.getAppServerInfo());
-//                } catch (InterruptedException | IOException ex) {
-//                    throw new RuntimeException("Failed to install adapter libs.", ex);
-//                }
-//            }
-//        }
-//    }
-    private void installAdapterLibsUsingJBossCLIClient(ContainerInfo appServerInfo) throws InterruptedException, IOException {
-        if (!appServerInfo.isAdapterLibsInstalled()) {
-
-            if (!appServerInfo.isJBossBased()) {
-                throw new IllegalArgumentException("App server must be JBoss-based to run jboss-cli-client.");
-            }
-
-            String jbossHomePath = appServerInfo.getProperties().get("jbossHome");
-
-            File bin = new File(jbossHomePath + "/bin");
-
-            File clientJar = new File(jbossHomePath + "/bin/client/jboss-cli-client.jar");
-            if (!clientJar.exists()) {
-                clientJar = new File(jbossHomePath + "/bin/client/jboss-client.jar"); // AS7
-            }
-            if (!clientJar.exists()) {
-                throw new IOException("JBoss CLI client JAR not found.");
-            }
-
-            String command = "java -jar " + clientJar.getAbsolutePath();
-            String adapterScript = "adapter-install.cli";
-            String samlAdapterScript = "adapter-install-saml.cli";
-            String managementPort = appServerInfo.getProperties().get("managementPort");
-
-            String controllerArg = " --controller=localhost:" + managementPort;
-            if (new File(bin, adapterScript).exists()) {
-                log.info("Installing adapter to app server via cli script");
-                execCommand(command + " --connect --file=" + adapterScript + controllerArg, bin);
-            }
-            if (new File(bin, samlAdapterScript).exists()) {
-                log.info("Installing saml adapter to app server via cli script");
-                execCommand(command + " --connect --file=" + samlAdapterScript + controllerArg, bin);
-            }
-            if (new File(bin, adapterScript).exists() || new File(bin, samlAdapterScript).exists()) {
-                log.info("Restarting container");
-                execCommand(command + " --connect --command=reload" + controllerArg, bin);
-                log.info("Container restarted");
-                pause(5000);
-                if (System.getProperty("app.server.log.check", "true").equals("true")) {
-                    LogChecker.checkJBossServerLog(jbossHomePath);
-                }
-            }
-
-            appServerInfo.setAdapterLibsInstalled(true);
-        }
-    }
-
     /**
      *
      * @param testClass
@@ -190,12 +124,6 @@ public class AppServerTestEnricher {
         return getAppServerQualifier(testClass).equals(AuthServerTestEnricher.AUTH_SERVER_CONTAINER);
     }
 
-    public static String getAdapterLibsLocationProperty(Class testClass) {
-        Class<? extends AuthServerTestEnricher> annotatedClass = getNearestSuperclassWithAnnotation(testClass, AdapterLibsLocationProperty.class);
-        return (annotatedClass == null ? "adapter.libs.home"
-                : annotatedClass.getAnnotation(AdapterLibsLocationProperty.class).value());
-    }
-
     public static boolean isWildflyAppServer(Class testClass) {
         return getAppServerQualifier(testClass).contains("wildfly");
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java
index e4a8ab2..68d7183 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/DeploymentArchiveProcessor.java
@@ -26,8 +26,8 @@ import org.jboss.logging.Logger.Level;
 import org.jboss.shrinkwrap.api.Archive;
 import org.jboss.shrinkwrap.api.asset.StringAsset;
 import org.jboss.shrinkwrap.api.spec.WebArchive;
-import org.keycloak.representations.adapters.config.BaseAdapterConfig;
-import org.keycloak.testsuite.adapter.AdapterLibsMode;
+import org.keycloak.representations.adapters.config.AdapterConfig;
+import org.keycloak.testsuite.arquillian.annotation.UseServletFilter;
 import org.keycloak.testsuite.util.IOUtil;
 import org.keycloak.util.JsonSerialization;
 import org.w3c.dom.Document;
@@ -37,12 +37,9 @@ import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.getAdapterLibsLocationProperty;
-import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.hasAppServerContainerAnnotation;
-import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.isRelative;
-import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.isTomcatAppServer;
 
-import static org.keycloak.testsuite.arquillian.AuthServerTestEnricher.*;
+import static org.keycloak.testsuite.arquillian.AppServerTestEnricher.*;
+import static org.keycloak.testsuite.arquillian.AuthServerTestEnricher.getAuthServerContextRoot;
 import static org.keycloak.testsuite.util.IOUtil.*;
 
 ;
@@ -70,7 +67,6 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
         log.info("Processing archive " + archive.getName());
 //        if (isAdapterTest(testClass)) {
         modifyAdapterConfigs(archive, testClass);
-        attachAdapterLibs(archive, testClass);
         modifyWebXml(archive, testClass);
 //        } else {
 //            log.info(testClass.getJavaClass().getSimpleName() + " is not an AdapterTest");
@@ -118,8 +114,8 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
                 }
             } else { // OIDC adapter config
                 try {
-                    BaseAdapterConfig adapterConfig = loadJson(archive.get(adapterConfigPath)
-                            .getAsset().openStream(), BaseAdapterConfig.class);
+                    AdapterConfig adapterConfig = loadJson(archive.get(adapterConfigPath)
+                            .getAsset().openStream(), AdapterConfig.class);
 
                     log.info(" setting " + (relative ? "" : "non-") + "relative auth-server-url");
                     if (relative) {
@@ -129,7 +125,7 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
                         adapterConfig.setAuthServerUrl(getAuthServerContextRoot() + "/auth");
                         adapterConfig.setRealmKey(REALM_KEY);
                     }
-                    
+
                     if ("true".equals(System.getProperty("app.server.ssl.required"))) {
                         adapterConfig.setSslRequired("all");
                     }
@@ -144,30 +140,6 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
         }
     }
 
-    protected void attachAdapterLibs(Archive<?> archive, TestClass testClass) {
-        AdapterLibsMode adapterType = AdapterLibsMode.getByType(System.getProperty("adapter.libs.mode",
-                AdapterLibsMode.PROVIDED.getType()));
-        log.info("Adapter type: " + adapterType);
-        if (adapterType.equals(AdapterLibsMode.BUNDLED)) {
-            log.info("Attaching keycloak adapter libs to " + archive.getName());
-
-            String libsLocationProperty = getAdapterLibsLocationProperty(testClass.getJavaClass());
-            assert libsLocationProperty != null;
-            File libsLocation = new File(System.getProperty(libsLocationProperty));
-            assert libsLocation.exists();
-            log.info("Libs location: " + libsLocation.getPath());
-
-            WebArchive war = (WebArchive) archive;
-
-            for (File lib : getAdapterLibs(libsLocation)) {
-                log.info(" attaching: " + lib.getName());
-                war.addAsLibrary(lib);
-            }
-        } else {
-            log.info("Expecting keycloak adapter libs to be provided by the server.");
-        }
-    }
-
     DirectoryScanner scanner = new DirectoryScanner();
 
     protected List<File> getAdapterLibs(File adapterLibsLocation) {
@@ -183,17 +155,46 @@ public class DeploymentArchiveProcessor implements ApplicationArchiveProcessor {
     }
 
     protected void modifyWebXml(Archive<?> archive, TestClass testClass) {
-        if (isTomcatAppServer(testClass.getJavaClass())) {
-            try {
-                String webXmlContent = IOUtils.toString(
-                        archive.get(WEBXML_PATH).getAsset().openStream());
-
+        try {
+            String webXmlContent = IOUtils.toString(
+                    archive.get(WEBXML_PATH).getAsset().openStream());
+            if (isTomcatAppServer(testClass.getJavaClass())) {
                 webXmlContent = webXmlContent.replace("<auth-method>KEYCLOAK</auth-method>", "<auth-method>BASIC</auth-method>");
+            }
+
+            if (testClass.getJavaClass().isAnnotationPresent(UseServletFilter.class)) {
+                //We need to add filter declaration to web.xml
+                log.info("Adding filter to " + testClass.getAnnotation(UseServletFilter.class).filterClass() + " with mapping " + testClass.getAnnotation(UseServletFilter.class).filterPattern() + " for " + archive.getName());
+                String filter = "\n<filter>\n" +
+                        "<filter-name>" + testClass.getAnnotation(UseServletFilter.class).filterName() + "</filter-name>\n" +
+                        "<filter-class>" + testClass.getAnnotation(UseServletFilter.class).filterClass() + "</filter-class>\n" +
+                        "</filter>\n" +
+                        "\n<filter-mapping>\n" +
+                        "<filter-name>" + testClass.getAnnotation(UseServletFilter.class).filterName() + "</filter-name>\n" +
+                        "<url-pattern>" + testClass.getAnnotation(UseServletFilter.class).filterPattern() + "</url-pattern>\n";
+                if (!testClass.getAnnotation(UseServletFilter.class).dispatcherType().isEmpty()) {
+                    filter += "<dispatcher>" + testClass.getAnnotation(UseServletFilter.class).dispatcherType() + "</dispatcher>\n";
+                }
+                filter += "</filter-mapping>\n";
+
+                webXmlContent = webXmlContent.replace("</module-name>", "</module-name> " + filter);
+
+                //Also we need to add all dependencies within war lib directory, because filter needs to work without installed adapter
+                log.info("Adding SAMLFilter dependencies to " + archive.getName());
+                ((WebArchive) archive).addAsLibraries(new SAMLFilterDependency().getDependencies());
 
-                archive.add(new StringAsset((webXmlContent)), WEBXML_PATH);
-            } catch (IOException ex) {
-                throw new RuntimeException("Cannot load web.xml from archive.");
+
+                //finally we need to remove all keycloak related configuration from web.xml
+                int start = webXmlContent.indexOf("<security-constraint>");
+                int end = webXmlContent.indexOf("</security-role>") + "</security-role>".length();
+
+
+                webXmlContent = webXmlContent.substring(0, start) + webXmlContent.substring(end);
             }
+
+            archive.add(new StringAsset((webXmlContent)), WEBXML_PATH);
+        } catch (IOException ex) {
+            throw new RuntimeException("Cannot load web.xml from archive.");
         }
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/URLProvider.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/URLProvider.java
index 424705c..5631b6a 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/URLProvider.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/provider/URLProvider.java
@@ -24,6 +24,7 @@ import org.jboss.arquillian.core.api.annotation.Inject;
 import org.jboss.arquillian.test.api.ArquillianResource;
 import org.jboss.logging.Logger;
 import org.jboss.logging.Logger.Level;
+import org.keycloak.testsuite.arquillian.SuiteContext;
 import org.keycloak.testsuite.arquillian.TestContext;
 import org.keycloak.testsuite.arquillian.annotation.AppServerContext;
 import org.keycloak.testsuite.arquillian.annotation.AuthServerContext;
@@ -33,7 +34,6 @@ import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.HashSet;
 import java.util.Set;
-import org.keycloak.testsuite.arquillian.SuiteContext;
 
 public class URLProvider extends URLResourceProvider {
 
@@ -83,7 +83,8 @@ public class URLProvider extends URLResourceProvider {
                     for (Annotation a : qualifiers) {
                         if (OperateOnDeployment.class.isAssignableFrom(a.annotationType())) {
                             String port = appServerSslRequired ?  System.getProperty("app.server.https.port", "8643"):System.getProperty("app.server.http.port", "8280");
-                            url = new URL(fixedUrl.toExternalForm().replace("8080", port) + "/" + ((OperateOnDeployment) a).value());
+                            String protocol = appServerSslRequired ? "https" : "http";
+                            url = new URL(fixedUrl.toExternalForm().replace("8080", port).replace("http", protocol) + ((OperateOnDeployment) a).value());
                         }
                     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/SAMLFilterDependency.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/SAMLFilterDependency.java
new file mode 100644
index 0000000..808a383
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/arquillian/SAMLFilterDependency.java
@@ -0,0 +1,87 @@
+package org.keycloak.testsuite.arquillian;
+
+import org.jboss.logging.Logger;
+import org.jboss.shrinkwrap.resolver.api.maven.Maven;
+import org.jboss.shrinkwrap.resolver.api.maven.PackagingType;
+import org.jboss.shrinkwrap.resolver.api.maven.ScopeType;
+import org.jboss.shrinkwrap.resolver.api.maven.coordinate.MavenDependency;
+import org.jboss.shrinkwrap.resolver.api.maven.coordinate.MavenDependencyExclusion;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * @author mhajas
+ */
+public class SAMLFilterDependency implements MavenDependency {
+
+    private static File[] files;
+
+    protected final Logger log = org.jboss.logging.Logger.getLogger(this.getClass());
+
+    @Override
+    public Set<MavenDependencyExclusion> getExclusions() {
+        return Collections.EMPTY_SET;
+    }
+
+    @Override
+    public ScopeType getScope() {
+        return ScopeType.COMPILE;
+    }
+
+    @Override
+    public boolean isOptional() {
+        return false;
+    }
+
+    @Override
+    public PackagingType getPackaging() {
+        return PackagingType.JAR;
+    }
+
+    @Override
+    public PackagingType getType() {
+        return PackagingType.JAR;
+    }
+
+    @Override
+    public String getClassifier() {
+        return null;
+    }
+
+    @Override
+    public String getVersion() {
+        return System.getProperty("project.version");
+    }
+
+    @Override
+    public String getGroupId() {
+        return "org.keycloak";
+    }
+
+    @Override
+    public String getArtifactId() {
+        return "keycloak-saml-servlet-filter-adapter";
+    }
+
+    @Override
+    public String toCanonicalForm() {
+        return getGroupId() + ":" + getArtifactId() +  ":" + getVersion();
+    }
+
+    private void resolve() {
+        log.info("Resolving SAMLFilter dependencies");
+        files = Maven.configureResolver().addDependency(this)
+                .resolve().withTransitivity().asFile();
+        log.info("Resolving dependencies is finished with " + files.length + " files");
+    }
+
+    public File[] getDependencies() {
+        if (files == null) {
+            resolve();
+        }
+
+        return files;
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountFields.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountFields.java
index fb08bfb..8ca2531 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountFields.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/AccountFields.java
@@ -20,6 +20,8 @@ package org.keycloak.testsuite.auth.page.account;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.testsuite.page.Form;
 import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
+import static org.keycloak.testsuite.util.WaitUtils.waitUntilElementIsNotPresent;
+
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
 
@@ -69,7 +71,7 @@ public class AccountFields extends Form {
     }
 
     public void waitForUsernameInputNotPresent() {
-        waitUntilElement(usernameInput).is().not().present();
+        waitUntilElementIsNotPresent(driver, usernameInput);
     }
 
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/fragment/AccountManagementAlert.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/fragment/AccountManagementAlert.java
index 4d5b264..f7b0911 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/fragment/AccountManagementAlert.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/account/fragment/AccountManagementAlert.java
@@ -25,7 +25,7 @@ import org.keycloak.testsuite.page.AbstractAlert;
 public class AccountManagementAlert extends AbstractAlert {
 
     public boolean isError() {
-        return getAttributeClass().contains("alert-error");
+        return checkAlertType("error");
     }
 
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginForm.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginForm.java
index ad914cd..ec92f58 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginForm.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/LoginForm.java
@@ -23,6 +23,7 @@ import static org.keycloak.testsuite.admin.Users.getPasswordOf;
 import org.keycloak.testsuite.auth.page.account.AccountFields;
 import org.keycloak.testsuite.auth.page.account.PasswordFields;
 import static org.keycloak.testsuite.util.WaitUtils.*;
+
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
 
@@ -51,6 +52,9 @@ public class LoginForm extends Form {
     @FindBy(id = "rememberMe")
     private WebElement rememberMe;
 
+    @FindBy(xpath = ".//label[@for='password']")
+    private WebElement labelPassword;
+
     public void setUsername(String username) {
         accountFields.setUsername(username);
     }
@@ -70,26 +74,28 @@ public class LoginForm extends Form {
     }
 
     public void register() {
-        waitForUsernameInputPresent();
-        waitUntilElement(registerLink).is().present();
         registerLink.click();
+        waitForPageToLoad(driver);
     }
 
     public void login() {
-        waitUntilElement(loginButton).is().present();
+        labelPassword.click(); // This is a nasty trick for IE; As IE was "moving the cursor" towards the login button
+                               // it opened the internationalization menu (when present) and then clicked
+                               // one of the languages instead of the Login button
         loginButton.click();
+        waitForPageToLoad(driver);
     }
 
     public void forgotPassword() {
-        waitUntilElement(forgottenPassword).is().present();
         forgottenPassword.click();
+        waitForPageToLoad(driver);
     }
 
     public void rememberMe(boolean value) {
-        waitForRememberMePresent();
         boolean selected = rememberMe.isSelected();
         if ((value && !selected) || !value && selected) {
             rememberMe.click();
+            waitForPageToLoad(driver);
         }
     }
 
@@ -103,7 +109,7 @@ public class LoginForm extends Form {
     }
 
     public void waitForRegisterLinkNotPresent() {
-        waitUntilElement(registerLink).is().not().present();
+        waitUntilElementIsNotPresent(driver, registerLink);
     }
 
     public void waitForResetPasswordLinkNotPresent() {
@@ -115,7 +121,7 @@ public class LoginForm extends Form {
     }
 
     public void waitForRememberMeNotPresent() {
-        waitUntilElement(rememberMe).is().not().present();
+        waitUntilElementIsNotPresent(driver, rememberMe);
     }
 
     public void waitForLoginButtonPresent() {
@@ -150,6 +156,7 @@ public class LoginForm extends Form {
         
         public void submit() {
             submit.click();
+            waitForPageToLoad(driver);
         }
     }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/TermsAndConditions.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/TermsAndConditions.java
index a4c425e..fb7d9b1 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/TermsAndConditions.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/TermsAndConditions.java
@@ -16,6 +16,7 @@
  */
 package org.keycloak.testsuite.auth.page.login;
 
+import org.keycloak.testsuite.util.UIUtils;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
 
@@ -35,7 +36,7 @@ public class TermsAndConditions extends LoginActions {
     
     @Override
     public boolean isCurrent() {
-        return driver.getTitle().equals("Terms and Conditions");
+        return UIUtils.currentTitleEquals(driver, "Terms and Conditions");
     }
 
     public void acceptTerms() {
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/VerifyEmail.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/VerifyEmail.java
index e566b41..848a9fa 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/VerifyEmail.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/auth/page/login/VerifyEmail.java
@@ -28,9 +28,17 @@ public class VerifyEmail extends Authenticate {
 
     @FindBy(xpath = "//div[@id='kc-form-wrapper']/p")
     private WebElement instruction;
-    
+
+    @FindBy(id = "kc-error-message")
+    private WebElement error;
+
     public String getInstructionMessage() {
         waitUntilElement(instruction).is().present();
         return instruction.getText();
     }
+
+    public String getErrorMessage() {
+        waitUntilElement(error).is().present();
+        return error.getText();
+    }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/KeycloakTestingClient.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/KeycloakTestingClient.java
index 46f7b23..dedc08d 100755
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/KeycloakTestingClient.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/KeycloakTestingClient.java
@@ -21,6 +21,7 @@ import org.jboss.resteasy.client.jaxrs.ResteasyClient;
 import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
 import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
 import org.keycloak.testsuite.client.resources.TestApplicationResource;
+import org.keycloak.testsuite.client.resources.TestExampleCompanyResource;
 import org.keycloak.testsuite.client.resources.TestingResource;
 
 /**
@@ -45,6 +46,8 @@ public class KeycloakTestingClient {
 
     public TestApplicationResource testApp() { return target.proxy(TestApplicationResource.class); }
 
+    public TestExampleCompanyResource testExampleCompany() { return target.proxy(TestExampleCompanyResource.class); }
+
     public void close() {
         client.close();
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestExampleCompanyResource.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestExampleCompanyResource.java
new file mode 100644
index 0000000..00d6e28
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestExampleCompanyResource.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.client.resources;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.keycloak.testsuite.domainextension.CompanyRepresentation;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+@Path("/realms/{realmName}/example/companies")
+@Consumes(MediaType.APPLICATION_JSON)
+public interface TestExampleCompanyResource {
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    List<CompanyRepresentation> getCompanies(@PathParam("realmName") String realmName);
+
+    @GET
+    @Path("/{companyId}")
+    @Produces(MediaType.APPLICATION_JSON)
+    CompanyRepresentation getCompany(@PathParam("realmName") String realmName, @PathParam("companyId") String companyId);
+
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    Response createCompany(@PathParam("realmName") String realmName, CompanyRepresentation rep);
+
+    @DELETE
+    void deleteAllCompanies(@PathParam("realmName") String realmName);
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java
index 59d8d0a..fcf5d83 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java
@@ -17,8 +17,12 @@
 
 package org.keycloak.testsuite.client.resources;
 
+import java.util.Date;
+import java.util.List;
 import org.keycloak.representations.idm.AdminEventRepresentation;
+import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
 import org.keycloak.representations.idm.EventRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.testsuite.rest.representation.AuthenticatorState;
 
 import javax.ws.rs.Consumes;
@@ -32,6 +36,8 @@ import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import java.util.Map;
+import org.jboss.resteasy.annotations.cache.NoCache;
+import org.keycloak.exportimport.ExportImportManager;
 
 /**
  * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
@@ -72,6 +78,99 @@ public interface TestingResource {
     @Produces(MediaType.APPLICATION_JSON)
     Response clearAdminEventQueue();
 
+    @GET
+    @Path("/clear-event-store")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response clearEventStore();
+
+    @GET
+    @Path("/clear-event-store-for-realm")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response clearEventStore(@QueryParam("realmId") String realmId);
+
+    @GET
+    @Path("/clear-event-store-older-than")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response clearEventStore(@QueryParam("realmId") String realmId, @QueryParam("olderThan") long olderThan);
+
+    /**
+     * Query events
+     *
+     * Returns all events, or filters them based on URL query parameters listed here
+     *
+     * @param realmId The realm
+     * @param types The types of events to return
+     * @param client App or oauth client name
+     * @param user User id
+     * @param dateFrom From date
+     * @param dateTo To date
+     * @param ipAddress IP address
+     * @param firstResult Paging offset
+     * @param maxResults Paging size
+     * @return
+     */
+    @Path("query-events")
+    @GET
+    @NoCache
+    @Produces(MediaType.APPLICATION_JSON)
+    public List<EventRepresentation> queryEvents(@QueryParam("realmId") String realmId, @QueryParam("type") List<String> types, @QueryParam("client") String client,
+            @QueryParam("user") String user, @QueryParam("dateFrom") String dateFrom, @QueryParam("dateTo") String dateTo,
+            @QueryParam("ipAddress") String ipAddress, @QueryParam("first") Integer firstResult,
+            @QueryParam("max") Integer maxResults);
+
+    @PUT
+    @Path("/on-event")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void onEvent(final EventRepresentation rep);
+
+    @GET
+    @Path("/clear-admin-event-store")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response clearAdminEventStore();
+
+    @GET
+    @Path("/clear-admin-event-store-for-realm")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response clearAdminEventStore(@QueryParam("realmId") String realmId);
+
+    @GET
+    @Path("/clear-admin-event-store-older-than")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response clearAdminEventStore(@QueryParam("realmId") String realmId, @QueryParam("olderThan") long olderThan);
+
+    /**
+     * Get admin events
+     *
+     * Returns all admin events, or filters events based on URL query parameters listed here
+     *
+     * @param realmId
+     * @param operationTypes
+     * @param authRealm
+     * @param authClient
+     * @param authUser user id
+     * @param authIpAddress
+     * @param resourcePath
+     * @param dateFrom
+     * @param dateTo
+     * @param firstResult
+     * @param maxResults
+     * @return
+     */
+    @Path("query-admin-events")
+    @GET
+    @NoCache
+    @Produces(MediaType.APPLICATION_JSON)
+    public List<AdminEventRepresentation> getAdminEvents(@QueryParam("realmId") String realmId, @QueryParam("operationTypes") List<String> operationTypes, @QueryParam("authRealm") String authRealm, @QueryParam("authClient") String authClient,
+            @QueryParam("authUser") String authUser, @QueryParam("authIpAddress") String authIpAddress,
+            @QueryParam("resourcePath") String resourcePath, @QueryParam("dateFrom") String dateFrom,
+            @QueryParam("dateTo") String dateTo, @QueryParam("first") Integer firstResult,
+            @QueryParam("max") Integer maxResults);
+
+    @POST
+    @Path("/on-admin-event")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void onAdminEvent(final AdminEventRepresentation rep, @QueryParam("includeRepresentation") boolean includeRepresentation);
+
     @POST
     @Path("/remove-user-session")
     @Produces(MediaType.APPLICATION_JSON)
@@ -106,4 +205,98 @@ public interface TestingResource {
     @Path("/update-pass-through-auth-state")
     @Produces(MediaType.APPLICATION_JSON)
     AuthenticatorState updateAuthenticator(AuthenticatorState state);
+
+    @GET
+    @Path("/run-import")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response runImport();
+
+    @GET
+    @Path("/run-export")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response runExport();
+    
+    @GET
+    @Path("/valid-credentials")
+    @Produces(MediaType.APPLICATION_JSON)
+    public boolean validCredentials(@QueryParam("realmName") String realmName, @QueryParam("userName") String userName, @QueryParam("password") String password);
+
+    @GET
+    @Path("/user-by-federated-identity")
+    @Produces(MediaType.APPLICATION_JSON)
+    public UserRepresentation getUserByFederatedIdentity(@QueryParam("realmName") String realmName,
+                                                         @QueryParam("identityProvider") String identityProvider,
+                                                         @QueryParam("userId") String userId,
+                                                         @QueryParam("userName") String userName);
+
+    @GET
+    @Path("/user-by-username-from-fed-factory")
+    @Produces(MediaType.APPLICATION_JSON)
+    public UserRepresentation getUserByUsernameFromFedProviderFactory(@QueryParam("realmName") String realmName,
+                                                                      @QueryParam("userName") String userName);
+
+    @GET
+    @Path("/get-client-auth-flow")
+    @Produces(MediaType.APPLICATION_JSON)
+    public AuthenticationFlowRepresentation getClientAuthFlow(@QueryParam("realmName") String realmName);
+
+    @GET
+    @Path("/get-reset-cred-flow")
+    @Produces(MediaType.APPLICATION_JSON)
+    public AuthenticationFlowRepresentation getResetCredFlow(@QueryParam("realmName") String realmName);
+
+    @GET
+    @Path("/get-user-by-service-account-client")
+    @Produces(MediaType.APPLICATION_JSON)
+    public UserRepresentation getUserByServiceAccountClient(@QueryParam("realmName") String realmName, @QueryParam("clientId") String clientId);
+
+
+    @GET
+    @Path("/get-users-per-file")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Integer getUsersPerFile();
+
+    @PUT
+    @Path("/set-users-per-file")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void setUsersPerFile(@QueryParam("usersPerFile") Integer usersPerFile);
+
+    @GET
+    @Path("/get-dir")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public String getDir();
+
+    @PUT
+    @Path("/set-dir")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public String setDir(@QueryParam("dir") String dir);
+
+    @PUT
+    @Path("/export-import-provider")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void setProvider(@QueryParam("exportImportProvider") String exportImportProvider);
+
+    @PUT
+    @Path("/export-import-file")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void setFile(@QueryParam("file") String file);
+
+    @PUT
+    @Path("/export-import-action")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void setAction(@QueryParam("exportImportAction") String exportImportAction);
+
+    @PUT
+    @Path("/set-realm-name")
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void setRealmName(@QueryParam("realmName") String realmName);
+
+    @GET
+    @Path("/get-test-dir")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public String getExportImportTestDirectory();
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/AdminEvents.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/AdminEvents.java
index cbcfc89..b46a13e 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/AdminEvents.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/AdminEvents.java
@@ -50,17 +50,14 @@ public class AdminEvents extends Events {
         private AdminEventsTableFilterForm filterForm;
 
         public void update() {
-            waitForBody();
             clickHeaderButton("Update");
         }
 
         public void reset() {
-            waitForBody();
             clickHeaderButton("Reset");
         }
 
         public void filter() {
-            waitForBody();
             filterButton.click();
         }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/LoginEvents.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/LoginEvents.java
index 6f2094f..a263a2f 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/LoginEvents.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/events/LoginEvents.java
@@ -50,17 +50,14 @@ public class LoginEvents extends Events {
         private LoginEventsTableFilterForm filterForm;
 
         public void update() {
-            waitForBody();
             clickHeaderButton("Update");
         }
 
         public void reset() {
-            waitForBody();
             clickHeaderButton("Reset");
         }
 
         public void filter() {
-            waitForBody();
             filterButton.click();
         }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/AdminConsoleAlert.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/AdminConsoleAlert.java
index 36d12d6..9e582d8 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/AdminConsoleAlert.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/AdminConsoleAlert.java
@@ -27,19 +27,19 @@ import org.openqa.selenium.support.FindBy;
  */
 public class AdminConsoleAlert extends AbstractAlert {
 
-    @FindBy(xpath = "//button[@class='close']")
+    @FindBy(xpath = ".//button[@class='close']")
     protected WebElement closeButton;
 
     public boolean isInfo() {
-        return getAttributeClass().contains("alert-info");
+        return checkAlertType("info");
     }
 
     public boolean isWarning() {
-        return getAttributeClass().contains("alert-warning");
+        return checkAlertType("waring");
     }
 
     public boolean isDanger() {
-        return getAttributeClass().contains("alert-danger");
+        return checkAlertType("danger");
     }
 
     public void close() {
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/DataTable.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/DataTable.java
index 2b1040a..a29814d 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/DataTable.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/DataTable.java
@@ -17,12 +17,14 @@
 
 package org.keycloak.testsuite.console.page.fragment;
 
+import org.jboss.arquillian.drone.api.annotation.Drone;
+import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
 
 import java.util.List;
 
-import static org.keycloak.testsuite.util.WaitUtils.pause;
+import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
 import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
 import org.openqa.selenium.By;
 import static org.openqa.selenium.By.xpath;
@@ -33,6 +35,9 @@ import static org.openqa.selenium.By.xpath;
  */
 public class DataTable {
 
+    @Drone
+    protected WebDriver driver;
+
     @FindBy(css = "input[class*='search']")
     private WebElement searchInput;
     @FindBy(css = "div[class='input-group-addon'] i")
@@ -49,38 +54,30 @@ public class DataTable {
     private WebElement infoRow;
 
     public void search(String pattern) {
-        waitForBody();
         searchInput.sendKeys(pattern);
         searchButton.click();
     }
 
     public void clickHeaderButton(String buttonText) {
-        waitForBody();
         header.findElement(By.xpath(".//button[text()='" + buttonText + "']")).click();
+        waitForPageToLoad(driver);
     }
 
     public void clickHeaderLink(String linkText) {
-        waitForBody();
         header.findElement(By.linkText(linkText)).click();
+        waitForPageToLoad(driver);
     }
 
     public WebElement body() {
         return body;
     }
 
-    public void waitForBody() {
-        waitUntilElement(body).is().present();
-    }
-
     public List<WebElement> rows() {
-        waitForBody();
-        pause(250);
         return rows;
     }
 
     public WebElement getRowByLinkText(String text) {
         WebElement row = body.findElement(By.xpath(".//tr[./td/a[text()='" + text + "']]"));
-        waitUntilElement(row).is().present();
         return row;
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/ModalDialog.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/ModalDialog.java
index 6dc9007..57918b7 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/ModalDialog.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/console/page/fragment/ModalDialog.java
@@ -17,12 +17,12 @@
 
 package org.keycloak.testsuite.console.page.fragment;
 
-import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
-
+import org.jboss.arquillian.drone.api.annotation.Drone;
 import org.jboss.arquillian.graphene.fragment.Root;
-import static org.keycloak.testsuite.util.WaitUtils.pause;
+import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
+import static org.keycloak.testsuite.util.WaitUtils.*;
 
 /**
  *
@@ -33,6 +33,9 @@ public class ModalDialog {
     @Root
     private WebElement root;
 
+    @Drone
+    private WebDriver driver;
+
     @FindBy(xpath = ".//button[text()='Cancel']")
     private WebElement cancelButton;
     @FindBy(xpath = ".//button[text()='Delete']")
@@ -44,26 +47,24 @@ public class ModalDialog {
     private WebElement nameInput;
 
     public void ok() {
-        waitUntilElement(okButton).is().present();
+        waitForModalFadeIn(driver);
         okButton.click();
-        waitUntilElement(root).is().not().present();
+        waitForModalFadeOut(driver);
     }
     
     public void confirmDeletion() {
-        waitUntilElement(deleteButton).is().present();
+        waitForModalFadeIn(driver);
         deleteButton.click();
-        waitUntilElement(root).is().not().present();
-        pause(200);
+        waitForModalFadeOut(driver);
     }
 
     public void cancel() {
-        waitUntilElement(cancelButton).is().present();
+        waitForModalFadeIn(driver);
         cancelButton.click();
-        waitUntilElement(root).is().not().present();
+        waitForModalFadeOut(driver);
     }
 
     public void setName(String name) {
-        waitUntilElement(nameInput).is().present();
         nameInput.clear();
         nameInput.sendKeys(name);
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractAlert.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractAlert.java
index c173f9a..a0c475f 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractAlert.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractAlert.java
@@ -17,14 +17,16 @@
 
 package org.keycloak.testsuite.page;
 
-import com.google.common.base.Predicate;
-import java.util.Arrays;
-import static org.jboss.arquillian.graphene.Graphene.waitModel;
+import org.jboss.arquillian.drone.api.annotation.Drone;
 import org.jboss.arquillian.graphene.fragment.Root;
 import org.jboss.logging.Logger;
-import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
+
+import org.keycloak.testsuite.util.WaitUtils;
+import org.openqa.selenium.TimeoutException;
 import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
 
 /**
  *
@@ -37,33 +39,27 @@ public abstract class AbstractAlert {
     @Root
     protected WebElement root;
 
-    public void waitUntilPresent() {
-        waitUntilElement(root, "Flash message should be present.").is().present();
-    }
-
-    public void waitUntilPresentAndClassSet() {
-        waitUntilPresent();
-        waitModel().until(new Predicate<WebDriver>() {
-            @Override
-            public boolean apply(WebDriver input) {
-                return !Arrays.asList(getAttributeClass().split(" ")).contains("alert-");
-            }
-        });
-    }
+    @Drone
+    protected WebDriver driver;
 
     public String getText() {
         return root.getText();
     }
 
-    public String getAttributeClass() {
-        String attrClass = root.getAttribute("class");
-        log.debug("Alert @class = '" + attrClass + "'");
-        return attrClass;
-    }
-
     public boolean isSuccess() {
         log.debug("Alert.isSuccess()");
-        return getAttributeClass().contains("alert-success");
+        return checkAlertType("success");
+    }
+
+    protected boolean checkAlertType(String type) {
+        WaitUtils.waitForPageToLoad(driver);
+        try {
+            (new WebDriverWait(driver, 1)).until(ExpectedConditions.attributeContains(root, "class", "alert-" + type));
+        }
+        catch (TimeoutException e) {
+            return false;
+        }
+        return true;
     }
 
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPage.java
index 2e5836e..5ed6afd 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPage.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/AbstractPage.java
@@ -23,10 +23,8 @@ import java.util.Map;
 import javax.ws.rs.core.UriBuilder;
 import org.jboss.arquillian.drone.api.annotation.Drone;
 import org.jboss.logging.Logger;
-import static org.keycloak.testsuite.util.WaitUtils.pause;
-import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
 
-import org.openqa.selenium.By;
+import org.keycloak.testsuite.util.URLUtils;
 import org.openqa.selenium.WebDriver;
 
 /**
@@ -74,6 +72,11 @@ public abstract class AbstractPage {
         return this;
     }
 
+    public AbstractPage removeUriParameter(String name) {
+        uriParameters.remove(name);
+        return this;
+    }
+
     public Object getUriParameter(String name) {
         return uriParameters.get(name);
     }
@@ -88,17 +91,15 @@ public abstract class AbstractPage {
     }
 
     public void navigateTo() {
-        String uri = buildUri().toASCIIString();
-        log.debug("current URL:  " + driver.getCurrentUrl());
-        log.info("navigating to " + uri);
-        driver.navigate().to(uri);
-        pause(300); // this is needed for FF for some reason
-        waitUntilElement(By.tagName("body")).is().visible();
-        log.info("current URL:  " + driver.getCurrentUrl());
+        navigateTo(true);
+    }
+
+    public void navigateTo(boolean waitForMatch) {
+        URLUtils.navigateToUri(driver, buildUri().toASCIIString(), waitForMatch);
     }
 
     public boolean isCurrent() {
-        return driver.getCurrentUrl().equals(toString());
+        return URLUtils.currentUrlEqual(driver, toString());
     }
 
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/Form.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/Form.java
index 8f3232b..1bec126 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/Form.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/page/Form.java
@@ -21,6 +21,8 @@ import org.jboss.arquillian.drone.api.annotation.Drone;
 import static org.jboss.arquillian.graphene.Graphene.guardAjax;
 import org.jboss.logging.Logger;
 import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
+
+import org.keycloak.testsuite.util.WaitUtils;
 import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
@@ -45,8 +47,8 @@ public class Form {
 
     public void save() {
 //        guardAjax(save).click();
-        waitUntilElement(save).is().present();
         save.click();
+        WaitUtils.waitForPageToLoad(driver);
     }
 
     public void cancel() {
@@ -54,14 +56,12 @@ public class Form {
     }
 
     public static String getInputValue(WebElement input) {
-        waitUntilElement(input).is().present();
         return input.getAttribute(VALUE);
     }
 
     public static final String VALUE = "value";
 
     public static void setInputValue(WebElement input, String value) {
-        waitUntilElement(input).is().present();
         if (input.isEnabled()) {
             input.clear();
             if (value != null) {
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/ConsentPage.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/ConsentPage.java
new file mode 100644
index 0000000..b8b244d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/pages/ConsentPage.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.pages;
+
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class ConsentPage extends AbstractPage {
+
+    @FindBy(id = "kc-login")
+    private WebElement submitButton;
+
+    public void confirm() {
+        submitButton.click();
+    }
+
+    @Override
+    public boolean isCurrent() {
+        return driver.getTitle().equalsIgnoreCase("grant access");
+    }
+
+    @Override
+    public void open() throws Exception {
+
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LDAPRule.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LDAPRule.java
index 5cebe8c..86b3cae 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LDAPRule.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/LDAPRule.java
@@ -21,6 +21,7 @@ import java.util.Map;
 import java.util.Properties;
 
 import org.junit.rules.ExternalResource;
+import org.keycloak.models.LDAPConstants;
 import org.keycloak.util.ldap.LDAPEmbeddedServer;
 
 /**
@@ -30,6 +31,14 @@ public class LDAPRule extends ExternalResource {
 
     public static final String LDAP_CONNECTION_PROPERTIES_LOCATION = "classpath:ldap/ldap-connection.properties";
 
+    private static final String PROPERTY_ENABLE_SSL = "enableSSL";
+
+    private static final String PROPERTY_KEYSTORE_FILE = "keystoreFile";
+
+    private static final String PRIVATE_KEY = "keystore/keycloak.jks";
+
+    private static final String PROPERTY_CERTIFICATE_PASSWORD = "certificatePassword";
+
     protected LDAPTestConfiguration ldapTestConfiguration;
     protected LDAPEmbeddedServer ldapEmbeddedServer;
 
@@ -66,6 +75,11 @@ public class LDAPRule extends ExternalResource {
         Properties defaultProperties = new Properties();
         defaultProperties.setProperty(LDAPEmbeddedServer.PROPERTY_DSF, LDAPEmbeddedServer.DSF_INMEMORY);
         defaultProperties.setProperty(LDAPEmbeddedServer.PROPERTY_LDIF_FILE, "classpath:ldap/users.ldif");
+        defaultProperties.setProperty(LDAPConstants.CONNECTION_URL, "ldaps://localhost:10636");
+        defaultProperties.setProperty(LDAPEmbeddedServer.PROPERTY_BIND_PORT, "10636");
+        defaultProperties.setProperty(PROPERTY_ENABLE_SSL, "true");
+        defaultProperties.setProperty(PROPERTY_CERTIFICATE_PASSWORD, "secret");
+        defaultProperties.setProperty(PROPERTY_KEYSTORE_FILE, this.getClass().getClassLoader().getResource(LDAPRule.PRIVATE_KEY).getFile());
 
         return new LDAPEmbeddedServer(defaultProperties);
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/MailServerConfiguration.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/MailServerConfiguration.java
index 5110e4c..50c8ed3 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/MailServerConfiguration.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/MailServerConfiguration.java
@@ -25,4 +25,6 @@ public class MailServerConfiguration {
     public static final String FROM = "server@mail.test";
     public static final String HOST = "localhost";
     public static final String PORT = "3025";
+    public static final String PORT_SSL = "3465";
+    public static final String STARTTLS = "true";
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/MessageHandlerFactoryImpl.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/MessageHandlerFactoryImpl.java
new file mode 100644
index 0000000..67a2e43
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/MessageHandlerFactoryImpl.java
@@ -0,0 +1,86 @@
+package org.keycloak.testsuite.util;
+
+import org.subethamail.smtp.MessageContext;
+import org.subethamail.smtp.MessageHandler;
+import org.subethamail.smtp.MessageHandlerFactory;
+import org.subethamail.smtp.RejectException;
+
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.internet.MimeMessage;
+import java.io.*;
+import java.util.Properties;
+
+
+public class MessageHandlerFactoryImpl implements MessageHandlerFactory {
+
+    MimeMessage message;
+
+    public MessageHandler create(MessageContext ctx) {
+        return new Handler(ctx);
+    }
+
+    class Handler implements MessageHandler {
+        MessageContext ctx;
+
+
+
+        public Handler(MessageContext ctx) {
+            this.ctx = ctx;
+        }
+
+        public void from(String from) throws RejectException {
+            System.out.println("FROM:" + from);
+        }
+
+        public void recipient(String recipient) throws RejectException {
+            System.out.println("RECIPIENT:" + recipient);
+        }
+
+        public void data(InputStream data) throws IOException {
+            String rawMail = this.convertStreamToString(data);
+
+            Session session = Session.getDefaultInstance(new Properties());
+            InputStream is = new ByteArrayInputStream(rawMail.getBytes());
+            try
+            {
+                message = new MimeMessage(session, is);
+                setMessage(message);
+            }
+            catch (MessagingException e)
+            {
+                e.printStackTrace();
+            }
+        }
+
+        public void done() {
+            System.out.println("Finished");
+        }
+
+        public String convertStreamToString(InputStream is) {
+            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+            StringBuilder sb = new StringBuilder();
+
+            String line = null;
+            try {
+                while ((line = reader.readLine()) != null) {
+                    sb.append(line + "\n");
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            return sb.toString();
+        }
+
+
+
+    }
+
+    public MimeMessage getMessage(){
+        return message;
+    }
+
+    public  void setMessage(MimeMessage msg){
+        this.message = msg;
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/MessageHandlerImpl.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/MessageHandlerImpl.java
new file mode 100644
index 0000000..ec6d430
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/MessageHandlerImpl.java
@@ -0,0 +1,37 @@
+package org.keycloak.testsuite.util;
+
+import org.jboss.logging.Logger;
+import org.subethamail.smtp.MessageContext;
+import org.subethamail.smtp.MessageHandler;
+
+import java.io.InputStream;
+
+public class MessageHandlerImpl implements MessageHandler {
+    MessageContext context;
+
+    private static final Logger log = Logger.getLogger(MessageHandlerImpl.class);
+
+    MessageHandlerImpl(MessageContext context) {
+        this.context = context;
+    }
+
+    @Override
+    public void from(String from) {
+        log.info("FROM: ${from}");
+    }
+
+    @Override
+    public void recipient(String recipient) {
+        log.info("RECIPIENT: ${recipient}");
+    }
+
+    @Override
+    public void data(InputStream data) {
+        log.info("DATA");
+    }
+
+    @Override
+    public void done() {
+        log.info("DONE");
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java
index c0088a1..586351d 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/OAuthClient.java
@@ -22,6 +22,8 @@ import org.apache.commons.io.output.ByteArrayOutputStream;
 import org.apache.http.HttpResponse;
 import org.apache.http.NameValuePair;
 import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.utils.URLEncodedUtils;
 import org.apache.http.impl.client.CloseableHttpClient;
@@ -36,13 +38,18 @@ import org.keycloak.common.util.PemUtils;
 import org.keycloak.constants.AdapterConstants;
 import org.keycloak.jose.jws.JWSInput;
 import org.keycloak.jose.jws.crypto.RSAProvider;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
+import org.keycloak.jose.jwk.JSONWebKeySet;
+import org.keycloak.protocol.oidc.utils.OIDCResponseType;
 import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.IDToken;
 import org.keycloak.representations.RefreshToken;
 import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
 import org.keycloak.util.BasicAuthHelper;
 import org.keycloak.util.JsonSerialization;
 
+import org.keycloak.util.TokenUtil;
 import org.openqa.selenium.By;
 import org.openqa.selenium.WebDriver;
 
@@ -51,7 +58,9 @@ import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.nio.charset.Charset;
 import java.security.PublicKey;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
@@ -88,6 +97,14 @@ public class OAuthClient {
 
     private String clientSessionHost;
 
+    private String maxAge;
+
+    private String responseType = OAuth2Constants.CODE;
+
+    private String responseMode;
+
+    private String nonce;
+
     private Map<String, PublicKey> publicKeys = new HashMap<>();
 
     public void init(Keycloak adminClient, WebDriver driver) {
@@ -103,9 +120,10 @@ public class OAuthClient {
         uiLocales = null;
         clientSessionState = null;
         clientSessionHost = null;
+        maxAge = null;
     }
 
-    public AuthorizationCodeResponse doLogin(String username, String password) {
+    public AuthorizationEndpointResponse doLogin(String username, String password) {
         openLoginForm();
         String src = driver.getPageSource();
         try {
@@ -117,7 +135,7 @@ public class OAuthClient {
             throw t;
         }
 
-        return new AuthorizationCodeResponse(this);
+        return new AuthorizationEndpointResponse(this);
     }
 
     public void doLoginGrant(String username, String password) {
@@ -279,6 +297,17 @@ public class OAuthClient {
         }
     }
 
+    public JSONWebKeySet doCertsRequest(String realm) throws Exception {
+        CloseableHttpClient client = new DefaultHttpClient();
+        try {
+            HttpGet get = new HttpGet(getCertsUrl(realm));
+            CloseableHttpResponse response = client.execute(get);
+            return JsonSerialization.readValue(response.getEntity().getContent(), JSONWebKeySet.class);
+        } finally {
+            closeClient(client);
+        }
+    }
+
     public AccessTokenResponse doClientCredentialsGrantAccessTokenRequest(String clientSecret) throws Exception {
         CloseableHttpClient client = new DefaultHttpClient();
         try {
@@ -398,6 +427,16 @@ public class OAuthClient {
         }
     }
 
+    public IDToken verifyIDToken(String token) {
+        try {
+            IDToken idToken = RSATokenVerifier.verifyToken(token, getRealmPublicKey(realm), baseUrl + "/realms/" + realm, true, false);
+            Assert.assertEquals(TokenUtil.TOKEN_TYPE_ID, idToken.getType());
+            return idToken;
+        } catch (VerificationException e) {
+            throw new RuntimeException("Failed to verify token", e);
+        }
+    }
+
     public RefreshToken verifyRefreshToken(String refreshToken) {
         try {
             JWSInput jws = new JWSInput(refreshToken);
@@ -415,7 +454,11 @@ public class OAuthClient {
     }
 
     public String getCurrentRequest() {
-        return driver.getCurrentUrl().substring(0, driver.getCurrentUrl().indexOf('?'));
+        int index = driver.getCurrentUrl().indexOf('?');
+        if (index == -1) {
+            index = driver.getCurrentUrl().indexOf('#');
+        }
+        return driver.getCurrentUrl().substring(0, index);
     }
 
     public URI getCurrentUri() {
@@ -435,6 +478,18 @@ public class OAuthClient {
         return m;
     }
 
+    public Map<String, String> getCurrentFragment() {
+        Map<String, String> m = new HashMap<String, String>();
+
+        String fragment = getCurrentUri().getRawFragment();
+        List<NameValuePair> pairs = (fragment == null || fragment.isEmpty()) ? Collections.emptyList() : URLEncodedUtils.parse(fragment, Charset.forName("UTF-8"));
+
+        for (NameValuePair p : pairs) {
+            m.put(p.getName(), p.getValue());
+        }
+        return m;
+    }
+
     public void openLoginForm() {
         driver.navigate().to(getLoginFormUrl());
     }
@@ -452,8 +507,13 @@ public class OAuthClient {
     }
 
     public String getLoginFormUrl() {
-        UriBuilder b = OIDCLoginProtocolService.authUrl(UriBuilder.fromUri(SERVER_ROOT + "/auth"));
-        b.queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE);
+        UriBuilder b = OIDCLoginProtocolService.authUrl(UriBuilder.fromUri(AUTH_SERVER_ROOT));
+        if (responseType != null) {
+            b.queryParam(OAuth2Constants.RESPONSE_TYPE, responseType);
+        }
+        if (responseMode != null) {
+            b.queryParam(OIDCLoginProtocol.RESPONSE_MODE_PARAM, responseMode);
+        }
         if (clientId != null) {
             b.queryParam(OAuth2Constants.CLIENT_ID, clientId);
         }
@@ -463,11 +523,18 @@ public class OAuthClient {
         if (state != null) {
             b.queryParam(OAuth2Constants.STATE, state);
         }
-        if(uiLocales != null){
+        if (uiLocales != null){
             b.queryParam(OAuth2Constants.UI_LOCALES_PARAM, uiLocales);
         }
-        if (scope != null) {
-            b.queryParam(OAuth2Constants.SCOPE, scope);
+        if (nonce != null){
+            b.queryParam(OIDCLoginProtocol.NONCE_PARAM, nonce);
+        }
+
+        String scopeParam = TokenUtil.attachOIDCScope(scope);
+        b.queryParam(OAuth2Constants.SCOPE, scopeParam);
+
+        if (maxAge != null) {
+            b.queryParam(OIDCLoginProtocol.MAX_AGE_PARAM, maxAge);
         }
         return b.build(realm).toString();
     }
@@ -503,6 +570,11 @@ public class OAuthClient {
         return b.build(realm).toString();
     }
 
+    public String getCertsUrl(String realm) {
+        UriBuilder b = OIDCLoginProtocolService.certsUrl(UriBuilder.fromUri(baseUrl));
+        return b.build(realm).toString();
+    }
+
     public String getServiceAccountUrl() {
         return getResourceOwnerPasswordCredentialGrantUrl();
     }
@@ -552,22 +624,66 @@ public class OAuthClient {
         return this;
     }
 
+    public OAuthClient maxAge(String maxAge) {
+        this.maxAge = maxAge;
+        return this;
+    }
+
+    public OAuthClient responseType(String responseType) {
+        this.responseType = responseType;
+        return this;
+    }
+
+    public OAuthClient responseMode(String responseMode) {
+        this.responseMode = responseMode;
+        return this;
+    }
+
+    public OAuthClient nonce(String nonce) {
+        this.nonce = nonce;
+        return this;
+    }
+
     public String getRealm() {
         return realm;
     }
 
-    public static class AuthorizationCodeResponse {
+    public static class AuthorizationEndpointResponse {
 
         private boolean isRedirected;
         private String code;
         private String state;
         private String error;
+        private String errorDescription;
+
+        // Just during OIDC implicit or hybrid flow
+        private String accessToken;
+        private String idToken;
+
+        public AuthorizationEndpointResponse(OAuthClient client) {
+            boolean fragment;
+            try {
+                fragment = client.responseType != null && OIDCResponseType.parse(client.responseType).isImplicitOrHybridFlow();
+            } catch (IllegalArgumentException iae) {
+                fragment = false;
+            }
+            init (client, fragment);
+        }
+
+        public AuthorizationEndpointResponse(OAuthClient client, boolean fragment) {
+            init(client, fragment);
+        }
 
-        public AuthorizationCodeResponse(OAuthClient client) {
+        private void init(OAuthClient client, boolean fragment) {
             isRedirected = client.getCurrentRequest().equals(client.getRedirectUri());
-            code = client.getCurrentQuery().get(OAuth2Constants.CODE);
-            state = client.getCurrentQuery().get(OAuth2Constants.STATE);
-            error = client.getCurrentQuery().get(OAuth2Constants.ERROR);
+            Map<String, String> params = fragment ? client.getCurrentFragment() : client.getCurrentQuery();
+
+            code = params.get(OAuth2Constants.CODE);
+            state = params.get(OAuth2Constants.STATE);
+            error = params.get(OAuth2Constants.ERROR);
+            errorDescription = params.get(OAuth2Constants.ERROR_DESCRIPTION);
+            accessToken = params.get(OAuth2Constants.ACCESS_TOKEN);
+            idToken = params.get(OAuth2Constants.ID_TOKEN);
         }
 
         public boolean isRedirected() {
@@ -586,11 +702,23 @@ public class OAuthClient {
             return error;
         }
 
+        public String getErrorDescription() {
+            return errorDescription;
+        }
+
+        public String getAccessToken() {
+            return accessToken;
+        }
+
+        public String getIdToken() {
+            return idToken;
+        }
     }
 
     public static class AccessTokenResponse {
         private int statusCode;
 
+        private String idToken;
         private String accessToken;
         private String tokenType;
         private int expiresIn;
@@ -610,6 +738,7 @@ public class OAuthClient {
             Map responseJson = JsonSerialization.readValue(s, Map.class);
 
             if (statusCode == 200) {
+                idToken = (String)responseJson.get("id_token");
                 accessToken = (String)responseJson.get("access_token");
                 tokenType = (String)responseJson.get("token_type");
                 expiresIn = (Integer)responseJson.get("expires_in");
@@ -624,6 +753,10 @@ public class OAuthClient {
             }
         }
 
+        public String getIdToken() {
+            return idToken;
+        }
+
         public String getAccessToken() {
             return accessToken;
         }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/UIUtils.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/UIUtils.java
new file mode 100644
index 0000000..ec54244
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/UIUtils.java
@@ -0,0 +1,33 @@
+package org.keycloak.testsuite.util;
+
+import org.openqa.selenium.TimeoutException;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.Select;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+/**
+ * @author Vaclav Muzikar <vmuzikar@redhat.com>
+ */
+public final class UIUtils {
+
+    public static boolean selectContainsOption(Select select, String optionText) {
+        for (WebElement option : select.getOptions()) {
+            if (option.getText().equals(optionText)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean currentTitleEquals(WebDriver driver, String url) {
+        try {
+            (new WebDriverWait(driver, 5)).until(ExpectedConditions.titleIs(url));
+        }
+        catch (TimeoutException e) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/URLUtils.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/URLUtils.java
new file mode 100644
index 0000000..1147bc7
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/URLUtils.java
@@ -0,0 +1,112 @@
+package org.keycloak.testsuite.util;
+
+
+import org.jboss.logging.Logger;
+import org.openqa.selenium.TimeoutException;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.ie.InternetExplorerDriver;
+import org.openqa.selenium.support.ui.ExpectedCondition;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import java.util.regex.Pattern;
+
+import static org.openqa.selenium.support.ui.ExpectedConditions.*;
+
+/**
+ * @author Vaclav Muzikar <vmuzikar@redhat.com>
+ */
+public final class URLUtils {
+
+    public static void navigateToUri(WebDriver driver, String uri, boolean waitForMatch) {
+        navigateToUri(driver, uri, waitForMatch, true);
+    }
+
+    private static void navigateToUri(WebDriver driver, String uri, boolean waitForMatch, boolean enableIEWorkaround) {
+        Logger log = Logger.getLogger(URLUtils.class);
+
+        log.info("starting navigation");
+
+        // In IE, sometime the current URL is not correct; one of the indicators is that the target URL
+        // equals the current URL
+        if (driver instanceof InternetExplorerDriver && driver.getCurrentUrl().equals(uri)) {
+            log.info("IE workaround: target URL equals current URL - refreshing the page");
+            driver.navigate().refresh();
+        }
+
+        WaitUtils.waitForPageToLoad(driver);
+
+        log.info("current URL:  " + driver.getCurrentUrl());
+        log.info("navigating to " + uri);
+        driver.navigate().to(uri);
+
+        if (waitForMatch) {
+            // Possible login URL; this is to eliminate unnecessary wait when navigating to a secured page and being
+            // redirected to the login page
+            String loginUrl = "^[^\\?]+/auth/realms/[^/]+/(protocol|login-actions).+$";
+
+            try {
+                (new WebDriverWait(driver, 3)).until(or(urlMatches("^" + Pattern.quote(uri) + ".*$"), urlMatches(loginUrl)));
+            } catch (TimeoutException e) {
+                log.info("new current URL doesn't start with desired URL");
+            }
+        }
+
+        WaitUtils.waitForPageToLoad(driver);
+
+        log.info("new current URL:  " + driver.getCurrentUrl());
+
+        // In IE, after deleting the cookies for test realm, the first loaded page in master's admin console
+        // contains invalid URL (misses #/realms/[realm] or contains state and code fragments), although the
+        // address bar states the correct URL; seemingly this is another bug in IE WebDriver)
+        if (enableIEWorkaround && driver instanceof InternetExplorerDriver
+                && (driver.getCurrentUrl().matches("^[^#]+/#state=[^#/&]+&code=[^#/&]+$")
+                ||  driver.getCurrentUrl().matches("^.+/auth/admin/[^/]+/console/$"))) {
+            log.info("IE workaround: reloading the page after deleting the cookies...");
+            navigateToUri(driver, uri, waitForMatch, false);
+        }
+        else {
+            log.info("navigation complete");
+        }
+    }
+
+    public static boolean currentUrlEqual(WebDriver driver, String url) {
+        return urlCheck(driver, urlToBe(url));
+    }
+
+    public static boolean currentUrlDoesntEqual(WebDriver driver, String url) {
+        return urlCheck(driver, not(urlToBe(url)));
+    }
+
+    public static boolean currentUrlStartWith(WebDriver driver, String url) {
+        return urlCheck(driver, urlMatches("^" + Pattern.quote(url) + ".*$"));
+    }
+
+    public static boolean currentUrlDoesntStartWith(WebDriver driver, String url) {
+        return urlCheck(driver, urlMatches("^(?!" + Pattern.quote(url) + ").+$"));
+    }
+
+    private static boolean urlCheck(WebDriver driver, ExpectedCondition condition) {
+        return urlCheck(driver, condition, false);
+    }
+
+    private static boolean urlCheck(WebDriver driver, ExpectedCondition condition, boolean secondTry) {
+        Logger log = Logger.getLogger(URLUtils.class);
+
+        try {
+            (new WebDriverWait(driver, 1, 100)).until(condition);
+        }
+        catch (TimeoutException e) {
+            if (driver instanceof InternetExplorerDriver && !secondTry) {
+                // IE WebDriver has sometimes invalid current URL
+                log.info("IE workaround: checking URL failed at first attempt - refreshing the page and trying one more time...");
+                driver.navigate().refresh();
+                urlCheck(driver, condition, true);
+            }
+            else {
+                return false;
+            }
+        }
+        return true;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/UserInfoClientUtil.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/UserInfoClientUtil.java
new file mode 100644
index 0000000..dd6a3db
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/UserInfoClientUtil.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.util;
+
+import java.net.URI;
+
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+
+import org.junit.Assert;
+import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
+import org.keycloak.representations.UserInfo;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class UserInfoClientUtil {
+
+    public static Response executeUserInfoRequest_getMethod(Client client, String accessToken) {
+        WebTarget userInfoTarget = getUserInfoWebTarget(client);
+
+        return userInfoTarget.request()
+                .header(HttpHeaders.AUTHORIZATION, "bearer " + accessToken)
+                .get();
+    }
+
+    public static WebTarget getUserInfoWebTarget(Client client) {
+        UriBuilder builder = UriBuilder.fromUri(OAuthClient.AUTH_SERVER_ROOT);
+        UriBuilder uriBuilder = OIDCLoginProtocolService.userInfoUrl(builder);
+        URI userInfoUri = uriBuilder.build("test");
+        return client.target(userInfoUri);
+    }
+
+    public static void testSuccessfulUserInfoResponse(Response response, String expectedUsername, String expectedEmail) {
+        Assert.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
+
+        UserInfo userInfo = response.readEntity(UserInfo.class);
+
+        response.close();
+
+        Assert.assertNotNull(userInfo);
+        Assert.assertNotNull(userInfo.getSubject());
+        Assert.assertEquals(expectedEmail, userInfo.getEmail());
+        Assert.assertEquals(expectedUsername, userInfo.getPreferredUsername());
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/WaitUtils.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/WaitUtils.java
index c81a22c..17a8485 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/WaitUtils.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/util/WaitUtils.java
@@ -16,42 +16,103 @@
  */
 package org.keycloak.testsuite.util;
 
+import java.util.Collections;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import static org.jboss.arquillian.graphene.Graphene.waitGui;
 import org.jboss.arquillian.graphene.wait.ElementBuilder;
 import org.openqa.selenium.By;
+import org.openqa.selenium.TimeoutException;
+import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import static org.jboss.arquillian.graphene.Graphene.waitModel;
+import static org.openqa.selenium.support.ui.ExpectedConditions.*;
 
 /**
  *
  * @author Petr Mensik
  * @author tkyjovsk
+ * @author Vaclav Muzikar <vmuzikar@redhat.com>
  */
 public final class WaitUtils {
 
+    protected final static org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(WaitUtils.class);
+
     public static final String PAGELOAD_TIMEOUT_PROP = "pageload.timeout";
 
-    public static final Integer PAGELOAD_TIMEOUT = Integer.parseInt(System.getProperty(PAGELOAD_TIMEOUT_PROP, "60000"));
+    public static final Integer PAGELOAD_TIMEOUT_MILLIS = Integer.parseInt(System.getProperty(PAGELOAD_TIMEOUT_PROP, "10000"));
+
+    public static final int IMPLICIT_ELEMENT_WAIT_MILLIS = 750;
 
+    // Should be no longer necessary for finding elements since we have implicit wait
     public static ElementBuilder<Void> waitUntilElement(By by) {
         return waitGui().until().element(by);
     }
 
+    // Should be no longer necessary for finding elements since we have implicit wait
     public static ElementBuilder<Void> waitUntilElement(WebElement element) {
         return waitGui().until().element(element);
     }
 
+    // Should be no longer necessary for finding elements since we have implicit wait
     public static ElementBuilder<Void> waitUntilElement(WebElement element, String failMessage) {
         return waitGui().until(failMessage).element(element);
     }
 
+    public static void waitUntilElementIsNotPresent(WebDriver driver, By locator) {
+        waitUntilElementIsNotPresent(driver, driver.findElement(locator));
+    }
+
+    public static void waitUntilElementIsNotPresent(WebDriver driver, WebElement element) {
+        (new WebDriverWait(driver, IMPLICIT_ELEMENT_WAIT_MILLIS))
+                .until(invisibilityOfAllElements(Collections.singletonList(element)));
+    }
+
     public static void pause(long millis) {
         try {
             Thread.sleep(millis);
         } catch (InterruptedException ex) {
             Logger.getLogger(WaitUtils.class.getName()).log(Level.SEVERE, null, ex);
+            Thread.currentThread().interrupt();
+        }
+    }
+
+    /**
+     * Waits for page to finish any pending redirects, REST API requests etc.
+     * Because Keycloak's Admin Console is a single-page application, we need to take extra steps to ensure
+     * the page is fully loaded
+     *
+     * @param driver
+     */
+    public static void waitForPageToLoad(WebDriver driver) {
+        WebDriverWait wait = new WebDriverWait(driver, PAGELOAD_TIMEOUT_MILLIS / 1000);
+
+        try {
+            wait.until(not(urlContains("redirect_fragment")));
+
+            // Checks if the document is ready and asks AngularJS, if present, whether there are any REST API requests
+            // in progress
+            wait.until(javaScriptThrowsNoExceptions(
+                "if (document.readyState !== 'complete' " +
+                    "|| (typeof angular !== 'undefined' && angular.element(document.body).injector().get('$http').pendingRequests.length !== 0)) {" +
+                        "throw \"Not ready\";" +
+                "}"));
+        }
+        catch (TimeoutException e) {
+            // Sometimes, for no obvious reason, the browser/JS doesn't set document.readyState to 'complete' correctly
+            // but that's no reason to let the test fail; after the timeout the page is surely fully loaded
+            log.warn("waitForPageToLoad time exceeded!");
         }
     }
 
+    public static void waitForModalFadeIn(WebDriver driver) {
+        pause(500); // TODO: Find out how to do in more 'elegant' way, e.g. like in the waitForModalFadeOut
+    }
+
+    public static void waitForModalFadeOut(WebDriver driver) {
+        waitUntilElementIsNotPresent(driver, By.className("modal-backdrop"));
+    }
+
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractAuthTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractAuthTest.java
index 697323c..570c9e8 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractAuthTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractAuthTest.java
@@ -22,6 +22,7 @@ import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.testsuite.auth.page.AuthRealm;
+import org.keycloak.testsuite.auth.page.account.Account;
 import org.keycloak.testsuite.auth.page.login.OIDCLogin;
 import org.keycloak.testsuite.auth.page.login.SAMLPostLogin;
 import org.keycloak.testsuite.auth.page.login.SAMLRedirectLogin;
@@ -46,6 +47,8 @@ public abstract class AbstractAuthTest extends AbstractKeycloakTest {
     protected AuthRealm testRealmPage;
     @Page
     protected OIDCLogin testRealmLoginPage;
+    @Page
+    protected Account testRealmAccountPage;
 
     @Page
     protected SAMLPostLogin testRealmSAMLPostLoginPage;
@@ -68,6 +71,7 @@ public abstract class AbstractAuthTest extends AbstractKeycloakTest {
     @Before
     public void beforeAuthTest() {
         testRealmLoginPage.setAuthRealm(testRealmPage);
+        testRealmAccountPage.setAuthRealm(testRealmPage);
 
         testUser = createUserRepresentation("test", "test@email.test", "test", "user", true);
         setPasswordFor(testUser, PASSWORD);
@@ -97,9 +101,7 @@ public abstract class AbstractAuthTest extends AbstractKeycloakTest {
     }
 
     public void deleteAllCookiesForTestRealm() {
-        testRealmPage.navigateTo();
-        log.debug("deleting cookies in test realm");
-        driver.manage().deleteAllCookies();
+        deleteAllCookiesForRealm(testRealmAccountPage);
     }
 
     public void listCookies() {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
index a14abf3..2ee8f73 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/AbstractKeycloakTest.java
@@ -169,13 +169,19 @@ public abstract class AbstractKeycloakTest {
     }
 
     public void deleteAllCookiesForMasterRealm() {
-        masterRealmPage.navigateTo();
-        log.debug("deleting cookies in master realm");
+        deleteAllCookiesForRealm(accountPage);
+    }
+
+    protected void deleteAllCookiesForRealm(Account realmAccountPage) {
+        // masterRealmPage.navigateTo();
+        realmAccountPage.navigateTo(); // Because IE webdriver freezes when loading a JSON page (realm page), we need to use this alternative
+        log.info("deleting cookies in '" + realmAccountPage.getAuthRealm() + "' realm");
         driver.manage().deleteAllCookies();
     }
 
     protected void driverSettings() {
-        driver.manage().timeouts().pageLoadTimeout(WaitUtils.PAGELOAD_TIMEOUT, TimeUnit.MILLISECONDS);
+        driver.manage().timeouts().implicitlyWait(WaitUtils.IMPLICIT_ELEMENT_WAIT_MILLIS, TimeUnit.MILLISECONDS);
+        driver.manage().timeouts().pageLoadTimeout(WaitUtils.PAGELOAD_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
         driver.manage().window().maximize();
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java
index a4f7257..e4dfe0e 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/AccountTest.java
@@ -21,6 +21,7 @@ import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.keycloak.events.Details;
+import org.keycloak.events.Errors;
 import org.keycloak.events.EventType;
 import org.keycloak.models.utils.TimeBasedOTP;
 import org.keycloak.services.resources.AccountService;
@@ -44,6 +45,7 @@ import javax.ws.rs.core.UriBuilder;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+
 import org.jboss.arquillian.drone.api.annotation.Drone;
 import org.jboss.arquillian.graphene.page.Page;
 import org.keycloak.representations.idm.EventRepresentation;
@@ -168,22 +170,20 @@ public class AccountTest extends TestRealmKeycloakTest {
         EventRepresentation event = events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
         String sessionId = event.getSessionId();
         String userId = event.getUserId();
-        changePasswordPage.changePassword("", "new-password", "new-password");
 
+        changePasswordPage.changePassword("", "new-password", "new-password");
         Assert.assertEquals("Please specify password.", profilePage.getError());
+        events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_MISSING).assertEvent();
 
         changePasswordPage.changePassword("password", "new-password", "new-password2");
-
         Assert.assertEquals("Password confirmation doesn't match.", profilePage.getError());
+        events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_CONFIRM_ERROR).assertEvent();
 
         changePasswordPage.changePassword("password", "new-password", "new-password");
-
         Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
-
         events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
 
         changePasswordPage.logout();
-
         events.expectLogout(sessionId).detail(Details.REDIRECT_URI, changePasswordPage.getPath()).assertEvent();
 
         loginPage.open();
@@ -191,7 +191,7 @@ public class AccountTest extends TestRealmKeycloakTest {
 
         Assert.assertEquals("Invalid username or password.", loginPage.getError());
 
-        events.expectLogin().session((String) null).error("invalid_user_credentials")
+        events.expectLogin().session((String) null).error(Errors.INVALID_USER_CREDENTIALS)
                 .removeDetail(Details.CONSENT)
                 .assertEvent();
 
@@ -208,24 +208,142 @@ public class AccountTest extends TestRealmKeycloakTest {
         testRealm.setPasswordPolicy(policy);
         testRealm().update(testRealm);
     }
+
+    @Test
+    public void changePasswordWithBlankCurrentPassword() {
+        changePasswordPage.open();
+        loginPage.login("test-user@localhost", "password");
+        events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
+
+        changePasswordPage.changePassword("", "new", "new");
+        Assert.assertEquals("Please specify password.", profilePage.getError());
+        events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_MISSING).assertEvent();
+
+        changePasswordPage.changePassword("password", "new", "new");
+        Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
+        events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
+    }
+
     @Test
     public void changePasswordWithLengthPasswordPolicy() {
-        setPasswordPolicy("length");
+        setPasswordPolicy("length(8)");
+
+        changePasswordPage.open();
+        loginPage.login("test-user@localhost", "password");
+        events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
+
+        changePasswordPage.changePassword("password", "1234", "1234");
+        Assert.assertEquals("Invalid password: minimum length 8.", profilePage.getError());
+        events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).assertEvent();
+
+        changePasswordPage.changePassword("password", "12345678", "12345678");
+        Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
+        events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
+    }
+
+    @Test
+    public void changePasswordWithDigitsPolicy() {
+        setPasswordPolicy("digits(2)");
 
         changePasswordPage.open();
         loginPage.login("test-user@localhost", "password");
+        events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
+
+        changePasswordPage.changePassword("password", "invalidPassword1", "invalidPassword1");
+        Assert.assertEquals("Invalid password: must contain at least 2 numerical digits.", profilePage.getError());
+        events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).assertEvent();
+
+        changePasswordPage.changePassword("password", "validPassword12", "validPassword12");
+        Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
+        events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
+    }
 
+    @Test
+    public void changePasswordWithLowerCasePolicy() {
+        setPasswordPolicy("lowerCase(2)");
 
+        changePasswordPage.open();
+        loginPage.login("test-user@localhost", "password");
         events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
 
-        changePasswordPage.changePassword("", "new", "new");
+        changePasswordPage.changePassword("password", "iNVALIDPASSWORD", "iNVALIDPASSWORD");
+        Assert.assertEquals("Invalid password: must contain at least 2 lower case characters.", profilePage.getError());
+        events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).assertEvent();
 
-        Assert.assertEquals("Please specify password.", profilePage.getError());
+        changePasswordPage.changePassword("password", "vaLIDPASSWORD", "vaLIDPASSWORD");
+        Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
+        events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
+    }
 
-        changePasswordPage.changePassword("password", "new-password", "new-password");
+    @Test
+    public void changePasswordWithUpperCasePolicy() {
+        setPasswordPolicy("upperCase(2)");
+
+        changePasswordPage.open();
+        loginPage.login("test-user@localhost", "password");
+        events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
+
+        changePasswordPage.changePassword("password", "Invalidpassword", "Invalidpassword");
+        Assert.assertEquals("Invalid password: must contain at least 2 upper case characters.", profilePage.getError());
+        events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).assertEvent();
+
+
+        changePasswordPage.changePassword("password", "VAlidpassword", "VAlidpassword");
+        Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
+        events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
+    }
+
+    @Test
+    public void changePasswordWithSpecialCharsPolicy() {
+        setPasswordPolicy("specialChars(2)");
+
+        changePasswordPage.open();
+        loginPage.login("test-user@localhost", "password");
+        events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
+
+        changePasswordPage.changePassword("password", "invalidPassword*", "invalidPassword*");
+        Assert.assertEquals("Invalid password: must contain at least 2 special characters.", profilePage.getError());
+        events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).assertEvent();
+
+
+        changePasswordPage.changePassword("password", "validPassword*#", "validPassword*#");
+        Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
+        events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
+    }
+
+    @Test
+    public void changePasswordWithNotUsernamePolicy() {
+        setPasswordPolicy("notUsername(1)");
+
+        changePasswordPage.open();
+        loginPage.login("test-user@localhost", "password");
+        events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
 
+        changePasswordPage.changePassword("password", "test-user@localhost", "test-user@localhost");
+        Assert.assertEquals("Invalid password: must not be equal to the username.", profilePage.getError());
+        events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).assertEvent();
+
+
+        changePasswordPage.changePassword("password", "newPassword", "newPassword");
         Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
+        events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
+    }
+
+    @Test
+    public void changePasswordWithRegexPatternsPolicy() {
+        setPasswordPolicy("regexPattern(^[A-Z]+#[a-z]{8}$)");
+
+        changePasswordPage.open();
+        loginPage.login("test-user@localhost", "password");
+        events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
+
+        changePasswordPage.changePassword("password", "invalidPassword", "invalidPassword");
+        Assert.assertEquals("Invalid password: fails to match regex pattern(s).", profilePage.getError());
+        events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).assertEvent();
+
 
+        changePasswordPage.changePassword("password", "VALID#password", "VALID#password");
+        Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
         events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
     }
 
@@ -235,31 +353,26 @@ public class AccountTest extends TestRealmKeycloakTest {
 
         changePasswordPage.open();
         loginPage.login("test-user@localhost", "password");
-
         events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
 
         changePasswordPage.changePassword("password", "password", "password");
-
         Assert.assertEquals("Invalid password: must not be equal to any of last 2 passwords.", profilePage.getError());
+        events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).assertEvent();
 
         changePasswordPage.changePassword("password", "password1", "password1");
-
         Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
-
         events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
 
         changePasswordPage.changePassword("password1", "password", "password");
-
         Assert.assertEquals("Invalid password: must not be equal to any of last 2 passwords.", profilePage.getError());
+        events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).assertEvent();
 
         changePasswordPage.changePassword("password1", "password1", "password1");
-
         Assert.assertEquals("Invalid password: must not be equal to any of last 2 passwords.", profilePage.getError());
+        events.expectAccount(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).assertEvent();
 
         changePasswordPage.changePassword("password1", "password2", "password2");
-
         Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
-
         events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
     }
 
@@ -620,7 +733,7 @@ public class AccountTest extends TestRealmKeycloakTest {
         Assert.assertTrue(applicationsPage.isCurrent());
 
         Map<String, AccountApplicationsPage.AppEntry> apps = applicationsPage.getApplications();
-        Assert.assertEquals(3, apps.size());
+        Assert.assertEquals(4, apps.size());
 
         AccountApplicationsPage.AppEntry accountEntry = apps.get("Account");
         Assert.assertEquals(2, accountEntry.getRolesAvailable().size());
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/custom/AbstractAccountManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/custom/AbstractAccountManagementTest.java
index 6ceb4f8..8122e0a 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/custom/AbstractAccountManagementTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/custom/AbstractAccountManagementTest.java
@@ -52,12 +52,10 @@ public abstract class AbstractAccountManagementTest extends AbstractAuthTest {
     }
 
     public void assertAlertSuccess() {
-        alert.waitUntilPresentAndClassSet();
         assertTrue(alert.isSuccess());
     }
 
     public void assertAlertError() {
-        alert.waitUntilPresentAndClassSet();
         assertTrue(alert.isError());
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ProfileTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ProfileTest.java
index 670e340..a1a1813 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ProfileTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/ProfileTest.java
@@ -53,6 +53,7 @@ import org.keycloak.testsuite.TestRealmKeycloakTest;
 import org.keycloak.testsuite.admin.ApiUtil;
 import org.keycloak.testsuite.util.ClientBuilder;
 import org.keycloak.testsuite.util.RealmBuilder;
+import org.keycloak.testsuite.util.RealmRepUtil;
 import org.keycloak.testsuite.util.UserBuilder;
 import twitter4j.JSONArray;
 import twitter4j.JSONObject;
@@ -68,7 +69,7 @@ public class ProfileTest extends TestRealmKeycloakTest {
 
     @Override
     public void configureTestRealm(RealmRepresentation testRealm) {
-        UserRepresentation user = findUserInRealmRep(testRealm, "test-user@localhost");
+        UserRepresentation user = RealmRepUtil.findUser(testRealm, "test-user@localhost");
         user.setFirstName("First");
         user.setLastName("Last");
         Map<String, Object> attributes = user.getAttributes();
@@ -87,7 +88,7 @@ public class ProfileTest extends TestRealmKeycloakTest {
         RealmBuilder.edit(testRealm)
                     .user(user2);
 
-        ClientBuilder.edit(findClientInRealmRep(testRealm, "test-app"))
+        ClientBuilder.edit(RealmRepUtil.findClientByClientId(testRealm, "test-app"))
                      .addWebOrigin("http://localtest.me:8180");
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/TrustStoreEmailTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/TrustStoreEmailTest.java
new file mode 100644
index 0000000..75ba24e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/account/TrustStoreEmailTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.account;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.After;
+import org.junit.Test;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+
+import org.keycloak.testsuite.TestRealmKeycloakTest;
+import org.keycloak.testsuite.auth.page.AuthRealm;
+import org.keycloak.testsuite.auth.page.account.AccountManagement;
+import org.keycloak.testsuite.auth.page.login.OIDCLogin;
+import org.keycloak.testsuite.auth.page.login.VerifyEmail;
+import org.keycloak.testsuite.util.*;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.keycloak.testsuite.util.MailAssert.assertEmailAndGetUrl;
+import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
+
+
+/**
+ *
+ * @author fkiss
+ */
+public class TrustStoreEmailTest extends TestRealmKeycloakTest {
+
+    @Page
+    protected OIDCLogin testRealmLoginPage;
+
+    @Page
+    protected AuthRealm testRealmPage;
+
+    @Page
+    protected AccountManagement accountManagement;
+
+    @Page
+    private VerifyEmail testRealmVerifyEmailPage;
+
+    private UserRepresentation user;
+
+    @Override
+    public void configureTestRealm(RealmRepresentation testRealm) {
+        log.info("enable verify email and configure smtp server to run with ssl in test realm");
+
+        user = RealmRepUtil.findUser(testRealm, "test-user@localhost");
+        testRealm.setSmtpServer(SslMailServer.getServerConfiguration());
+        testRealm.setVerifyEmail(true);
+    }
+
+
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmPage.setAuthRealm("test");
+        testRealmVerifyEmailPage.setAuthRealm(testRealmPage);
+        accountManagement.setAuthRealm(testRealmPage);
+        testRealmLoginPage.setAuthRealm(testRealmPage);
+    }
+
+    @After
+    public void afterTrustStoreEmailTest() {
+        SslMailServer.stop();
+    }
+
+
+    @Test
+    public void verifyEmailWithSslEnabled() {
+        SslMailServer.startWithSsl(this.getClass().getClassLoader().getResource(SslMailServer.PRIVATE_KEY).getFile());
+        accountManagement.navigateTo();
+        testRealmLoginPage.form().login(user.getUsername(), "password");
+
+        assertEquals("You need to verify your email address to activate your account.",
+                testRealmVerifyEmailPage.getFeedbackText());
+
+        String verifyEmailUrl = assertEmailAndGetUrl(MailServerConfiguration.FROM, user.getEmail(),
+                "Someone has created a Test account with this email address.", true);
+
+        log.info("navigating to url from email: " + verifyEmailUrl);
+
+        driver.navigate().to(verifyEmailUrl);
+
+        assertCurrentUrlStartsWith(accountManagement);
+        accountManagement.signOut();
+        testRealmLoginPage.form().login(user);
+        assertCurrentUrlStartsWith(accountManagement);
+    }
+
+    @Test
+    public void verifyEmailWithSslWrongCertificate() {
+        SslMailServer.startWithSsl(this.getClass().getClassLoader().getResource(SslMailServer.INVALID_KEY).getFile());
+        accountManagement.navigateTo();
+        loginPage.form().login(user);
+
+        assertEquals("Failed to send email, please try again later.\n" +
+                        "« Back to Application",
+                testRealmVerifyEmailPage.getErrorMessage());
+    }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/actions/TermsAndConditionsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/actions/TermsAndConditionsTest.java
index 0647fcd..ee5f6c9 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/actions/TermsAndConditionsTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/actions/TermsAndConditionsTest.java
@@ -23,6 +23,8 @@ import org.keycloak.authentication.requiredactions.TermsAndConditions;
 import org.keycloak.events.Details;
 import org.keycloak.events.Errors;
 import org.keycloak.events.EventType;
+import org.keycloak.models.RequiredActionProviderModel;
+import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.testsuite.AssertEvents;
 import org.keycloak.testsuite.pages.AppPage;
@@ -66,6 +68,10 @@ public class TermsAndConditionsTest extends TestRealmKeycloakTest {
         UserRepresentation user = ActionUtil.findUserWithAdminClient(adminClient, "test-user@localhost");
         UserBuilder.edit(user).requiredAction(TermsAndConditions.PROVIDER_ID);
         adminClient.realm("test").users().get(user.getId()).update(user);
+
+        RequiredActionProviderRepresentation rep = adminClient.realm("test").flows().getRequiredAction("terms_and_conditions");
+        rep.setEnabled(true);
+        adminClient.realm("test").flows().updateRequiredAction("terms_and_conditions", rep);
     }
 
     @Test
@@ -128,4 +134,21 @@ public class TermsAndConditionsTest extends TestRealmKeycloakTest {
     }
 
 
+    @Test
+    // KEYCLOAK-3192
+    public void termsDisabled() {
+        RequiredActionProviderRepresentation rep = adminClient.realm("test").flows().getRequiredAction("terms_and_conditions");
+        rep.setEnabled(false);
+        adminClient.realm("test").flows().updateRequiredAction("terms_and_conditions", rep);
+
+        loginPage.open();
+
+        loginPage.login("test-user@localhost", "password");
+
+        assertTrue(appPage.isCurrent());
+
+        events.expectLogin().assertEvent();
+
+    }
+
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java
index a2d0355..badf51c 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/AbstractServletsAdapterTest.java
@@ -22,11 +22,15 @@ import org.jboss.shrinkwrap.api.ShrinkWrap;
 import org.jboss.shrinkwrap.api.asset.StringAsset;
 import org.jboss.shrinkwrap.api.spec.WebArchive;
 import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.util.WaitUtils;
+import org.openqa.selenium.By;
 
 import java.io.IOException;
 import java.net.URL;
 import java.util.List;
 
+import javax.ws.rs.core.UriBuilder;
+
 import static org.keycloak.testsuite.auth.page.AuthRealm.DEMO;
 import static org.keycloak.testsuite.util.IOUtil.loadRealm;
 
@@ -107,4 +111,14 @@ public abstract class AbstractServletsAdapterTest extends AbstractAdapterTest {
         testRealmPage.setAuthRealm(DEMO);
     }
 
+    protected void setAdapterAndServerTimeOffset(int timeOffset, String servletUri) {
+        setTimeOffset(timeOffset);
+        String timeOffsetUri = UriBuilder.fromUri(servletUri)
+                .queryParam("timeOffset", timeOffset)
+                .build().toString();
+
+        driver.navigate().to(timeOffsetUri);
+        WaitUtils.waitUntilElement(By.tagName("body")).is().visible();
+    }
+
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractCorsExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractCorsExampleAdapterTest.java
index 0828343..b7301e0 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractCorsExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractCorsExampleAdapterTest.java
@@ -22,6 +22,7 @@ import org.jboss.arquillian.graphene.page.Page;
 import org.jboss.shrinkwrap.api.spec.WebArchive;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
@@ -39,6 +40,7 @@ import static org.keycloak.testsuite.util.URLAssert.assertCurrentUrlStartsWith;
 /**
  * Created by fkiss.
  */
+@Ignore //Needs a discussion about future work.
 public abstract class AbstractCorsExampleAdapterTest extends AbstractExampleAdapterTest {
 
     public static final String CORS = "cors";
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java
index 6100b13..a91b26b 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractJSConsoleExampleAdapterTest.java
@@ -25,7 +25,8 @@ import org.keycloak.admin.client.resource.ClientResource;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
-import org.keycloak.testsuite.adapter.page.JSConsoleExample;
+import org.keycloak.testsuite.adapter.page.JSConsoleTestApp;
+import org.keycloak.testsuite.adapter.page.JSDatabaseTestApp;
 import org.keycloak.testsuite.admin.ApiUtil;
 import org.keycloak.testsuite.auth.page.account.Applications;
 import org.keycloak.testsuite.auth.page.login.OAuthGrant;
@@ -51,7 +52,7 @@ import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
 public abstract class AbstractJSConsoleExampleAdapterTest extends AbstractExampleAdapterTest {
 
     @Page
-    private JSConsoleExample jsConsoleExamplePage;
+    private JSConsoleTestApp jsConsoleTestAppPage;
 
     @Page
     private Config configPage;
@@ -67,9 +68,14 @@ public abstract class AbstractJSConsoleExampleAdapterTest extends AbstractExampl
 
     public static int TOKEN_LIFESPAN_LEEWAY = 3; // seconds
 
-    @Deployment(name = JSConsoleExample.DEPLOYMENT_NAME)
-    private static WebArchive jsConsoleExample() throws IOException {
-        return exampleDeployment(JSConsoleExample.CLIENT_ID);
+    @Deployment(name = JSConsoleTestApp.DEPLOYMENT_NAME)
+    private static WebArchive jsConsoleTestApp() throws IOException {
+        return exampleDeployment(JSConsoleTestApp.CLIENT_ID);
+    }
+
+    @Deployment(name = JSDatabaseTestApp.DEPLOYMENT_NAME)
+    private static WebArchive jsDbApp() throws IOException {
+        return exampleDeployment(JSDatabaseTestApp.CLIENT_ID);
     }
 
     @Override
@@ -77,7 +83,7 @@ public abstract class AbstractJSConsoleExampleAdapterTest extends AbstractExampl
         RealmRepresentation jsConsoleRealm = loadRealm(new File(TEST_APPS_HOME_DIR + "/js-console/example-realm.json"));
 
         fixClientUrisUsingDeploymentUrl(jsConsoleRealm,
-                JSConsoleExample.CLIENT_ID, jsConsoleExamplePage.buildUri().toASCIIString());
+                JSConsoleTestApp.CLIENT_ID, jsConsoleTestAppPage.buildUri().toASCIIString());
 
         jsConsoleRealm.setAccessTokenLifespan(30 + TOKEN_LIFESPAN_LEEWAY); // seconds
 
@@ -92,92 +98,93 @@ public abstract class AbstractJSConsoleExampleAdapterTest extends AbstractExampl
 
     @Test
     public void testJSConsoleAuth() {
-        jsConsoleExamplePage.navigateTo();
-        assertCurrentUrlStartsWith(jsConsoleExamplePage);
+        jsConsoleTestAppPage.navigateTo();
+        assertCurrentUrlStartsWith(jsConsoleTestAppPage);
 
-        waitUntilElement(jsConsoleExamplePage.getInitButtonElement()).is().present();
+        waitUntilElement(jsConsoleTestAppPage.getInitButtonElement()).is().present();
 
-        jsConsoleExamplePage.init();
-        jsConsoleExamplePage.logIn();
+        jsConsoleTestAppPage.init();
+        jsConsoleTestAppPage.logIn();
         testRealmLoginPage.form().login("user", "invalid-password");
-        assertCurrentUrlDoesntStartWith(jsConsoleExamplePage);
+        assertCurrentUrlDoesntStartWith(jsConsoleTestAppPage);
 
         testRealmLoginPage.form().login("invalid-user", "password");
-        assertCurrentUrlDoesntStartWith(jsConsoleExamplePage);
+        assertCurrentUrlDoesntStartWith(jsConsoleTestAppPage);
 
         testRealmLoginPage.form().login("user", "password");
-        assertCurrentUrlStartsWith(jsConsoleExamplePage);
-        jsConsoleExamplePage.init();
+        assertCurrentUrlStartsWith(jsConsoleTestAppPage);
+        jsConsoleTestAppPage.init();
 
-        waitUntilElement(jsConsoleExamplePage.getOutputElement()).text().contains("Init Success (Authenticated)");
-        waitUntilElement(jsConsoleExamplePage.getEventsElement()).text().contains("Auth Success");
+        waitUntilElement(jsConsoleTestAppPage.getOutputElement()).text().contains("Init Success (Authenticated)");
+        waitUntilElement(jsConsoleTestAppPage.getEventsElement()).text().contains("Auth Success");
 
-        jsConsoleExamplePage.logOut();
-        assertCurrentUrlStartsWith(jsConsoleExamplePage);
-        jsConsoleExamplePage.init();
+        jsConsoleTestAppPage.logOut();
+        assertCurrentUrlStartsWith(jsConsoleTestAppPage);
+        waitUntilElement(jsConsoleTestAppPage.getInitButtonElement()).is().present();
+        jsConsoleTestAppPage.init();
 
-        waitUntilElement(jsConsoleExamplePage.getOutputElement()).text().contains("Init Success (Not Authenticated)");
+        waitUntilElement(jsConsoleTestAppPage.getOutputElement()).text().contains("Init Success (Not Authenticated)");
     }
 
     @Test
     public void testRefreshToken() {
-        jsConsoleExamplePage.navigateTo();
-        assertCurrentUrlStartsWith(jsConsoleExamplePage);
+        jsConsoleTestAppPage.navigateTo();
+        assertCurrentUrlStartsWith(jsConsoleTestAppPage);
 
-        jsConsoleExamplePage.init();
-        jsConsoleExamplePage.refreshToken();
-        waitUntilElement(jsConsoleExamplePage.getOutputElement()).text().contains("Failed to refresh token");
+        jsConsoleTestAppPage.init();
+        jsConsoleTestAppPage.refreshToken();
+        waitUntilElement(jsConsoleTestAppPage.getOutputElement()).text().contains("Failed to refresh token");
 
-        jsConsoleExamplePage.logIn();
+        jsConsoleTestAppPage.logIn();
         testRealmLoginPage.form().login("user", "password");
-        assertCurrentUrlStartsWith(jsConsoleExamplePage);
-        jsConsoleExamplePage.init();
-        waitUntilElement(jsConsoleExamplePage.getEventsElement()).text().contains("Auth Success");
+        assertCurrentUrlStartsWith(jsConsoleTestAppPage);
+        jsConsoleTestAppPage.init();
+        waitUntilElement(jsConsoleTestAppPage.getEventsElement()).text().contains("Auth Success");
 
-        jsConsoleExamplePage.refreshToken();
-        waitUntilElement(jsConsoleExamplePage.getEventsElement()).text().contains("Auth Refresh Success");
+        jsConsoleTestAppPage.refreshToken();
+        waitUntilElement(jsConsoleTestAppPage.getEventsElement()).text().contains("Auth Refresh Success");
     }
 
     @Test
     public void testRefreshTokenIfUnder30s() {
-        jsConsoleExamplePage.navigateTo();
-        assertCurrentUrlStartsWith(jsConsoleExamplePage);
-        jsConsoleExamplePage.init();
-        jsConsoleExamplePage.refreshToken();
-        waitUntilElement(jsConsoleExamplePage.getOutputElement()).text().contains("Failed to refresh token");
+        jsConsoleTestAppPage.navigateTo();
+        assertCurrentUrlStartsWith(jsConsoleTestAppPage);
+        jsConsoleTestAppPage.init();
+        jsConsoleTestAppPage.refreshToken();
+        waitUntilElement(jsConsoleTestAppPage.getOutputElement()).text().contains("Failed to refresh token");
 
-        jsConsoleExamplePage.logIn();
+        jsConsoleTestAppPage.logIn();
         testRealmLoginPage.form().login("user", "password");
-        assertCurrentUrlStartsWith(jsConsoleExamplePage);
-        jsConsoleExamplePage.init();
-        waitUntilElement(jsConsoleExamplePage.getEventsElement()).text().contains("Auth Success");
+        assertCurrentUrlStartsWith(jsConsoleTestAppPage);
+        jsConsoleTestAppPage.init();
+        waitUntilElement(jsConsoleTestAppPage.getEventsElement()).text().contains("Auth Success");
 
-        jsConsoleExamplePage.refreshTokenIfUnder30s();
-        waitUntilElement(jsConsoleExamplePage.getOutputElement()).text().contains("Token not refreshed, valid for");
+        jsConsoleTestAppPage.refreshTokenIfUnder30s();
+        waitUntilElement(jsConsoleTestAppPage.getOutputElement()).text().contains("Token not refreshed, valid for");
 
         pause((TOKEN_LIFESPAN_LEEWAY + 2) * 1000);
 
-        jsConsoleExamplePage.refreshTokenIfUnder30s();
-        waitUntilElement(jsConsoleExamplePage.getEventsElement()).text().contains("Auth Refresh Success");
+        jsConsoleTestAppPage.refreshTokenIfUnder30s();
+        waitUntilElement(jsConsoleTestAppPage.getEventsElement()).text().contains("Auth Refresh Success");
     }
 
     @Test
     public void testGetProfile() {
-        jsConsoleExamplePage.navigateTo();
-        assertCurrentUrlStartsWith(jsConsoleExamplePage);
+        jsConsoleTestAppPage.navigateTo();
+        assertCurrentUrlStartsWith(jsConsoleTestAppPage);
 
-        jsConsoleExamplePage.init();
-        jsConsoleExamplePage.getProfile();
-        waitUntilElement(jsConsoleExamplePage.getOutputElement()).text().contains("Failed to load profile");
+        jsConsoleTestAppPage.init();
+        jsConsoleTestAppPage.getProfile();
+        waitUntilElement(jsConsoleTestAppPage.getOutputElement()).text().contains("Failed to load profile");
 
-        jsConsoleExamplePage.logIn();
+        jsConsoleTestAppPage.logIn();
         testRealmLoginPage.form().login("user", "password");
-        assertCurrentUrlStartsWith(jsConsoleExamplePage);
-        jsConsoleExamplePage.init();
-        waitUntilElement(jsConsoleExamplePage.getEventsElement()).text().contains("Auth Success");
+        assertCurrentUrlStartsWith(jsConsoleTestAppPage);
+        jsConsoleTestAppPage.init();
+        waitUntilElement(jsConsoleTestAppPage.getEventsElement()).text().contains("Auth Success");
 
-        jsConsoleExamplePage.getProfile();
-        waitUntilElement(jsConsoleExamplePage.getOutputElement()).text().contains("\"username\": \"user\"");
+        jsConsoleTestAppPage.getProfile();
+        waitUntilElement(jsConsoleTestAppPage.getOutputElement()).text().contains("\"username\": \"user\"");
     }
 
     @Test
@@ -188,7 +195,7 @@ public abstract class AbstractJSConsoleExampleAdapterTest extends AbstractExampl
         loginEventsPage.setConsoleRealm(EXAMPLE);
         applicationsPage.setAuthRealm(EXAMPLE);
 
-        jsConsoleExamplePage.navigateTo();
+        jsConsoleTestAppPage.navigateTo();
         driver.manage().deleteAllCookies();
 
         ClientResource clientResource = ApiUtil.findClientResourceByClientId(testRealmResource(), "js-console");
@@ -201,26 +208,27 @@ public abstract class AbstractJSConsoleExampleAdapterTest extends AbstractExampl
         realm.setEnabledEventTypes(Arrays.asList("REVOKE_GRANT", "LOGIN"));
         testRealmResource().update(realm);
 
-        jsConsoleExamplePage.navigateTo();
-        jsConsoleExamplePage.init();
-        jsConsoleExamplePage.logIn();
+        jsConsoleTestAppPage.navigateTo();
+        jsConsoleTestAppPage.init();
+        jsConsoleTestAppPage.logIn();
 
         testRealmLoginPage.form().login("user", "password");
 
         assertTrue(oAuthGrantPage.isCurrent());
         oAuthGrantPage.accept();
 
-        jsConsoleExamplePage.init();
+        jsConsoleTestAppPage.init();
 
-        waitUntilElement(jsConsoleExamplePage.getOutputElement()).text().contains("Init Success (Authenticated)");
+        waitUntilElement(jsConsoleTestAppPage.getOutputElement()).text().contains("Init Success (Authenticated)");
 
         applicationsPage.navigateTo();
         applicationsPage.revokeGrantForApplication("js-console");
 
-        jsConsoleExamplePage.navigateTo();
-        jsConsoleExamplePage.init();
-        jsConsoleExamplePage.logIn();
+        jsConsoleTestAppPage.navigateTo();
+        jsConsoleTestAppPage.setOnLoad("login-required");
+        jsConsoleTestAppPage.init();
 
+        waitUntilElement(By.tagName("body")).is().visible();
         assertTrue(oAuthGrantPage.isCurrent());
 
         loginEventsPage.navigateTo();
@@ -255,46 +263,46 @@ public abstract class AbstractJSConsoleExampleAdapterTest extends AbstractExampl
 
     @Test
     public void implicitFlowTest() {
-        jsConsoleExamplePage.navigateTo();
-        jsConsoleExamplePage.setFlow("implicit");
-        jsConsoleExamplePage.init();
+        jsConsoleTestAppPage.navigateTo();
+        jsConsoleTestAppPage.setFlow("implicit");
+        jsConsoleTestAppPage.init();
 
-        jsConsoleExamplePage.logIn();
-        assertTrue(driver.getPageSource().contains("Implicit flow is disabled for the client"));
+        jsConsoleTestAppPage.logIn();
+        assertResponseError("Implicit flow is disabled for the client");
 
-        setImplicitFlowFroClient();
+        setImplicitFlowForClient();
 
-        jsConsoleExamplePage.navigateTo();
-        jsConsoleExamplePage.init();
-        jsConsoleExamplePage.logIn();
-        assertTrue(driver.getPageSource().contains("Standard flow is disabled for the client"));
+        jsConsoleTestAppPage.navigateTo();
+        jsConsoleTestAppPage.init();
+        jsConsoleTestAppPage.logIn();
+        assertResponseError("Standard flow is disabled for the client");
 
         logInAndInit("implicit");
 
-        waitUntilElement(jsConsoleExamplePage.getOutputElement()).text().contains("Init Success (Authenticated)");
+        waitUntilElement(jsConsoleTestAppPage.getOutputElement()).text().contains("Init Success (Authenticated)");
     }
 
     @Test
     public void implicitFlowQueryTest() {
-        setImplicitFlowFroClient();
-
-        jsConsoleExamplePage.navigateTo();
-        jsConsoleExamplePage.setFlow("implicit");
-        jsConsoleExamplePage.setResponseMode("query");
-        jsConsoleExamplePage.init();
-        jsConsoleExamplePage.logIn();
-        assertTrue(driver.getPageSource().contains("Invalid parameter: response_mode"));
+        setImplicitFlowForClient();
+
+        jsConsoleTestAppPage.navigateTo();
+        jsConsoleTestAppPage.setFlow("implicit");
+        jsConsoleTestAppPage.setResponseMode("query");
+        jsConsoleTestAppPage.init();
+        jsConsoleTestAppPage.logIn();
+        assertResponseError("Response_mode 'query' not allowed");
     }
 
     @Test
     public void implicitFlowRefreshTokenTest() {
-        setImplicitFlowFroClient();
+        setImplicitFlowForClient();
 
         logInAndInit("implicit");
 
-        jsConsoleExamplePage.refreshToken();
+        jsConsoleTestAppPage.refreshToken();
 
-        waitUntilElement(jsConsoleExamplePage.getOutputElement()).text().contains("Failed to refresh token");
+        waitUntilElement(jsConsoleTestAppPage.getOutputElement()).text().contains("Failed to refresh token");
     }
 
     @Test
@@ -303,16 +311,47 @@ public abstract class AbstractJSConsoleExampleAdapterTest extends AbstractExampl
         realm.setAccessTokenLifespanForImplicitFlow(5);
         testRealmResource().update(realm);
 
-        setImplicitFlowFroClient();
+        setImplicitFlowForClient();
 
         logInAndInit("implicit");
 
         pause(6000);
 
-        waitUntilElement(jsConsoleExamplePage.getEventsElement()).text().contains("Access token expired");
+        waitUntilElement(jsConsoleTestAppPage.getEventsElement()).text().contains("Access token expired");
+    }
+
+    @Test
+    public void testBearerRequest() {
+        jsConsoleTestAppPage.navigateTo();
+        jsConsoleTestAppPage.init();
+        jsConsoleTestAppPage.createBearerRequest();
+        waitUntilElement(jsConsoleTestAppPage.getOutputElement()).text().contains("Unauthorized");
+
+        logInAndInit("standard", "unauthorized");
+        jsConsoleTestAppPage.createBearerRequest();
+        waitUntilElement(jsConsoleTestAppPage.getOutputElement()).text().contains("Forbidden");
+
+        jsConsoleTestAppPage.logOut();
+        logInAndInit("standard");
+        jsConsoleTestAppPage.createBearerRequest();
+        waitUntilElement(jsConsoleTestAppPage.getOutputElement()).text().contains("[\"Bill Burke\",\"Stian Thorgersen\",\"Stan Silvert\",\"Gabriel Cardoso\",\"Viliam Rockai\",\"Marek Posolda\",\"Boleslaw Dawidowicz\"]");
+    }
+
+    @Test
+    public void loginRequiredAction() {
+        jsConsoleTestAppPage.navigateTo();
+        jsConsoleTestAppPage.setOnLoad("login-required");
+        jsConsoleTestAppPage.init();
+
+        assertCurrentUrlStartsWith(testRealmLoginPage);
+        testRealmLoginPage.form().login("user", "password");
+
+        waitUntilElement(jsConsoleTestAppPage.getInitButtonElement()).is().present();
+        jsConsoleTestAppPage.init();
+        waitUntilElement(jsConsoleTestAppPage.getOutputElement()).text().contains("Init Success (Authenticated)");
     }
 
-    private void setImplicitFlowFroClient() {
+    private void setImplicitFlowForClient() {
         ClientResource clientResource = ApiUtil.findClientResourceByClientId(testRealmResource(), "js-console");
         ClientRepresentation client = clientResource.toRepresentation();
         client.setImplicitFlowEnabled(true);
@@ -320,14 +359,23 @@ public abstract class AbstractJSConsoleExampleAdapterTest extends AbstractExampl
         clientResource.update(client);
     }
 
+    private void logInAndInit(String flow, String user) {
+        jsConsoleTestAppPage.navigateTo();
+        jsConsoleTestAppPage.setFlow(flow);
+        jsConsoleTestAppPage.init();
+        jsConsoleTestAppPage.logIn();
+        testRealmLoginPage.form().login(user, "password");
+        jsConsoleTestAppPage.setFlow(flow);
+        jsConsoleTestAppPage.init();
+    }
+
     private void logInAndInit(String flow) {
-        jsConsoleExamplePage.navigateTo();
-        jsConsoleExamplePage.setFlow(flow);
-        jsConsoleExamplePage.init();
-        jsConsoleExamplePage.logIn();
-        testRealmLoginPage.form().login("user", "password");
-        jsConsoleExamplePage.setFlow(flow);
-        jsConsoleExamplePage.init();
+        logInAndInit(flow, "user");
+    }
+
+    private void assertResponseError(String errorDescription) {
+        jsConsoleTestAppPage.showErrorResponse();
+        assertTrue(jsConsoleTestAppPage.getOutputElement().getText().contains(errorDescription));
     }
 
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractSAMLExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractSAMLExampleAdapterTest.java
index 450c094..3a0676e 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractSAMLExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/AbstractSAMLExampleAdapterTest.java
@@ -88,6 +88,7 @@ public abstract class AbstractSAMLExampleAdapterTest extends AbstractExampleAdap
         waitUntilElement(By.xpath("//body")).text().contains("Welcome to the Sales Tool, " + bburkeUser.getUsername());
 
         samlPostSigExamplePage.logout();
+        waitUntilElement(By.xpath("//body")).text().contains("Logged out.");
 
         samlPostSigExamplePage.navigateTo();
         URLAssert.assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
@@ -102,6 +103,7 @@ public abstract class AbstractSAMLExampleAdapterTest extends AbstractExampleAdap
         waitUntilElement(By.xpath("//body")).text().contains("Welcome to the Sales Tool, " + bburkeUser.getUsername());
 
         samlPostEncExamplePage.logout();
+        waitUntilElement(By.xpath("//body")).text().contains("Logged out.");
 
         samlPostEncExamplePage.navigateTo();
         URLAssert.assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
@@ -116,6 +118,7 @@ public abstract class AbstractSAMLExampleAdapterTest extends AbstractExampleAdap
         waitUntilElement(By.xpath("//body")).text().contains("Welcome to the Employee Tool,");
 
         samlRedirectSigExamplePage.logout();
+        URLAssert.assertCurrentUrlStartsWith(testRealmSAMLRedirectLoginPage);
 
         samlRedirectSigExamplePage.navigateTo();
         URLAssert.assertCurrentUrlStartsWith(testRealmSAMLRedirectLoginPage);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractDefaultAuthzConfigAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractDefaultAuthzConfigAdapterTest.java
new file mode 100644
index 0000000..87c0024
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractDefaultAuthzConfigAdapterTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.adapter.example.authorization;
+
+import org.jboss.arquillian.container.test.api.Deployer;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Test;
+import org.keycloak.admin.client.resource.AuthorizationResource;
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.admin.client.resource.ClientsResource;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.List;
+
+import static org.junit.Assert.assertTrue;
+import static org.keycloak.testsuite.util.IOUtil.loadRealm;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public abstract class AbstractDefaultAuthzConfigAdapterTest extends AbstractExampleAdapterTest {
+
+    private static final String REALM_NAME = "hello-world-authz";
+    private static final String RESOURCE_SERVER_ID = "hello-world-authz-service";
+
+    @ArquillianResource
+    private Deployer deployer;
+
+    @Override
+    public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
+        testRealms.add(
+                loadRealm(new File(TEST_APPS_HOME_DIR + "/hello-world-authz-service/hello-world-authz-realm.json")));
+    }
+
+    @Deployment(name = RESOURCE_SERVER_ID, managed = false)
+    public static WebArchive deployment() throws IOException {
+        return exampleDeployment(RESOURCE_SERVER_ID);
+    }
+
+    @Test
+    public void testDefaultAuthzConfig() throws Exception {
+        try {
+            configureAuthorizationServices();
+            this.deployer.deploy(RESOURCE_SERVER_ID);
+
+            login();
+
+            assertTrue(this.driver.getPageSource().contains("Your permissions are"));
+            assertTrue(this.driver.getPageSource().contains("Default Resource"));
+
+            boolean hasDefaultPermission = false;
+            boolean hasDefaultPolicy = false;
+
+            for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+                if ("Default Policy".equals(policy.getName())) {
+                    hasDefaultPolicy = true;
+                }
+                if ("Default Permission".equals(policy.getName())) {
+                    hasDefaultPermission = true;
+                }
+            }
+
+            assertTrue(hasDefaultPermission);
+            assertTrue(hasDefaultPolicy);
+        } finally {
+            this.deployer.undeploy(RESOURCE_SERVER_ID);
+        }
+    }
+
+    private void login() throws MalformedURLException {
+        this.driver.navigate().to(getResourceServerUrl());
+        this.loginPage.form().login("alice", "alice");
+    }
+
+    private URL getResourceServerUrl() throws MalformedURLException {
+        return this.appServerContextRootPage.getUriBuilder().path(RESOURCE_SERVER_ID).build().toURL();
+    }
+
+    private void configureAuthorizationServices() {
+        ClientsResource clients = realmsResouce().realm(REALM_NAME).clients();
+        ClientRepresentation client = clients.findByClientId(RESOURCE_SERVER_ID).get(0);
+
+        client.setAuthorizationServicesEnabled(false);
+
+        // disables authorization services and remove authorization configuration from the client app
+        clients.get(client.getId()).update(client);
+
+        client.setAuthorizationServicesEnabled(true);
+
+        // enable authorization services in order to generate the default config and continue with tests
+        clients.get(client.getId()).update(client);
+    }
+
+    private AuthorizationResource getAuthorizationResource() throws FileNotFoundException {
+        return getClientResource(RESOURCE_SERVER_ID).authorization();
+    }
+
+    private ClientResource getClientResource(String clientId) {
+        ClientsResource clients = this.realmsResouce().realm(REALM_NAME).clients();
+        ClientRepresentation resourceServer = clients.findByClientId(clientId).get(0);
+        return clients.get(resourceServer.getId());
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractPhotozExampleAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractPhotozExampleAdapterTest.java
new file mode 100644
index 0000000..66702a9
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractPhotozExampleAdapterTest.java
@@ -0,0 +1,627 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.adapter.example.authorization;
+
+import org.jboss.arquillian.container.test.api.Deployer;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.admin.client.resource.AuthorizationResource;
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.admin.client.resource.ClientsResource;
+import org.keycloak.admin.client.resource.ResourcesResource;
+import org.keycloak.admin.client.resource.RoleResource;
+import org.keycloak.admin.client.resource.UserResource;
+import org.keycloak.admin.client.resource.UsersResource;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
+import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
+import org.keycloak.testsuite.adapter.page.PhotozClientAuthzTestApp;
+import org.keycloak.util.JsonSerialization;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.keycloak.testsuite.util.IOUtil.loadJson;
+import static org.keycloak.testsuite.util.IOUtil.loadRealm;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public abstract class AbstractPhotozExampleAdapterTest extends AbstractExampleAdapterTest {
+
+    private static final String REALM_NAME = "photoz";
+    private static final String RESOURCE_SERVER_ID = "photoz-restful-api";
+    private static int TOKEN_LIFESPAN_LEEWAY = 3; // seconds
+
+    @ArquillianResource
+    private Deployer deployer;
+
+    @Page
+    private PhotozClientAuthzTestApp clientPage;
+
+    @Override
+    public void setDefaultPageUriParameters() {
+        super.setDefaultPageUriParameters();
+        testRealmPage.setAuthRealm(REALM_NAME);
+    }
+
+    @Before
+    public void beforePhotozExampleAdapterTest() {
+        deleteAllCookiesForClientPage();
+    }
+
+    @Override
+    public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
+        RealmRepresentation realm = loadRealm(new File(TEST_APPS_HOME_DIR + "/photoz/photoz-realm.json"));
+
+        realm.setAccessTokenLifespan(30 + TOKEN_LIFESPAN_LEEWAY); // seconds
+
+        testRealms.add(realm);
+    }
+
+    @Deployment(name = PhotozClientAuthzTestApp.DEPLOYMENT_NAME)
+    public static WebArchive deploymentClient() throws IOException {
+        return exampleDeployment(PhotozClientAuthzTestApp.DEPLOYMENT_NAME);
+    }
+
+    @Deployment(name = RESOURCE_SERVER_ID, managed = false)
+    public static WebArchive deploymentResourceServer() throws IOException {
+        return exampleDeployment(RESOURCE_SERVER_ID);
+    }
+
+    @Override
+    public void beforeAbstractKeycloakTest() throws Exception {
+        super.beforeAbstractKeycloakTest();
+        importResourceServerSettings();
+    }
+
+    @Test
+    public void testUserCanCreateAndDeleteAlbum() throws Exception {
+        try {
+            this.deployer.deploy(RESOURCE_SERVER_ID);
+
+            loginToClientPage("alice", "alice");
+            this.clientPage.createAlbum("Alice Family Album");
+
+            List<ResourceRepresentation> resources = getAuthorizationResource().resources().resources();
+            assertFalse(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
+
+            this.clientPage.deleteAlbum("Alice Family Album");
+
+            resources = getAuthorizationResource().resources().resources();
+            assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
+        } finally {
+            this.deployer.undeploy(RESOURCE_SERVER_ID);
+        }
+    }
+
+    @Test
+    public void testOnlyOwnerCanDeleteAlbum() throws Exception {
+        try {
+            this.deployer.deploy(RESOURCE_SERVER_ID);
+            loginToClientPage("alice", "alice");
+            this.clientPage.createAlbum("Alice-Family-Album");
+
+            loginToClientPage("admin", "admin");
+            this.clientPage.navigateToAdminAlbum();
+
+            List<ResourceRepresentation> resources = getAuthorizationResource().resources().resources();
+            assertFalse(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
+
+            for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+                if ("Delete Album Permission".equals(policy.getName())) {
+                    policy.getConfig().put("applyPolicies", "[\"Only Owner Policy\"]");
+                    getAuthorizationResource().policies().policy(policy.getId()).update(policy);
+                }
+            }
+
+            loginToClientPage("admin", "admin");
+
+            this.clientPage.navigateToAdminAlbum();
+            this.clientPage.deleteAlbum("Alice-Family-Album");
+            assertTrue(this.clientPage.wasDenied());
+            resources = getAuthorizationResource().resources().resources();
+            assertFalse(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
+
+            for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+                if ("Delete Album Permission".equals(policy.getName())) {
+                    policy.getConfig().put("applyPolicies", "[\"Only Owner and Administrators Policy\"]");
+                    getAuthorizationResource().policies().policy(policy.getId()).update(policy);
+                }
+            }
+
+            this.clientPage.navigateToAdminAlbum();
+            this.clientPage.deleteAlbum("Alice-Family-Album");
+            assertFalse(this.clientPage.wasDenied());
+            resources = getAuthorizationResource().resources().resources();
+            assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
+        } finally {
+            this.deployer.undeploy(RESOURCE_SERVER_ID);
+        }
+    }
+
+    @Test
+    public void testRegularUserCanNotAccessAdminResources() throws Exception {
+        try {
+            this.deployer.deploy(RESOURCE_SERVER_ID);
+
+            loginToClientPage("alice", "alice");
+            this.clientPage.navigateToAdminAlbum();
+            assertTrue(this.clientPage.wasDenied());
+        } finally {
+            this.deployer.undeploy(RESOURCE_SERVER_ID);
+        }
+    }
+
+    @Test
+    public void testAdminOnlyFromSpecificAddress() throws Exception {
+        try {
+            this.deployer.deploy(RESOURCE_SERVER_ID);
+
+            loginToClientPage("admin", "admin");
+            this.clientPage.navigateToAdminAlbum();
+            assertFalse(this.clientPage.wasDenied());
+
+            for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+                if ("Only From a Specific Client Address".equals(policy.getName())) {
+                    String code = policy.getConfig().get("code");
+                    policy.getConfig().put("code", code.replaceAll("127.0.0.1", "127.3.3.3"));
+                    getAuthorizationResource().policies().policy(policy.getId()).update(policy);
+                }
+            }
+
+            this.clientPage.navigateToAdminAlbum();
+            assertTrue(this.clientPage.wasDenied());
+        } finally {
+            this.deployer.undeploy(RESOURCE_SERVER_ID);
+        }
+    }
+
+    @Test
+    public void testAdminWithoutPermissionsToTypedResource() throws Exception {
+        try {
+            this.deployer.deploy(RESOURCE_SERVER_ID);
+
+            loginToClientPage("alice", "alice");
+            this.clientPage.createAlbum("Alice Family Album");
+
+            loginToClientPage("admin", "admin");
+            this.clientPage.navigateToAdminAlbum();
+            assertFalse(this.clientPage.wasDenied());
+
+            this.clientPage.viewAlbum("Alice Family Album");
+            assertFalse(this.clientPage.wasDenied());
+
+            for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+                if ("Album Resource Permission".equals(policy.getName())) {
+                    policy.getConfig().put("applyPolicies", "[\"Any User Policy\"]");
+                    getAuthorizationResource().policies().policy(policy.getId()).update(policy);
+                }
+                if ("Any User Policy".equals(policy.getName())) {
+                    ClientResource resourceServerClient = getClientResource(RESOURCE_SERVER_ID);
+                    RoleResource manageAlbumRole = resourceServerClient.roles().get("manage-albums");
+                    RoleRepresentation roleRepresentation = manageAlbumRole.toRepresentation();
+                    List<Map> roles = JsonSerialization.readValue(policy.getConfig().get("roles"), List.class);
+
+                    roles = roles.stream().filter(new Predicate<Map>() {
+                        @Override
+                        public boolean test(Map map) {
+                            return !map.get("id").equals(roleRepresentation.getId());
+                        }
+                    }).collect(Collectors.toList());
+
+                    policy.getConfig().put("roles", JsonSerialization.writeValueAsString(roles));
+
+                    getAuthorizationResource().policies().policy(policy.getId()).update(policy);
+                }
+            }
+
+            this.clientPage.navigateToAdminAlbum();
+            this.clientPage.viewAlbum("Alice Family Album");
+            assertTrue(this.clientPage.wasDenied());
+
+            for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+                if ("Album Resource Permission".equals(policy.getName())) {
+                    policy.getConfig().put("applyPolicies", "[\"Any User Policy\", \"Administration Policy\"]");
+                    getAuthorizationResource().policies().policy(policy.getId()).update(policy);
+                }
+            }
+
+            this.clientPage.navigateToAdminAlbum();
+            this.clientPage.viewAlbum("Alice Family Album");
+            assertFalse(this.clientPage.wasDenied());
+
+            this.clientPage.navigateToAdminAlbum();
+            this.clientPage.deleteAlbum("Alice Family Album");
+            List<ResourceRepresentation> resources = getAuthorizationResource().resources().resources();
+            assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
+        } finally {
+            this.deployer.undeploy(RESOURCE_SERVER_ID);
+        }
+    }
+
+    @Test
+    public void testAdminWithoutPermissionsToDeleteAlbum() throws Exception {
+        try {
+            this.deployer.deploy(RESOURCE_SERVER_ID);
+
+            loginToClientPage("alice", "alice");
+            this.clientPage.createAlbum("Alice Family Album");
+
+            loginToClientPage("admin", "admin");
+            this.clientPage.navigateToAdminAlbum();
+            assertFalse(this.clientPage.wasDenied());
+
+            this.clientPage.deleteAlbum("Alice Family Album");
+            assertFalse(this.clientPage.wasDenied());
+            List<ResourceRepresentation> resources = getAuthorizationResource().resources().resources();
+            assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
+
+            for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+                if ("Delete Album Permission".equals(policy.getName())) {
+                    policy.getConfig().put("applyPolicies", "[\"Only Owner Policy\"]");
+                    getAuthorizationResource().policies().policy(policy.getId()).update(policy);
+                }
+            }
+
+            loginToClientPage("alice", "alice");
+            this.clientPage.createAlbum("Alice Family Album");
+
+            loginToClientPage("admin", "admin");
+            this.clientPage.navigateToAdminAlbum();
+            this.clientPage.viewAlbum("Alice Family Album");
+            assertFalse(this.clientPage.wasDenied());
+            resources = getAuthorizationResource().resources().resources();
+            assertFalse(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
+
+            this.clientPage.navigateToAdminAlbum();
+            this.clientPage.deleteAlbum("Alice Family Album");
+            assertTrue(this.clientPage.wasDenied());
+
+            for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+                if ("Delete Album Permission".equals(policy.getName())) {
+                    policy.getConfig().put("applyPolicies", "[\"Only Owner and Administrators Policy\"]");
+                    getAuthorizationResource().policies().policy(policy.getId()).update(policy);
+                }
+            }
+
+            this.clientPage.navigateToAdminAlbum();
+            this.clientPage.deleteAlbum("Alice Family Album");
+            assertFalse(this.clientPage.wasDenied());
+            resources = getAuthorizationResource().resources().resources();
+            assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
+        } finally {
+            this.deployer.undeploy(RESOURCE_SERVER_ID);
+        }
+    }
+
+    @Test
+    public void testClientRoleRepresentingUserConsent() throws Exception {
+        try {
+            this.deployer.deploy(RESOURCE_SERVER_ID);
+
+            loginToClientPage("alice", "alice");
+            assertFalse(this.clientPage.wasDenied());
+
+            UsersResource usersResource = realmsResouce().realm(REALM_NAME).users();
+            List<UserRepresentation> users = usersResource.search("alice", null, null, null, null, null);
+
+            assertFalse(users.isEmpty());
+
+            UserRepresentation userRepresentation = users.get(0);
+            UserResource userResource = usersResource.get(userRepresentation.getId());
+
+            ClientResource html5ClientApp = getClientResource("photoz-html5-client");
+
+            userResource.revokeConsent(html5ClientApp.toRepresentation().getClientId());
+
+            ClientResource resourceServerClient = getClientResource(RESOURCE_SERVER_ID);
+            RoleResource roleResource = resourceServerClient.roles().get("manage-albums");
+            RoleRepresentation roleRepresentation = roleResource.toRepresentation();
+
+            roleRepresentation.setScopeParamRequired(true);
+
+            roleResource.update(roleRepresentation);
+
+            loginToClientPage("alice", "alice");
+            assertTrue(this.clientPage.wasDenied());
+
+            loginToClientPage("alice", "alice", RESOURCE_SERVER_ID + "/manage-albums");
+            assertFalse(this.clientPage.wasDenied());
+        } finally {
+            this.deployer.undeploy(RESOURCE_SERVER_ID);
+        }
+    }
+
+    @Test
+    public void testClientRoleNotRequired() throws Exception {
+        try {
+            this.deployer.deploy(RESOURCE_SERVER_ID);
+
+            loginToClientPage("alice", "alice");
+
+            assertFalse(this.clientPage.wasDenied());
+
+            UsersResource usersResource = realmsResouce().realm(REALM_NAME).users();
+            List<UserRepresentation> users = usersResource.search("alice", null, null, null, null, null);
+
+            assertFalse(users.isEmpty());
+
+            UserRepresentation userRepresentation = users.get(0);
+            UserResource userResource = usersResource.get(userRepresentation.getId());
+
+            ClientResource html5ClientApp = getClientResource("photoz-html5-client");
+
+            userResource.revokeConsent(html5ClientApp.toRepresentation().getClientId());
+
+            ClientResource resourceServerClient = getClientResource(RESOURCE_SERVER_ID);
+            RoleResource manageAlbumRole = resourceServerClient.roles().get("manage-albums");
+            RoleRepresentation roleRepresentation = manageAlbumRole.toRepresentation();
+
+            roleRepresentation.setScopeParamRequired(true);
+
+            manageAlbumRole.update(roleRepresentation);
+
+            loginToClientPage("alice", "alice");
+            assertTrue(this.clientPage.wasDenied());
+
+            for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+                if ("Any User Policy".equals(policy.getName())) {
+                    List<Map> roles = JsonSerialization.readValue(policy.getConfig().get("roles"), List.class);
+
+                    roles.forEach(role -> {
+                        String roleId = (String) role.get("id");
+                        if (roleId.equals(manageAlbumRole.toRepresentation().getId())) {
+                            role.put("required", false);
+                        }
+                    });
+
+                    policy.getConfig().put("roles", JsonSerialization.writeValueAsString(roles));
+                    getAuthorizationResource().policies().policy(policy.getId()).update(policy);
+                }
+            }
+
+            loginToClientPage("alice", "alice");
+            assertFalse(this.clientPage.wasDenied());
+        } finally {
+            this.deployer.undeploy(RESOURCE_SERVER_ID);
+        }
+    }
+
+    @Test
+    public void testOverridePermissionFromResourceParent() throws Exception {
+        try {
+            this.deployer.deploy(RESOURCE_SERVER_ID);
+
+            loginToClientPage("alice", "alice");
+            String resourceName = "My Resource Instance";
+            this.clientPage.createAlbum(resourceName);
+            assertFalse(this.clientPage.wasDenied());
+
+            this.clientPage.viewAlbum(resourceName);
+            assertFalse(this.clientPage.wasDenied());
+
+            this.clientPage.navigateTo();
+            this.clientPage.deleteAlbum(resourceName);
+            assertFalse(this.clientPage.wasDenied());
+
+            this.clientPage.createAlbum(resourceName);
+
+            loginToClientPage("admin", "admin");
+
+            this.clientPage.navigateToAdminAlbum();
+            this.clientPage.viewAlbum(resourceName);
+            assertFalse(this.clientPage.wasDenied());
+
+            this.clientPage.navigateToAdminAlbum();;
+            this.clientPage.deleteAlbum(resourceName);
+            assertFalse(this.clientPage.wasDenied());
+
+            loginToClientPage("alice", "alice");
+            this.clientPage.createAlbum(resourceName);
+            assertFalse(this.clientPage.wasDenied());
+
+            getAuthorizationResource().resources().resources().forEach(resource -> {
+                if (resource.getName().equals(resourceName)) {
+                    try {
+                        PolicyRepresentation resourceInstancePermission = new PolicyRepresentation();
+
+                        resourceInstancePermission.setName(resourceName + "Permission");
+                        resourceInstancePermission.setType("resource");
+
+                        Map<String, String> config = new HashMap<>();
+
+                        config.put("resources", JsonSerialization.writeValueAsString(Arrays.asList(resource.getId())));
+                        config.put("applyPolicies", JsonSerialization.writeValueAsString(Arrays.asList("Only Owner Policy")));
+
+                        resourceInstancePermission.setConfig(config);
+                        getAuthorizationResource().policies().create(resourceInstancePermission);
+                    } catch (Exception e) {
+                        throw new RuntimeException("Error creating policy.", e);
+                    }
+                }
+            });
+
+            loginToClientPage("admin", "admin");
+
+            this.clientPage.navigateToAdminAlbum();
+            this.clientPage.viewAlbum(resourceName);
+            assertTrue(this.clientPage.wasDenied());
+
+            this.clientPage.navigateToAdminAlbum();
+            this.clientPage.deleteAlbum(resourceName);
+            assertTrue(this.clientPage.wasDenied());
+
+            loginToClientPage("alice", "alice");
+            this.clientPage.deleteAlbum(resourceName);
+            assertFalse(this.clientPage.wasDenied());
+
+            ResourcesResource resourcesResource = getAuthorizationResource().resources();
+            List<ResourceRepresentation> resources = resourcesResource.resources();
+            assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
+        } finally {
+            this.deployer.undeploy(RESOURCE_SERVER_ID);
+        }
+    }
+
+    @Test
+    public void testInheritPermissionFromResourceParent() throws Exception {
+        try {
+            this.deployer.deploy(RESOURCE_SERVER_ID);
+
+            loginToClientPage("alice", "alice");
+
+            String resourceName = "My Resource Instance";
+            this.clientPage.createAlbum(resourceName);
+            assertFalse(this.clientPage.wasDenied());
+
+            this.clientPage.viewAlbum(resourceName);
+            assertFalse(this.clientPage.wasDenied());
+
+            this.clientPage.navigateTo();
+            this.clientPage.deleteAlbum(resourceName);
+            assertFalse(this.clientPage.wasDenied());
+
+            this.clientPage.createAlbum(resourceName);
+
+            loginToClientPage("admin", "admin");
+
+            this.clientPage.navigateToAdminAlbum();
+            this.clientPage.viewAlbum(resourceName);
+            assertFalse(this.clientPage.wasDenied());
+
+            this.clientPage.navigateToAdminAlbum();;
+            this.clientPage.deleteAlbum(resourceName);
+            assertFalse(this.clientPage.wasDenied());
+
+            loginToClientPage("alice", "alice");
+            this.clientPage.createAlbum(resourceName);
+            assertFalse(this.clientPage.wasDenied());
+
+            ResourcesResource resourcesResource = getAuthorizationResource().resources();
+            resourcesResource.resources().forEach(resource -> {
+                if (resource.getName().equals(resourceName)) {
+                    try {
+                        PolicyRepresentation resourceInstancePermission = new PolicyRepresentation();
+
+                        resourceInstancePermission.setName(resourceName + "Permission");
+                        resourceInstancePermission.setType("resource");
+
+                        Map<String, String> config = new HashMap<>();
+
+                        config.put("resources", JsonSerialization.writeValueAsString(Arrays.asList(resource.getId())));
+                        config.put("applyPolicies", JsonSerialization.writeValueAsString(Arrays.asList("Only Owner Policy")));
+
+                        resourceInstancePermission.setConfig(config);
+                        getAuthorizationResource().policies().create(resourceInstancePermission);
+                    } catch (Exception e) {
+                        throw new RuntimeException("Error creating policy.", e);
+                    }
+                }
+            });
+
+            loginToClientPage("admin", "admin");
+
+            this.clientPage.navigateToAdminAlbum();
+            this.clientPage.viewAlbum(resourceName);
+            assertTrue(this.clientPage.wasDenied());
+
+            this.clientPage.navigateToAdminAlbum();
+            this.clientPage.deleteAlbum(resourceName);
+            assertTrue(this.clientPage.wasDenied());
+
+            resourcesResource.resources().forEach(resource -> {
+                if (resource.getName().equals(resourceName)) {
+                    resource.setScopes(resource.getScopes().stream().filter(scope -> !scope.getName().equals("urn:photoz.com:scopes:album:view")).collect(Collectors.toSet()));
+                    resourcesResource.resource(resource.getId()).update(resource);
+                }
+            });
+
+            loginToClientPage("admin", "admin");
+
+            this.clientPage.navigateToAdminAlbum();
+            this.clientPage.viewAlbum(resourceName);
+            assertFalse(this.clientPage.wasDenied());
+
+            this.clientPage.navigateToAdminAlbum();
+            this.clientPage.deleteAlbum(resourceName);
+            assertTrue(this.clientPage.wasDenied());
+
+            loginToClientPage("alice", "alice");
+            this.clientPage.deleteAlbum(resourceName);
+            assertFalse(this.clientPage.wasDenied());
+            List<ResourceRepresentation> resources = resourcesResource.resources();
+            assertTrue(resources.stream().filter(resource -> resource.getOwner().getName().equals("alice")).collect(Collectors.toList()).isEmpty());
+
+            resourcesResource.resources().forEach(resource -> {
+                if (resource.getName().equals(resourceName)) {
+                    resource.setScopes(Collections.emptySet());
+                    resourcesResource.resource(resource.getId()).update(resource);
+                }
+            });
+        } finally {
+            this.deployer.undeploy(RESOURCE_SERVER_ID);
+        }
+    }
+
+    private void importResourceServerSettings() throws FileNotFoundException {
+        getAuthorizationResource().importSettings(loadJson(new FileInputStream(new File(TEST_APPS_HOME_DIR + "/photoz/photoz-restful-api-authz-service.json")), ResourceServerRepresentation.class));
+    }
+
+    private AuthorizationResource getAuthorizationResource() throws FileNotFoundException {
+        return getClientResource(RESOURCE_SERVER_ID).authorization();
+    }
+
+    private ClientResource getClientResource(String clientId) {
+        ClientsResource clients = this.realmsResouce().realm(REALM_NAME).clients();
+        ClientRepresentation resourceServer = clients.findByClientId(clientId).get(0);
+        return clients.get(resourceServer.getId());
+    }
+
+    private void deleteAllCookiesForClientPage() {
+        clientPage.navigateTo();
+        driver.manage().deleteAllCookies();
+    }
+    
+    private void loginToClientPage(String username, String password, String... scopes) {
+        // We need to log out by deleting cookies because the log out button sometimes doesn't work in PhantomJS
+        deleteAllCookiesForClientPage();
+        deleteAllCookiesForTestRealm();
+        clientPage.navigateTo();
+        clientPage.login(username, password, scopes);
+    }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletAuthzAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletAuthzAdapterTest.java
new file mode 100644
index 0000000..7f61556
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/example/authorization/AbstractServletAuthzAdapterTest.java
@@ -0,0 +1,345 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.adapter.example.authorization;
+
+import org.jboss.arquillian.container.test.api.Deployer;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Test;
+import org.keycloak.admin.client.resource.AuthorizationResource;
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.admin.client.resource.ClientsResource;
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.admin.client.resource.UserResource;
+import org.keycloak.admin.client.resource.UsersResource;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
+import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
+import org.keycloak.testsuite.util.WaitUtils;
+import org.keycloak.util.JsonSerialization;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.keycloak.testsuite.util.IOUtil.loadJson;
+import static org.keycloak.testsuite.util.IOUtil.loadRealm;
+import static org.keycloak.testsuite.util.WaitUtils.pause;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public abstract class AbstractServletAuthzAdapterTest extends AbstractExampleAdapterTest {
+
+    private static final String REALM_NAME = "servlet-authz";
+    private static final String RESOURCE_SERVER_ID = "servlet-authz-app";
+
+    @ArquillianResource
+    private Deployer deployer;
+
+    @Override
+    public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
+        testRealms.add(
+                loadRealm(new File(TEST_APPS_HOME_DIR + "/servlet-authz-app/servlet-authz-realm.json")));
+    }
+
+    @Deployment(name = RESOURCE_SERVER_ID, managed = false)
+    public static WebArchive deployment() throws IOException {
+        return exampleDeployment(RESOURCE_SERVER_ID);
+    }
+
+    @Override
+    public void beforeAbstractKeycloakTest() throws Exception {
+        super.beforeAbstractKeycloakTest();
+        importResourceServerSettings();
+    }
+
+    @Test
+    public void testRegularUserPermissions() throws Exception {
+        try {
+            this.deployer.deploy(RESOURCE_SERVER_ID);
+
+            login("alice", "alice");
+            assertFalse(wasDenied());
+            assertTrue(hasLink("User Premium"));
+            assertTrue(hasLink("Administration"));
+            assertTrue(hasText("urn:servlet-authz:page:main:actionForUser"));
+            assertFalse(hasText("urn:servlet-authz:page:main:actionForAdmin"));
+            assertFalse(hasText("urn:servlet-authz:page:main:actionForPremiumUser"));
+
+            navigateToDynamicMenuPage();
+            assertTrue(hasText("Do user thing"));
+            assertFalse(hasText("Do  user premium thing"));
+            assertFalse(hasText("Do administration thing"));
+
+            navigateToUserPremiumPage();
+            assertTrue(wasDenied());
+
+            navigateToAdminPage();
+            assertTrue(wasDenied());
+        } finally {
+            this.deployer.undeploy(RESOURCE_SERVER_ID);
+        }
+    }
+
+    @Test
+    public void testUserPremiumPermissions() throws Exception {
+        try {
+            this.deployer.deploy(RESOURCE_SERVER_ID);
+
+            login("jdoe", "jdoe");
+            assertFalse(wasDenied());
+            assertTrue(hasLink("User Premium"));
+            assertTrue(hasLink("Administration"));
+            assertTrue(hasText("urn:servlet-authz:page:main:actionForUser"));
+            assertTrue(hasText("urn:servlet-authz:page:main:actionForPremiumUser"));
+            assertFalse(hasText("urn:servlet-authz:page:main:actionForAdmin"));
+
+            navigateToDynamicMenuPage();
+            assertTrue(hasText("Do user thing"));
+            assertTrue(hasText("Do  user premium thing"));
+            assertFalse(hasText("Do administration thing"));
+
+            navigateToUserPremiumPage();
+            assertFalse(wasDenied());
+
+            navigateToAdminPage();
+            assertTrue(wasDenied());
+        } finally {
+            this.deployer.undeploy(RESOURCE_SERVER_ID);
+        }
+    }
+
+    @Test
+    public void testAdminPermissions() throws Exception {
+        try {
+            this.deployer.deploy(RESOURCE_SERVER_ID);
+
+            login("admin", "admin");
+            assertFalse(wasDenied());
+            assertTrue(hasLink("User Premium"));
+            assertTrue(hasLink("Administration"));
+            assertTrue(hasText("urn:servlet-authz:page:main:actionForUser"));
+            assertTrue(hasText("urn:servlet-authz:page:main:actionForAdmin"));
+            assertFalse(hasText("urn:servlet-authz:page:main:actionForPremiumUser"));
+
+            navigateToDynamicMenuPage();
+            assertTrue(hasText("Do user thing"));
+            assertTrue(hasText("Do administration thing"));
+            assertFalse(hasText("Do  user premium thing"));
+
+            navigateToUserPremiumPage();
+            assertTrue(wasDenied());
+
+            navigateToAdminPage();
+            assertFalse(wasDenied());
+        } finally {
+            this.deployer.undeploy(RESOURCE_SERVER_ID);
+        }
+    }
+
+    @Test
+    public void testGrantPremiumAccessToUser() throws Exception {
+        try {
+            this.deployer.deploy(RESOURCE_SERVER_ID);
+
+            login("alice", "alice");
+            assertFalse(wasDenied());
+
+            navigateToUserPremiumPage();
+            assertTrue(wasDenied());
+
+            for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+                if ("Premium Resource Permission".equals(policy.getName())) {
+                    policy.getConfig().put("applyPolicies", "[\"Any User Policy\"]");
+                    getAuthorizationResource().policies().policy(policy.getId()).update(policy);
+                }
+            }
+
+            login("alice", "alice");
+
+            navigateToUserPremiumPage();
+            assertFalse(wasDenied());
+
+            for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+                if ("Premium Resource Permission".equals(policy.getName())) {
+                    policy.getConfig().put("applyPolicies", "[\"Only Premium User Policy\"]");
+                    getAuthorizationResource().policies().policy(policy.getId()).update(policy);
+                }
+            }
+
+            login("alice", "alice");
+
+            navigateToUserPremiumPage();
+            assertTrue(wasDenied());
+
+            PolicyRepresentation onlyAlicePolicy = new PolicyRepresentation();
+
+            onlyAlicePolicy.setName("Temporary Premium Access Policy");
+            onlyAlicePolicy.setType("user");
+            HashMap<String, String> config = new HashMap<>();
+            UsersResource usersResource = realmsResouce().realm(REALM_NAME).users();
+            List<UserRepresentation> users = usersResource.search("alice", null, null, null, null, null);
+
+            assertFalse(users.isEmpty());
+
+            config.put("users", JsonSerialization.writeValueAsString(Arrays.asList(users.get(0).getId())));
+
+            onlyAlicePolicy.setConfig(config);
+            getAuthorizationResource().policies().create(onlyAlicePolicy);
+
+            for (PolicyRepresentation policy : getAuthorizationResource().policies().policies()) {
+                if ("Premium Resource Permission".equals(policy.getName())) {
+                    policy.getConfig().put("applyPolicies", "[\"Temporary Premium Access Policy\"]");
+                    getAuthorizationResource().policies().policy(policy.getId()).update(policy);
+                }
+            }
+
+            login("alice", "alice");
+
+            navigateToUserPremiumPage();
+            assertFalse(wasDenied());
+        } finally {
+            this.deployer.undeploy(RESOURCE_SERVER_ID);
+        }
+    }
+
+    @Test
+    public void testGrantAdministrativePermissions() throws Exception {
+        try {
+            this.deployer.deploy(RESOURCE_SERVER_ID);
+
+            login("jdoe", "jdoe");
+
+            navigateToAdminPage();
+            assertTrue(wasDenied());
+
+            RealmResource realmResource = realmsResouce().realm(REALM_NAME);
+            UsersResource usersResource = realmResource.users();
+            List<UserRepresentation> users = usersResource.search("jdoe", null, null, null, null, null);
+
+            assertFalse(users.isEmpty());
+
+            UserResource userResource = usersResource.get(users.get(0).getId());
+
+            RoleRepresentation adminRole = realmResource.roles().get("admin").toRepresentation();
+            userResource.roles().realmLevel().add(Arrays.asList(adminRole));
+
+            login("jdoe", "jdoe");
+
+            navigateToAdminPage();
+            assertFalse(wasDenied());
+        } finally {
+            this.deployer.undeploy(RESOURCE_SERVER_ID);
+        }
+    }
+
+    private boolean hasLink(String text) {
+        return getLink(text) != null;
+    }
+
+    private boolean hasText(String text) {
+        return this.driver.getPageSource().contains(text);
+    }
+
+    private WebElement getLink(String text) {
+        return this.driver.findElement(By.xpath("//a[text() = '" + text + "']"));
+    }
+
+    private void importResourceServerSettings() throws FileNotFoundException {
+        getAuthorizationResource().importSettings(loadJson(new FileInputStream(new File(TEST_APPS_HOME_DIR + "/servlet-authz-app/servlet-authz-app-authz-service.json")), ResourceServerRepresentation.class));
+    }
+
+    private AuthorizationResource getAuthorizationResource() throws FileNotFoundException {
+        return getClientResource(RESOURCE_SERVER_ID).authorization();
+    }
+
+    private ClientResource getClientResource(String clientId) {
+        ClientsResource clients = this.realmsResouce().realm(REALM_NAME).clients();
+        ClientRepresentation resourceServer = clients.findByClientId(clientId).get(0);
+        return clients.get(resourceServer.getId());
+    }
+
+    private void logOut() {
+        navigateTo();
+        By by = By.xpath("//a[text() = 'Sign Out']");
+        WaitUtils.waitUntilElement(by);
+        this.driver.findElement(by).click();
+        pause(500);
+    }
+
+    private void login(String username, String password) throws InterruptedException {
+        navigateTo();
+        Thread.sleep(2000);
+        if (this.driver.getCurrentUrl().startsWith(getResourceServerUrl().toString())) {
+            Thread.sleep(2000);
+            logOut();
+            navigateTo();
+        }
+
+        Thread.sleep(2000);
+
+        this.loginPage.form().login(username, password);
+    }
+
+    private void navigateTo() {
+        this.driver.navigate().to(getResourceServerUrl());
+        WaitUtils.waitUntilElement(By.xpath("//a[text() = 'Dynamic Menu']"));
+    }
+
+    private  boolean wasDenied() {
+        return this.driver.getPageSource().contains("You can not access this resource.");
+    }
+
+    private URL getResourceServerUrl() {
+        try {
+            return new URL(this.appServerContextRootPage + "/" + RESOURCE_SERVER_ID);
+        } catch (MalformedURLException e) {
+            throw new RuntimeException("Could not obtain resource server url.", e);
+        }
+    }
+
+    private void navigateToDynamicMenuPage() {
+        navigateTo();
+        getLink("Dynamic Menu").click();
+    }
+
+    private void navigateToUserPremiumPage() {
+        navigateTo();
+        getLink("User Premium").click();
+    }
+
+    private void navigateToAdminPage() {
+        navigateTo();
+        getLink("Administration").click();
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoServletsAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoServletsAdapterTest.java
index c754cd3..083867f 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoServletsAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractDemoServletsAdapterTest.java
@@ -21,16 +21,22 @@ import org.jboss.arquillian.container.test.api.Deployment;
 import org.jboss.arquillian.graphene.page.Page;
 import org.jboss.shrinkwrap.api.spec.WebArchive;
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.keycloak.OAuth2Constants;
 import org.keycloak.common.Version;
+import org.keycloak.common.util.Time;
 import org.keycloak.constants.AdapterConstants;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
+import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.VersionRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
+import org.keycloak.testsuite.adapter.filter.AdapterActionsFilter;
 import org.keycloak.testsuite.adapter.page.*;
+import org.keycloak.testsuite.util.URLUtils;
 import org.keycloak.util.BasicAuthHelper;
 
 import javax.ws.rs.client.Client;
@@ -70,6 +76,8 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
     private ProductPortal productPortal;
     @Page
     private InputPortal inputPortal;
+    @Page
+    private TokenMinTTLPage tokenMinTTLPage;
 
     @Deployment(name = CustomerPortal.DEPLOYMENT_NAME)
     protected static WebArchive customerPortal() {
@@ -106,6 +114,18 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
         return servletDeployment(InputPortal.DEPLOYMENT_NAME, "keycloak.json", InputServlet.class);
     }
 
+    @Deployment(name = TokenMinTTLPage.DEPLOYMENT_NAME)
+    protected static WebArchive tokenMinTTLPage() {
+        return servletDeployment(TokenMinTTLPage.DEPLOYMENT_NAME, AdapterActionsFilter.class, AbstractShowTokensServlet.class, TokenMinTTLServlet.class, ErrorServlet.class);
+    }
+
+    @Before
+    public void beforeDemoServletsAdapterTest() {
+        // Delete all cookies from token-min-ttl page to be sure we are logged out
+        tokenMinTTLPage.navigateTo();
+        driver.manage().deleteAllCookies();
+    }
+
     @Test
     public void testCustomerPortalWithSubsystemSettings() {
         customerPortalSubsystem.navigateTo();
@@ -408,4 +428,63 @@ public abstract class AbstractDemoServletsAdapterTest extends AbstractServletsAd
         assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
     }
 
+    // Tests "token-minimum-time-to-live" adapter configuration option
+    @Test
+    public void testTokenMinTTL() {
+        // Login
+        tokenMinTTLPage.navigateTo();
+        testRealmLoginPage.form().waitForUsernameInputPresent();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+        testRealmLoginPage.form().login("bburke@redhat.com", "password");
+        assertCurrentUrlEquals(tokenMinTTLPage);
+
+        // Get time of token
+        AccessToken token = tokenMinTTLPage.getAccessToken();
+        int tokenIssued1 = token.getIssuedAt();
+
+        // Sets 5 minutes offset and assert access token will be still the same
+        setAdapterAndServerTimeOffset(300, tokenMinTTLPage.toString());
+        token = tokenMinTTLPage.getAccessToken();
+        int tokenIssued2 = token.getIssuedAt();
+        Assert.assertEquals(tokenIssued1, tokenIssued2);
+        Assert.assertFalse(token.isExpired());
+
+        // Sets 9 minutes offset and assert access token will be refreshed (accessTokenTimeout is 10 minutes, token-min-ttl is 2 minutes. Hence 8 minutes or more should be sufficient)
+        setAdapterAndServerTimeOffset(540, tokenMinTTLPage.toString());
+        token = tokenMinTTLPage.getAccessToken();
+        int tokenIssued3 = token.getIssuedAt();
+        Assert.assertTrue(tokenIssued3 > tokenIssued1);
+
+        // Revert times
+        setAdapterAndServerTimeOffset(0, tokenMinTTLPage.toString());
+    }
+
+    // Tests forwarding of parameters like "prompt"
+    @Test
+    public void testOIDCParamsForwarding() {
+        // test login to customer-portal which does a bearer request to customer-db
+        securePortal.navigateTo();
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+        testRealmLoginPage.form().login("bburke@redhat.com", "password");
+        assertCurrentUrlEquals(securePortal);
+        String pageSource = driver.getPageSource();
+        assertTrue(pageSource.contains("Bill Burke") && pageSource.contains("Stian Thorgersen"));
+
+        int currentTime = Time.currentTime();
+        setAdapterAndServerTimeOffset(10, securePortal.toString());
+
+        // Test I need to reauthenticate with prompt=login
+        String appUri = tokenMinTTLPage.getUriBuilder().queryParam(OIDCLoginProtocol.PROMPT_PARAM, OIDCLoginProtocol.PROMPT_VALUE_LOGIN).build().toString();
+        URLUtils.navigateToUri(driver, appUri, true);
+        assertCurrentUrlStartsWithLoginUrlOf(testRealmPage);
+        testRealmLoginPage.form().login("bburke@redhat.com", "password");
+        AccessToken token = tokenMinTTLPage.getAccessToken();
+        int authTime = token.getAuthTime();
+        Assert.assertTrue(currentTime + 10 <= authTime);
+
+        // Revert times
+        setAdapterAndServerTimeOffset(0, tokenMinTTLPage.toString());
+    }
+
+
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractOfflineServletsAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractOfflineServletsAdapterTest.java
index 9d8da7b..fa6d0a8 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractOfflineServletsAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractOfflineServletsAdapterTest.java
@@ -12,6 +12,7 @@ import org.keycloak.events.EventType;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.testsuite.AssertEvents;
 import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
+import org.keycloak.testsuite.adapter.filter.AdapterActionsFilter;
 import org.keycloak.testsuite.adapter.page.OfflineToken;
 import org.keycloak.testsuite.pages.AccountApplicationsPage;
 import org.keycloak.testsuite.pages.LoginPage;
@@ -48,7 +49,7 @@ public abstract class AbstractOfflineServletsAdapterTest extends AbstractServlet
 
     @Deployment(name = OfflineToken.DEPLOYMENT_NAME)
     protected static WebArchive offlineClient() {
-        return servletDeployment(OfflineToken.DEPLOYMENT_NAME, OfflineTokenServlet.class, ErrorServlet.class);
+        return servletDeployment(OfflineToken.DEPLOYMENT_NAME, AdapterActionsFilter.class, AbstractShowTokensServlet.class, OfflineTokenServlet.class, ErrorServlet.class);
     }
 
     @Override
@@ -186,14 +187,7 @@ public abstract class AbstractOfflineServletsAdapterTest extends AbstractServlet
     }
 
     private void setAdapterAndServerTimeOffset(int timeOffset) {
-        setTimeOffset(timeOffset);
-        String timeOffsetUri = UriBuilder.fromUri(offlineTokenPage.toString())
-                .queryParam("timeOffset", timeOffset)
-                .build().toString();
-
-        driver.navigate().to(timeOffsetUri);
-        waitUntilElement(By.tagName("body")).is().visible();
-
+        super.setAdapterAndServerTimeOffset(timeOffset, offlineTokenPage.toString());
     }
 
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLFilterServletAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLFilterServletAdapterTest.java
new file mode 100644
index 0000000..0df65a4
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLFilterServletAdapterTest.java
@@ -0,0 +1,54 @@
+package org.keycloak.testsuite.adapter.servlet;
+
+import org.junit.After;
+import org.junit.Before;
+import org.keycloak.testsuite.arquillian.annotation.UseServletFilter;
+
+/**
+ * @author mhajas
+ */
+
+@UseServletFilter(filterName = "saml-filter", filterClass = "org.keycloak.adapters.saml.servlet.SamlFilter")
+public abstract class AbstractSAMLFilterServletAdapterTest extends AbstractSAMLServletsAdapterTest {
+
+    @Before
+    public void checkRoles() {
+        badClientSalesPostSigServletPage.checkRoles(true);
+        badRealmSalesPostSigServletPage.checkRoles(true);
+        employeeSigServletPage.checkRoles(true);
+        employeeSigFrontServletPage.checkRoles(true);
+        salesMetadataServletPage.checkRoles(true);
+        salesPostServletPage.checkRoles(true);
+        salesPostEncServletPage.checkRoles(true);
+        salesPostSigServletPage.checkRoles(true);
+        salesPostPassiveServletPage.checkRoles(true);
+        salesPostSigEmailServletPage.checkRoles(true);
+        salesPostSigPersistentServletPage.checkRoles(true);
+        salesPostSigTransientServletPage.checkRoles(true);
+        employee2ServletPage.navigateTo();
+
+        //using endpoint instead of query param because we are not able to put query param to IDP initiated login
+        testRealmLoginPage.form().login(bburkeUser);
+        employee2ServletPage.checkRolesEndPoint();
+        employee2ServletPage.logout();
+
+        forbiddenIfNotAuthenticated = false;
+    }
+
+    @After
+    public void uncheckRoles() {
+        badClientSalesPostSigServletPage.checkRoles(false);
+        badRealmSalesPostSigServletPage.checkRoles(false);
+        employee2ServletPage.checkRoles(false);
+        employeeSigServletPage.checkRoles(false);
+        employeeSigFrontServletPage.checkRoles(false);
+        salesMetadataServletPage.checkRoles(false);
+        salesPostServletPage.checkRoles(false);
+        salesPostEncServletPage.checkRoles(false);
+        salesPostSigServletPage.checkRoles(false);
+        salesPostPassiveServletPage.checkRoles(false);
+        salesPostSigEmailServletPage.checkRoles(false);
+        salesPostSigPersistentServletPage.checkRoles(false);
+        salesPostSigTransientServletPage.checkRoles(false);
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java
index 0034f36..ddc23b7 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/adapter/servlet/AbstractSAMLServletsAdapterTest.java
@@ -50,46 +50,48 @@ import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
  */
 public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAdapterTest {
     @Page
-    private BadClientSalesPostSigServlet badClientSalesPostSigServletPage;
+    protected BadClientSalesPostSigServlet badClientSalesPostSigServletPage;
 
     @Page
-    private BadRealmSalesPostSigServlet badRealmSalesPostSigServletPage;
+    protected BadRealmSalesPostSigServlet badRealmSalesPostSigServletPage;
 
     @Page
-    private Employee2Servlet employee2ServletPage;
+    protected Employee2Servlet employee2ServletPage;
 
     @Page
-    private EmployeeSigServlet employeeSigServletPage;
+    protected EmployeeSigServlet employeeSigServletPage;
 
     @Page
-    private EmployeeSigFrontServlet employeeSigFrontServletPage;
+    protected EmployeeSigFrontServlet employeeSigFrontServletPage;
 
     @Page
-    private SalesMetadataServlet salesMetadataServletPage;
+    protected SalesMetadataServlet salesMetadataServletPage;
 
     @Page
-    private SalesPostServlet salesPostServletPage;
+    protected SalesPostServlet salesPostServletPage;
 
     @Page
-    private SalesPostEncServlet salesPostEncServletPage;
+    protected SalesPostEncServlet salesPostEncServletPage;
 
     @Page
-    private SalesPostPassiveServlet salesPostPassiveServletPage;
+    protected SalesPostPassiveServlet salesPostPassiveServletPage;
 
     @Page
-    private SalesPostSigServlet salesPostSigServletPage;
+    protected SalesPostSigServlet salesPostSigServletPage;
 
     @Page
-    private SalesPostSigEmailServlet salesPostSigEmailServletPage;
+    protected SalesPostSigEmailServlet salesPostSigEmailServletPage;
 
     @Page
-    private SalesPostSigPersistentServlet salesPostSigPersistentServletPage;
+    protected SalesPostSigPersistentServlet salesPostSigPersistentServletPage;
 
     @Page
-    private SalesPostSigTransientServlet salesPostSigTransientServletPage;
+    protected SalesPostSigTransientServlet salesPostSigTransientServletPage;
 
     @Page
-    private SAMLIDPInitiatedLogin samlidpInitiatedLogin;
+    protected SAMLIDPInitiatedLogin samlidpInitiatedLogin;
+
+    protected boolean forbiddenIfNotAuthenticated = true;
 
     @Deployment(name = BadClientSalesPostSigServlet.DEPLOYMENT_NAME)
     protected static WebArchive badClientSalesPostSig() {
@@ -196,7 +198,7 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
         waitUntilElement(By.xpath("//body")).text().contains("principal=bburke");
     }
 
-    private void testSuccessfulAndUnauthorizedLogin(SAMLServletWithLogout page, Login loginPage) {
+    private void testSuccessfulAndUnauthorizedLogin(SAMLServlet page, Login loginPage) {
         assertSuccessfulLogin(page, bburkeUser, loginPage);
         page.logout();
         assertForbiddenLogin(page, "unauthorized", "password", loginPage);
@@ -223,7 +225,6 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
         assertForbidden(employee2ServletPage);
         assertForbidden(employeeSigFrontServletPage);
         assertForbidden(salesPostSigPersistentServletPage);
-
         salesPostServletPage.logout();
     }
 
@@ -243,8 +244,12 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
         assertCurrentUrlStartsWith(testRealmSAMLRedirectLoginPage);
 
         salesPostPassiveServletPage.navigateTo();
-        waitUntilElement(By.xpath("//body")).text().not().contains("principal=");
-        assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains("<body></body>") || driver.getPageSource().contains("<body><pre></pre></body>"));
+        if (forbiddenIfNotAuthenticated) {
+            waitUntilElement(By.xpath("//body")).text().not().contains("principal=");
+            assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains("<body></body>") || driver.getPageSource().equals(""));
+        } else {
+            waitUntilElement(By.xpath("//body")).text().contains("principal=null");
+        }
 
         salesPostSigEmailServletPage.navigateTo();
         assertCurrentUrlStartsWith(testRealmSAMLPostLoginPage);
@@ -253,7 +258,7 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
     @Test
     public void badClientSalesPostSigTest() {
         badClientSalesPostSigServletPage.navigateTo();
-        waitUntilElement(By.xpath("//body")).text().contains("invalidRequesterMessage");
+        waitUntilElement(By.xpath("//body")).text().contains("Invalid requester");
     }
 
     @Test
@@ -320,9 +325,13 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
     public void salesPostPassiveTest() {
         salesPostPassiveServletPage.navigateTo();
 
-        waitUntilElement(By.xpath("//body")).text().not().contains("principal=");
-        //Different 403 status page on EAP and Wildfly
-        assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains("<body></body>") || driver.getPageSource().contains("<body><pre></pre></body>"));
+        if (forbiddenIfNotAuthenticated) {
+            waitUntilElement(By.xpath("//body")).text().not().contains("principal=");
+            //Different 403 status page on EAP and Wildfly
+            assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains("<body></body>") || driver.getPageSource().equals(""));
+        } else {
+            waitUntilElement(By.xpath("//body")).text().contains("principal=null");
+        }
 
         assertSuccessfulLogin(salesPostServletPage, bburkeUser, testRealmSAMLPostLoginPage);
 
@@ -331,10 +340,13 @@ public abstract class AbstractSAMLServletsAdapterTest extends AbstractServletsAd
         salesPostPassiveServletPage.logout();
         salesPostPassiveServletPage.navigateTo();
 
-        waitUntilElement(By.xpath("//body")).text().not().contains("principal=");
-        //Different 403 status page on EAP and Wildfly
-        assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains("<body></body>") || driver.getPageSource().contains("<body><pre></pre></body>"));
-
+        if (forbiddenIfNotAuthenticated) {
+            waitUntilElement(By.xpath("//body")).text().not().contains("principal=");
+            //Different 403 status page on EAP and Wildfly
+            assertTrue(driver.getPageSource().contains("Forbidden") || driver.getPageSource().contains("<body></body>") || driver.getPageSource().equals(""));
+        } else {
+            waitUntilElement(By.xpath("//body")).text().contains("principal=null");
+        }
         assertForbiddenLogin(salesPostServletPage, "unauthorized", "password", testRealmSAMLPostLoginPage);
         assertForbidden(salesPostPassiveServletPage);
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ApiUtil.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ApiUtil.java
index dca666f..006dc92 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ApiUtil.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ApiUtil.java
@@ -17,6 +17,7 @@
 package org.keycloak.testsuite.admin;
 
 import org.jboss.logging.Logger;
+import org.keycloak.admin.client.resource.AuthorizationResource;
 import org.keycloak.admin.client.resource.ClientResource;
 import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.admin.client.resource.RoleResource;
@@ -60,6 +61,15 @@ public class ApiUtil {
         return path.substring(path.lastIndexOf('/') + 1);
     }
 
+    public static ClientResource findClientResourceById(RealmResource realm, String id) {
+        for (ClientRepresentation c : realm.clients().findAll()) {
+            if (c.getId().equals(id)) {
+                return realm.clients().get(c.getId());
+            }
+        }
+        return null;
+    }
+
     public static ClientResource findClientResourceByClientId(RealmResource realm, String clientId) {
         for (ClientRepresentation c : realm.clients().findAll()) {
             if (c.getClientId().equals(clientId)) {
@@ -183,4 +193,13 @@ public class ApiUtil {
         }
         return contains;
     }
+
+    public static AuthorizationResource findAuthorizationSettings(RealmResource realm, String clientId) {
+        for (ClientRepresentation c : realm.clients().findAll()) {
+            if (c.getClientId().equals(clientId)) {
+                return realm.clients().get(c.getId()).authorization();
+            }
+        }
+        return null;
+    }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/AttackDetectionResourceTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/AttackDetectionResourceTest.java
index d39f43c..531b556 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/AttackDetectionResourceTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/AttackDetectionResourceTest.java
@@ -21,6 +21,7 @@ import org.jboss.arquillian.test.api.ArquillianResource;
 import org.junit.Test;
 import org.keycloak.admin.client.resource.AttackDetectionResource;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.testsuite.util.AdminEventPaths;
 import org.keycloak.testsuite.util.OAuthClient;
@@ -52,7 +53,7 @@ public class AttackDetectionResourceTest extends AbstractAdminTest {
     public void test() {
         AttackDetectionResource detection = adminClient.realm("test").attackDetection();
 
-        assertBruteForce(detection.bruteForceUserStatus("test-user@localhost"), 0, false, false);
+        assertBruteForce(detection.bruteForceUserStatus(findUser("test-user@localhost").getId()), 0, false, false);
 
         oauthClient.doLogin("test-user@localhost", "invalid");
         oauthClient.doLogin("test-user@localhost", "invalid");
@@ -62,21 +63,21 @@ public class AttackDetectionResourceTest extends AbstractAdminTest {
         oauthClient.doLogin("test-user2", "invalid");
         oauthClient.doLogin("nosuchuser", "invalid");
 
-        assertBruteForce(detection.bruteForceUserStatus("test-user@localhost"), 3, true, true);
-        assertBruteForce(detection.bruteForceUserStatus("test-user2"), 2, true, true);
+        assertBruteForce(detection.bruteForceUserStatus(findUser("test-user@localhost").getId()), 3, true, true);
+        assertBruteForce(detection.bruteForceUserStatus(findUser("test-user2").getId()), 2, true, true);
         assertBruteForce(detection.bruteForceUserStatus("nosuchuser"), 0, false, false);
 
-        detection.clearBruteForceForUser("test-user@localhost");
-        assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.attackDetectionClearBruteForceForUserPath("test-user@localhost"));
+        detection.clearBruteForceForUser(findUser("test-user@localhost").getId());
+        assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.attackDetectionClearBruteForceForUserPath(findUser("test-user@localhost").getId()), ResourceType.USER_LOGIN_FAILURE);
 
-        assertBruteForce(detection.bruteForceUserStatus("test-user@localhost"), 0, false, false);
-        assertBruteForce(detection.bruteForceUserStatus("test-user2"), 2, true, true);
+        assertBruteForce(detection.bruteForceUserStatus(findUser("test-user@localhost").getId()), 0, false, false);
+        assertBruteForce(detection.bruteForceUserStatus(findUser("test-user2").getId()), 2, true, true);
 
         detection.clearAllBruteForce();
-        assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.attackDetectionClearAllBruteForcePath());
+        assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.attackDetectionClearAllBruteForcePath(), ResourceType.USER_LOGIN_FAILURE);
 
-        assertBruteForce(detection.bruteForceUserStatus("test-user@localhost"), 0, false, false);
-        assertBruteForce(detection.bruteForceUserStatus("test-user2"), 0, false, false);
+        assertBruteForce(detection.bruteForceUserStatus(findUser("test-user@localhost").getId()), 0, false, false);
+        assertBruteForce(detection.bruteForceUserStatus(findUser("test-user2").getId()), 0, false, false);
     }
 
     private void assertBruteForce(Map<String, Object> status, Integer expectedNumFailures, Boolean expectedFailure, Boolean expectedDisabled) {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AbstractAuthenticationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AbstractAuthenticationTest.java
index d77c76c..f115c49 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AbstractAuthenticationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AbstractAuthenticationTest.java
@@ -23,6 +23,7 @@ import org.junit.Rule;
 import org.keycloak.admin.client.resource.AuthenticationManagementResource;
 import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.representations.idm.AuthenticationExecutionExportRepresentation;
 import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
 import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
@@ -196,6 +197,6 @@ public abstract class AbstractAuthenticationTest extends AbstractKeycloakTest {
         Response response = authMgmtResource.createFlow(flowRep);
         org.keycloak.testsuite.Assert.assertEquals(201, response.getStatus());
         response.close();
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AssertAdminEvents.isExpectedPrefixFollowedByUuid(AdminEventPaths.authFlowsPath()), flowRep);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AssertAdminEvents.isExpectedPrefixFollowedByUuid(AdminEventPaths.authFlowsPath()), flowRep, ResourceType.AUTH_FLOW);
     }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AuthenticatorConfigTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AuthenticatorConfigTest.java
index eb1cda5..00c1943 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AuthenticatorConfigTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/AuthenticatorConfigTest.java
@@ -29,6 +29,7 @@ import org.junit.Test;
 import org.keycloak.authentication.authenticators.broker.IdpCreateUserIfUniqueAuthenticator;
 import org.keycloak.authentication.authenticators.broker.IdpCreateUserIfUniqueAuthenticatorFactory;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
 import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
 import org.keycloak.representations.idm.AuthenticatorConfigRepresentation;
@@ -52,7 +53,7 @@ public class AuthenticatorConfigTest extends AbstractAuthenticationTest {
         HashMap<String, String> params = new HashMap<>();
         params.put("provider", IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID);
         authMgmtResource.addExecution("firstBrokerLogin2", params);
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionPath("firstBrokerLogin2"), params);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionPath("firstBrokerLogin2"), params, ResourceType.AUTH_EXECUTION);
 
         List<AuthenticationExecutionInfoRepresentation> executionReps = authMgmtResource.getExecutions("firstBrokerLogin2");
         AuthenticationExecutionInfoRepresentation exec = findExecutionByProvider(IdpCreateUserIfUniqueAuthenticatorFactory.PROVIDER_ID, executionReps);
@@ -79,7 +80,7 @@ public class AuthenticatorConfigTest extends AbstractAuthenticationTest {
 
         // Cleanup
         authMgmtResource.removeAuthenticatorConfig(cfgId);
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authExecutionConfigPath(cfgId));
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authExecutionConfigPath(cfgId), ResourceType.AUTHENTICATOR_CONFIG);
     }
 
 
@@ -105,7 +106,7 @@ public class AuthenticatorConfigTest extends AbstractAuthenticationTest {
         cfgRep.setAlias("foo2");
         cfgRep.getConfig().put("configKey2", "configValue2");
         authMgmtResource.updateAuthenticatorConfig(cfgRep.getId(), cfgRep);
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authExecutionConfigPath(cfgId), cfgRep);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authExecutionConfigPath(cfgId), cfgRep, ResourceType.AUTHENTICATOR_CONFIG);
 
         // Assert updated
         cfgRep = authMgmtResource.getAuthenticatorConfig(cfgRep.getId());
@@ -137,7 +138,7 @@ public class AuthenticatorConfigTest extends AbstractAuthenticationTest {
 
         // Test remove our config
         authMgmtResource.removeAuthenticatorConfig(cfgId);
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authExecutionConfigPath(cfgId));
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authExecutionConfigPath(cfgId), ResourceType.AUTHENTICATOR_CONFIG);
 
         // Assert config not found
         try {
@@ -159,7 +160,7 @@ public class AuthenticatorConfigTest extends AbstractAuthenticationTest {
         Assert.assertEquals(201, resp.getStatus());
         String cfgId = ApiUtil.getCreatedId(resp);
         Assert.assertNotNull(cfgId);
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionConfigPath(executionId), cfg);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionConfigPath(executionId), cfg, ResourceType.AUTH_EXECUTION);
         return cfgId;
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ExecutionTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ExecutionTest.java
index ae19ff6..42015ed 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ExecutionTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ExecutionTest.java
@@ -22,6 +22,7 @@ import org.junit.Test;
 import org.keycloak.authentication.AuthenticationFlow;
 import org.keycloak.authentication.authenticators.client.ClientIdAndSecretAuthenticator;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
 import org.keycloak.representations.idm.AuthenticationExecutionRepresentation;
 import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
@@ -64,7 +65,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
         // copy built-in flow so we get a new editable flow
         params.put("newName", "Copy-of-browser");
         Response response = authMgmtResource.copy("browser", params);
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params, ResourceType.AUTH_FLOW);
         try {
             Assert.assertEquals("Copy flow", 201, response.getStatus());
         } finally {
@@ -83,7 +84,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
         // add execution - should succeed
         params.put("provider", "idp-review-profile");
         authMgmtResource.addExecution("Copy-of-browser", params);
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionPath("Copy-of-browser"), params);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionPath("Copy-of-browser"), params, ResourceType.AUTH_EXECUTION);
 
         // check execution was added
         List<AuthenticationExecutionInfoRepresentation> executionReps = authMgmtResource.getExecutions("Copy-of-browser");
@@ -97,7 +98,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
 
         // remove execution
         authMgmtResource.removeExecution(exec.getId());
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authExecutionPath(exec.getId()));
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authExecutionPath(exec.getId()), ResourceType.AUTH_EXECUTION);
 
         // check execution was removed
         executionReps = authMgmtResource.getExecutions("Copy-of-browser");
@@ -108,7 +109,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
 
         // delete auth-cookie
         authMgmtResource.removeExecution(authCookieExec.getId());
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authExecutionPath(authCookieExec.getId()));
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authExecutionPath(authCookieExec.getId()), ResourceType.AUTH_EXECUTION);
 
         AuthenticationExecutionRepresentation rep = new AuthenticationExecutionRepresentation();
         rep.setPriority(10);
@@ -149,7 +150,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
 
         // add execution - should succeed
         response = authMgmtResource.addExecution(rep);
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AssertAdminEvents.isExpectedPrefixFollowedByUuid(AdminEventPaths.authMgmtBasePath() + "/executions"), rep);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AssertAdminEvents.isExpectedPrefixFollowedByUuid(AdminEventPaths.authMgmtBasePath() + "/executions"), rep, ResourceType.AUTH_EXECUTION);
         try {
             Assert.assertEquals("added execution", 201, response.getStatus());
         } finally {
@@ -178,7 +179,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
         // switch from DISABLED to ALTERNATIVE
         exec.setRequirement(DISABLED);
         authMgmtResource.updateExecutions("browser", exec);
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("browser"), exec);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("browser"), exec, ResourceType.AUTH_EXECUTION);
 
         // make sure the change is visible
         executionReps = authMgmtResource.getExecutions("browser");
@@ -198,7 +199,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
         Map<String, String> executionData = new HashMap<>();
         executionData.put("provider", ClientIdAndSecretAuthenticator.PROVIDER_ID);
         authMgmtResource.addExecution("new-client-flow", executionData);
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionPath("new-client-flow"), executionData);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionPath("new-client-flow"), executionData, ResourceType.AUTH_EXECUTION);
 
         // Check executions of not-existent flow - SHOULD FAIL
         try {
@@ -234,7 +235,7 @@ public class ExecutionTest extends AbstractAuthenticationTest {
         // Update success
         executionRep.setRequirement(ALTERNATIVE);
         authMgmtResource.updateExecutions("new-client-flow", executionRep);
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("new-client-flow"), executionRep);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("new-client-flow"), executionRep, ResourceType.AUTH_EXECUTION);
 
         // Check updated
         executionRep = findExecutionByProvider(ClientIdAndSecretAuthenticator.PROVIDER_ID, authMgmtResource.getExecutions("new-client-flow"));
@@ -250,10 +251,10 @@ public class ExecutionTest extends AbstractAuthenticationTest {
 
         // Successfuly remove execution and flow
         authMgmtResource.removeExecution(executionRep.getId());
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authExecutionPath(executionRep.getId()));
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authExecutionPath(executionRep.getId()), ResourceType.AUTH_EXECUTION);
 
         AuthenticationFlowRepresentation rep = findFlowByAlias("new-client-flow", authMgmtResource.getFlows());
         authMgmtResource.deleteFlow(rep.getId());
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authFlowPath(rep.getId()));
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authFlowPath(rep.getId()), ResourceType.AUTH_FLOW);
     }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/FlowTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/FlowTest.java
index 7e2f4a8..fc50bc6 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/FlowTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/FlowTest.java
@@ -20,6 +20,7 @@ package org.keycloak.testsuite.admin.authentication;
 import org.junit.Assert;
 import org.junit.Test;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.representations.idm.AuthenticationExecutionExportRepresentation;
 import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
 import org.keycloak.testsuite.util.AdminEventPaths;
@@ -119,7 +120,7 @@ public class FlowTest extends AbstractAuthenticationTest {
         // Successfully add flow
         data.put("alias", "SomeFlow");
         authMgmtResource.addExecutionFlow("browser-2", data);
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("browser-2"), data);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("browser-2"), data, ResourceType.AUTH_EXECUTION_FLOW);
 
         // check that new flow is returned in a children list
         flows = authMgmtResource.getFlows();
@@ -141,7 +142,7 @@ public class FlowTest extends AbstractAuthenticationTest {
 
         // delete non-built-in flow
         authMgmtResource.deleteFlow(found.getId());
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authFlowPath(found.getId()));
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authFlowPath(found.getId()), ResourceType.AUTH_FLOW);
 
         // check the deleted flow is no longer returned
         flows = authMgmtResource.getFlows();
@@ -184,7 +185,7 @@ public class FlowTest extends AbstractAuthenticationTest {
         // copy that should succeed
         params.put("newName", "Copy of browser");
         response = authMgmtResource.copy("browser", params);
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params, ResourceType.AUTH_FLOW);
         try {
             Assert.assertEquals("Copy flow", 201, response.getStatus());
         } finally {
@@ -219,7 +220,7 @@ public class FlowTest extends AbstractAuthenticationTest {
         Response response = authMgmtResource.copy("browser", params);
         Assert.assertEquals(201, response.getStatus());
         response.close();
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params, ResourceType.AUTH_FLOW);
 
         params = new HashMap<>();
         params.put("alias", "child");
@@ -228,7 +229,7 @@ public class FlowTest extends AbstractAuthenticationTest {
         params.put("type", "basic-flow");
 
         authMgmtResource.addExecutionFlow("parent", params);
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("parent"), params);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("parent"), params, ResourceType.AUTH_EXECUTION_FLOW);
     }
 
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/InitialFlowsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/InitialFlowsTest.java
index b243711..3640af5 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/InitialFlowsTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/InitialFlowsTest.java
@@ -200,7 +200,7 @@ public class InitialFlowsTest extends AbstractAuthenticationTest {
         addExecExport(flow, null, false, "http-basic-authenticator", false, null, REQUIRED, 10);
 
         execs = new LinkedList<>();
-        addExecInfo(execs, null, "http-basic-authenticator", false, 0, 0, REQUIRED, null, new String[]{});
+        addExecInfo(execs, "HTTP Basic Authentication", "http-basic-authenticator", false, 0, 0, REQUIRED, null, new String[]{});
         expected.add(new FlowExecutions(flow, execs));
 
         return expected;
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ProvidersTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ProvidersTest.java
index a6f899c..858e06e 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ProvidersTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ProvidersTest.java
@@ -136,6 +136,7 @@ public class ProvidersTest extends AbstractAuthenticationTest {
                 "Validates a OTP on a separate OTP form. Only shown if required based on the configured conditions.");
         addProviderInfo(result, "auth-cookie", "Cookie", "Validates the SSO cookie set by the auth server.");
         addProviderInfo(result, "auth-otp-form", "OTP Form", "Validates a OTP on a separate OTP form.");
+        addProviderInfo(result, "auth-script-based", "Script-based Authentication", "Script based authentication.");
         addProviderInfo(result, "auth-spnego", "Kerberos", "Initiates the SPNEGO protocol.  Most often used with Kerberos.");
         addProviderInfo(result, "auth-username-password-form", "Username Password Form",
                 "Validates a username and password from login form.");
@@ -144,7 +145,7 @@ public class ProvidersTest extends AbstractAuthenticationTest {
                 "Validates the password supplied as a 'password' form parameter in direct grant request");
         addProviderInfo(result, "direct-grant-validate-username", "Username Validation",
                 "Validates the username supplied as a 'username' form parameter in direct grant request");
-        addProviderInfo(result, "http-basic-authenticator", null, null);
+        addProviderInfo(result, "http-basic-authenticator", "HTTP Basic Authentication", "Validates username and password from Authorization HTTP header");
         addProviderInfo(result, "idp-confirm-link", "Confirm link existing account", "Show the form where user confirms if he wants " +
                 "to link identity provider with existing account or rather edit user profile data retrieved from identity provider to avoid conflict");
         addProviderInfo(result, "idp-create-user-if-unique", "Create User If Unique", "Detect if there is existing Keycloak account " +
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/RegistrationFlowTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/RegistrationFlowTest.java
index d7e25b6..c38086b 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/RegistrationFlowTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/RegistrationFlowTest.java
@@ -26,6 +26,7 @@ import javax.ws.rs.core.Response;
 import org.junit.Assert;
 import org.junit.Test;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
 import org.keycloak.testsuite.util.AdminEventPaths;
 
@@ -47,7 +48,7 @@ public class RegistrationFlowTest extends AbstractAuthenticationTest {
         data.put("description", "registrationForm2 flow");
         data.put("provider", "registration-page-form");
         authMgmtResource.addExecutionFlow("registration2", data);
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("registration2"), data);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionFlowPath("registration2"), data, ResourceType.AUTH_EXECUTION_FLOW);
 
         // Should fail to add execution under top level flow
         Map<String, String> data2 = new HashMap<>();
@@ -62,7 +63,7 @@ public class RegistrationFlowTest extends AbstractAuthenticationTest {
 
         // Should success to add execution under form flow
         authMgmtResource.addExecution("registrationForm2", data2);
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionPath("registrationForm2"), data2);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authAddExecutionPath("registrationForm2"), data2, ResourceType.AUTH_EXECUTION);
     }
 
     // TODO: More type-safety instead of passing generic maps
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/RequiredActionsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/RequiredActionsTest.java
index 8d45830..1b7f79f 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/RequiredActionsTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/RequiredActionsTest.java
@@ -20,6 +20,7 @@ package org.keycloak.testsuite.admin.authentication;
 import org.junit.Assert;
 import org.junit.Test;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.representations.idm.RequiredActionProviderRepresentation;
 import org.keycloak.representations.idm.RequiredActionProviderSimpleRepresentation;
 import org.keycloak.testsuite.actions.DummyRequiredActionFactory;
@@ -44,7 +45,7 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
         List<RequiredActionProviderRepresentation> result = authMgmtResource.getRequiredActions();
 
         List<RequiredActionProviderRepresentation> expected = new ArrayList<>();
-        addRequiredAction(expected, "CONFIGURE_TOTP", "Configure Totp", true, false, null);
+        addRequiredAction(expected, "CONFIGURE_TOTP", "Configure OTP", true, false, null);
         addRequiredAction(expected, "UPDATE_PASSWORD", "Update Password", true, false, null);
         addRequiredAction(expected, "UPDATE_PROFILE", "Update Profile", true, false, null);
         addRequiredAction(expected, "VERIFY_EMAIL", "Verify Email", true, false, null);
@@ -61,7 +62,7 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
 
         forUpdate.setConfig(Collections.<String, String>emptyMap());
         authMgmtResource.updateRequiredAction(forUpdate.getAlias(), forUpdate);
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authRequiredActionPath(forUpdate.getAlias()));
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authRequiredActionPath(forUpdate.getAlias()), ResourceType.REQUIRED_ACTION);
 
         result = authMgmtResource.getRequiredActions();
         RequiredActionProviderRepresentation updated = findRequiredActionByAlias(forUpdate.getAlias(), result);
@@ -81,7 +82,7 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
 
         // Register it
         authMgmtResource.registerRequiredAction(action);
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authMgmtBasePath() + "/register-required-action", action);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authMgmtBasePath() + "/register-required-action", action, ResourceType.REQUIRED_ACTION);
 
         // Try to find not-existent action - should fail
         try {
@@ -107,7 +108,7 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
         // Update (set it as defaultAction)
         rep.setDefaultAction(true);
         authMgmtResource.updateRequiredAction(DummyRequiredActionFactory.PROVIDER_ID, rep);
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authRequiredActionPath(rep.getAlias()), rep);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authRequiredActionPath(rep.getAlias()), rep, ResourceType.REQUIRED_ACTION);
         compareRequiredAction(rep, newRequiredAction(DummyRequiredActionFactory.PROVIDER_ID, "Dummy Action",
                 true, true, Collections.emptyMap()));
 
@@ -121,7 +122,7 @@ public class RequiredActionsTest extends AbstractAuthenticationTest {
 
         // Remove success
         authMgmtResource.removeRequiredAction(DummyRequiredActionFactory.PROVIDER_ID);
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authRequiredActionPath(rep.getAlias()));
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.DELETE, AdminEventPaths.authRequiredActionPath(rep.getAlias()), ResourceType.REQUIRED_ACTION);
 
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ShiftExecutionTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ShiftExecutionTest.java
index ba8ae09..ac2ab44 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ShiftExecutionTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/authentication/ShiftExecutionTest.java
@@ -20,6 +20,7 @@ package org.keycloak.testsuite.admin.authentication;
 import org.junit.Assert;
 import org.junit.Test;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.representations.idm.AuthenticationExecutionInfoRepresentation;
 import org.keycloak.testsuite.util.AdminEventPaths;
 
@@ -41,7 +42,7 @@ public class ShiftExecutionTest extends AbstractAuthenticationTest {
         HashMap<String, String> params = new HashMap<>();
         params.put("newName", "Copy of browser");
         Response response = authMgmtResource.copy("browser", params);
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params);
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.CREATE, AdminEventPaths.authCopyFlowPath("browser"), params, ResourceType.AUTH_FLOW);
         try {
             Assert.assertEquals("Copy flow", 201, response.getStatus());
         } finally {
@@ -64,7 +65,7 @@ public class ShiftExecutionTest extends AbstractAuthenticationTest {
 
         // shift last execution up
         authMgmtResource.raisePriority(last.getId());
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authRaiseExecutionPath(last.getId()));
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authRaiseExecutionPath(last.getId()), ResourceType.AUTH_EXECUTION);
 
         List<AuthenticationExecutionInfoRepresentation> executions2 = authMgmtResource.getExecutions("Copy of browser");
 
@@ -84,7 +85,7 @@ public class ShiftExecutionTest extends AbstractAuthenticationTest {
 
         // shift one before last down
         authMgmtResource.lowerPriority(oneButLast2.getId());
-        assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authLowerExecutionPath(oneButLast2.getId()));
+        assertAdminEvents.assertEvent(REALM_NAME, OperationType.UPDATE, AdminEventPaths.authLowerExecutionPath(oneButLast2.getId()), ResourceType.AUTH_EXECUTION);
 
         executions2 = authMgmtResource.getExecutions("Copy of browser");
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/AbstractClientTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/AbstractClientTest.java
index 2fb5ccd..813f067 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/AbstractClientTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/AbstractClientTest.java
@@ -25,6 +25,7 @@ import org.junit.Before;
 import org.junit.Rule;
 import org.keycloak.admin.client.resource.ClientResource;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
@@ -97,7 +98,7 @@ public abstract class AbstractClientTest extends AbstractAuthTest {
         resp.close();
         String id = ApiUtil.getCreatedId(resp);
 
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientResourcePath(id), clientRep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientResourcePath(id), clientRep, ResourceType.CLIENT);
 
         return id;
     }
@@ -105,7 +106,7 @@ public abstract class AbstractClientTest extends AbstractAuthTest {
     protected void removeClient(String clientDbId) {
         testRealmResource().clients().get(clientDbId).remove();
 
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientResourcePath(clientDbId));
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientResourcePath(clientDbId), ResourceType.CLIENT);
     }
 
     protected ClientRepresentation findClientRepresentation(String name) {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/AbstractProtocolMapperTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/AbstractProtocolMapperTest.java
index e245e42..af7cf3b 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/AbstractProtocolMapperTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/AbstractProtocolMapperTest.java
@@ -27,6 +27,7 @@ import java.util.Map;
 import com.fasterxml.jackson.core.type.TypeReference;
 import org.keycloak.admin.client.resource.ProtocolMappersResource;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.representations.idm.AdminEventRepresentation;
 import org.keycloak.representations.idm.ProtocolMapperRepresentation;
 import org.keycloak.testsuite.Assert;
@@ -109,7 +110,7 @@ public abstract class AbstractProtocolMapperTest extends AbstractClientTest {
         // This is used by admin console to add builtin mappers
         resource.createMapper(mappersToAdd);
 
-        AdminEventRepresentation adminEvent = assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, adminEventPath + "/add-models");
+        AdminEventRepresentation adminEvent = assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, adminEventPath + "/add-models", ResourceType.PROTOCOL_MAPPER);
         try {
             List<ProtocolMapperRepresentation> eventMappers = JsonSerialization.readValue(new ByteArrayInputStream(adminEvent.getRepresentation().getBytes()), new TypeReference<List<ProtocolMapperRepresentation>>() {
             });
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AbstractAuthorizationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AbstractAuthorizationTest.java
new file mode 100644
index 0000000..c4979e0
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AbstractAuthorizationTest.java
@@ -0,0 +1,93 @@
+/*
+  Copyright 2016 Red Hat, Inc. and/or its affiliates
+  and other contributors as indicated by the @author tags.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ */
+package org.keycloak.testsuite.admin.client.authorization;
+
+import org.junit.After;
+import org.junit.Before;
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.admin.client.resource.ResourceScopeResource;
+import org.keycloak.admin.client.resource.ResourceScopesResource;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+import org.keycloak.testsuite.admin.client.AbstractClientTest;
+
+import javax.ws.rs.core.Response;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public abstract class AbstractAuthorizationTest extends AbstractClientTest {
+
+    protected static final String RESOURCE_SERVER_CLIENT_ID = "test-resource-server";
+
+    @Before
+    public void onBeforeAuthzTests() {
+        createOidcClient(RESOURCE_SERVER_CLIENT_ID);
+
+        ClientRepresentation resourceServer = getResourceServer();
+
+        assertEquals(RESOURCE_SERVER_CLIENT_ID, resourceServer.getName());
+        assertFalse(resourceServer.getAuthorizationServicesEnabled());
+    }
+
+    @After
+    public void onAfterAuthzTests() {
+        getClientResource().remove();
+    }
+
+    protected ClientResource getClientResource() {
+        return findClientResource(RESOURCE_SERVER_CLIENT_ID);
+    }
+
+    protected ClientRepresentation getResourceServer() {
+        return findClientRepresentation(RESOURCE_SERVER_CLIENT_ID);
+    }
+
+    protected void enableAuthorizationServices() {
+        ClientRepresentation resourceServer = getResourceServer();
+
+        resourceServer.setAuthorizationServicesEnabled(true);
+        resourceServer.setServiceAccountsEnabled(true);
+
+        getClientResource().update(resourceServer);
+    }
+
+    protected ResourceScopeResource createDefaultScope() {
+        return createScope("Test Scope", "Scope Icon");
+    }
+
+    protected ResourceScopeResource createScope(String name, String iconUri) {
+        ScopeRepresentation newScope = new ScopeRepresentation();
+
+        newScope.setName(name);
+        newScope.setIconUri(iconUri);
+
+        ResourceScopesResource resources = getClientResource().authorization().scopes();
+
+        Response response = resources.create(newScope);
+
+        assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus());
+
+        ScopeRepresentation stored = response.readEntity(ScopeRepresentation.class);
+
+        return resources.scope(stored.getId());
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AuthorizationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AuthorizationTest.java
new file mode 100644
index 0000000..55936b2
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/AuthorizationTest.java
@@ -0,0 +1,58 @@
+/*
+  Copyright 2016 Red Hat, Inc. and/or its affiliates
+  and other contributors as indicated by the @author tags.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ */
+
+package org.keycloak.testsuite.admin.client.authorization;
+
+import org.junit.Test;
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.representations.adapters.config.PolicyEnforcerConfig;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class AuthorizationTest extends AbstractAuthorizationTest {
+
+    @Test
+    public void testEnableAuthorizationServices() {
+        ClientResource clientResource = getClientResource();
+        ClientRepresentation resourceServer = getResourceServer();
+
+        enableAuthorizationServices();
+
+        ResourceServerRepresentation settings = clientResource.authorization().getSettings();
+
+        assertEquals(PolicyEnforcerConfig.EnforcementMode.ENFORCING.name(), settings.getPolicyEnforcementMode().name());
+        assertEquals(resourceServer.getId(), settings.getClientId());
+        List<ResourceRepresentation> defaultResources = clientResource.authorization().resources().resources();
+
+        assertEquals(1, defaultResources.size());
+
+        List<PolicyRepresentation> defaultPolicies = clientResource.authorization().policies().policies();
+
+        assertEquals(2, defaultPolicies.size());
+    }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/GenericPolicyManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/GenericPolicyManagementTest.java
new file mode 100644
index 0000000..e6f83d8
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/GenericPolicyManagementTest.java
@@ -0,0 +1,290 @@
+/*
+  Copyright 2016 Red Hat, Inc. and/or its affiliates
+  and other contributors as indicated by the @author tags.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ */
+package org.keycloak.testsuite.admin.client.authorization;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.admin.client.resource.PoliciesResource;
+import org.keycloak.admin.client.resource.PolicyResource;
+import org.keycloak.admin.client.resource.ResourceResource;
+import org.keycloak.admin.client.resource.ResourceScopeResource;
+import org.keycloak.admin.client.resource.ResourceScopesResource;
+import org.keycloak.admin.client.resource.ResourcesResource;
+import org.keycloak.representations.idm.authorization.DecisionStrategy;
+import org.keycloak.representations.idm.authorization.Logic;
+import org.keycloak.representations.idm.authorization.PolicyProviderRepresentation;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+
+import javax.ws.rs.core.Response;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class GenericPolicyManagementTest extends AbstractAuthorizationTest {
+
+    private static final String[] EXPECTED_BUILTIN_POLICY_PROVIDERS = {"test", "user", "role", "drools", "js", "time", "aggregate", "scope", "resource"};
+
+    @Before
+    @Override
+    public void onBeforeAuthzTests() {
+        super.onBeforeAuthzTests();
+        enableAuthorizationServices();
+    }
+
+    @After
+    @Override
+    public void onAfterAuthzTests() {
+        super.onAfterAuthzTests();
+    }
+
+    @Test
+    public void testCreate() {
+        PolicyRepresentation newPolicy = createTestingPolicy().toRepresentation();
+
+        assertEquals("Test Generic Policy", newPolicy.getName());
+        assertEquals("test", newPolicy.getType());
+        assertEquals(Logic.POSITIVE, newPolicy.getLogic());
+        assertEquals(DecisionStrategy.UNANIMOUS, newPolicy.getDecisionStrategy());
+        assertEquals("configuration for A", newPolicy.getConfig().get("configA"));
+        assertEquals("configuration for B", newPolicy.getConfig().get("configB"));
+        assertEquals("configuration for C", newPolicy.getConfig().get("configC"));
+
+        List<PolicyRepresentation> policies = getClientResource().authorization().policies().policies();
+
+        assertEquals(6, policies.size());
+
+        assertAssociatedPolicy("Test Associated A", newPolicy);
+        assertAssociatedPolicy("Test Associated B", newPolicy);
+        assertAssociatedPolicy("Test Associated C", newPolicy);
+
+        assertAssociatedResource("Test Resource A", newPolicy);
+        assertAssociatedResource("Test Resource B", newPolicy);
+        assertAssociatedResource("Test Resource C", newPolicy);
+
+        assertAssociatedScope("Test Scope A", newPolicy);
+        assertAssociatedScope("Test Scope B", newPolicy);
+        assertAssociatedScope("Test Scope C", newPolicy);
+    }
+
+    @Test
+    public void testUpdate() {
+        PolicyResource policyResource = createTestingPolicy();
+        PolicyRepresentation resource = policyResource.toRepresentation();
+
+        resource.setName("changed");
+        resource.setLogic(Logic.NEGATIVE);
+        resource.setDecisionStrategy(DecisionStrategy.AFFIRMATIVE);
+        resource.getConfig().put("configA", "changed configuration for A");
+        resource.getConfig().remove("configB");
+        resource.getConfig().put("configC", "changed configuration for C");
+
+        policyResource.update(resource);
+
+        resource = policyResource.toRepresentation();
+
+        assertEquals("changed", resource.getName());
+        assertEquals(Logic.NEGATIVE, resource.getLogic());
+
+        assertEquals(DecisionStrategy.AFFIRMATIVE, resource.getDecisionStrategy());
+        assertEquals("changed configuration for A", resource.getConfig().get("configA"));
+        assertNull(resource.getConfig().get("configB"));
+        assertEquals("changed configuration for C", resource.getConfig().get("configC"));
+
+        Map<String, String> config = resource.getConfig();
+
+        config.put("applyPolicies", buildConfigOption(findPolicyByName("Test Associated C").getId()));
+
+        config.put("resources", buildConfigOption(findResourceByName("Test Resource B").getId()));
+
+        config.put("scopes", buildConfigOption(findScopeByName("Test Scope A").getId()));
+
+        policyResource.update(resource);
+
+        resource = policyResource.toRepresentation();
+        config = resource.getConfig();
+
+        assertAssociatedPolicy("Test Associated C", resource);
+        assertFalse(config.get("applyPolicies").contains(findPolicyByName("Test Associated A").getId()));
+        assertFalse(config.get("applyPolicies").contains(findPolicyByName("Test Associated B").getId()));
+
+        assertAssociatedResource("Test Resource B", resource);
+        assertFalse(config.get("resources").contains(findResourceByName("Test Resource A").getId()));
+        assertFalse(config.get("resources").contains(findResourceByName("Test Resource C").getId()));
+
+        assertAssociatedScope("Test Scope A", resource);
+        assertFalse(config.get("scopes").contains(findScopeByName("Test Scope B").getId()));
+        assertFalse(config.get("scopes").contains(findScopeByName("Test Scope C").getId()));
+    }
+
+    @Test
+    public void testDefaultPolicyProviders() {
+        List<String> providers = getClientResource().authorization().policies()
+                .policyProviders().stream().map(PolicyProviderRepresentation::getType).collect(Collectors.toList());
+
+        assertFalse(providers.isEmpty());
+        assertTrue(providers.containsAll(Arrays.asList(EXPECTED_BUILTIN_POLICY_PROVIDERS)));
+    }
+
+    private PolicyResource createTestingPolicy() {
+        Map<String, String> config = new HashMap<>();
+
+        config.put("configA", "configuration for A");
+        config.put("configB", "configuration for B");
+        config.put("configC", "configuration for C");
+
+        config.put("applyPolicies", buildConfigOption(
+                createPolicy("Test Associated A", new HashMap<>()).toRepresentation().getId(),
+                createPolicy("Test Associated B", new HashMap<>()).toRepresentation().getId(),
+                createPolicy("Test Associated C", new HashMap<>()).toRepresentation().getId()
+        ));
+
+        config.put("resources", buildConfigOption(
+                createResource("Test Resource A").toRepresentation().getId(),
+                createResource("Test Resource B").toRepresentation().getId(),
+                createResource("Test Resource C").toRepresentation().getId()
+        ));
+
+        config.put("scopes", buildConfigOption(
+                createScope("Test Scope A").toRepresentation().getId(),
+                createScope("Test Scope B").toRepresentation().getId(),
+                createScope("Test Scope C").toRepresentation().getId()
+        ));
+
+        return createPolicy("Test Generic Policy", config);
+    }
+
+    private PolicyResource createPolicy(String name, Map<String, String> config) {
+        PolicyRepresentation newPolicy = new PolicyRepresentation();
+
+        newPolicy.setName(name);
+        newPolicy.setType("test");
+        newPolicy.setConfig(config);
+
+        PoliciesResource policies = getClientResource().authorization().policies();
+        Response response = policies.create(newPolicy);
+
+        assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus());
+
+        PolicyRepresentation stored = response.readEntity(PolicyRepresentation.class);
+
+        return policies.policy(stored.getId());
+    }
+
+    private ResourceResource createResource(String name) {
+        ResourceRepresentation newResource = new ResourceRepresentation();
+
+        newResource.setName(name);
+
+        ResourcesResource resources = getClientResource().authorization().resources();
+
+        Response response = resources.create(newResource);
+
+        assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus());
+
+        ResourceRepresentation stored = response.readEntity(ResourceRepresentation.class);
+
+        return resources.resource(stored.getId());
+    }
+
+    private ResourceScopeResource createScope(String name) {
+        ScopeRepresentation newScope = new ScopeRepresentation();
+
+        newScope.setName(name);
+
+        ResourceScopesResource scopes = getClientResource().authorization().scopes();
+
+        Response response = scopes.create(newScope);
+
+        assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus());
+
+        ScopeRepresentation stored = response.readEntity(ScopeRepresentation.class);
+
+        return scopes.scope(stored.getId());
+    }
+
+    private String buildConfigOption(String... values) {
+        StringBuilder builder = new StringBuilder();
+
+        for (String value : values) {
+            if (builder.length() > 0) {
+                builder.append(",");
+            }
+            builder.append("\"" + value + "\"");
+        }
+
+        return builder.insert(0, "[").append("]").toString();
+    }
+
+    private PolicyRepresentation findPolicyByName(String name) {
+        return getClientResource().authorization().policies().policies()
+                .stream().filter(policyRepresentation -> policyRepresentation.getName().equals(name))
+                .findFirst().orElse(null);
+    }
+
+    private ResourceRepresentation findResourceByName(String name) {
+        return getClientResource().authorization().resources().resources()
+                .stream().filter(resource -> resource.getName().equals(name))
+                .findFirst().orElse(null);
+    }
+
+    private ScopeRepresentation findScopeByName(String name) {
+        return getClientResource().authorization().scopes().scopes()
+                .stream().filter(scope -> scope.getName().equals(name))
+                .findFirst().orElse(null);
+    }
+
+    private void assertAssociatedPolicy(String associatedPolicyName, PolicyRepresentation dependentPolicy) {
+        PolicyRepresentation associatedPolicy = findPolicyByName(associatedPolicyName);
+        assertNotNull(associatedPolicy);
+        assertTrue(dependentPolicy.getConfig().get("applyPolicies").contains(associatedPolicy.getId()));
+        assertEquals(1, associatedPolicy.getDependentPolicies().size());
+        assertEquals(dependentPolicy.getId(), associatedPolicy.getDependentPolicies().get(0).getId());
+    }
+
+    private void assertAssociatedResource(String resourceName, PolicyRepresentation policy) {
+        ResourceRepresentation resource = findResourceByName(resourceName);
+        assertNotNull(resource);
+        assertTrue(policy.getConfig().get("resources").contains(resource.getId()));
+        assertEquals(1, resource.getPolicies().size());
+        assertTrue(resource.getPolicies().stream().map(PolicyRepresentation::getId).collect(Collectors.toList())
+                .contains(policy.getId()));
+    }
+
+    private void assertAssociatedScope(String scopeName, PolicyRepresentation policy) {
+        ScopeRepresentation scope =  findScopeByName(scopeName);
+        assertNotNull(scope);
+        assertTrue(policy.getConfig().get("scopes").contains(scope.getId()));
+        assertEquals(1, scope.getPolicies().size());
+        assertTrue(scope.getPolicies().stream().map(PolicyRepresentation::getId).collect(Collectors.toList())
+                .contains(policy.getId()));
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourceManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourceManagementTest.java
new file mode 100644
index 0000000..9907472
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ResourceManagementTest.java
@@ -0,0 +1,185 @@
+/*
+  Copyright 2016 Red Hat, Inc. and/or its affiliates
+  and other contributors as indicated by the @author tags.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ */
+
+package org.keycloak.testsuite.admin.client.authorization;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.admin.client.resource.ResourceResource;
+import org.keycloak.admin.client.resource.ResourcesResource;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+
+import javax.ws.rs.NotFoundException;
+import javax.ws.rs.core.Response;
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ResourceManagementTest extends AbstractAuthorizationTest {
+
+    @Before
+    @Override
+    public void onBeforeAuthzTests() {
+        super.onBeforeAuthzTests();
+        enableAuthorizationServices();
+    }
+
+    @Test
+    public void testCreate() {
+        ResourceRepresentation newResource = createResource().toRepresentation();
+
+        assertEquals("Test Resource", newResource.getName());
+        assertEquals("/test/*", newResource.getUri());
+        assertEquals("test-resource", newResource.getType());
+        assertEquals("icon-test-resource", newResource.getIconUri());
+    }
+
+    @Test
+    public void testUpdate() {
+        ResourceResource resourceResource = createResource();
+        ResourceRepresentation resource = resourceResource.toRepresentation();
+
+        resource.setType("changed");
+        resource.setIconUri("changed");
+        resource.setUri("changed");
+
+        resourceResource.update(resource);
+
+        resource = resourceResource.toRepresentation();
+
+        assertEquals("changed", resource.getIconUri());
+        assertEquals("changed", resource.getType());
+        assertEquals("changed", resource.getUri());
+    }
+
+    @Test(expected = NotFoundException.class)
+    public void testDelete() {
+        ResourceResource resourceResource = createResource();
+
+        resourceResource.remove();
+
+        resourceResource.toRepresentation();
+    }
+
+    @Test
+    public void testAssociateScopes() {
+        ResourceResource resourceResource = createResourceWithDefaultScopes();
+        ResourceRepresentation updated = resourceResource.toRepresentation();
+
+        assertEquals(3, updated.getScopes().size());
+
+        assertTrue(containsScope("Scope A", updated));
+        assertTrue(containsScope("Scope B", updated));
+        assertTrue(containsScope("Scope C", updated));
+    }
+
+    @Test
+    public void testUpdateScopes() {
+        ResourceResource resourceResource = createResourceWithDefaultScopes();
+        ResourceRepresentation resource = resourceResource.toRepresentation();
+        Set<ScopeRepresentation> scopes = new HashSet<>(resource.getScopes());
+
+        assertEquals(3, scopes.size());
+        assertTrue(scopes.removeIf(scopeRepresentation -> scopeRepresentation.getName().equals("Scope B")));
+
+        resource.setScopes(scopes);
+
+        resourceResource.update(resource);
+
+        ResourceRepresentation updated = resourceResource.toRepresentation();
+
+        assertEquals(2, resource.getScopes().size());
+
+        assertFalse(containsScope("Scope B", updated));
+        assertTrue(containsScope("Scope A", updated));
+        assertTrue(containsScope("Scope C", updated));
+
+        scopes = new HashSet<>(updated.getScopes());
+
+        assertTrue(scopes.removeIf(scopeRepresentation -> scopeRepresentation.getName().equals("Scope A")));
+        assertTrue(scopes.removeIf(scopeRepresentation -> scopeRepresentation.getName().equals("Scope C")));
+
+        updated.setScopes(scopes);
+
+        resourceResource.update(updated);
+
+        updated = resourceResource.toRepresentation();
+
+        assertEquals(0, updated.getScopes().size());
+    }
+
+    private ResourceResource createResourceWithDefaultScopes() {
+        ResourceResource resourceResource = createResource();
+        ResourceRepresentation resource = resourceResource.toRepresentation();
+
+        assertEquals(0, resource.getScopes().size());
+
+        HashSet<ScopeRepresentation> scopes = new HashSet<>();
+
+        scopes.add(createScope("Scope A", "").toRepresentation());
+        scopes.add(createScope("Scope B", "").toRepresentation());
+        scopes.add(createScope("Scope C", "").toRepresentation());
+
+        resource.setScopes(scopes);
+
+        resourceResource.update(resource);
+
+        return resourceResource;
+    }
+
+    private boolean containsScope(String scopeName, ResourceRepresentation resource) {
+        Set<ScopeRepresentation> scopes = resource.getScopes();
+
+        if (scopes != null) {
+            for (ScopeRepresentation scope : scopes) {
+                if (scope.getName().equals(scopeName)) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    private ResourceResource createResource() {
+        ResourceRepresentation newResource = new ResourceRepresentation();
+
+        newResource.setName("Test Resource");
+        newResource.setUri("/test/*");
+        newResource.setType("test-resource");
+        newResource.setIconUri("icon-test-resource");
+
+        ResourcesResource resources = getClientResource().authorization().resources();
+
+        Response response = resources.create(newResource);
+
+        assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus());
+
+        ResourceRepresentation stored = response.readEntity(ResourceRepresentation.class);
+
+        return resources.resource(stored.getId());
+    }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ScopeManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ScopeManagementTest.java
new file mode 100644
index 0000000..bcb8b1b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/authorization/ScopeManagementTest.java
@@ -0,0 +1,75 @@
+/*
+  Copyright 2016 Red Hat, Inc. and/or its affiliates
+  and other contributors as indicated by the @author tags.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ */
+
+package org.keycloak.testsuite.admin.client.authorization;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.admin.client.resource.ResourceScopeResource;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+
+import javax.ws.rs.NotFoundException;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ *
+ * @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
+ */
+public class ScopeManagementTest extends AbstractAuthorizationTest {
+
+    @Before
+    @Override
+    public void onBeforeAuthzTests() {
+        super.onBeforeAuthzTests();
+        enableAuthorizationServices();
+    }
+
+    @Test
+    public void testCreate() {
+        ScopeRepresentation newScope = createDefaultScope().toRepresentation();
+
+        assertEquals("Test Scope", newScope.getName());
+        assertEquals("Scope Icon", newScope.getIconUri());
+    }
+
+    @Test
+    public void testUpdate() {
+        ResourceScopeResource scopeResource = createDefaultScope();
+        ScopeRepresentation scope = scopeResource.toRepresentation();
+
+        scope.setName("changed");
+        scope.setIconUri("changed");
+
+        scopeResource.update(scope);
+
+        scope = scopeResource.toRepresentation();
+
+        assertEquals("changed", scope.getName());
+        assertEquals("changed", scope.getIconUri());
+    }
+
+    @Test(expected = NotFoundException.class)
+    public void testDelete() {
+        ResourceScopeResource scopeResource = createDefaultScope();
+
+        scopeResource.remove();
+
+        scopeResource.toRepresentation();
+    }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientProtocolMapperTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientProtocolMapperTest.java
index 439c0df..3f609b7 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientProtocolMapperTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientProtocolMapperTest.java
@@ -25,6 +25,7 @@ import org.junit.Test;
 import org.keycloak.admin.client.resource.ClientResource;
 import org.keycloak.admin.client.resource.ProtocolMappersResource;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.representations.idm.ProtocolMapperRepresentation;
 import org.keycloak.testsuite.Assert;
 import org.keycloak.testsuite.admin.ApiUtil;
@@ -97,7 +98,7 @@ public class ClientProtocolMapperTest extends AbstractProtocolMapperTest {
         Response resp = samlMappersRsc.createMapper(rep);
         resp.close();
         String createdId = ApiUtil.getCreatedId(resp);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientProtocolMapperPath(samlClientId, createdId), rep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientProtocolMapperPath(samlClientId, createdId), rep, ResourceType.PROTOCOL_MAPPER);
 
         assertEquals(totalMappers + 1, samlMappersRsc.getMappers().size());
         assertEquals(totalSamlMappers + 1, samlMappersRsc.getMappersPerProtocol("saml").size());
@@ -121,7 +122,7 @@ public class ClientProtocolMapperTest extends AbstractProtocolMapperTest {
         Response resp = oidcMappersRsc.createMapper(rep);
         resp.close();
         String createdId = ApiUtil.getCreatedId(resp);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientProtocolMapperPath(oidcClientId, createdId), rep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientProtocolMapperPath(oidcClientId, createdId), rep, ResourceType.PROTOCOL_MAPPER);
 
         assertEquals(totalMappers + 1, oidcMappersRsc.getMappers().size());
         assertEquals(totalOidcMappers + 1, oidcMappersRsc.getMappersPerProtocol("openid-connect").size());
@@ -138,13 +139,13 @@ public class ClientProtocolMapperTest extends AbstractProtocolMapperTest {
         Response resp = samlMappersRsc.createMapper(rep);
         resp.close();
         String createdId = ApiUtil.getCreatedId(resp);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientProtocolMapperPath(samlClientId, createdId), rep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientProtocolMapperPath(samlClientId, createdId), rep, ResourceType.PROTOCOL_MAPPER);
 
         rep.getConfig().put("role", "account.manage-account");
         rep.setId(createdId);
         rep.setConsentRequired(false);
         samlMappersRsc.update(createdId, rep);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientProtocolMapperPath(samlClientId, createdId), rep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientProtocolMapperPath(samlClientId, createdId), rep, ResourceType.PROTOCOL_MAPPER);
 
         ProtocolMapperRepresentation updated = samlMappersRsc.getMapperById(createdId);
         assertEqualMappers(rep, updated);
@@ -157,13 +158,13 @@ public class ClientProtocolMapperTest extends AbstractProtocolMapperTest {
         Response resp = oidcMappersRsc.createMapper(rep);
         resp.close();
         String createdId = ApiUtil.getCreatedId(resp);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientProtocolMapperPath(oidcClientId, createdId), rep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientProtocolMapperPath(oidcClientId, createdId), rep, ResourceType.PROTOCOL_MAPPER);
 
         rep.getConfig().put("role", "myotherrole");
         rep.setId(createdId);
         rep.setConsentRequired(false);
         oidcMappersRsc.update(createdId, rep);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientProtocolMapperPath(oidcClientId, createdId), rep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientProtocolMapperPath(oidcClientId, createdId), rep, ResourceType.PROTOCOL_MAPPER);
 
         ProtocolMapperRepresentation updated = oidcMappersRsc.getMapperById(createdId);
         assertEqualMappers(rep, updated);
@@ -176,10 +177,10 @@ public class ClientProtocolMapperTest extends AbstractProtocolMapperTest {
         Response resp = samlMappersRsc.createMapper(rep);
         resp.close();
         String createdId = ApiUtil.getCreatedId(resp);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientProtocolMapperPath(samlClientId, createdId), rep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientProtocolMapperPath(samlClientId, createdId), rep, ResourceType.PROTOCOL_MAPPER);
 
         samlMappersRsc.delete(createdId);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientProtocolMapperPath(samlClientId, createdId));
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientProtocolMapperPath(samlClientId, createdId), ResourceType.PROTOCOL_MAPPER);
 
         try {
             samlMappersRsc.getMapperById(createdId);
@@ -196,10 +197,10 @@ public class ClientProtocolMapperTest extends AbstractProtocolMapperTest {
         Response resp = oidcMappersRsc.createMapper(rep);
         resp.close();
         String createdId = ApiUtil.getCreatedId(resp);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientProtocolMapperPath(oidcClientId, createdId), rep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientProtocolMapperPath(oidcClientId, createdId), rep, ResourceType.PROTOCOL_MAPPER);
 
         oidcMappersRsc.delete(createdId);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientProtocolMapperPath(oidcClientId, createdId));
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientProtocolMapperPath(oidcClientId, createdId), ResourceType.PROTOCOL_MAPPER);
 
         try {
             oidcMappersRsc.getMapperById(createdId);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientRolesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientRolesTest.java
index aed3461..2aa5933 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientRolesTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientRolesTest.java
@@ -23,6 +23,7 @@ import org.junit.Test;
 import org.keycloak.admin.client.resource.ClientResource;
 import org.keycloak.admin.client.resource.RolesResource;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.representations.idm.RoleRepresentation;
 import org.keycloak.testsuite.Assert;
 import org.keycloak.testsuite.util.AdminEventPaths;
@@ -75,7 +76,7 @@ public class ClientRolesTest extends AbstractClientTest {
     public void testAddRole() {
         RoleRepresentation role1 = makeRole("role1");
         rolesRsc.create(role1);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientRoleResourcePath(clientDbId, "role1"), role1);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientRoleResourcePath(clientDbId, "role1"), role1, ResourceType.CLIENT_ROLE);
         assertTrue(hasRole(rolesRsc, "role1"));
     }
 
@@ -83,10 +84,10 @@ public class ClientRolesTest extends AbstractClientTest {
     public void testRemoveRole() {
         RoleRepresentation role2 = makeRole("role2");
         rolesRsc.create(role2);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientRoleResourcePath(clientDbId, "role2"), role2);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientRoleResourcePath(clientDbId, "role2"), role2, ResourceType.CLIENT_ROLE);
 
         rolesRsc.deleteRole("role2");
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientRoleResourcePath(clientDbId, "role2"));
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientRoleResourcePath(clientDbId, "role2"), ResourceType.CLIENT_ROLE);
 
         assertFalse(hasRole(rolesRsc, "role2"));
     }
@@ -95,24 +96,24 @@ public class ClientRolesTest extends AbstractClientTest {
     public void testComposites() {
         RoleRepresentation roleA = makeRole("role-a");
         rolesRsc.create(roleA);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientRoleResourcePath(clientDbId, "role-a"), roleA);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientRoleResourcePath(clientDbId, "role-a"), roleA, ResourceType.CLIENT_ROLE);
 
         assertFalse(rolesRsc.get("role-a").toRepresentation().isComposite());
         assertEquals(0, rolesRsc.get("role-a").getRoleComposites().size());
 
         RoleRepresentation roleB = makeRole("role-b");
         rolesRsc.create(roleB);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientRoleResourcePath(clientDbId, "role-b"), roleB);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientRoleResourcePath(clientDbId, "role-b"), roleB, ResourceType.CLIENT_ROLE);
 
         RoleRepresentation roleC = makeRole("role-c");
         testRealmResource().roles().create(roleC);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.roleResourcePath("role-c"), roleC);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.roleResourcePath("role-c"), roleC, ResourceType.REALM_ROLE);
 
         List<RoleRepresentation> l = new LinkedList<>();
         l.add(rolesRsc.get("role-b").toRepresentation());
         l.add(testRealmResource().roles().get("role-c").toRepresentation());
         rolesRsc.get("role-a").addComposites(l);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientRoleResourceCompositesPath(clientDbId, "role-a"), l);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientRoleResourceCompositesPath(clientDbId, "role-a"), l, ResourceType.CLIENT_ROLE);
 
         Set<RoleRepresentation> composites = rolesRsc.get("role-a").getRoleComposites();
 
@@ -126,7 +127,7 @@ public class ClientRolesTest extends AbstractClientTest {
         Assert.assertNames(clientComposites, "role-b");
 
         rolesRsc.get("role-a").deleteComposites(l);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientRoleResourceCompositesPath(clientDbId, "role-a"), l);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientRoleResourceCompositesPath(clientDbId, "role-a"), l, ResourceType.CLIENT_ROLE);
 
         assertFalse(rolesRsc.get("role-a").toRepresentation().isComposite());
         assertEquals(0, rolesRsc.get("role-a").getRoleComposites().size());
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientTemplateProtocolMapperTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientTemplateProtocolMapperTest.java
index 1036005..5a82f0d 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientTemplateProtocolMapperTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientTemplateProtocolMapperTest.java
@@ -29,6 +29,7 @@ import org.junit.runners.MethodSorters;
 import org.keycloak.admin.client.resource.ClientTemplatesResource;
 import org.keycloak.admin.client.resource.ProtocolMappersResource;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.protocol.saml.SamlProtocol;
 import org.keycloak.representations.idm.ClientTemplateRepresentation;
@@ -100,7 +101,7 @@ public class ClientTemplateProtocolMapperTest extends AbstractProtocolMapperTest
         resp.close();
         String createdId = ApiUtil.getCreatedId(resp);
 
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateProtocolMapperPath(samlClientTemplateId, createdId), rep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateProtocolMapperPath(samlClientTemplateId, createdId), rep, ResourceType.PROTOCOL_MAPPER);
 
         assertEquals(totalMappers + 1, samlMappersRsc.getMappers().size());
         assertEquals(totalSamlMappers + 1, samlMappersRsc.getMappersPerProtocol("saml").size());
@@ -125,7 +126,7 @@ public class ClientTemplateProtocolMapperTest extends AbstractProtocolMapperTest
         resp.close();
         String createdId = ApiUtil.getCreatedId(resp);
 
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateProtocolMapperPath(oidcClientTemplateId, createdId), rep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateProtocolMapperPath(oidcClientTemplateId, createdId), rep, ResourceType.PROTOCOL_MAPPER);
 
         assertEquals(totalMappers + 1, oidcMappersRsc.getMappers().size());
         assertEquals(totalOidcMappers + 1, oidcMappersRsc.getMappersPerProtocol("openid-connect").size());
@@ -141,13 +142,13 @@ public class ClientTemplateProtocolMapperTest extends AbstractProtocolMapperTest
         Response resp = samlMappersRsc.createMapper(rep);
         resp.close();
         String createdId = ApiUtil.getCreatedId(resp);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateProtocolMapperPath(samlClientTemplateId, createdId), rep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateProtocolMapperPath(samlClientTemplateId, createdId), rep, ResourceType.PROTOCOL_MAPPER);
 
         rep.getConfig().put("role", "account.manage-account");
         rep.setId(createdId);
         rep.setConsentRequired(false);
         samlMappersRsc.update(createdId, rep);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientTemplateProtocolMapperPath(samlClientTemplateId, createdId), rep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientTemplateProtocolMapperPath(samlClientTemplateId, createdId), rep, ResourceType.PROTOCOL_MAPPER);
 
         ProtocolMapperRepresentation updated = samlMappersRsc.getMapperById(createdId);
         assertEqualMappers(rep, updated);
@@ -160,13 +161,13 @@ public class ClientTemplateProtocolMapperTest extends AbstractProtocolMapperTest
         Response resp = oidcMappersRsc.createMapper(rep);
         resp.close();
         String createdId = ApiUtil.getCreatedId(resp);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateProtocolMapperPath(oidcClientTemplateId, createdId), rep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateProtocolMapperPath(oidcClientTemplateId, createdId), rep, ResourceType.PROTOCOL_MAPPER);
 
         rep.getConfig().put("role", "myotherrole");
         rep.setId(createdId);
         rep.setConsentRequired(false);
         oidcMappersRsc.update(createdId, rep);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientTemplateProtocolMapperPath(oidcClientTemplateId, createdId), rep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientTemplateProtocolMapperPath(oidcClientTemplateId, createdId), rep, ResourceType.PROTOCOL_MAPPER);
 
         ProtocolMapperRepresentation updated = oidcMappersRsc.getMapperById(createdId);
         assertEqualMappers(rep, updated);
@@ -179,10 +180,10 @@ public class ClientTemplateProtocolMapperTest extends AbstractProtocolMapperTest
         Response resp = samlMappersRsc.createMapper(rep);
         resp.close();
         String createdId = ApiUtil.getCreatedId(resp);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateProtocolMapperPath(samlClientTemplateId, createdId), rep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateProtocolMapperPath(samlClientTemplateId, createdId), rep, ResourceType.PROTOCOL_MAPPER);
 
         samlMappersRsc.delete(createdId);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientTemplateProtocolMapperPath(samlClientTemplateId, createdId));
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientTemplateProtocolMapperPath(samlClientTemplateId, createdId), ResourceType.PROTOCOL_MAPPER);
 
         try {
             samlMappersRsc.getMapperById(createdId);
@@ -199,10 +200,10 @@ public class ClientTemplateProtocolMapperTest extends AbstractProtocolMapperTest
         Response resp = oidcMappersRsc.createMapper(rep);
         resp.close();
         String createdId = ApiUtil.getCreatedId(resp);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateProtocolMapperPath(oidcClientTemplateId, createdId), rep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateProtocolMapperPath(oidcClientTemplateId, createdId), rep, ResourceType.PROTOCOL_MAPPER);
 
         oidcMappersRsc.delete(createdId);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientTemplateProtocolMapperPath(oidcClientTemplateId, createdId));
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientTemplateProtocolMapperPath(oidcClientTemplateId, createdId), ResourceType.PROTOCOL_MAPPER);
 
         try {
             oidcMappersRsc.getMapperById(createdId);
@@ -227,13 +228,13 @@ public class ClientTemplateProtocolMapperTest extends AbstractProtocolMapperTest
         resp.close();
         String templateId = ApiUtil.getCreatedId(resp);
 
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateResourcePath(templateId), rep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateResourcePath(templateId), rep, ResourceType.CLIENT_TEMPLATE);
 
         return templateId;
     }
 
     private void removeTemplate(String templateId) {
         clientTemplates().get(templateId).remove();
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientTemplateResourcePath(templateId));
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientTemplateResourcePath(templateId), ResourceType.CLIENT_TEMPLATE);
     }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientTemplateTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientTemplateTest.java
index 2b469a9..113630a 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientTemplateTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientTemplateTest.java
@@ -32,6 +32,7 @@ import org.junit.Test;
 import org.keycloak.admin.client.resource.ClientTemplatesResource;
 import org.keycloak.admin.client.resource.RoleMappingResource;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.AccountRoles;
 import org.keycloak.models.Constants;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
@@ -137,7 +138,7 @@ public class ClientTemplateTest extends AbstractClientTest {
 
         clientTemplates().get(template1Id).update(templateRep);
 
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientTemplateResourcePath(template1Id), templateRep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientTemplateResourcePath(template1Id), templateRep, ResourceType.CLIENT_TEMPLATE);
 
         // Assert updated attributes
         templateRep = clientTemplates().get(template1Id).toRepresentation();
@@ -161,7 +162,7 @@ public class ClientTemplateTest extends AbstractClientTest {
 
         // Add role2 as composite to role1
         testRealmResource().roles().get("role1").addComposites(Collections.singletonList(roleRep2));
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.roleResourceCompositesPath("role1"), Collections.singletonList(roleRep2));
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.roleResourceCompositesPath("role1"), Collections.singletonList(roleRep2), ResourceType.REALM_ROLE);
 
         // create client template
         ClientTemplateRepresentation templateRep = new ClientTemplateRepresentation();
@@ -175,10 +176,10 @@ public class ClientTemplateTest extends AbstractClientTest {
         RoleMappingResource scopesResource = clientTemplates().get(templateId).getScopeMappings();
 
         scopesResource.realmLevel().add(Collections.singletonList(roleRep1));
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateScopeMappingsRealmLevelPath(templateId), Collections.singletonList(roleRep1));
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateScopeMappingsRealmLevelPath(templateId), Collections.singletonList(roleRep1), ResourceType.REALM_SCOPE_MAPPING);
 
         scopesResource.clientLevel(accountMgmtId).add(Collections.singletonList(viewAccountRoleRep));
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateScopeMappingsClientLevelPath(templateId, accountMgmtId), Collections.singletonList(viewAccountRoleRep));
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateScopeMappingsClientLevelPath(templateId, accountMgmtId), Collections.singletonList(viewAccountRoleRep), ResourceType.CLIENT_SCOPE_MAPPING);
 
         // test that scopes are available (also through composite role)
         List<RoleRepresentation> allRealm = scopesResource.realmLevel().listAll();
@@ -197,10 +198,10 @@ public class ClientTemplateTest extends AbstractClientTest {
 
         // remove scopes
         scopesResource.realmLevel().remove(Collections.singletonList(roleRep1));
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientTemplateScopeMappingsRealmLevelPath(templateId), Collections.singletonList(roleRep1));
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientTemplateScopeMappingsRealmLevelPath(templateId), Collections.singletonList(roleRep1), ResourceType.REALM_SCOPE_MAPPING);
 
         scopesResource.clientLevel(accountMgmtId).remove(Collections.singletonList(viewAccountRoleRep));
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientTemplateScopeMappingsClientLevelPath(templateId, accountMgmtId), Collections.singletonList(viewAccountRoleRep));
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientTemplateScopeMappingsClientLevelPath(templateId, accountMgmtId), Collections.singletonList(viewAccountRoleRep), ResourceType.CLIENT_SCOPE_MAPPING);
 
         // assert scopes are removed
         allRealm = scopesResource.realmLevel().listAll();
@@ -255,7 +256,7 @@ public class ClientTemplateTest extends AbstractClientTest {
 
         // Add realm role to scopes of clientTemplate
         clientTemplates().get(templateId).getScopeMappings().realmLevel().add(Collections.singletonList(roleRep));
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateScopeMappingsRealmLevelPath(templateId), Collections.singletonList(roleRep));
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateScopeMappingsRealmLevelPath(templateId), Collections.singletonList(roleRep), ResourceType.REALM_SCOPE_MAPPING);
 
         List<RoleRepresentation> roleReps = clientTemplates().get(templateId).getScopeMappings().realmLevel().listAll();
         Assert.assertEquals(1, roleReps.size());
@@ -263,7 +264,7 @@ public class ClientTemplateTest extends AbstractClientTest {
 
         // Remove realm role
         testRealmResource().roles().deleteRole("foo-role");
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.roleResourcePath("foo-role"));
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.roleResourcePath("foo-role"), ResourceType.REALM_ROLE);
 
         // Get scope mappings
         roleReps = clientTemplates().get(templateId).getScopeMappings().realmLevel().listAll();
@@ -278,7 +279,7 @@ public class ClientTemplateTest extends AbstractClientTest {
         roleRep.setName(roleName);
         testRealmResource().roles().create(roleRep);
 
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.roleResourcePath(roleName), roleRep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.roleResourcePath(roleName), roleRep, ResourceType.REALM_ROLE);
 
         return testRealmResource().roles().get(roleName).toRepresentation();
     }
@@ -329,14 +330,14 @@ public class ClientTemplateTest extends AbstractClientTest {
         resp.close();
         String templateId = ApiUtil.getCreatedId(resp);
 
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateResourcePath(templateId), templateRep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateResourcePath(templateId), templateRep, ResourceType.CLIENT_TEMPLATE);
 
         return templateId;
     }
 
     private void removeTemplate(String templateId) {
         clientTemplates().get(templateId).remove();
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientTemplateResourcePath(templateId));
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientTemplateResourcePath(templateId), ResourceType.CLIENT_TEMPLATE);
     }
 
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientTest.java
index 5216c36..5dddbc5 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/ClientTest.java
@@ -19,13 +19,12 @@ package org.keycloak.testsuite.admin.client;
 
 import java.util.List;
 
-import org.junit.Rule;
 import org.junit.Test;
 import org.keycloak.admin.client.resource.ClientResource;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.testsuite.util.AdminEventPaths;
-import org.keycloak.testsuite.util.AssertAdminEvents;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -66,7 +65,7 @@ public class ClientTest extends AbstractClientTest {
         clientRsc.remove();
         assertNull(findClientResource("deleteMe"));
 
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientResourcePath(clientDbId));
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientResourcePath(clientDbId), ResourceType.CLIENT);
     }
 
     @Test
@@ -87,7 +86,7 @@ public class ClientTest extends AbstractClientTest {
         ClientRepresentation expectedClientRep = new ClientRepresentation();
         expectedClientRep.setClientId("updateMe");
         expectedClientRep.setName("iWasUpdated");
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientResourcePath(clientRep.getId()), expectedClientRep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientResourcePath(clientRep.getId()), expectedClientRep, ResourceType.CLIENT);
     }
 
     @Test
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/CredentialsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/CredentialsTest.java
index a9d038e..b76e670 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/CredentialsTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/CredentialsTest.java
@@ -22,6 +22,7 @@ import org.junit.Before;
 import org.junit.Test;
 import org.keycloak.admin.client.resource.ClientAttributeCertificateResource;
 import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.representations.KeyStoreConfig;
 import org.keycloak.events.admin.OperationType;
@@ -70,7 +71,7 @@ public class CredentialsTest extends AbstractClientTest {
 
         CredentialRepresentation secretRep = new CredentialRepresentation();
         secretRep.setType(CredentialRepresentation.SECRET);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.ACTION, AdminEventPaths.clientGenerateSecretPath(accountClientDbId), secretRep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.ACTION, AdminEventPaths.clientGenerateSecretPath(accountClientDbId), secretRep, ResourceType.CLIENT);
 
         assertNotNull(oldCredential);
         assertNotNull(newCredential);
@@ -91,7 +92,7 @@ public class CredentialsTest extends AbstractClientTest {
         ClientRepresentation testedRep = new ClientRepresentation();
         testedRep.setClientId(rep.getClientId());
         testedRep.setRegistrationAccessToken(newToken);
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.ACTION, AdminEventPaths.clientRegenerateRegistrationAccessTokenPath(accountClientDbId), testedRep);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.ACTION, AdminEventPaths.clientRegenerateRegistrationAccessTokenPath(accountClientDbId), testedRep, ResourceType.CLIENT);
     }
 
     @Test
@@ -102,7 +103,7 @@ public class CredentialsTest extends AbstractClientTest {
         assertEquals(cert.getCertificate(), certFromGet.getCertificate());
         assertEquals(cert.getPrivateKey(), certFromGet.getPrivateKey());
 
-        assertAdminEvents.assertEvent(getRealmId(), OperationType.ACTION, AdminEventPaths.clientCertificateGenerateSecretPath(accountClientDbId, "jwt.credential"), cert);
+        assertAdminEvents.assertEvent(getRealmId(), OperationType.ACTION, AdminEventPaths.clientCertificateGenerateSecretPath(accountClientDbId, "jwt.credential"), cert, ResourceType.CLIENT);
     }
 
     @Test
@@ -147,8 +148,7 @@ public class CredentialsTest extends AbstractClientTest {
         // Get the certificate - to make sure cert was properly updated, and privateKey is null
         cert = certRsc.getKeyInfo();
         assertEquals("cert properly set", certificate2, cert.getCertificate());
-        // TODO: KEYCLOAK-2981
-        //assertNull("privateKey nullified", cert.getPrivateKey());
+        assertNull("privateKey nullified", cert.getPrivateKey());
 
         // Re-upload the private key
         certRsc.uploadJks(keyCertForm);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/SessionTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/SessionTest.java
index 8685603..0ba2a41 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/SessionTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/client/SessionTest.java
@@ -23,6 +23,7 @@ import org.junit.Before;
 import org.junit.Test;
 import org.keycloak.admin.client.resource.ClientResource;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.representations.idm.UserSessionRepresentation;
 import org.keycloak.testsuite.auth.page.account.AccountManagement;
@@ -47,8 +48,8 @@ public class SessionTest extends AbstractClientTest {
         if (!testUserCreated) {
             createTestUserWithAdminClient();
 
-            assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.userResourcePath(testUser.getId()));
-            assertAdminEvents.assertEvent(getRealmId(), OperationType.ACTION, AdminEventPaths.userResetPasswordPath(testUser.getId()));
+            assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.userResourcePath(testUser.getId()), ResourceType.USER);
+            assertAdminEvents.assertEvent(getRealmId(), OperationType.ACTION, AdminEventPaths.userResetPasswordPath(testUser.getId()), ResourceType.USER);
         }
         testUserCreated = true;
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientRegTrustedHostTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientRegTrustedHostTest.java
new file mode 100644
index 0000000..f430e6a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientRegTrustedHostTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.admin;
+
+import java.util.List;
+
+import javax.ws.rs.core.Response;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.admin.client.resource.ClientRegistrationTrustedHostResource;
+import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
+import org.keycloak.representations.idm.ClientRegistrationTrustedHostRepresentation;
+import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.util.AdminEventPaths;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ClientRegTrustedHostTest extends AbstractAdminTest {
+
+
+    private ClientRegistrationTrustedHostResource resource;
+
+    @Before
+    public void before() {
+        resource = realm.clientRegistrationTrustedHost();
+    }
+
+    @Test
+    public void testInitialAccessTokens() {
+
+        // Successfully create "localhost1" rep
+        ClientRegistrationTrustedHostRepresentation rep = new ClientRegistrationTrustedHostRepresentation();
+        rep.setHostName("localhost1");
+        rep.setCount(5);
+
+        Response res = resource.create(rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientRegistrationTrustedHostPath("localhost1"), rep, ResourceType.CLIENT_REGISTRATION_TRUSTED_HOST_MODEL);
+        res.close();
+
+        // Failed to create conflicting rep "localhost1" again
+        res = resource.create(rep);
+        Assert.assertEquals(409, res.getStatus());
+        assertAdminEvents.assertEmpty();
+        res.close();
+
+        // Successfully create "localhost2" rep
+        rep = new ClientRegistrationTrustedHostRepresentation();
+        rep.setHostName("localhost2");
+        rep.setCount(10);
+
+        res = resource.create(rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientRegistrationTrustedHostPath("localhost2"), rep, ResourceType.CLIENT_REGISTRATION_TRUSTED_HOST_MODEL);
+        res.close();
+
+        // Get "localhost1"
+        rep = resource.get("localhost1");
+        assertRep(rep, "localhost1", 5, 5);
+
+        // Update "localhost1"
+        rep.setCount(7);
+        rep.setRemainingCount(7);
+        resource.update("localhost1", rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.clientRegistrationTrustedHostPath("localhost1"), rep, ResourceType.CLIENT_REGISTRATION_TRUSTED_HOST_MODEL);
+
+        // Get all
+        List<ClientRegistrationTrustedHostRepresentation> alls = resource.list();
+        Assert.assertEquals(2, alls.size());
+        assertRep(findByHost(alls, "localhost1"), "localhost1", 7, 7);
+        assertRep(findByHost(alls, "localhost2"), "localhost2", 10, 10);
+
+        // Delete "localhost1"
+        resource.delete("localhost1");
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientRegistrationTrustedHostPath("localhost1"), ResourceType.CLIENT_REGISTRATION_TRUSTED_HOST_MODEL);
+
+        // Get all and check just "localhost2" available
+        alls = resource.list();
+        Assert.assertEquals(1, alls.size());
+        assertRep(alls.get(0), "localhost2", 10, 10);
+    }
+
+    private ClientRegistrationTrustedHostRepresentation findByHost(List<ClientRegistrationTrustedHostRepresentation> list, String hostName) {
+        for (ClientRegistrationTrustedHostRepresentation rep : list) {
+            if (hostName.equals(rep.getHostName())) {
+                return rep;
+            }
+        }
+        return null;
+    }
+
+    private void assertRep(ClientRegistrationTrustedHostRepresentation rep, String expectedHost, int expectedCount, int expectedRemaining) {
+        Assert.assertEquals(expectedHost, rep.getHostName());
+        Assert.assertEquals(expectedCount, rep.getCount().intValue());
+        Assert.assertEquals(expectedRemaining, rep.getRemainingCount().intValue());
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
index fc7a341..ee06750 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ClientTest.java
@@ -24,6 +24,7 @@ import org.keycloak.admin.client.resource.ProtocolMappersResource;
 import org.keycloak.admin.client.resource.RoleMappingResource;
 import org.keycloak.common.util.Time;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.AccountRoles;
 import org.keycloak.models.Constants;
 import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
@@ -77,7 +78,7 @@ public class ClientTest extends AbstractAdminTest {
         response.close();
         String id = ApiUtil.getCreatedId(response);
 
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientResourcePath(id), rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientResourcePath(id), rep, ResourceType.CLIENT);
 
         rep.setId(id);
 
@@ -98,7 +99,7 @@ public class ClientTest extends AbstractAdminTest {
 
         realm.clients().get(id).remove();
 
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientResourcePath(id));
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientResourcePath(id), ResourceType.CLIENT);
     }
 
     @Test
@@ -128,7 +129,7 @@ public class ClientTest extends AbstractAdminTest {
         OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("password", "test-user@localhost", "password");
         assertEquals(200, response.getStatusCode());
 
-        OAuthClient.AuthorizationCodeResponse codeResponse = oauth.doLogin("test-user@localhost", "password");
+        OAuthClient.AuthorizationEndpointResponse codeResponse = oauth.doLogin("test-user@localhost", "password");
 
         OAuthClient.AccessTokenResponse response2 = oauth.doAccessTokenRequest(codeResponse.getCode(), "password");
         assertEquals(200, response2.getStatusCode());
@@ -151,19 +152,19 @@ public class ClientTest extends AbstractAdminTest {
         RoleRepresentation role = new RoleRepresentation("test", "test", false);
         realm.clients().get(id).roles().create(role);
 
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientRoleResourcePath(id, "test"), role);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientRoleResourcePath(id, "test"), role, ResourceType.CLIENT_ROLE);
 
         ClientRepresentation foundClientRep = realm.clients().get(id).toRepresentation();
         foundClientRep.setDefaultRoles(new String[]{"test"});
         realm.clients().get(id).update(foundClientRep);
 
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.clientResourcePath(id), rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.clientResourcePath(id), rep, ResourceType.CLIENT);
 
         assertArrayEquals(new String[]{"test"}, realm.clients().get(id).toRepresentation().getDefaultRoles());
 
         realm.clients().get(id).roles().deleteRole("test");
 
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientRoleResourcePath(id, "test"));
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientRoleResourcePath(id, "test"), ResourceType.CLIENT_ROLE);
 
         assertNull(realm.clients().get(id).toRepresentation().getDefaultRoles());
     }
@@ -187,7 +188,7 @@ public class ClientTest extends AbstractAdminTest {
 
         realm.clients().get(client.getId()).update(newClient);
 
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.clientResourcePath(client.getId()), newClient);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.clientResourcePath(client.getId()), newClient, ResourceType.CLIENT);
 
         ClientRepresentation storedClient = realm.clients().get(client.getId()).toRepresentation();
 
@@ -197,7 +198,7 @@ public class ClientTest extends AbstractAdminTest {
 
         realm.clients().get(client.getId()).update(newClient);
 
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.clientResourcePath(client.getId()), newClient);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.clientResourcePath(client.getId()), newClient, ResourceType.CLIENT);
 
         storedClient = realm.clients().get(client.getId()).toRepresentation();
         assertClient(client, storedClient);
@@ -223,7 +224,7 @@ public class ClientTest extends AbstractAdminTest {
         PushNotBeforeAction pushNotBefore = testingClient.testApp().getAdminPushNotBefore();
         assertEquals(client.getNotBefore().intValue(), pushNotBefore.getNotBefore());
 
-        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.clientPushRevocationPath(id));
+        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.clientPushRevocationPath(id), ResourceType.CLIENT);
     }
 
     private ClientRepresentation createAppClient() {
@@ -242,7 +243,7 @@ public class ClientTest extends AbstractAdminTest {
         String id = ApiUtil.getCreatedId(response);
         response.close();
 
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientResourcePath(id), client);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientResourcePath(id), client, ResourceType.CLIENT);
 
         client.setId(id);
         return client;
@@ -259,14 +260,14 @@ public class ClientTest extends AbstractAdminTest {
         realm.clients().get(id).registerNode(Collections.singletonMap("node", myhost));
         realm.clients().get(id).registerNode(Collections.singletonMap("node", "invalid"));
 
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientNodePath(id, myhost));
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientNodePath(id, "invalid"));
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientNodePath(id, myhost), ResourceType.CLUSTER_NODE);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientNodePath(id, "invalid"), ResourceType.CLUSTER_NODE);
 
         GlobalRequestResult result = realm.clients().get(id).testNodesAvailable();
         assertEquals(1, result.getSuccessRequests().size());
         assertEquals(1, result.getFailedRequests().size());
 
-        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.clientTestNodesAvailablePath(id), result);
+        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.clientTestNodesAvailablePath(id), result, ResourceType.CLUSTER_NODE);
 
         TestAvailabilityAction testAvailable = testingClient.testApp().getTestAvailable();
         assertEquals("test-app", testAvailable.getResource());
@@ -275,7 +276,7 @@ public class ClientTest extends AbstractAdminTest {
 
         realm.clients().get(id).unregisterNode("invalid");
 
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientNodePath(id, "invalid"));
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientNodePath(id, "invalid"), ResourceType.CLUSTER_NODE);
 
         assertEquals(1, realm.clients().get(id).toRepresentation().getRegisteredNodes().size());
     }
@@ -294,6 +295,9 @@ public class ClientTest extends AbstractAdminTest {
         Map<String, Long> offlineSessionCount = realm.clients().get(id).getOfflineSessionCount();
         assertEquals(new Long(0), offlineSessionCount.get("count"));
 
+        List<UserSessionRepresentation> userSessions = realm.users().get(userId).getOfflineSessions(id);
+        assertEquals("There should be no offline sessions", 0, userSessions.size());
+
         oauth.realm(REALM_NAME);
         oauth.redirectUri(client.getRedirectUris().get(0));
         oauth.scope(OAuth2Constants.OFFLINE_ACCESS);
@@ -307,6 +311,17 @@ public class ClientTest extends AbstractAdminTest {
         List<UserSessionRepresentation> offlineUserSessions = realm.clients().get(id).getOfflineUserSessions(0, 100);
         assertEquals(1, offlineUserSessions.size());
         assertEquals("testuser", offlineUserSessions.get(0).getUsername());
+
+        userSessions = realm.users().get(userId).getOfflineSessions(id);
+        assertEquals("There should be one offline session", 1, userSessions.size());
+        assertOfflineSession(offlineUserSessions.get(0), userSessions.get(0));
+    }
+
+    private void assertOfflineSession(UserSessionRepresentation expected, UserSessionRepresentation actual) {
+        assertEquals("id", expected.getId(), actual.getId());
+        assertEquals("userId", expected.getUserId(), actual.getUserId());
+        assertEquals("userName", expected.getUsername(), actual.getUsername());
+        assertEquals("clients", expected.getClients(), actual.getClients());
     }
 
     @Test
@@ -324,28 +339,28 @@ public class ClientTest extends AbstractAdminTest {
         realm.roles().create(roleRep1);
         realm.roles().create(roleRep2);
 
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.roleResourcePath("role1"), roleRep1);
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.roleResourcePath("role2"), roleRep2);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.roleResourcePath("role1"), roleRep1, ResourceType.REALM_ROLE);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.roleResourcePath("role2"), roleRep2, ResourceType.REALM_ROLE);
 
         roleRep1 = realm.roles().get("role1").toRepresentation();
         roleRep2 = realm.roles().get("role2").toRepresentation();
 
         realm.roles().get("role1").addComposites(Collections.singletonList(roleRep2));
 
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.roleResourceCompositesPath("role1"), Collections.singletonList(roleRep2));
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.roleResourceCompositesPath("role1"), Collections.singletonList(roleRep2), ResourceType.REALM_ROLE);
 
         String accountMgmtId = realm.clients().findByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID).get(0).getId();
         RoleRepresentation viewAccountRoleRep = realm.clients().get(accountMgmtId).roles().get(AccountRoles.VIEW_PROFILE).toRepresentation();
 
         scopesResource.realmLevel().add(Collections.singletonList(roleRep1));
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientScopeMappingsRealmLevelPath(id), Collections.singletonList(roleRep1));
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientScopeMappingsRealmLevelPath(id), Collections.singletonList(roleRep1), ResourceType.REALM_SCOPE_MAPPING);
 
         scopesResource.clientLevel(accountMgmtId).add(Collections.singletonList(viewAccountRoleRep));
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientScopeMappingsClientLevelPath(id, accountMgmtId), Collections.singletonList(viewAccountRoleRep));
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientScopeMappingsClientLevelPath(id, accountMgmtId), Collections.singletonList(viewAccountRoleRep), ResourceType.CLIENT_SCOPE_MAPPING);
 
         Assert.assertNames(scopesResource.realmLevel().listAll(), "role1");
         Assert.assertNames(scopesResource.realmLevel().listEffective(), "role1", "role2");
-        Assert.assertNames(scopesResource.realmLevel().listAvailable(), "offline_access");
+        Assert.assertNames(scopesResource.realmLevel().listAvailable(), "offline_access", Constants.AUTHZ_UMA_AUTHORIZATION);
 
         Assert.assertNames(scopesResource.clientLevel(accountMgmtId).listAll(), AccountRoles.VIEW_PROFILE);
         Assert.assertNames(scopesResource.clientLevel(accountMgmtId).listEffective(), AccountRoles.VIEW_PROFILE);
@@ -355,14 +370,14 @@ public class ClientTest extends AbstractAdminTest {
         Assert.assertNames(scopesResource.getAll().getClientMappings().get(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID).getMappings(), AccountRoles.VIEW_PROFILE);
 
         scopesResource.realmLevel().remove(Collections.singletonList(roleRep1));
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientScopeMappingsRealmLevelPath(id), Collections.singletonList(roleRep1));
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientScopeMappingsRealmLevelPath(id), Collections.singletonList(roleRep1), ResourceType.REALM_SCOPE_MAPPING);
 
         scopesResource.clientLevel(accountMgmtId).remove(Collections.singletonList(viewAccountRoleRep));
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientScopeMappingsClientLevelPath(id, accountMgmtId), Collections.singletonList(viewAccountRoleRep));
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientScopeMappingsClientLevelPath(id, accountMgmtId), Collections.singletonList(viewAccountRoleRep), ResourceType.CLIENT_SCOPE_MAPPING);
 
         Assert.assertNames(scopesResource.realmLevel().listAll());
         Assert.assertNames(scopesResource.realmLevel().listEffective());
-        Assert.assertNames(scopesResource.realmLevel().listAvailable(), "offline_access", "role1", "role2");
+        Assert.assertNames(scopesResource.realmLevel().listAvailable(), "offline_access", Constants.AUTHZ_UMA_AUTHORIZATION, "role1", "role2");
         Assert.assertNames(scopesResource.clientLevel(accountMgmtId).listAll());
         Assert.assertNames(scopesResource.clientLevel(accountMgmtId).listAvailable(), AccountRoles.VIEW_PROFILE, AccountRoles.MANAGE_ACCOUNT);
         Assert.assertNames(scopesResource.clientLevel(accountMgmtId).listEffective());
@@ -400,7 +415,7 @@ public class ClientTest extends AbstractAdminTest {
         fooMapperId = location.substring(location.lastIndexOf("/") + 1);
         response.close();
 
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientProtocolMapperPath(clientDbId, fooMapperId), fooMapper);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientProtocolMapperPath(clientDbId, fooMapperId), fooMapper, ResourceType.PROTOCOL_MAPPER);
 
         fooMapper = mappersResource.getMapperById(fooMapperId);
         assertEquals(fooMapper.getName(), "foo");
@@ -409,14 +424,14 @@ public class ClientTest extends AbstractAdminTest {
         fooMapper.setProtocolMapper("foo-mapper-updated");
         mappersResource.update(fooMapperId, fooMapper);
 
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.clientProtocolMapperPath(clientDbId, fooMapperId), fooMapper);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.clientProtocolMapperPath(clientDbId, fooMapperId), fooMapper, ResourceType.PROTOCOL_MAPPER);
 
         fooMapper = mappersResource.getMapperById(fooMapperId);
         assertEquals(fooMapper.getProtocolMapper(), "foo-mapper-updated");
 
         // Remove foo mapper
         mappersResource.delete(fooMapperId);
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientProtocolMapperPath(clientDbId, fooMapperId));
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientProtocolMapperPath(clientDbId, fooMapperId), ResourceType.PROTOCOL_MAPPER);
         try {
             mappersResource.getMapperById(fooMapperId);
             fail("Not expected to find deleted mapper");
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ConsentsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ConsentsTest.java
new file mode 100644
index 0000000..fb0a863
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ConsentsTest.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.admin;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.admin.client.resource.UserResource;
+import org.keycloak.admin.client.resource.UsersResource;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.representations.idm.UserSessionRepresentation;
+import org.keycloak.testsuite.AbstractKeycloakTest;
+import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.pages.ConsentPage;
+import org.keycloak.testsuite.pages.LoginPage;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient;
+import static org.keycloak.testsuite.admin.ApiUtil.resetUserPassword;
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class ConsentsTest extends AbstractKeycloakTest {
+
+    final static String REALM_PROV_NAME = "provider";
+    final static String REALM_CONS_NAME = "consumer";
+
+    final static String IDP_OIDC_ALIAS = "kc-oidc-idp";
+    final static String IDP_OIDC_PROVIDER_ID = "keycloak-oidc";
+
+    final static String CLIENT_ID = "brokerapp";
+    final static String CLIENT_SECRET = "secret";
+
+    final static String USER_LOGIN = "testuser";
+    final static String USER_EMAIL = "user@localhost.com";
+    final static String USER_PASSWORD = "password";
+    final static String USER_FIRSTNAME = "User";
+    final static String USER_LASTNAME = "Tester";
+
+    protected RealmRepresentation createProviderRealm() {
+        RealmRepresentation realm = new RealmRepresentation();
+        realm.setRealm(REALM_PROV_NAME);
+        realm.setEnabled(true);
+
+        return realm;
+    }
+
+    protected RealmRepresentation createConsumerRealm() {
+        RealmRepresentation realm = new RealmRepresentation();
+        realm.setRealm(REALM_CONS_NAME);
+        realm.setEnabled(true);
+
+        return realm;
+    }
+
+    protected List<ClientRepresentation> createProviderClients() {
+        ClientRepresentation client = new ClientRepresentation();
+        client.setId(CLIENT_ID);
+        client.setName(CLIENT_ID);
+        client.setSecret(CLIENT_SECRET);
+        client.setEnabled(true);
+        client.setConsentRequired(true);
+
+        client.setRedirectUris(Collections.singletonList(getAuthRoot() +
+                "/auth/realms/" + REALM_CONS_NAME + "/broker/" + IDP_OIDC_ALIAS + "/endpoint/*"));
+
+        client.setAdminUrl(getAuthRoot() +
+                "/auth/realms/" + REALM_CONS_NAME + "/broker/" + IDP_OIDC_ALIAS + "/endpoint");
+
+        return Collections.singletonList(client);
+    }
+
+    protected IdentityProviderRepresentation setUpIdentityProvider() {
+        IdentityProviderRepresentation idp = createIdentityProvider(IDP_OIDC_ALIAS, IDP_OIDC_PROVIDER_ID);
+
+        Map<String, String> config = idp.getConfig();
+
+        config.put("clientId", CLIENT_ID);
+        config.put("clientSecret", CLIENT_SECRET);
+        config.put("prompt", "login");
+        config.put("authorizationUrl", getAuthRoot() + "/auth/realms/" + REALM_PROV_NAME + "/protocol/openid-connect/auth");
+        config.put("tokenUrl", getAuthRoot() + "/auth/realms/" + REALM_PROV_NAME + "/protocol/openid-connect/token");
+        config.put("logoutUrl", getAuthRoot() + "/auth/realms/" + REALM_PROV_NAME + "/protocol/openid-connect/logout");
+        config.put("userInfoUrl", getAuthRoot() + "/auth/realms/" + REALM_PROV_NAME + "/protocol/openid-connect/userinfo");
+        config.put("defaultScope", "email profile");
+        config.put("backchannelSupported", "true");
+
+        return idp;
+    }
+
+    protected String getUserLogin() {
+        return USER_LOGIN;
+    }
+
+    protected String getUserPassword() {
+        return USER_PASSWORD;
+    }
+
+    protected String getUserEmail() {
+        return USER_EMAIL;
+    }
+
+    protected String getUserFirstName() {
+        return USER_FIRSTNAME;
+    }
+
+    protected String getUserLastName() {
+        return USER_LASTNAME;
+    }
+    protected String providerRealmName() {
+        return REALM_PROV_NAME;
+    }
+
+    protected String consumerRealmName() {
+        return REALM_CONS_NAME;
+    }
+
+    protected String getIDPAlias() {
+        return IDP_OIDC_ALIAS;
+    }
+
+
+    @Page
+    protected LoginPage accountLoginPage;
+
+    @Page
+    protected ConsentPage consentPage;
+
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+        RealmRepresentation providerRealm = createProviderRealm();
+        RealmRepresentation consumerRealm = createConsumerRealm();
+
+        testRealms.add(providerRealm);
+        testRealms.add(consumerRealm);
+    }
+
+    @Before
+    public void createUser() {
+        log.debug("creating user for realm " + providerRealmName());
+
+        UserRepresentation user = new UserRepresentation();
+        user.setUsername(getUserLogin());
+        user.setEmail(getUserEmail());
+        user.setFirstName(getUserFirstName());
+        user.setLastName(getUserLastName());
+        user.setEmailVerified(true);
+        user.setEnabled(true);
+
+        RealmResource realmResource = adminClient.realm(providerRealmName());
+        String userId = createUserWithAdminClient(realmResource, user);
+
+        resetUserPassword(realmResource.users().get(userId), getUserPassword(), false);
+    }
+
+    @Before
+    public void addIdentityProviderToProviderRealm() {
+        log.debug("adding identity provider to realm " + consumerRealmName());
+
+        RealmResource realm = adminClient.realm(consumerRealmName());
+        realm.identityProviders().create(setUpIdentityProvider());
+    }
+
+    @Before
+    public void addClients() {
+        List<ClientRepresentation> clients = createProviderClients();
+        if (clients != null) {
+            RealmResource providerRealm = adminClient.realm(providerRealmName());
+            for (ClientRepresentation client : clients) {
+                log.debug("adding client " + client.getName() + " to realm " + providerRealmName());
+
+                providerRealm.clients().create(client);
+            }
+        }
+    }
+
+    protected String getAuthRoot() {
+        return suiteContext.getAuthServerInfo().getContextRoot().toString();
+    }
+
+    protected IdentityProviderRepresentation createIdentityProvider(String alias, String providerId) {
+        IdentityProviderRepresentation identityProviderRepresentation = new IdentityProviderRepresentation();
+
+        identityProviderRepresentation.setAlias(alias);
+        identityProviderRepresentation.setProviderId(providerId);
+        identityProviderRepresentation.setEnabled(true);
+
+        return identityProviderRepresentation;
+    }
+
+    private void waitForPage(String title) {
+        long startAt = System.currentTimeMillis();
+
+        while (!driver.getTitle().toLowerCase().contains(title)
+                && System.currentTimeMillis() - startAt < 200) {
+            try {
+                Thread.sleep(5);
+            } catch (InterruptedException ignore) {}
+        }
+    }
+
+    @Test
+    public void testConsents() {
+        driver.navigate().to(getAccountUrl(consumerRealmName()));
+
+        log.debug("Clicking social " + getIDPAlias());
+        accountLoginPage.clickSocial(getIDPAlias());
+
+        if (!driver.getCurrentUrl().contains("/auth/realms/" + providerRealmName() + "/")) {
+            log.debug("Not on provider realm page, url: " + driver.getCurrentUrl());
+        }
+
+        Assert.assertTrue("Driver should be on the provider realm page right now",
+                driver.getCurrentUrl().contains("/auth/realms/" + providerRealmName() + "/"));
+
+        log.debug("Logging in");
+        accountLoginPage.login(getUserLogin(), getUserPassword());
+
+        waitForPage("grant access");
+
+        Assert.assertTrue(consentPage.isCurrent());
+        consentPage.confirm();
+
+        Assert.assertTrue("We must be on correct realm right now",
+                driver.getCurrentUrl().contains("/auth/realms/" + consumerRealmName() + "/"));
+
+        UsersResource consumerUsers = adminClient.realm(consumerRealmName()).users();
+        Assert.assertTrue("There must be at least one user", consumerUsers.count() > 0);
+
+        List<UserRepresentation> users = consumerUsers.search("", 0, 5);
+
+        UserRepresentation foundUser = null;
+        for (UserRepresentation user : users) {
+            if (user.getUsername().equals(getUserLogin()) && user.getEmail().equals(getUserEmail())) {
+                foundUser = user;
+                break;
+            }
+        }
+
+        Assert.assertNotNull("There must be user " + getUserLogin() + " in realm " + consumerRealmName(),
+                foundUser);
+
+        // get user with the same username from provider realm
+        RealmResource providerRealm = adminClient.realm(providerRealmName());
+        users = providerRealm.users().search(null, foundUser.getFirstName(), foundUser.getLastName(), null, 0, 1);
+        Assert.assertEquals("Same user should be in provider realm", 1, users.size());
+
+        String userId = users.get(0).getId();
+        UserResource userResource = providerRealm.users().get(userId);
+
+        // list consents
+        List<Map<String, Object>> consents = userResource.getConsents();
+        Assert.assertEquals("There should be one consent", 1, consents.size());
+
+        Map<String, Object> consent = consents.get(0);
+        Assert.assertEquals("Consent should be given to " + CLIENT_ID, CLIENT_ID, consent.get("clientId"));
+
+        // list sessions
+        List<UserSessionRepresentation> sessions = userResource.getUserSessions();
+        Assert.assertEquals("There should be one active session", 1, sessions.size());
+
+        // revoke consent
+        userResource.revokeConsent(CLIENT_ID);
+
+        // list consents
+        consents = userResource.getConsents();
+        Assert.assertEquals("There should be no consents", 0, consents.size());
+
+        // list sessions
+        sessions = userResource.getUserSessions();
+        Assert.assertEquals("There should be no active session", 0, sessions.size());
+    }
+
+    private String getAccountUrl(String realmName) {
+        return getAuthRoot() + "/auth/realms/" + realmName + "/account";
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/event/AdminEventAuthDetailsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/event/AdminEventAuthDetailsTest.java
index 9413836..195f733 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/event/AdminEventAuthDetailsTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/event/AdminEventAuthDetailsTest.java
@@ -27,6 +27,7 @@ import org.junit.Test;
 import org.keycloak.admin.client.Keycloak;
 import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.AdminRoles;
 import org.keycloak.models.Constants;
 import org.keycloak.models.utils.KeycloakModelUtils;
@@ -136,6 +137,7 @@ public class AdminEventAuthDetailsTest extends AbstractAuthTest {
                     .realmId(realmUuid)
                     .operationType(OperationType.UPDATE)
                     .resourcePath(AdminEventPaths.userResourcePath(appUserId))
+                    .resourceType(ResourceType.USER)
                     .representation(rep)
                     .authDetails(expectedRealmId, expectedClientUuid, expectedUserId)
                     .assertEvent();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/group/GroupTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/group/GroupTest.java
index 988ecaf..0543238 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/group/GroupTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/group/GroupTest.java
@@ -23,6 +23,8 @@ import org.junit.Test;
 import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.admin.client.resource.RoleMappingResource;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
+import org.keycloak.models.Constants;
 import org.keycloak.models.RoleModel;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.idm.ClientRepresentation;
@@ -104,13 +106,13 @@ public class GroupTest extends AbstractGroupTest {
         Response response = realm.clients().create(client);
         response.close();
         String clientUuid = ApiUtil.getCreatedId(response);
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.clientResourcePath(clientUuid), client);
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.clientResourcePath(clientUuid), client, ResourceType.CLIENT);
         client = realm.clients().findByClientId("foo").get(0);
 
         RoleRepresentation role = new RoleRepresentation();
         role.setName("foo-role");
         realm.clients().get(client.getId()).roles().create(role);
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.clientRoleResourcePath(clientUuid, "foo-role"), role);
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.clientRoleResourcePath(clientUuid, "foo-role"), role, ResourceType.CLIENT_ROLE);
         role = realm.clients().get(client.getId()).roles().get("foo-role").toRepresentation();
 
         GroupRepresentation group = new GroupRepresentation();
@@ -120,10 +122,10 @@ public class GroupTest extends AbstractGroupTest {
         List<RoleRepresentation> list = new LinkedList<>();
         list.add(role);
         realm.groups().group(group.getId()).roles().clientLevel(client.getId()).add(list);
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupRolesClientRolesPath(group.getId(), clientUuid), list);
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupRolesClientRolesPath(group.getId(), clientUuid), list, ResourceType.CLIENT_ROLE_MAPPING);
 
         realm.clients().get(client.getId()).remove();
-        assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.clientResourcePath(clientUuid));
+        assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.clientResourcePath(clientUuid), ResourceType.CLIENT);
     }
 
     private GroupRepresentation createGroup(RealmResource realm, GroupRepresentation group) {
@@ -131,7 +133,7 @@ public class GroupTest extends AbstractGroupTest {
         String groupId = ApiUtil.getCreatedId(response);
         response.close();
 
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupPath(groupId), group);
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupPath(groupId), group, ResourceType.GROUP);
 
         // Set ID to the original rep
         group.setId(groupId);
@@ -170,13 +172,13 @@ public class GroupTest extends AbstractGroupTest {
         List<RoleRepresentation> roles = new LinkedList<>();
         roles.add(topRole);
         realm.groups().group(topGroup.getId()).roles().realmLevel().add(roles);
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupRolesRealmRolesPath(topGroup.getId()), roles);
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupRolesRealmRolesPath(topGroup.getId()), roles, ResourceType.REALM_ROLE_MAPPING);
 
         GroupRepresentation level2Group = new GroupRepresentation();
         level2Group.setName("level2");
         Response response = realm.groups().group(topGroup.getId()).subGroup(level2Group);
         response.close();
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupSubgroupsPath(topGroup.getId()), level2Group);
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupSubgroupsPath(topGroup.getId()), level2Group, ResourceType.GROUP);
 
         URI location = response.getLocation();
         final String level2Id = ApiUtil.getCreatedId(response);
@@ -197,20 +199,20 @@ public class GroupTest extends AbstractGroupTest {
         roles.clear();
         roles.add(level2Role);
         realm.groups().group(level2Group.getId()).roles().realmLevel().add(roles);
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupRolesRealmRolesPath(level2Group.getId()), roles);
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupRolesRealmRolesPath(level2Group.getId()), roles, ResourceType.REALM_ROLE_MAPPING);
 
         GroupRepresentation level3Group = new GroupRepresentation();
         level3Group.setName("level3");
         response = realm.groups().group(level2Group.getId()).subGroup(level3Group);
         response.close();
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupSubgroupsPath(level2Group.getId()), level3Group);
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupSubgroupsPath(level2Group.getId()), level3Group, ResourceType.GROUP);
 
         level3Group = realm.getGroupByPath("/top/level2/level3");
         Assert.assertNotNull(level3Group);
         roles.clear();
         roles.add(level3Role);
         realm.groups().group(level3Group.getId()).roles().realmLevel().add(roles);
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupRolesRealmRolesPath(level3Group.getId()), roles);
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupRolesRealmRolesPath(level3Group.getId()), roles, ResourceType.REALM_ROLE_MAPPING);
 
         topGroup = realm.getGroupByPath("/top");
         assertEquals(1, topGroup.getRealmRoles().size());
@@ -230,7 +232,7 @@ public class GroupTest extends AbstractGroupTest {
 
         UserRepresentation user = realm.users().search("direct-login", -1, -1).get(0);
         realm.users().get(user.getId()).joinGroup(level3Group.getId());
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userGroupPath(user.getId(), level3Group.getId()));
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userGroupPath(user.getId(), level3Group.getId()), ResourceType.GROUP_MEMBERSHIP);
 
         List<GroupRepresentation> membership = realm.users().get(user.getId()).groups();
         assertEquals(1, membership.size());
@@ -242,7 +244,7 @@ public class GroupTest extends AbstractGroupTest {
         assertTrue(token.getRealmAccess().getRoles().contains("level3Role"));
 
         realm.addDefaultGroup(level3Group.getId());
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.defaultGroupPath(level3Group.getId()));
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.defaultGroupPath(level3Group.getId()), ResourceType.GROUP);
 
         List<GroupRepresentation> defaultGroups = realm.getDefaultGroups();
         assertEquals(1, defaultGroups.size());
@@ -254,20 +256,20 @@ public class GroupTest extends AbstractGroupTest {
         response = realm.users().create(newUser);
         String userId = ApiUtil.getCreatedId(response);
         response.close();
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userResourcePath(userId), newUser);
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userResourcePath(userId), newUser, ResourceType.USER);
 
         membership = realm.users().get(userId).groups();
         assertEquals(1, membership.size());
         assertEquals("level3", membership.get(0).getName());
 
         realm.removeDefaultGroup(level3Group.getId());
-        assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.defaultGroupPath(level3Group.getId()));
+        assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.defaultGroupPath(level3Group.getId()), ResourceType.GROUP);
 
         defaultGroups = realm.getDefaultGroups();
         assertEquals(0, defaultGroups.size());
 
         realm.groups().group(topGroup.getId()).remove();
-        assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.groupPath(topGroup.getId()));
+        assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.groupPath(topGroup.getId()), ResourceType.GROUP);
 
         try {
             realm.getGroupByPath("/top/level2/level3");
@@ -319,7 +321,7 @@ public class GroupTest extends AbstractGroupTest {
         group.getAttributes().put("attr3", Collections.singletonList("attrval2"));
 
         realm.groups().group(group.getId()).update(group);
-        assertAdminEvents.assertEvent("test", OperationType.UPDATE, AdminEventPaths.groupPath(group.getId()), group);
+        assertAdminEvents.assertEvent("test", OperationType.UPDATE, AdminEventPaths.groupPath(group.getId()), group, ResourceType.GROUP);
 
         group = realm.getGroupByPath("/group-new");
 
@@ -340,27 +342,27 @@ public class GroupTest extends AbstractGroupTest {
         Response response = realm.users().create(UserBuilder.create().username("user-a").build());
         String userAId = ApiUtil.getCreatedId(response);
         response.close();
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userResourcePath(userAId));
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userResourcePath(userAId), ResourceType.USER);
 
         response = realm.users().create(UserBuilder.create().username("user-b").build());
         String userBId = ApiUtil.getCreatedId(response);
         response.close();
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userResourcePath(userBId));
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userResourcePath(userBId), ResourceType.USER);
 
         realm.users().get(userAId).joinGroup(groupId);
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userGroupPath(userAId, groupId), group);
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userGroupPath(userAId, groupId), group, ResourceType.GROUP_MEMBERSHIP);
 
         List<UserRepresentation> members = realm.groups().group(groupId).members(0, 10);
         assertNames(members, "user-a");
 
         realm.users().get(userBId).joinGroup(groupId);
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userGroupPath(userBId, groupId), group);
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userGroupPath(userBId, groupId), group, ResourceType.GROUP_MEMBERSHIP);
 
         members = realm.groups().group(groupId).members(0, 10);
         assertNames(members, "user-a", "user-b");
 
         realm.users().get(userAId).leaveGroup(groupId);
-        assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.userGroupPath(userAId, groupId), group);
+        assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.userGroupPath(userAId, groupId), group, ResourceType.GROUP_MEMBERSHIP);
 
         members = realm.groups().group(groupId).members(0, 10);
         assertNames(members, "user-b");
@@ -418,19 +420,19 @@ public class GroupTest extends AbstractGroupTest {
         l.add(realm.roles().get("realm-role").toRepresentation());
         l.add(realm.roles().get("realm-composite").toRepresentation());
         roles.realmLevel().add(l);
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupRolesRealmRolesPath(group.getId()), l);
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupRolesRealmRolesPath(group.getId()), l, ResourceType.REALM_ROLE_MAPPING);
 
         // Add client roles
         RoleRepresentation clientRole = realm.clients().get(clientId).roles().get("client-role").toRepresentation();
         RoleRepresentation clientComposite = realm.clients().get(clientId).roles().get("client-composite").toRepresentation();
         roles.clientLevel(clientId).add(Collections.singletonList(clientRole));
         roles.clientLevel(clientId).add(Collections.singletonList(clientComposite));
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupRolesClientRolesPath(group.getId(), clientId), Collections.singletonList(clientRole));
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupRolesClientRolesPath(group.getId(), clientId), Collections.singletonList(clientComposite));
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupRolesClientRolesPath(group.getId(), clientId), Collections.singletonList(clientRole), ResourceType.CLIENT_ROLE_MAPPING);
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupRolesClientRolesPath(group.getId(), clientId), Collections.singletonList(clientComposite), ResourceType.CLIENT_ROLE_MAPPING);
 
         // List realm roles
         assertNames(roles.realmLevel().listAll(), "realm-role", "realm-composite");
-        assertNames(roles.realmLevel().listAvailable(), "admin", "offline_access", "user");
+        assertNames(roles.realmLevel().listAvailable(), "admin", "offline_access", Constants.AUTHZ_UMA_AUTHORIZATION, "user", "customer-user-premium");
         assertNames(roles.realmLevel().listEffective(), "realm-role", "realm-composite", "realm-child");
 
         // List client roles
@@ -447,13 +449,13 @@ public class GroupTest extends AbstractGroupTest {
         // Remove realm role
         RoleRepresentation realmRoleRep = realm.roles().get("realm-role").toRepresentation();
         roles.realmLevel().remove(Collections.singletonList(realmRoleRep));
-        assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.groupRolesRealmRolesPath(group.getId()), Collections.singletonList(realmRoleRep));
+        assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.groupRolesRealmRolesPath(group.getId()), Collections.singletonList(realmRoleRep), ResourceType.REALM_ROLE_MAPPING);
         assertNames(roles.realmLevel().listAll(), "realm-composite");
 
         // Remove client role
         RoleRepresentation clientRoleRep = realm.clients().get(clientId).roles().get("client-role").toRepresentation();
         roles.clientLevel(clientId).remove(Collections.singletonList(clientRoleRep));
-        assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.groupRolesClientRolesPath(group.getId(), clientId), Collections.singletonList(clientRoleRep));
+        assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.groupRolesClientRolesPath(group.getId(), clientId), Collections.singletonList(clientRoleRep), ResourceType.CLIENT_ROLE_MAPPING);
         assertNames(roles.clientLevel(clientId).listAll(), "client-composite");
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java
index a283cfc..b9102e1 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/IdentityProviderTest.java
@@ -26,6 +26,7 @@ import org.keycloak.dom.saml.v2.metadata.IndexedEndpointType;
 import org.keycloak.dom.saml.v2.metadata.KeyTypes;
 import org.keycloak.dom.saml.v2.metadata.SPSSODescriptorType;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
 import org.keycloak.representations.idm.IdentityProviderMapperTypeRepresentation;
 import org.keycloak.representations.idm.IdentityProviderRepresentation;
@@ -122,7 +123,7 @@ public class IdentityProviderTest extends AbstractAdminTest {
         representation.getConfig().put("clientId", "changedClientId");
 
         identityProviderResource.update(representation);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.identityProviderPath("update-identity-provider"), representation);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.identityProviderPath("update-identity-provider"), representation, ResourceType.IDENTITY_PROVIDER);
 
         identityProviderResource = realm.identityProviders().get(representation.getInternalId());
 
@@ -150,7 +151,7 @@ public class IdentityProviderTest extends AbstractAdminTest {
         assertNotNull(representation);
 
         identityProviderResource.remove();
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.identityProviderPath("remove-identity-provider"));
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.identityProviderPath("remove-identity-provider"), ResourceType.IDENTITY_PROVIDER);
 
         try {
             realm.identityProviders().get("remove-identity-provider").toRepresentation();
@@ -165,7 +166,7 @@ public class IdentityProviderTest extends AbstractAdminTest {
         Assert.assertNotNull(ApiUtil.getCreatedId(response));
         response.close();
 
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.identityProviderPath(idpRep.getAlias()), idpRep);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.identityProviderPath(idpRep.getAlias()), idpRep, ResourceType.IDENTITY_PROVIDER);
     }
 
     private IdentityProviderRepresentation createRep(String id, String providerId) {
@@ -320,7 +321,7 @@ public class IdentityProviderTest extends AbstractAdminTest {
         String id = ApiUtil.getCreatedId(response);
         Assert.assertNotNull(id);
         response.close();
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.identityProviderMapperPath("google", id), mapper);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.identityProviderMapperPath("google", id), mapper, ResourceType.IDENTITY_PROVIDER_MAPPER);
 
         // list mappers
         List<IdentityProviderMapperRepresentation> mappers = provider.getMappers();
@@ -337,7 +338,7 @@ public class IdentityProviderTest extends AbstractAdminTest {
         // update mapper
         mapper.getConfig().put("role", "master-realm.manage-realm");
         provider.update(id, mapper);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.identityProviderMapperPath("google", id), mapper);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.identityProviderMapperPath("google", id), mapper, ResourceType.IDENTITY_PROVIDER_MAPPER);
 
         mapper = provider.getMapperById(id);
         Assert.assertNotNull("mapperById not null", mapper);
@@ -345,7 +346,7 @@ public class IdentityProviderTest extends AbstractAdminTest {
 
         // delete mapper
         provider.delete(id);
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.identityProviderMapperPath("google", id));
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.identityProviderMapperPath("google", id), ResourceType.IDENTITY_PROVIDER_MAPPER);
         try {
             provider.getMapperById(id);
             Assert.fail("Should fail with NotFoundException");
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java
index 7ec1da2..ca01045 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java
@@ -21,6 +21,7 @@ import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;
 import org.keycloak.Config;
+import org.keycloak.admin.client.Keycloak;
 import org.keycloak.admin.client.resource.ClientResource;
 import org.keycloak.admin.client.resource.UserResource;
 import org.keycloak.events.Details;
@@ -29,25 +30,20 @@ import org.keycloak.models.AdminRoles;
 import org.keycloak.models.Constants;
 import org.keycloak.models.ImpersonationConstants;
 import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.representations.idm.EventRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.RoleRepresentation;
-import org.keycloak.services.resources.admin.AdminRoot;
 import org.keycloak.testsuite.AbstractKeycloakTest;
 import org.keycloak.testsuite.AssertEvents;
+import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
+import org.keycloak.testsuite.auth.page.AuthRealm;
 import org.keycloak.testsuite.util.ClientBuilder;
 import org.keycloak.testsuite.util.CredentialBuilder;
-import org.keycloak.testsuite.util.OAuthClient.AccessTokenResponse;
 import org.keycloak.testsuite.util.RealmBuilder;
 import org.keycloak.testsuite.util.UserBuilder;
 
-import javax.ws.rs.client.Client;
-import javax.ws.rs.client.ClientRequestContext;
-import javax.ws.rs.client.ClientRequestFilter;
-import javax.ws.rs.client.WebTarget;
-import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.ClientErrorException;
 import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-import java.io.IOException;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -85,21 +81,6 @@ public class ImpersonationTest extends AbstractKeycloakTest {
         testRealms.add(realm.build());
     }
 
-    private String createAdminToken(String username, String realm) {
-        try {
-            String password = username.equals("admin") ? "admin" : "password";
-            String clientId = realm.equals("master") ? Constants.ADMIN_CLI_CLIENT_ID : "myclient";
-            AccessTokenResponse tokenResponse = oauth.doGrantAccessTokenRequest(realm, username, password, null, clientId, null);
-            if (tokenResponse.getStatusCode() != 200) {
-                throw new RuntimeException("Failed to get token: " + tokenResponse.getErrorDescription());
-            }
-            events.clear();
-            return tokenResponse.getAccessToken();
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-
     @Test
     public void testImpersonateByMasterAdmin() {
         // test that composite is set up right for impersonation role
@@ -157,51 +138,65 @@ public class ImpersonationTest extends AbstractKeycloakTest {
     }
 
 
-
     protected void testSuccessfulImpersonation(String admin, String adminRealm) {
-        Client client = createClient(admin, adminRealm);
-        WebTarget impersonate = createImpersonateTarget(client);
-        Map data = impersonate.request().post(null, Map.class);
-        Assert.assertNotNull(data);
-        Assert.assertNotNull(data.get("redirect"));
-
-        // TODO Events not working
-        events.expect(EventType.IMPERSONATE)
-                .session(AssertEvents.isUUID())
-                .user(impersonatedUserId)
-                .detail(Details.IMPERSONATOR, admin)
-                .detail(Details.IMPERSONATOR_REALM, adminRealm)
-                .client((String) null).assertEvent();
-
-        client.close();
+
+        Keycloak client = login(admin, adminRealm);
+        try {
+            Map data = client.realms().realm("test").users().get(impersonatedUserId).impersonate();
+            Assert.assertNotNull(data);
+            Assert.assertNotNull(data.get("redirect"));
+
+            events.expect(EventType.IMPERSONATE)
+                    .session(AssertEvents.isUUID())
+                    .user(impersonatedUserId)
+                    .detail(Details.IMPERSONATOR, admin)
+                    .detail(Details.IMPERSONATOR_REALM, adminRealm)
+                    .client((String) null).assertEvent();
+        } finally {
+            client.close();
+        }
     }
 
     protected void testForbiddenImpersonation(String admin, String adminRealm) {
-        Client client = createClient(admin, adminRealm);
-        WebTarget impersonate = createImpersonateTarget(client);
-        Response response = impersonate.request().post(null);
-        response.close();
-        client.close();
+        Keycloak client = createAdminClient(adminRealm, establishClientId(adminRealm), admin);
+        try {
+            client.realms().realm("test").users().get(impersonatedUserId).impersonate();
+        } catch (ClientErrorException e) {
+            Assert.assertTrue(e.getMessage().indexOf("403 Forbidden") != -1);
+        } finally {
+            client.close();
+        }
     }
 
+    Keycloak createAdminClient(String realm, String clientId, String username) {
+        return createAdminClient(realm, clientId, username, null);
+    }
 
-    protected WebTarget createImpersonateTarget(Client client) {
-        UriBuilder authBase = UriBuilder.fromUri(getAuthServerRoot());
-        WebTarget adminRealms = client.target(AdminRoot.realmsUrl(authBase));
-        WebTarget realmTarget = adminRealms.path("test");
-        return realmTarget.path("users").path(impersonatedUserId).path("impersonation");
+    String establishClientId(String realm) {
+        return realm.equals("master") ? Constants.ADMIN_CLI_CLIENT_ID : "myclient";
     }
 
-    protected Client createClient(String admin, String adminRealm) {
-        String token = createAdminToken(admin, adminRealm);
-        final String authHeader = "Bearer " + token;
-        ClientRequestFilter authFilter = new ClientRequestFilter() {
-            @Override
-            public void filter(ClientRequestContext requestContext) throws IOException {
-                requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader);
-            }
-        };
-        return javax.ws.rs.client.ClientBuilder.newBuilder().register(authFilter).build();
+    Keycloak createAdminClient(String realm, String clientId, String username, String password) {
+        if (password == null) {
+            password = username.equals("admin") ? "admin" : "password";
+        }
+        return Keycloak.getInstance(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth",
+                realm, username, password, clientId);
     }
 
+    private Keycloak login(String username, String realm) {
+        String clientId = establishClientId(realm);
+        Keycloak client = createAdminClient(realm, clientId, username);
+
+        client.tokenManager().grantToken();
+        // only poll for LOGIN event if realm is not master
+        // - since for master testing event listener is not installed
+        if (!AuthRealm.MASTER.equals(realm)) {
+            EventRepresentation e = events.poll();
+            Assert.assertEquals("Event type", EventType.LOGIN.toString(), e.getType());
+            Assert.assertEquals("Client ID", clientId, e.getClientId());
+            Assert.assertEquals("Username", username, e.getDetails().get("username"));
+        }
+        return client;
+    }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/InitialAccessTokenResourceTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/InitialAccessTokenResourceTest.java
index 9f9538d..055bfa2 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/InitialAccessTokenResourceTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/InitialAccessTokenResourceTest.java
@@ -22,6 +22,7 @@ import org.junit.Test;
 import org.keycloak.admin.client.resource.ClientInitialAccessResource;
 import org.keycloak.common.util.Time;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.representations.idm.ClientInitialAccessCreatePresentation;
 import org.keycloak.representations.idm.ClientInitialAccessPresentation;
 import org.keycloak.testsuite.util.AdminEventPaths;
@@ -54,7 +55,7 @@ public class InitialAccessTokenResourceTest extends AbstractAdminTest {
         int time = Time.currentTime();
 
         ClientInitialAccessPresentation response = resource.create(rep);
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientInitialAccessPath(response.getId()), rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientInitialAccessPath(response.getId()), rep, ResourceType.CLIENT_INITIAL_ACCESS_MODEL);
 
         assertNotNull(response.getId());
         assertEquals(new Integer(2), response.getCount());
@@ -65,12 +66,12 @@ public class InitialAccessTokenResourceTest extends AbstractAdminTest {
 
         rep.setCount(3);
         response = resource.create(rep);
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientInitialAccessPath(response.getId()), rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientInitialAccessPath(response.getId()), rep, ResourceType.CLIENT_INITIAL_ACCESS_MODEL);
 
         rep.setCount(4);
         response = resource.create(rep);
         String lastId = response.getId();
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientInitialAccessPath(lastId), rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientInitialAccessPath(lastId), rep, ResourceType.CLIENT_INITIAL_ACCESS_MODEL);
 
         List<ClientInitialAccessPresentation> list = resource.list();
         assertEquals(3, list.size());
@@ -80,7 +81,7 @@ public class InitialAccessTokenResourceTest extends AbstractAdminTest {
 
         // Delete last and assert it was deleted
         resource.delete(lastId);
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientInitialAccessPath(lastId));
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientInitialAccessPath(lastId), ResourceType.CLIENT_INITIAL_ACCESS_MODEL);
 
         list = resource.list();
         assertEquals(2, list.size());
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/PermissionsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/PermissionsTest.java
index 98bf9e6..81de894 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/PermissionsTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/PermissionsTest.java
@@ -182,6 +182,15 @@ public class PermissionsTest extends AbstractKeycloakTest {
         Assert.assertNames(realms, REALM_NAME);
         assertNotNull(realms.get(0).getAccessTokenLifespan());
 
+        // Check the same when access with users from 'master' realm
+        realms = clients.get("master-" + AdminRoles.VIEW_USERS).realms().findAll();
+        Assert.assertNames(realms, REALM_NAME);
+        assertGettersEmpty(realms.get(0));
+
+        realms = clients.get("master-" + AdminRoles.VIEW_REALM).realms().findAll();
+        Assert.assertNames(realms, REALM_NAME);
+        assertNotNull(realms.get(0).getAccessTokenLifespan());
+
         // Create realm
         invoke(new Invocation() {
             public void invoke(RealmResource realm) {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmRolesTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmRolesTest.java
index 04221c0..bf9c794 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmRolesTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmRolesTest.java
@@ -21,6 +21,7 @@ import org.junit.Before;
 import org.junit.Test;
 import org.keycloak.admin.client.resource.RolesResource;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.RoleRepresentation;
 import org.keycloak.testsuite.Assert;
@@ -78,11 +79,11 @@ public class RealmRolesTest extends AbstractAdminTest {
 
         resource = adminClient.realm(REALM_NAME).roles();
 
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.roleResourcePath("role-a"), roleA);
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.roleResourcePath("role-b"), roleB);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.roleResourcePath("role-a"), roleA, ResourceType.REALM_ROLE);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.roleResourcePath("role-b"), roleB, ResourceType.REALM_ROLE);
 
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientResourcePath(clientUuid), clientRep);
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientRoleResourcePath(clientUuid, "role-c"), roleC);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientResourcePath(clientUuid), clientRep, ResourceType.CLIENT);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientRoleResourcePath(clientUuid, "role-c"), roleC, ResourceType.CLIENT_ROLE);
     }
 
     @Test
@@ -102,7 +103,7 @@ public class RealmRolesTest extends AbstractAdminTest {
         role.setDescription("Role A New");
 
         resource.get("role-a").update(role);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.roleResourcePath("role-a"), role);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.roleResourcePath("role-a"), role, ResourceType.REALM_ROLE);
 
         role = resource.get("role-a-new").toRepresentation();
 
@@ -116,7 +117,7 @@ public class RealmRolesTest extends AbstractAdminTest {
     public void deleteRole() {
         assertNotNull(resource.get("role-a"));
         resource.deleteRole("role-a");
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.roleResourcePath("role-a"));
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.roleResourcePath("role-a"), ResourceType.REALM_ROLE);
 
         try {
             resource.get("role-a").toRepresentation();
@@ -136,7 +137,7 @@ public class RealmRolesTest extends AbstractAdminTest {
         l.add(RoleBuilder.create().id(ids.get("role-c")).build());
         resource.get("role-a").addComposites(l);
 
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.roleResourceCompositesPath("role-a"), l);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.roleResourceCompositesPath("role-a"), l, ResourceType.REALM_ROLE);
 
         Set<RoleRepresentation> composites = resource.get("role-a").getRoleComposites();
 
@@ -150,7 +151,7 @@ public class RealmRolesTest extends AbstractAdminTest {
         Assert.assertNames(clientComposites, "role-c");
 
         resource.get("role-a").deleteComposites(l);
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.roleResourceCompositesPath("role-a"), l);
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.roleResourceCompositesPath("role-a"), l, ResourceType.REALM_ROLE);
 
         assertFalse(resource.get("role-a").toRepresentation().isComposite());
         assertEquals(0, resource.get("role-a").getRoleComposites().size());
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java
index 2ba3c5c..f08f790 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/realm/RealmTest.java
@@ -27,6 +27,7 @@ import org.keycloak.admin.client.resource.ServerInfoResource;
 import org.keycloak.common.util.StreamUtil;
 import org.keycloak.common.util.Time;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.Constants;
 import org.keycloak.representations.adapters.action.GlobalRequestResult;
 import org.keycloak.representations.adapters.action.PushNotBeforeAction;
@@ -213,7 +214,7 @@ public class RealmTest extends AbstractAdminTest {
         rep.setEditUsernameAllowed(true);
 
         realm.update(rep);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep, ResourceType.REALM);
 
         rep = realm.toRepresentation();
 
@@ -230,7 +231,7 @@ public class RealmTest extends AbstractAdminTest {
         rep.setEditUsernameAllowed(false);
 
         realm.update(rep);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep, ResourceType.REALM);
 
         rep = realm.toRepresentation();
         assertEquals(Boolean.FALSE, rep.isRegistrationAllowed());
@@ -246,7 +247,7 @@ public class RealmTest extends AbstractAdminTest {
         rep.setSupportedLocales(new HashSet<>(Arrays.asList("en", "de")));
 
         realm.update(rep);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep, ResourceType.REALM);
 
         rep = realm.toRepresentation();
 
@@ -258,7 +259,7 @@ public class RealmTest extends AbstractAdminTest {
         rep.setEditUsernameAllowed(false);
 
         realm.update(rep);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep, ResourceType.REALM);
 
         rep = realm.toRepresentation();
         assertEquals(Boolean.FALSE, rep.isEditUsernameAllowed());
@@ -282,7 +283,7 @@ public class RealmTest extends AbstractAdminTest {
     public void deleteDefaultRole() {
         RoleRepresentation role = new RoleRepresentation("test", "test", false);
         realm.roles().create(role);
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.roleResourcePath("test"), role);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.roleResourcePath("test"), role, ResourceType.REALM_ROLE);
 
         assertNotNull(realm.roles().get("test").toRepresentation());
 
@@ -291,10 +292,10 @@ public class RealmTest extends AbstractAdminTest {
         rep.getDefaultRoles().add("test");
 
         realm.update(rep);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep, ResourceType.REALM);
 
         realm.roles().deleteRole("test");
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.roleResourcePath("test"));
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.roleResourcePath("test"), ResourceType.REALM_ROLE);
 
         try {
             realm.roles().get("testsadfsadf").toRepresentation();
@@ -425,7 +426,7 @@ public class RealmTest extends AbstractAdminTest {
 
         rep.setPublicKey(PUBLIC_KEY);
         realm.update(rep);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep, ResourceType.REALM);
 
         assertEquals(PUBLIC_KEY, rep.getPublicKey());
 
@@ -444,10 +445,23 @@ public class RealmTest extends AbstractAdminTest {
 
         Assert.assertEquals(PUBLIC_KEY, realm.toRepresentation().getPublicKey());
 
+        rep.setPrivateKey("{}{}{}{}{}{}324re9gvj0r");
+        rep.setPublicKey("{}{}{}{}{}{}324re9gvj0r");
+        try {
+            realm.update(rep);
+            fail("Expected BadRequestException");
+        } catch (BadRequestException e) {
+            // Expected
+            assertAdminEvents.assertEmpty();
+        }
+
+        Assert.assertEquals(PUBLIC_KEY, realm.toRepresentation().getPublicKey());
+
+        rep.setPrivateKey(privateKey2048);
         rep.setPublicKey(publicKey2048);
 
         realm.update(rep);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep, ResourceType.REALM);
 
         Assert.assertEquals(publicKey2048, realm.toRepresentation().getPublicKey());
 
@@ -457,7 +471,7 @@ public class RealmTest extends AbstractAdminTest {
         rep.setPublicKey(publicKey4096);
 
         realm.update(rep);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep, ResourceType.REALM);
 
         Assert.assertEquals(publicKey4096, realm.toRepresentation().getPublicKey());
     }
@@ -468,7 +482,7 @@ public class RealmTest extends AbstractAdminTest {
         rep.setCertificate(CERTIFICATE);
 
         realm.update(rep);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep, ResourceType.REALM);
 
         assertEquals(CERTIFICATE, rep.getCertificate());
 
@@ -476,9 +490,29 @@ public class RealmTest extends AbstractAdminTest {
         rep.setCertificate(certificate);
 
         realm.update(rep);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep, ResourceType.REALM);
+
+        assertEquals(certificate, realm.toRepresentation().getCertificate());
+
+        rep.setCertificate("{}{}{}{}{}{}324re9gvj0r");
+        try {
+            realm.update(rep);
+            fail("Expected BadRequestException");
+        } catch (BadRequestException e) {
+            // Expected
+            assertAdminEvents.assertEmpty();
+        }
+
+        rep.setCertificate("invalid");
+        try {
+            realm.update(rep);
+            fail("Expected BadRequestException");
+        } catch (BadRequestException e) {
+            // Expected
+            assertAdminEvents.assertEmpty();
+        }
 
-        assertEquals(certificate, rep.getCertificate());
+        assertEquals(certificate, realm.toRepresentation().getCertificate());
     }
 
     @Test
@@ -487,7 +521,7 @@ public class RealmTest extends AbstractAdminTest {
         assertTrue(testingClient.testing().isCached("realms", realmRep.getId()));
 
         realm.clearRealmCache();
-        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, "clear-realm-cache");
+        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, "clear-realm-cache", ResourceType.REALM);
 
         assertFalse(testingClient.testing().isCached("realms", realmRep.getId()));
     }
@@ -499,14 +533,14 @@ public class RealmTest extends AbstractAdminTest {
         Response response = realm.users().create(user);
         String userId = ApiUtil.getCreatedId(response);
         response.close();
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userResourcePath(userId), user);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userResourcePath(userId), user, ResourceType.USER);
 
         realm.users().get(userId).toRepresentation();
 
         assertTrue(testingClient.testing().isCached("users", userId));
 
         realm.clearUserCache();
-        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, "clear-user-cache");
+        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, "clear-user-cache", ResourceType.REALM);
 
         assertFalse(testingClient.testing().isCached("users", userId));
     }
@@ -520,10 +554,10 @@ public class RealmTest extends AbstractAdminTest {
         RealmRepresentation rep = realm.toRepresentation();
         rep.setNotBefore(time);
         realm.update(rep);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep, ResourceType.REALM);
 
         GlobalRequestResult globalRequestResult = realm.pushRevocation();
-        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, "push-revocation", globalRequestResult);
+        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, "push-revocation", globalRequestResult, ResourceType.REALM);
 
         assertEquals(1, globalRequestResult.getSuccessRequests().size());
         assertEquals("http://localhost:8180/auth/realms/master/app/admin", globalRequestResult.getSuccessRequests().get(0));
@@ -540,15 +574,15 @@ public class RealmTest extends AbstractAdminTest {
         Response response = realm.users().create(UserBuilder.create().username("user").build());
         String userId = ApiUtil.getCreatedId(response);
         response.close();
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userResourcePath(userId));
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userResourcePath(userId), ResourceType.USER);
 
         realm.users().get(userId).resetPassword(CredentialBuilder.create().password("password").build());
-        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userResetPasswordPath(userId));
+        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userResetPasswordPath(userId), ResourceType.USER);
 
         oauth.doLogin("user", "password");
 
         GlobalRequestResult globalRequestResult = realm.logoutAll();
-        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, "logout-all", globalRequestResult);
+        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, "logout-all", globalRequestResult, ResourceType.REALM);
 
         assertEquals(1, globalRequestResult.getSuccessRequests().size());
         assertEquals("http://localhost:8180/auth/realms/master/app/admin", globalRequestResult.getSuccessRequests().get(0));
@@ -569,7 +603,7 @@ public class RealmTest extends AbstractAdminTest {
         assertNotNull(event);
 
         realm.deleteSession(event.getSessionId());
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.deleteSessionPath(event.getSessionId()));
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.deleteSessionPath(event.getSessionId()), ResourceType.USER_SESSION);
         try {
             realm.deleteSession(event.getSessionId());
             fail("Expected 404");
@@ -616,7 +650,7 @@ public class RealmTest extends AbstractAdminTest {
         Response resp = realm.clients().create(client);
         String clientDbId = ApiUtil.getCreatedId(resp);
         resp.close();
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientResourcePath(clientDbId), client);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientResourcePath(clientDbId), client, ResourceType.CLIENT);
 
         oauth.realm(REALM_NAME);
         oauth.redirectUri(redirectUri);
@@ -625,10 +659,10 @@ public class RealmTest extends AbstractAdminTest {
         Response response = realm.users().create(userRep);
         String userId = ApiUtil.getCreatedId(response);
         response.close();
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userResourcePath(userId), userRep);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userResourcePath(userId), userRep, ResourceType.USER);
 
         realm.users().get(userId).resetPassword(CredentialBuilder.create().password("password").build());
-        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userResetPasswordPath(userId));
+        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userResetPasswordPath(userId), ResourceType.USER);
 
         testingClient.testApp().clearAdminActions();
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/RoleByIdResourceTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/RoleByIdResourceTest.java
index 6db07e1..9297b0f 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/RoleByIdResourceTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/RoleByIdResourceTest.java
@@ -21,6 +21,7 @@ import org.junit.Before;
 import org.junit.Test;
 import org.keycloak.admin.client.resource.RoleByIdResource;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.representations.idm.RoleRepresentation;
 import org.keycloak.testsuite.Assert;
 import org.keycloak.testsuite.util.AdminEventPaths;
@@ -86,7 +87,7 @@ public class RoleByIdResourceTest extends AbstractAdminTest {
         role.setDescription("Role A New");
 
         resource.updateRole(ids.get("role-a"), role);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.roleByIdResourcePath(ids.get("role-a")), role);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.roleByIdResourcePath(ids.get("role-a")), role, ResourceType.REALM_ROLE);
 
         role = resource.getRole(ids.get("role-a"));
 
@@ -100,7 +101,7 @@ public class RoleByIdResourceTest extends AbstractAdminTest {
     public void deleteRole() {
         assertNotNull(resource.getRole(ids.get("role-a")));
         resource.deleteRole(ids.get("role-a"));
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.roleByIdResourcePath(ids.get("role-a")));
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.roleByIdResourcePath(ids.get("role-a")), ResourceType.REALM_ROLE);
 
         try {
             resource.getRole(ids.get("role-a"));
@@ -119,7 +120,7 @@ public class RoleByIdResourceTest extends AbstractAdminTest {
         l.add(RoleBuilder.create().id(ids.get("role-c")).build());
         resource.addComposites(ids.get("role-a"), l);
 
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.roleByIdResourceCompositesPath(ids.get("role-a")), l);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.roleByIdResourceCompositesPath(ids.get("role-a")), l, ResourceType.REALM_ROLE);
 
         Set<RoleRepresentation> composites = resource.getRoleComposites(ids.get("role-a"));
 
@@ -133,7 +134,7 @@ public class RoleByIdResourceTest extends AbstractAdminTest {
         Assert.assertNames(clientComposites, "role-c");
 
         resource.deleteComposites(ids.get("role-a"), l);
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.roleByIdResourceCompositesPath(ids.get("role-a")), l);
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.roleByIdResourceCompositesPath(ids.get("role-a")), l, ResourceType.REALM_ROLE);
 
         assertFalse(resource.getRole(ids.get("role-a")).isComposite());
         assertEquals(0, resource.getRoleComposites(ids.get("role-a")).size());
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationLdapConnectionTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationLdapConnectionTest.java
index 041d58c..dc48b7d 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationLdapConnectionTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationLdapConnectionTest.java
@@ -57,6 +57,22 @@ public class UserFederationLdapConnectionTest extends AbstractAdminTest {
 
     }
 
+    @Test
+    public void testLdapConnectionsSsl() {
+
+        Response response = realm.testLDAPConnection(LDAPConnectionTestManager.TEST_CONNECTION, "ldaps://localhost:10636", "foo", "bar", "false");
+        assertStatus(response, 204);
+
+        response = realm.testLDAPConnection(LDAPConnectionTestManager.TEST_CONNECTION, "ldaps://localhostt:10636", "foo", "bar", "false");
+        assertStatus(response, 400);
+
+        response = realm.testLDAPConnection(LDAPConnectionTestManager.TEST_AUTHENTICATION, "ldaps://localhost:10636", "foo", "bar", "false");
+        assertStatus(response, 400);
+
+        response = realm.testLDAPConnection(LDAPConnectionTestManager.TEST_AUTHENTICATION, "ldaps://localhost:10636", "uid=admin,ou=system", "secret", "true");
+        assertStatus(response, 204);
+    }
+
     private void assertStatus(Response response, int status) {
         Assert.assertEquals(status, response.getStatus());
         response.close();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationMapperTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationMapperTest.java
index 52e1699..6ee35a7 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationMapperTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationMapperTest.java
@@ -33,6 +33,7 @@ import org.junit.Before;
 import org.junit.Test;
 import org.keycloak.admin.client.resource.UserFederationProviderResource;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.federation.ldap.mappers.UserAttributeLDAPFederationMapper;
 import org.keycloak.federation.ldap.mappers.UserAttributeLDAPFederationMapperFactory;
 import org.keycloak.federation.ldap.mappers.membership.role.RoleLDAPFederationMapperFactory;
@@ -65,7 +66,7 @@ public class UserFederationMapperTest extends AbstractAdminTest {
         Response resp = realm.userFederation().create(ldapRep);
         this.ldapProviderId = ApiUtil.getCreatedId(resp);
         resp.close();
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userFederationResourcePath(this.ldapProviderId), ldapRep);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userFederationResourcePath(this.ldapProviderId), ldapRep, ResourceType.USER_FEDERATION_PROVIDER);
 
         UserFederationProviderRepresentation dummyRep = UserFederationProviderBuilder.create()
                 .displayName("dummy-1")
@@ -75,16 +76,16 @@ public class UserFederationMapperTest extends AbstractAdminTest {
         resp = realm.userFederation().create(dummyRep);
         this.dummyProviderId = ApiUtil.getCreatedId(resp);
         resp.close();
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userFederationResourcePath(this.dummyProviderId), dummyRep);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userFederationResourcePath(this.dummyProviderId), dummyRep, ResourceType.USER_FEDERATION_PROVIDER);
     }
 
     @After
     public void cleanFederationProviders() {
         realm.userFederation().get(ldapProviderId).remove();
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userFederationResourcePath(ldapProviderId));
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userFederationResourcePath(ldapProviderId), ResourceType.USER_FEDERATION_PROVIDER);
 
         realm.userFederation().get(dummyProviderId).remove();
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userFederationResourcePath(dummyProviderId));
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userFederationResourcePath(dummyProviderId), ResourceType.USER_FEDERATION_PROVIDER);
     }
 
 
@@ -169,14 +170,14 @@ public class UserFederationMapperTest extends AbstractAdminTest {
         mapperRep.getConfig().put(UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, "email-updated");
         mapperRep.getConfig().put(UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, "mail-updated");
         ldapProviderResource().updateMapper(mapperId, mapperRep);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userFederationMapperResourcePath(ldapProviderId, mapperId), mapperRep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userFederationMapperResourcePath(ldapProviderId, mapperId), mapperRep, ResourceType.USER_FEDERATION_MAPPER);
 
         mapperRep = ldapProviderResource().getMapperById(mapperId);
         assertMapper(mapperRep, mapperId, "email-mapper", UserAttributeLDAPFederationMapperFactory.PROVIDER_ID, UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, "email-updated", UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, "mail-updated");
 
         // Test removed successfully
         ldapProviderResource().removeMapper(mapperId);
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userFederationMapperResourcePath(ldapProviderId, mapperId));
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userFederationMapperResourcePath(ldapProviderId, mapperId), ResourceType.USER_FEDERATION_MAPPER);
 
         try {
             ldapProviderResource().getMapperById(mapperId);
@@ -192,7 +193,7 @@ public class UserFederationMapperTest extends AbstractAdminTest {
         response.close();
         String mapperId = ApiUtil.getCreatedId(response);
 
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userFederationMapperResourcePath(userFederationProviderId , mapperId), mapper);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userFederationMapperResourcePath(userFederationProviderId , mapperId), mapper, ResourceType.USER_FEDERATION_MAPPER);
 
         return mapperId;
     }
@@ -227,7 +228,7 @@ public class UserFederationMapperTest extends AbstractAdminTest {
 
         // Remove role mapper and assert not found anymore
         ldapProviderResource().removeMapper(roleMapperId);
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userFederationMapperResourcePath(ldapProviderId, roleMapperId));
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userFederationMapperResourcePath(ldapProviderId, roleMapperId), ResourceType.USER_FEDERATION_MAPPER);
 
         mappers = ldapProviderResource().getMappers();
         Assert.assertNull(findMapperByName(mappers, "role-mapper"));
@@ -257,14 +258,14 @@ public class UserFederationMapperTest extends AbstractAdminTest {
 
         Map<String, Object> eventRep = new HashMap<>();
         eventRep.put("action", "fedToKeycloak");
-        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userFederationMapperResourcePath(ldapProviderId, mapperId) + "/sync", eventRep);
+        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userFederationMapperResourcePath(ldapProviderId, mapperId) + "/sync", eventRep, ResourceType.USER_FEDERATION_PROVIDER);
 
         // Try keycloak to fed
         result = ldapProviderResource().syncMapperData(mapperId, "keycloakToFed");
         Assert.assertEquals("dummyKeycloakToFedSuccess mapper=some-dummy", result.getStatus());
 
         eventRep.put("action", "keycloakToFed");
-        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userFederationMapperResourcePath(ldapProviderId, mapperId) + "/sync");
+        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userFederationMapperResourcePath(ldapProviderId, mapperId) + "/sync", ResourceType.USER_FEDERATION_PROVIDER);
 
     }
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationTest.java
index 90b14a2..8cef8a1 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserFederationTest.java
@@ -30,6 +30,7 @@ import org.junit.Test;
 import org.keycloak.admin.client.resource.UserFederationProvidersResource;
 import org.keycloak.common.constants.KerberosConstants;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.AuthenticationExecutionModel;
 import org.keycloak.models.LDAPConstants;
 import org.keycloak.provider.ProviderConfigProperty;
@@ -209,7 +210,7 @@ public class UserFederationTest extends AbstractAdminTest {
         // Change filter to be valid
         ldapRep.getConfig().put(LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "(dc=something2)");
         userFederation().get(id).update(ldapRep);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userFederationResourcePath(id), ldapRep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userFederationResourcePath(id), ldapRep, ResourceType.USER_FEDERATION_PROVIDER);
 
         // Assert updated successfully
         ldapRep = userFederation().get(id).toRepresentation();
@@ -219,7 +220,7 @@ public class UserFederationTest extends AbstractAdminTest {
         // Assert update displayName
         ldapRep.setDisplayName("ldap2");
         userFederation().get(id).update(ldapRep);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userFederationResourcePath(id), ldapRep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userFederationResourcePath(id), ldapRep, ResourceType.USER_FEDERATION_PROVIDER);
 
         assertFederationProvider(userFederation().get(id).toRepresentation(), id, "ldap2", "ldap", 2, -1, -1, -1, LDAPConstants.BIND_DN, "cn=manager-updated", LDAPConstants.BIND_CREDENTIAL, "password",
                 LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "(dc=something2)");
@@ -253,12 +254,12 @@ public class UserFederationTest extends AbstractAdminTest {
         // Switch kerberos authenticator to DISABLED
         kerberosExecution.setRequirement(AuthenticationExecutionModel.Requirement.DISABLED.toString());
         realm.flows().updateExecutions("browser", kerberosExecution);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("browser"), kerberosExecution);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("browser"), kerberosExecution, ResourceType.AUTH_EXECUTION);
 
         // update LDAP provider with kerberos
         ldapRep = userFederation().get(id).toRepresentation();
         userFederation().get(id).update(ldapRep);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userFederationResourcePath(id), ldapRep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userFederationResourcePath(id), ldapRep, ResourceType.USER_FEDERATION_PROVIDER);
 
         // Assert kerberos authenticator ALTERNATIVE
         kerberosExecution = findKerberosExecution();
@@ -267,10 +268,48 @@ public class UserFederationTest extends AbstractAdminTest {
         // Cleanup
         kerberosExecution.setRequirement(AuthenticationExecutionModel.Requirement.DISABLED.toString());
         realm.flows().updateExecutions("browser", kerberosExecution);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("browser"), kerberosExecution);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("browser"), kerberosExecution, ResourceType.AUTH_EXECUTION);
         removeUserFederationProvider(id);
     }
 
+    @Test
+    public void testKerberosAuthenticatorChangedOnlyIfDisabled() {
+        // Change kerberos to REQUIRED
+        AuthenticationExecutionInfoRepresentation kerberosExecution = findKerberosExecution();
+        kerberosExecution.setRequirement(AuthenticationExecutionModel.Requirement.REQUIRED.toString());
+        realm.flows().updateExecutions("browser", kerberosExecution);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("browser"), kerberosExecution, ResourceType.AUTH_EXECUTION);
+
+        // create LDAP provider with kerberos
+        UserFederationProviderRepresentation ldapRep = UserFederationProviderBuilder.create()
+                .displayName("ldap2")
+                .providerName("ldap")
+                .priority(2)
+                .configProperty(KerberosConstants.ALLOW_KERBEROS_AUTHENTICATION, "true")
+                .build();
+        String id = createUserFederationProvider(ldapRep);
+
+        // Assert kerberos authenticator still REQUIRED
+        kerberosExecution = findKerberosExecution();
+        Assert.assertEquals(kerberosExecution.getRequirement(), AuthenticationExecutionModel.Requirement.REQUIRED.toString());
+
+        // update LDAP provider with kerberos
+        ldapRep = userFederation().get(id).toRepresentation();
+        userFederation().get(id).update(ldapRep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userFederationResourcePath(id), ldapRep, ResourceType.USER_FEDERATION_PROVIDER);
+
+        // Assert kerberos authenticator still REQUIRED
+        kerberosExecution = findKerberosExecution();
+        Assert.assertEquals(kerberosExecution.getRequirement(), AuthenticationExecutionModel.Requirement.REQUIRED.toString());
+
+        // Cleanup
+        kerberosExecution.setRequirement(AuthenticationExecutionModel.Requirement.DISABLED.toString());
+        realm.flows().updateExecutions("browser", kerberosExecution);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.authUpdateExecutionPath("browser"), kerberosExecution, ResourceType.AUTH_EXECUTION);
+        removeUserFederationProvider(id);
+
+    }
+
 
     @Test (expected = NotFoundException.class)
     public void testLookupNotExistentProvider() {
@@ -304,7 +343,7 @@ public class UserFederationTest extends AbstractAdminTest {
 
         Map<String, Object> eventRep = new HashMap<>();
         eventRep.put("action", "triggerFullSync");
-        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userFederationResourcePath(id1) + "/sync", eventRep);
+        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userFederationResourcePath(id1) + "/sync", eventRep, ResourceType.USER_FEDERATION_PROVIDER);
 
         int fullSyncTime = userFederation().get(id1).toRepresentation().getLastSync();
         Assert.assertTrue(fullSyncTime > 0);
@@ -314,7 +353,7 @@ public class UserFederationTest extends AbstractAdminTest {
         syncResult = userFederation().get(id1).syncUsers("triggerChangedUsersSync");
 
         eventRep.put("action", "triggerChangedUsersSync");
-        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userFederationResourcePath(id1) + "/sync", eventRep);
+        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userFederationResourcePath(id1) + "/sync", eventRep, ResourceType.USER_FEDERATION_PROVIDER);
 
         Assert.assertEquals("0 imported users, 0 updated users", syncResult.getStatus());
         int changedSyncTime = userFederation().get(id1).toRepresentation().getLastSync();
@@ -332,13 +371,13 @@ public class UserFederationTest extends AbstractAdminTest {
         resp.close();
         String federationProviderId = ApiUtil.getCreatedId(resp);
 
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userFederationResourcePath(federationProviderId), rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userFederationResourcePath(federationProviderId), rep, ResourceType.USER_FEDERATION_PROVIDER);
         return federationProviderId;
     }
 
     private void removeUserFederationProvider(String id) {
         userFederation().get(id).remove();
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userFederationResourcePath(id));
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userFederationResourcePath(id), ResourceType.USER_FEDERATION_PROVIDER);
     }
 
     private void assertFederationProvider(UserFederationProviderRepresentation rep, String id, String displayName, String providerName,
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserTest.java
index 19645a8..c87bdf1 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserTest.java
@@ -29,6 +29,8 @@ import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.admin.client.resource.RoleMappingResource;
 import org.keycloak.admin.client.resource.UserResource;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
+import org.keycloak.models.Constants;
 import org.keycloak.models.UserModel;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.representations.idm.ErrorRepresentation;
@@ -110,13 +112,13 @@ public class UserTest extends AbstractAdminTest {
         String createdId = ApiUtil.getCreatedId(response);
         response.close();
 
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userResourcePath(createdId), userRep);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userResourcePath(createdId), userRep, ResourceType.USER);
         return createdId;
     }
 
     private void updateUser(UserResource user, UserRepresentation userRep) {
         user.update(userRep);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userResourcePath(userRep.getId()), userRep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userResourcePath(userRep.getId()), userRep, ResourceType.USER);
     }
 
     @Test
@@ -276,7 +278,7 @@ public class UserTest extends AbstractAdminTest {
         Response response = realm.users().delete( userId );
         assertEquals(204, response.getStatus());
         response.close();
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userResourcePath(userId));
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userResourcePath(userId), ResourceType.USER);
     }
 
     @Test
@@ -325,7 +327,7 @@ public class UserTest extends AbstractAdminTest {
         link.setUserName("social-username");
         Response response = user.addFederatedIdentity("social-provider-id", link);
         assertEquals(204, response.getStatus());
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userFederatedIdentityLink(id, "social-provider-id"), link);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userFederatedIdentityLink(id, "social-provider-id"), link, ResourceType.USER);
 
         // Verify social link is here
         user = realm.users().get(id);
@@ -338,7 +340,7 @@ public class UserTest extends AbstractAdminTest {
 
         // Remove social link now
         user.removeFederatedIdentity("social-provider-id");
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userFederatedIdentityLink(id, "social-provider-id"));
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userFederatedIdentityLink(id, "social-provider-id"), ResourceType.USER);
         assertEquals(0, user.getFederatedIdentity().size());
 
         removeSampleIdentityProvider();
@@ -353,14 +355,14 @@ public class UserTest extends AbstractAdminTest {
         rep.setProviderId("social-provider-type");
 
         realm.identityProviders().create(rep);
-        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.identityProviderPath(rep.getAlias()), rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.identityProviderPath(rep.getAlias()), rep, ResourceType.IDENTITY_PROVIDER);
     }
 
     private void removeSampleIdentityProvider() {
         IdentityProviderResource resource = realm.identityProviders().get("social-provider-id");
         Assert.assertNotNull(resource);
         resource.remove();
-        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.identityProviderPath("social-provider-id"));
+        assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.identityProviderPath("social-provider-id"), ResourceType.IDENTITY_PROVIDER);
     }
 
     @Test
@@ -518,7 +520,7 @@ public class UserTest extends AbstractAdminTest {
         List<String> actions = new LinkedList<>();
         actions.add(UserModel.RequiredAction.UPDATE_PASSWORD.name());
         user.executeActionsEmail("account", actions);
-        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userResourcePath(id) + "/execute-actions-email");
+        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userResourcePath(id) + "/execute-actions-email", ResourceType.USER);
 
         Assert.assertEquals(1, greenMail.getReceivedMessages().length);
 
@@ -586,7 +588,7 @@ public class UserTest extends AbstractAdminTest {
         }
 
         user.sendVerifyEmail();
-        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userResourcePath(id) + "/send-verify-email");
+        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userResourcePath(id) + "/send-verify-email", ResourceType.USER);
 
         Assert.assertEquals(1, greenMail.getReceivedMessages().length);
 
@@ -613,6 +615,8 @@ public class UserTest extends AbstractAdminTest {
 
     @Test
     public void updateUserWithoutUsername() {
+
+
         switchEditUsernameAllowedOn();
 
         String id = createUser();
@@ -623,13 +627,13 @@ public class UserTest extends AbstractAdminTest {
         rep.setFirstName("Firstname");
 
         user.update(rep);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userResourcePath(id), rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userResourcePath(id), rep, ResourceType.USER);
 
         rep = new UserRepresentation();
         rep.setLastName("Lastname");
 
         user.update(rep);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userResourcePath(id), rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userResourcePath(id), rep, ResourceType.USER);
 
         rep = realm.users().get(id).toRepresentation();
 
@@ -673,6 +677,7 @@ public class UserTest extends AbstractAdminTest {
     @Test
     public void updateUserWithExistingUsername() {
         switchEditUsernameAllowedOn();
+        enableBruteForce();
         createUser();
 
         UserRepresentation userRep = new UserRepresentation();
@@ -705,7 +710,7 @@ public class UserTest extends AbstractAdminTest {
         cred.setTemporary(false);
 
         realm.users().get(userId).resetPassword(cred);
-        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userResetPasswordPath(userId));
+        assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userResetPasswordPath(userId), ResourceType.USER);
 
         String accountUrl = RealmsResource.accountUrl(UriBuilder.fromUri(getAuthServerRoot())).build(REALM_NAME).toString();
 
@@ -742,7 +747,7 @@ public class UserTest extends AbstractAdminTest {
         RequiredActionProviderRepresentation updatePasswordReqAction = realm.flows().getRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD.toString());
         updatePasswordReqAction.setDefaultAction(true);
         realm.flows().updateRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD.toString(), updatePasswordReqAction);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.authRequiredActionPath(UserModel.RequiredAction.UPDATE_PASSWORD.toString()), updatePasswordReqAction);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.authRequiredActionPath(UserModel.RequiredAction.UPDATE_PASSWORD.toString()), updatePasswordReqAction, ResourceType.REQUIRED_ACTION);
 
         // Create user
         String userId = createUser("user1", "user1@localhost");
@@ -755,7 +760,7 @@ public class UserTest extends AbstractAdminTest {
         updatePasswordReqAction = realm.flows().getRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD.toString());
         updatePasswordReqAction.setDefaultAction(true);
         realm.flows().updateRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD.toString(), updatePasswordReqAction);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.authRequiredActionPath(UserModel.RequiredAction.UPDATE_PASSWORD.toString()), updatePasswordReqAction);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.authRequiredActionPath(UserModel.RequiredAction.UPDATE_PASSWORD.toString()), updatePasswordReqAction, ResourceType.REQUIRED_ACTION);
     }
 
     @Test
@@ -789,28 +794,28 @@ public class UserTest extends AbstractAdminTest {
         assertAdminEvents.clear();
 
         RoleMappingResource roles = realm.users().get(userId).roles();
-        assertNames(roles.realmLevel().listAll(), "user", "offline_access");
+        assertNames(roles.realmLevel().listAll(), "user", "offline_access", Constants.AUTHZ_UMA_AUTHORIZATION);
 
         // Add realm roles
         List<RoleRepresentation> l = new LinkedList<>();
         l.add(realm.roles().get("realm-role").toRepresentation());
         l.add(realm.roles().get("realm-composite").toRepresentation());
         roles.realmLevel().add(l);
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userRealmRoleMappingsPath(userId), l);
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userRealmRoleMappingsPath(userId), l, ResourceType.REALM_ROLE_MAPPING);
 
         // Add client roles
         List<RoleRepresentation> list = Collections.singletonList(realm.clients().get(clientUuid).roles().get("client-role").toRepresentation());
         roles.clientLevel(clientUuid).add(list);
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userClientRoleMappingsPath(userId, clientUuid), list);
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userClientRoleMappingsPath(userId, clientUuid), list, ResourceType.CLIENT_ROLE_MAPPING);
 
         list = Collections.singletonList(realm.clients().get(clientUuid).roles().get("client-composite").toRepresentation());
         roles.clientLevel(clientUuid).add(list);
-        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userClientRoleMappingsPath(userId, clientUuid), list);
+        assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userClientRoleMappingsPath(userId, clientUuid), ResourceType.CLIENT_ROLE_MAPPING);
 
         // List realm roles
-        assertNames(roles.realmLevel().listAll(), "realm-role", "realm-composite", "user", "offline_access");
-        assertNames(roles.realmLevel().listAvailable(), "admin");
-        assertNames(roles.realmLevel().listEffective(), "realm-role", "realm-composite", "realm-child", "user", "offline_access");
+        assertNames(roles.realmLevel().listAll(), "realm-role", "realm-composite", "user", "offline_access", Constants.AUTHZ_UMA_AUTHORIZATION);
+        assertNames(roles.realmLevel().listAvailable(), "admin", "customer-user-premium");
+        assertNames(roles.realmLevel().listEffective(), "realm-role", "realm-composite", "realm-child", "user", "offline_access", Constants.AUTHZ_UMA_AUTHORIZATION);
 
         // List client roles
         assertNames(roles.clientLevel(clientUuid).listAll(), "client-role", "client-composite");
@@ -819,7 +824,7 @@ public class UserTest extends AbstractAdminTest {
 
         // Get mapping representation
         MappingsRepresentation all = roles.getAll();
-        assertNames(all.getRealmMappings(), "realm-role", "realm-composite", "user", "offline_access");
+        assertNames(all.getRealmMappings(), "realm-role", "realm-composite", "user", "offline_access", Constants.AUTHZ_UMA_AUTHORIZATION);
         assertEquals(2, all.getClientMappings().size());
         assertNames(all.getClientMappings().get("myclient").getMappings(), "client-role", "client-composite");
         assertNames(all.getClientMappings().get("account").getMappings(), "manage-account", "view-profile");
@@ -827,14 +832,14 @@ public class UserTest extends AbstractAdminTest {
         // Remove realm role
         RoleRepresentation realmRoleRep = realm.roles().get("realm-role").toRepresentation();
         roles.realmLevel().remove(Collections.singletonList(realmRoleRep));
-        assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.userRealmRoleMappingsPath(userId), Collections.singletonList(realmRoleRep));
+        assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.userRealmRoleMappingsPath(userId), Collections.singletonList(realmRoleRep), ResourceType.REALM_ROLE_MAPPING);
 
-        assertNames(roles.realmLevel().listAll(), "realm-composite", "user", "offline_access");
+        assertNames(roles.realmLevel().listAll(), "realm-composite", "user", "offline_access", Constants.AUTHZ_UMA_AUTHORIZATION);
 
         // Remove client role
         RoleRepresentation clientRoleRep = realm.clients().get(clientUuid).roles().get("client-role").toRepresentation();
         roles.clientLevel(clientUuid).remove(Collections.singletonList(clientRoleRep));
-        assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.userClientRoleMappingsPath(userId, clientUuid), Collections.singletonList(clientRoleRep));
+        assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.userClientRoleMappingsPath(userId, clientUuid), Collections.singletonList(clientRoleRep), ResourceType.CLIENT_ROLE_MAPPING);
 
         assertNames(roles.clientLevel(clientUuid).listAll(), "client-composite");
     }
@@ -843,7 +848,14 @@ public class UserTest extends AbstractAdminTest {
         RealmRepresentation rep = realm.toRepresentation();
         rep.setEditUsernameAllowed(true);
         realm.update(rep);
-        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep, ResourceType.REALM);
+    }
+
+    private void enableBruteForce() {
+        RealmRepresentation rep = realm.toRepresentation();
+        rep.setBruteForceProtected(true);
+        realm.update(rep);
+        assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep, ResourceType.REALM);
     }
 
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserTotpTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserTotpTest.java
new file mode 100644
index 0000000..28f0305
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserTotpTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.admin;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.admin.client.resource.UsersResource;
+import org.keycloak.events.Details;
+import org.keycloak.events.EventType;
+import org.keycloak.events.admin.OperationType;
+import org.keycloak.models.utils.TimeBasedOTP;
+import org.keycloak.representations.idm.AdminEventRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.services.resources.AccountService;
+import org.keycloak.testsuite.AssertEvents;
+import org.keycloak.testsuite.TestRealmKeycloakTest;
+import org.keycloak.testsuite.pages.AccountTotpPage;
+import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
+import org.keycloak.testsuite.pages.LoginPage;
+
+import javax.ws.rs.core.UriBuilder;
+import java.util.List;
+
+
+/**
+ * @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
+ */
+public class UserTotpTest extends TestRealmKeycloakTest {
+
+    private static final UriBuilder BASE = UriBuilder.fromUri("http://localhost:8180/auth");
+    public static String ACCOUNT_REDIRECT = AccountService.loginRedirectUrl(BASE.clone()).build("test").toString();
+
+    @Rule
+    public AssertEvents events = new AssertEvents(this);
+
+    @Page
+    protected AccountTotpPage totpPage;
+
+    @Page
+    protected AccountUpdateProfilePage profilePage;
+
+    @Page
+    protected LoginPage loginPage;
+
+    private TimeBasedOTP totp = new TimeBasedOTP();
+
+
+    @Override
+    public void configureTestRealm(RealmRepresentation testRealm) {
+    }
+
+    @Test
+    public void setupTotp() {
+        totpPage.open();
+        loginPage.login("test-user@localhost", "password");
+
+        events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=totp").assertEvent();
+
+        Assert.assertTrue(totpPage.isCurrent());
+
+        Assert.assertFalse(driver.getPageSource().contains("Remove Google"));
+
+        totpPage.configure(totp.generateTOTP(totpPage.getTotpSecret()));
+
+        Assert.assertEquals("Mobile authenticator configured.", profilePage.getSuccess());
+
+        events.expectAccount(EventType.UPDATE_TOTP).assertEvent();
+
+        Assert.assertTrue(driver.getPageSource().contains("pficon-delete"));
+
+        List<UserRepresentation> users = adminClient.realms().realm("test").users().search("test-user@localhost", null, null, null, 0, 1);
+        String userId = users.get(0).getId();
+        testingClient.testing().clearAdminEventQueue();
+        adminClient.realms().realm("test").users().get(userId).removeTotp();
+
+        totpPage.open();
+        Assert.assertFalse(driver.getPageSource().contains("pficon-delete"));
+
+        AdminEventRepresentation event = testingClient.testing().pollAdminEvent();
+        Assert.assertNotNull(event);
+        Assert.assertEquals(OperationType.ACTION.name(), event.getOperationType());
+        Assert.assertEquals("users/" + userId + "/remove-totp", event.getResourcePath());
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBrokerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBrokerTest.java
index aa44d85..29f796f 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBrokerTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/AbstractBrokerTest.java
@@ -1,5 +1,13 @@
 package org.keycloak.testsuite.broker;
 
+import static org.junit.Assert.assertEquals;
+import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient;
+import static org.keycloak.testsuite.admin.ApiUtil.resetUserPassword;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.List;
+
 import org.jboss.arquillian.graphene.page.Page;
 import org.junit.Before;
 import org.junit.Test;
@@ -11,15 +19,17 @@ import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.testsuite.AbstractKeycloakTest;
 import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.pages.AccountPasswordPage;
+import org.keycloak.testsuite.pages.ErrorPage;
 import org.keycloak.testsuite.pages.LoginPage;
 import org.keycloak.testsuite.pages.UpdateAccountInformationPage;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.util.List;
-
-import static org.keycloak.testsuite.admin.ApiUtil.createUserWithAdminClient;
-import static org.keycloak.testsuite.admin.ApiUtil.resetUserPassword;
+import org.keycloak.testsuite.util.RealmBuilder;
+import org.openqa.selenium.By;
+import org.openqa.selenium.TimeoutException;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.ExpectedCondition;
+import org.openqa.selenium.support.ui.WebDriverWait;
 
 public abstract class AbstractBrokerTest extends AbstractKeycloakTest {
 
@@ -42,9 +52,16 @@ public abstract class AbstractBrokerTest extends AbstractKeycloakTest {
 
     @Page
     protected LoginPage accountLoginPage;
+
     @Page
     protected UpdateAccountInformationPage updateAccountInformationPage;
 
+    @Page
+    protected AccountPasswordPage accountPasswordPage;
+
+    @Page
+    protected ErrorPage errorPage;
+
     @Override
     public void addTestRealms(List<RealmRepresentation> testRealms) {
         RealmRepresentation providerRealm = createProviderRealm();
@@ -115,17 +132,6 @@ public abstract class AbstractBrokerTest extends AbstractKeycloakTest {
         return identityProviderRepresentation;
     }
 
-    private void waitForPage(String title) {
-        long startAt = System.currentTimeMillis();
-
-        while (!driver.getTitle().toLowerCase().contains(title)
-                && System.currentTimeMillis() - startAt < 200) {
-            try {
-                Thread.sleep(5);
-            } catch (InterruptedException ignore) {}
-        }
-    }
-
     @Test
     public void logInAsUserInIDP() {
         driver.navigate().to(getAccountUrl(consumerRealmName()));
@@ -133,9 +139,7 @@ public abstract class AbstractBrokerTest extends AbstractKeycloakTest {
         log.debug("Clicking social " + getIDPAlias());
         accountLoginPage.clickSocial(getIDPAlias());
 
-        if (!driver.getCurrentUrl().contains("/auth/realms/" + providerRealmName() + "/")) {
-            log.debug("Not on provider realm page, url: " + driver.getCurrentUrl());
-        }
+        waitForPage("log in to");
 
         Assert.assertTrue("Driver should be on the provider realm page right now",
                 driver.getCurrentUrl().contains("/auth/realms/" + providerRealmName() + "/"));
@@ -153,9 +157,11 @@ public abstract class AbstractBrokerTest extends AbstractKeycloakTest {
         updateAccountInformationPage.updateAccountInformation("Firstname", "Lastname");
 
         UsersResource consumerUsers = adminClient.realm(consumerRealmName()).users();
-        Assert.assertTrue("There must be at least one user", consumerUsers.count() > 0);
 
-        List<UserRepresentation> users = consumerUsers.search("", 0, 5);
+        int userCount = consumerUsers.count();
+        Assert.assertTrue("There must be at least one user", userCount > 0);
+
+        List<UserRepresentation> users = consumerUsers.search("", 0, userCount);
 
         boolean isUserFound = false;
         for (UserRepresentation user : users) {
@@ -171,24 +177,94 @@ public abstract class AbstractBrokerTest extends AbstractKeycloakTest {
         testSingleLogout();
     }
 
-    protected void testSingleLogout() {
-        log.debug("Testing single log out");
+    @Test
+    public void loginWithExistingUser() {
+        logInAsUserInIDP();
 
-        driver.navigate().to(getAccountUrl(providerRealmName()));
+        Integer userCount = adminClient.realm(consumerRealmName()).users().count();
 
-        Assert.assertTrue("Should be logged in the account page", driver.getTitle().endsWith("Account Management"));
+        driver.navigate().to(getAccountUrl(consumerRealmName()));
+
+        log.debug("Clicking social " + getIDPAlias());
+        accountLoginPage.clickSocial(getIDPAlias());
+
+        waitForPage("log in to");
+
+        Assert.assertTrue("Driver should be on the provider realm page right now", driver.getCurrentUrl().contains("/auth/realms/" + providerRealmName() + "/"));
+
+        accountLoginPage.login(getUserLogin(), getUserPassword());
+
+        assertEquals(accountPage.buildUri().toASCIIString().replace("master", "consumer") + "/", driver.getCurrentUrl());
+
+        assertEquals(userCount, adminClient.realm(consumerRealmName()).users().count());
+    }
+
+    // KEYCLOAK-3267
+    @Test
+    public void loginWithExistingUserWithBruteForceEnabled() {
+        adminClient.realm(consumerRealmName()).update(RealmBuilder.create().bruteForceProtected(true).failureFactor(2).build());
+
+        loginWithExistingUser();
+
+        driver.navigate().to(getAccountPasswordUrl(consumerRealmName()));
+
+        accountPasswordPage.changePassword("password", "password");
+
+        driver.navigate().to(getAuthRoot()
+                + "/auth/realms/" + providerRealmName()
+                + "/protocol/" + "openid-connect"
+                + "/logout?redirect_uri=" + encodeUrl(getAccountUrl(providerRealmName())));
+
+        driver.navigate().to(getAccountUrl(consumerRealmName()));
 
-        String encodedAccount;
         try {
-            encodedAccount = URLEncoder.encode(getAccountUrl(providerRealmName()), "UTF-8");
-        } catch (UnsupportedEncodingException e) {
-            encodedAccount = getAccountUrl(providerRealmName());
+            waitForPage("log in to");
+        } catch (TimeoutException e) {
+            log.debug(driver.getTitle());
+            log.debug(driver.getPageSource());
+            Assert.fail("Timeout while waiting for login page");
+        }
+
+        for (int i = 0; i < 3; i++) {
+            try {
+                waitForElementEnabled("login");
+            } catch (TimeoutException e) {
+                Assert.fail("Timeout while waiting for login element enabled");
+            }
+
+            accountLoginPage.login(getUserLogin(), "invalid");
+        }
+
+        assertEquals("Invalid username or password.", accountLoginPage.getError());
+
+        accountLoginPage.clickSocial(getIDPAlias());
+
+        try {
+            waitForPage("log in to");
+        } catch (TimeoutException e) {
+            log.debug(driver.getTitle());
+            log.debug(driver.getPageSource());
+            Assert.fail("Timeout while waiting for login page");
         }
 
+        Assert.assertTrue("Driver should be on the provider realm page right now", driver.getCurrentUrl().contains("/auth/realms/" + providerRealmName() + "/"));
+
+        accountLoginPage.login(getUserLogin(), getUserPassword());
+
+        assertEquals("Account is disabled, contact admin.", errorPage.getError());
+    }
+
+    private void testSingleLogout() {
+        log.debug("Testing single log out");
+
+        driver.navigate().to(getAccountUrl(providerRealmName()));
+
+        Assert.assertTrue("Should be logged in the account page", driver.getTitle().endsWith("Account Management"));
+
         driver.navigate().to(getAuthRoot()
                 + "/auth/realms/" + providerRealmName()
                 + "/protocol/" + "openid-connect"
-                + "/logout?redirect_uri=" + encodedAccount);
+                + "/logout?redirect_uri=" + encodeUrl(getAccountUrl(providerRealmName())));
 
         waitForPage("log in to " + providerRealmName());
 
@@ -203,4 +279,49 @@ public abstract class AbstractBrokerTest extends AbstractKeycloakTest {
     private String getAccountUrl(String realmName) {
         return getAuthRoot() + "/auth/realms/" + realmName + "/account";
     }
+
+    private String getAccountPasswordUrl(String realmName) {
+        return getAuthRoot() + "/auth/realms/" + realmName + "/account/password";
+    }
+
+    private void waitForPage(final String title) {
+        WebDriverWait wait = new WebDriverWait(driver, 5);
+
+        ExpectedCondition<Boolean> condition = new ExpectedCondition<Boolean>() {
+            @Override
+            public Boolean apply(WebDriver input) {
+                return input.getTitle().toLowerCase().contains(title);
+            }
+        };
+
+        wait.until(condition);
+    }
+
+    private void waitForElementEnabled(final String elementName) {
+        WebDriverWait wait = new WebDriverWait(driver, 5);
+
+        ExpectedCondition<Boolean> condition = new ExpectedCondition<Boolean>() {
+            @Override
+            public Boolean apply(WebDriver input) {
+                List<WebElement> elements = input.findElements(By.name(elementName));
+                if (elements.size() == 0)
+                    return false;
+
+                return elements.get(0).isEnabled();
+            }
+        };
+
+        wait.until(condition);
+    }
+
+    private String encodeUrl(String url) {
+        String result;
+        try {
+            result = URLEncoder.encode(url, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            result = url;
+        }
+
+        return result;
+    }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlBrokerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlBrokerTest.java
index cdacaa7..7a8fb9c 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlBrokerTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlBrokerTest.java
@@ -1,5 +1,6 @@
 package org.keycloak.testsuite.broker;
 
+import org.junit.Ignore;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.IdentityProviderRepresentation;
 import org.keycloak.representations.idm.ProtocolMapperRepresentation;
@@ -12,6 +13,7 @@ import java.util.Map;
 
 import static org.keycloak.testsuite.broker.BrokerTestConstants.*;
 
+@Ignore
 public class KcSamlBrokerTest extends AbstractBrokerTest {
 
     @Override
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlSignedBrokerTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlSignedBrokerTest.java
index 128d1e0..1a2eca8 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlSignedBrokerTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/broker/KcSamlSignedBrokerTest.java
@@ -1,5 +1,6 @@
 package org.keycloak.testsuite.broker;
 
+import org.junit.Ignore;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.IdentityProviderRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
@@ -10,6 +11,7 @@ import java.util.Map;
 
 import static org.keycloak.testsuite.broker.BrokerTestConstants.*;
 
+@Ignore
 public class KcSamlSignedBrokerTest extends KcSamlBrokerTest {
 
     @Override
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java
index ab587c3..5d7d2c1 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/client/OIDCClientRegistrationTest.java
@@ -17,27 +17,61 @@
 
 package org.keycloak.testsuite.client;
 
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.message.BasicNameValuePair;
 import org.junit.Before;
 import org.junit.Test;
 import org.keycloak.OAuth2Constants;
+import org.keycloak.adapters.authentication.JWTClientCredentialsProvider;
 import org.keycloak.client.registration.Auth;
 import org.keycloak.client.registration.ClientRegistrationException;
+import org.keycloak.client.registration.HttpErrorException;
 import org.keycloak.common.util.CollectionUtil;
+import org.keycloak.common.util.KeycloakUriBuilder;
+import org.keycloak.constants.ServiceUrlConstants;
+import org.keycloak.jose.jwk.JSONWebKeySet;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.protocol.oidc.utils.OIDCResponseType;
+import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.idm.ClientInitialAccessCreatePresentation;
 import org.keycloak.representations.idm.ClientInitialAccessPresentation;
+import org.keycloak.representations.idm.ClientRegistrationTrustedHostRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.oidc.OIDCClientRepresentation;
-
+import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.util.OAuthClient;
+import java.security.PrivateKey;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.ws.rs.core.Response;
 
 import static org.junit.Assert.*;
+import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
 public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest {
 
+    private static final String PRIVATE_KEY = "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=";
+    private static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB";
+
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+        super.addTestRealms(testRealms);
+        testRealms.get(0).setPrivateKey(PRIVATE_KEY);
+        testRealms.get(0).setPublicKey(PUBLIC_KEY);
+    }
+
     @Before
     public void before() throws Exception {
         super.before();
@@ -46,11 +80,16 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest {
         reg.auth(Auth.token(token));
     }
 
-    public OIDCClientRepresentation create() throws ClientRegistrationException {
+    private OIDCClientRepresentation createRep() {
         OIDCClientRepresentation client = new OIDCClientRepresentation();
         client.setClientName("RegistrationAccessTokenTest");
         client.setClientUri("http://root");
         client.setRedirectUris(Collections.singletonList("http://redirect"));
+        return client;
+    }
+
+    public OIDCClientRepresentation create() throws ClientRegistrationException {
+        OIDCClientRepresentation client = createRep();
 
         OIDCClientRepresentation response = reg.oidc().create(client);
 
@@ -58,13 +97,53 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest {
     }
 
     @Test
+    public void testCreateWithTrustedHost() throws Exception {
+        reg.auth(null);
+
+        OIDCClientRepresentation client = createRep();
+
+        // Failed to create client
+        try {
+            reg.oidc().create(client);
+            Assert.fail("Not expected to successfuly register client");
+        } catch (ClientRegistrationException expected) {
+            HttpErrorException httpEx = (HttpErrorException) expected.getCause();
+            Assert.assertEquals(401, httpEx.getStatusLine().getStatusCode());
+        }
+
+        // Create trusted host entry
+        Response response = adminClient.realm(REALM_NAME).clientRegistrationTrustedHost().create(ClientRegistrationTrustedHostRepresentation.create("localhost", 2, 2));
+        Assert.assertEquals(201, response.getStatus());
+
+        // Successfully register client
+        reg.oidc().create(client);
+
+        // Just one remaining available
+        ClientRegistrationTrustedHostRepresentation rep = adminClient.realm(REALM_NAME).clientRegistrationTrustedHost().get("localhost");
+        Assert.assertEquals(1, rep.getRemainingCount().intValue());
+
+        // Successfully register client2
+        reg.oidc().create(client);
+
+        // Failed to create 3rd client
+        try {
+            reg.oidc().create(client);
+            Assert.fail("Not expected to successfuly register client");
+        } catch (ClientRegistrationException expected) {
+            HttpErrorException httpEx = (HttpErrorException) expected.getCause();
+            Assert.assertEquals(401, httpEx.getStatusLine().getStatusCode());
+        }
+    }
+
+    @Test
     public void createClient() throws ClientRegistrationException {
         OIDCClientRepresentation response = create();
 
         assertNotNull(response.getRegistrationAccessToken());
         assertNotNull(response.getClientIdIssuedAt());
         assertNotNull(response.getClientId());
-        assertNull(response.getClientSecretExpiresAt());
+        assertNotNull(response.getClientSecret());
+        assertEquals(0, response.getClientSecretExpiresAt().intValue());
         assertNotNull(response.getRegistrationClientUri());
         assertEquals("RegistrationAccessTokenTest", response.getClientName());
         assertEquals("http://root", response.getClientUri());
@@ -72,6 +151,7 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest {
         assertEquals("http://redirect", response.getRedirectUris().get(0));
         assertEquals(Arrays.asList("code", "none"), response.getResponseTypes());
         assertEquals(Arrays.asList(OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.REFRESH_TOKEN), response.getGrantTypes());
+        assertEquals(OIDCLoginProtocol.CLIENT_SECRET_BASIC, response.getTokenEndpointAuthMethod());
     }
 
     @Test
@@ -84,6 +164,9 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest {
         assertNotEquals(response.getRegistrationAccessToken(), rep.getRegistrationAccessToken());
         assertTrue(CollectionUtil.collectionEquals(Arrays.asList("code", "none"), response.getResponseTypes()));
         assertTrue(CollectionUtil.collectionEquals(Arrays.asList(OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.REFRESH_TOKEN), response.getGrantTypes()));
+        assertNotNull(response.getClientSecret());
+        assertEquals(0, response.getClientSecretExpiresAt().intValue());
+        assertEquals(OIDCLoginProtocol.CLIENT_SECRET_BASIC, response.getTokenEndpointAuthMethod());
     }
 
     @Test
@@ -122,4 +205,89 @@ public class OIDCClientRegistrationTest extends AbstractClientRegistrationTest {
         reg.oidc().delete(response);
     }
 
+    @Test
+    public void createClientWithJWKS() throws Exception {
+        OIDCClientRepresentation clientRep = createRep();
+
+        clientRep.setGrantTypes(Collections.singletonList(OAuth2Constants.CLIENT_CREDENTIALS));
+        clientRep.setTokenEndpointAuthMethod(OIDCLoginProtocol.PRIVATE_KEY_JWT);
+
+        // Corresponds to PRIVATE_KEY
+        JSONWebKeySet keySet = loadJson(getClass().getResourceAsStream("/clientreg-test/jwks.json"), JSONWebKeySet.class);
+        clientRep.setJwks(keySet);
+
+        OIDCClientRepresentation response = reg.oidc().create(clientRep);
+        Assert.assertEquals(OIDCLoginProtocol.PRIVATE_KEY_JWT, response.getTokenEndpointAuthMethod());
+        Assert.assertNull(response.getClientSecret());
+        Assert.assertNull(response.getClientSecretExpiresAt());
+
+        // Tries to authenticate client with privateKey JWT
+        String signedJwt = getClientSignedJWT(response.getClientId());
+        OAuthClient.AccessTokenResponse accessTokenResponse = doClientCredentialsGrantRequest(signedJwt);
+        Assert.assertEquals(200, accessTokenResponse.getStatusCode());
+        AccessToken accessToken = oauth.verifyToken(accessTokenResponse.getAccessToken());
+        Assert.assertEquals(response.getClientId(), accessToken.getAudience()[0]);
+    }
+
+    @Test
+    public void createClientWithJWKSURI() throws Exception {
+        OIDCClientRepresentation clientRep = createRep();
+
+        clientRep.setGrantTypes(Collections.singletonList(OAuth2Constants.CLIENT_CREDENTIALS));
+        clientRep.setTokenEndpointAuthMethod(OIDCLoginProtocol.PRIVATE_KEY_JWT);
+
+        // Use the realmKey for client authentication too
+        clientRep.setJwksUri(oauth.getCertsUrl(REALM_NAME));
+
+        OIDCClientRepresentation response = reg.oidc().create(clientRep);
+        Assert.assertEquals(OIDCLoginProtocol.PRIVATE_KEY_JWT, response.getTokenEndpointAuthMethod());
+        Assert.assertNull(response.getClientSecret());
+        Assert.assertNull(response.getClientSecretExpiresAt());
+
+        // Tries to authenticate client with privateKey JWT
+        String signedJwt = getClientSignedJWT(response.getClientId());
+        OAuthClient.AccessTokenResponse accessTokenResponse = doClientCredentialsGrantRequest(signedJwt);
+        Assert.assertEquals(200, accessTokenResponse.getStatusCode());
+        AccessToken accessToken = oauth.verifyToken(accessTokenResponse.getAccessToken());
+        Assert.assertEquals(response.getClientId(), accessToken.getAudience()[0]);
+    }
+
+
+    // Client auth with signedJWT - helper methods
+
+    private String getClientSignedJWT(String clientId) {
+        String realmInfoUrl = KeycloakUriBuilder.fromUri(getAuthServerRoot()).path(ServiceUrlConstants.REALM_INFO_PATH).build(REALM_NAME).toString();
+
+        PrivateKey privateKey = KeycloakModelUtils.getPrivateKey(PRIVATE_KEY);
+
+        JWTClientCredentialsProvider jwtProvider = new JWTClientCredentialsProvider();
+        jwtProvider.setPrivateKey(privateKey);
+        jwtProvider.setTokenTimeout(10);
+        return jwtProvider.createSignedRequestToken(clientId, realmInfoUrl);
+
+    }
+
+
+    private OAuthClient.AccessTokenResponse doClientCredentialsGrantRequest(String signedJwt) throws Exception {
+        List<NameValuePair> parameters = new LinkedList<NameValuePair>();
+        parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.CLIENT_CREDENTIALS));
+        parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION_TYPE, OAuth2Constants.CLIENT_ASSERTION_TYPE_JWT));
+        parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ASSERTION, signedJwt));
+
+        HttpResponse response = sendRequest(oauth.getServiceAccountUrl(), parameters);
+        return new OAuthClient.AccessTokenResponse(response);
+    }
+
+    private HttpResponse sendRequest(String requestUrl, List<NameValuePair> parameters) throws Exception {
+        CloseableHttpClient client = new DefaultHttpClient();
+        try {
+            HttpPost post = new HttpPost(requestUrl);
+            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
+            post.setEntity(formEntity);
+            return client.execute(post);
+        } finally {
+            oauth.closeClient(client);
+        }
+    }
+
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/domainextension/CustomExtensionTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/domainextension/CustomExtensionTest.java
new file mode 100644
index 0000000..36b5702
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/domainextension/CustomExtensionTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.domainextension;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.Test;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.AbstractKeycloakTest;
+import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.client.resources.TestExampleCompanyResource;
+import org.keycloak.testsuite.util.RealmBuilder;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class CustomExtensionTest extends AbstractKeycloakTest {
+
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+        RealmRepresentation foo = RealmBuilder.create().name("foo").build();
+        testRealms.add(foo);
+    }
+
+    @Test
+    public void testDomainExtension() throws Exception {
+        companyResource().createCompany("foo", buildCompany("foo-company"));
+        companyResource().createCompany("foo", buildCompany("bar-company"));
+        companyResource().createCompany("master", buildCompany("master-company"));
+
+        List<CompanyRepresentation> fooCompanies = companyResource().getCompanies("foo");
+        List<CompanyRepresentation> masterCompanies = companyResource().getCompanies("master");
+
+        assertCompanyNames(fooCompanies, "foo-company", "bar-company");
+        assertCompanyNames(masterCompanies, "master-company");
+
+        companyResource().deleteAllCompanies("foo");
+        companyResource().deleteAllCompanies("master");
+    }
+
+    private TestExampleCompanyResource companyResource() {
+        return testingClient.testExampleCompany();
+    }
+
+    private CompanyRepresentation buildCompany(String companyName) {
+        CompanyRepresentation rep = new CompanyRepresentation();
+        rep.setName(companyName);
+        return rep;
+    }
+
+    private void assertCompanyNames(List<CompanyRepresentation> companies, String... expectedNames) {
+        Set<String> names = new HashSet<>();
+        for (CompanyRepresentation comp : companies) {
+            names.add(comp.getName());
+        }
+
+        Assert.assertEquals(expectedNames.length, names.size());
+        for (String expectedName : expectedNames) {
+            Assert.assertTrue(names.contains(expectedName));
+        }
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/events/AbstractEventsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/events/AbstractEventsTest.java
new file mode 100644
index 0000000..d94353e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/events/AbstractEventsTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.keycloak.testsuite.events;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.AbstractKeycloakTest;
+import org.keycloak.testsuite.client.resources.TestingResource;
+
+/**
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
+ */
+public abstract class AbstractEventsTest extends AbstractKeycloakTest {
+
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+    }
+
+    protected TestingResource testing() {
+        return getTestingClient().testing();
+    }
+
+    protected List<String> toList(Enum... enumTypes) {
+        List<String> enumList = new ArrayList<>();
+        for (Enum type : enumTypes) {
+            enumList.add(type.toString());
+        }
+
+        return enumList;
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/events/AdminEventStoreProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/events/AdminEventStoreProviderTest.java
new file mode 100644
index 0000000..497fe97
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/events/AdminEventStoreProviderTest.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.events;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Test;
+import org.keycloak.events.admin.OperationType;
+import org.keycloak.representations.idm.AdminEventRepresentation;
+import org.keycloak.representations.idm.AuthDetailsRepresentation;
+
+/**
+ * @author <a href="mailto:giriraj.sharma27@gmail.com">Giriraj Sharma</a>
+ * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
+ */
+public class AdminEventStoreProviderTest extends AbstractEventsTest {
+
+    @After
+    public void after() {
+        testing().clearAdminEventStore();
+    }
+
+    @Test
+    public void save() {
+        testing().onAdminEvent(create("realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+    }
+
+    @Test
+    public void query() {
+        long oldest = System.currentTimeMillis() - 30000;
+        long newest = System.currentTimeMillis() + 30000;
+
+        testing().onAdminEvent(create("realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create(newest, "realmId", OperationType.ACTION, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create(newest, "realmId", OperationType.ACTION, "realmId", "clientId", "userId2", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create("realmId2", OperationType.CREATE, "realmId2", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create(oldest, "realmId", OperationType.CREATE, "realmId", "clientId2", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create("realmId", OperationType.CREATE, "realmId", "clientId", "userId2", "127.0.0.1", "/admin/realms/master", "error"), false);
+
+        Assert.assertEquals(5, testing().getAdminEvents(null, null, null, "clientId", null, null, null, null, null, null, null).size());
+        Assert.assertEquals(5, testing().getAdminEvents(null, null, "realmId", null, null, null, null, null, null, null, null).size());
+        Assert.assertEquals(4, testing().getAdminEvents(null, toList(OperationType.CREATE), null, null, null, null, null, null, null, null, null).size());
+        Assert.assertEquals(6, testing().getAdminEvents(null, toList(OperationType.CREATE, OperationType.ACTION), null, null, null, null, null, null, null, null, null).size());
+        Assert.assertEquals(4, testing().getAdminEvents(null, null, null, null, "userId", null, null, null, null, null, null).size());
+
+        Assert.assertEquals(1, testing().getAdminEvents(null, toList(OperationType.ACTION), null, null, "userId", null, null, null, null, null, null).size());
+
+        Assert.assertEquals(2, testing().getAdminEvents(null, null, null, null, null, null, null, null, null, null, 2).size());
+        Assert.assertEquals(1, testing().getAdminEvents(null, null, null, null, null, null, null, null, null, 5, null).size());
+
+        Assert.assertEquals(newest, testing().getAdminEvents(null, null, null, null, null, null, null, null, null, null, 1).get(0).getTime());
+        Assert.assertEquals(oldest, testing().getAdminEvents(null, null, null, null, null, null, null, null, null, 5, 1).get(0).getTime());
+
+        testing().clearAdminEventStore("realmId");
+        testing().clearAdminEventStore("realmId2");
+
+        Assert.assertEquals(0, testing().getAdminEvents(null, null, null, null, null, null, null, null, null, null, null).size());
+
+        String d1 = new String("2015-03-04");
+        String d2 = new String("2015-03-05");
+        String d3 = new String("2015-03-06");
+        String d4 = new String("2015-03-07");
+
+        String d5 = new String("2015-03-01");
+        String d6 = new String("2015-03-03");
+        String d7 = new String("2015-03-08");
+        String d8 = new String("2015-03-10");
+
+        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
+        Date date1 = null, date2 = null, date3 = null, date4 = null;
+
+        try {
+            date1 = formatter.parse(d1);
+            date2 = formatter.parse(d2);
+            date3 = formatter.parse(d3);
+            date4 = formatter.parse(d4);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+
+        testing().onAdminEvent(create(date1, "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create(date1, "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create(date2, "realmId", OperationType.ACTION, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create(date2, "realmId", OperationType.ACTION, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create(date3, "realmId", OperationType.UPDATE, "realmId", "clientId", "userId2", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create(date3, "realmId", OperationType.DELETE, "realmId", "clientId", "userId2", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create(date4, "realmId2", OperationType.CREATE, "realmId2", "clientId2", "userId2", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create(date4, "realmId2", OperationType.CREATE, "realmId2", "clientId2", "userId2", "127.0.0.1", "/admin/realms/master", "error"), false);
+
+        Assert.assertEquals(6, testing().getAdminEvents(null, null, null, "clientId", null, null, null, null, null, null, null).size());
+        Assert.assertEquals(2, testing().getAdminEvents(null, null, null, "clientId2", null, null, null, null, null, null, null).size());
+
+        Assert.assertEquals(6, testing().getAdminEvents(null, null, "realmId", null, null, null, null, null, null, null, null).size());
+        Assert.assertEquals(2, testing().getAdminEvents(null, null, "realmId2", null, null, null, null, null, null, null, null).size());
+
+        Assert.assertEquals(4, testing().getAdminEvents(null, null, null, null, "userId", null, null, null, null, null, null).size());
+        Assert.assertEquals(4, testing().getAdminEvents(null, null, null, null, "userId2", null, null, null, null, null, null).size());
+
+        Assert.assertEquals(2, testing().getAdminEvents(null, toList(OperationType.ACTION), null, null, null, null, null, null, null, null, null).size());
+        Assert.assertEquals(6, testing().getAdminEvents(null, toList(OperationType.CREATE, OperationType.ACTION), null, null, null, null, null, null, null, null, null).size());
+        Assert.assertEquals(1, testing().getAdminEvents(null, toList(OperationType.UPDATE), null, null, null, null, null, null, null, null, null).size());
+        Assert.assertEquals(1, testing().getAdminEvents(null, toList(OperationType.DELETE), null, null, null, null, null, null, null, null, null).size());
+        Assert.assertEquals(4, testing().getAdminEvents(null, toList(OperationType.CREATE), null, null, null, null, null, null, null, null, null).size());
+
+        Assert.assertEquals(8, testing().getAdminEvents(null, null, null, null, null, null, null, d1, null, null, null).size());
+        Assert.assertEquals(8, testing().getAdminEvents(null, null, null, null, null, null, null, null, d4, null, null).size());
+
+        Assert.assertEquals(4, testing().getAdminEvents(null, null, null, null, null, null, null, d3, null, null, null).size());
+        Assert.assertEquals(4, testing().getAdminEvents(null, null, null, null, null, null, null, null, d2, null, null).size());
+
+        Assert.assertEquals(0, testing().getAdminEvents(null, null, null, null, null, null, null, d7, null, null, null).size());
+        Assert.assertEquals(0, testing().getAdminEvents(null, null, null, null, null, null, null, null, d6, null, null).size());
+
+        Assert.assertEquals(8, testing().getAdminEvents(null, null, null, null, null, null, null, d1, d4, null, null).size());
+        Assert.assertEquals(6, testing().getAdminEvents(null, null, null, null, null, null, null, d2, d4, null, null).size());
+        Assert.assertEquals(4, testing().getAdminEvents(null, null, null, null, null, null, null, d1, d2, null, null).size());
+        Assert.assertEquals(4, testing().getAdminEvents(null, null, null, null, null, null, null, d3, d4, null, null).size());
+
+        Assert.assertEquals(0, testing().getAdminEvents(null, null, null, null, null, null, null, d5, d6, null, null).size());
+        Assert.assertEquals(0, testing().getAdminEvents(null, null, null, null, null, null, null, d7, d8, null, null).size());
+
+    }
+
+    @Test
+    public void queryResourcePath() {
+        long oldest = System.currentTimeMillis() - 30000;
+        long newest = System.currentTimeMillis() + 30000;
+
+        testing().onAdminEvent(create("realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create(newest, "realmId", OperationType.ACTION, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create(newest, "realmId", OperationType.ACTION, "realmId", "clientId", "userId2", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create("realmId2", OperationType.CREATE, "realmId2", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create(oldest, "realmId", OperationType.CREATE, "realmId", "clientId2", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create("realmId", OperationType.CREATE, "realmId", "clientId", "userId2", "127.0.0.1", "/admin/realms/master", "error"), false);
+
+        Assert.assertEquals(6, testing().getAdminEvents(null, null, null, null, null, null, "/admin", null, null, null, null).size());
+        Assert.assertEquals(6, testing().getAdminEvents(null, null, null, null, null, null, "/realms", null, null, null, null).size());
+        Assert.assertEquals(6, testing().getAdminEvents(null, null, null, null, null, null, "/master", null, null, null, null).size());
+        Assert.assertEquals(6, testing().getAdminEvents(null, null, null, null, null, null, "/admin/realms", null, null, null, null).size());
+        Assert.assertEquals(6, testing().getAdminEvents(null, null, null, null, null, null, "/realms/master", null, null, null, null).size());
+        Assert.assertEquals(6, testing().getAdminEvents(null, null, null, null, null, null, "/admin/realms/master", null, null, null, null).size());
+    }
+
+    @Test
+    public void clear() {
+        testing().onAdminEvent(create(System.currentTimeMillis() - 30000, "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create(System.currentTimeMillis() - 20000, "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create(System.currentTimeMillis(), "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create(System.currentTimeMillis(), "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create(System.currentTimeMillis() - 30000, "realmId2", OperationType.CREATE, "realmId2", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+
+        testing().clearAdminEventStore("realmId");
+
+        Assert.assertEquals(1, testing().getAdminEvents(null, null, null, null, null, null, null, null, null, null, null).size());
+    }
+
+    @Test
+    public void clearOld() {
+        testing().onAdminEvent(create(System.currentTimeMillis() - 30000, "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create(System.currentTimeMillis() - 20000, "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create(System.currentTimeMillis(), "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create(System.currentTimeMillis(), "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+        testing().onAdminEvent(create(System.currentTimeMillis() - 30000, "realmId", OperationType.CREATE, "realmId", "clientId", "userId", "127.0.0.1", "/admin/realms/master", "error"), false);
+
+        testing().clearAdminEventStore("realmId", System.currentTimeMillis() - 10000);
+
+        Assert.assertEquals(2, testing().getAdminEvents(null, null, null, null, null, null, null, null, null, null, null).size());
+    }
+
+    private AdminEventRepresentation create(String realmId, OperationType operation, String authRealmId, String authClientId, String authUserId, String authIpAddress, String resourcePath, String error) {
+        return create(System.currentTimeMillis(), realmId, operation, authRealmId, authClientId, authUserId, authIpAddress, resourcePath, error);
+    }
+
+    private AdminEventRepresentation create(Date date, String realmId, OperationType operation, String authRealmId, String authClientId, String authUserId, String authIpAddress, String resourcePath, String error) {
+        return create(date.getTime(), realmId, operation, authRealmId, authClientId, authUserId, authIpAddress, resourcePath, error);
+    }
+
+    private AdminEventRepresentation create(long time, String realmId, OperationType operation, String authRealmId, String authClientId, String authUserId, String authIpAddress, String resourcePath, String error) {
+        AdminEventRepresentation e = new AdminEventRepresentation();
+        e.setTime(time);
+        e.setRealmId(realmId);
+        e.setOperationType(operation.toString());
+        AuthDetailsRepresentation authDetails = new AuthDetailsRepresentation();
+        authDetails.setRealmId(authRealmId);
+        authDetails.setClientId(authClientId);
+        authDetails.setUserId(authUserId);
+        authDetails.setIpAddress(authIpAddress);
+        e.setAuthDetails(authDetails);
+        e.setResourcePath(resourcePath);
+        e.setError(error);
+
+        return e;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/events/EventStoreProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/events/EventStoreProviderTest.java
new file mode 100755
index 0000000..d8a08fc
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/events/EventStoreProviderTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.events;
+
+import org.apache.commons.lang3.StringUtils;
+import org.junit.Assert;
+import org.junit.Test;
+import org.keycloak.events.EventType;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.After;
+import org.keycloak.representations.idm.EventRepresentation;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
+ */
+public class EventStoreProviderTest extends AbstractEventsTest {
+
+    @After
+    public void after() {
+        testing().clearEventStore();
+    }
+
+    @Test
+    public void save() {
+        testing().onEvent(create(EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
+    }
+
+    @Test
+    public void query() {
+        long oldest = System.currentTimeMillis() - 30000;
+        long newest = System.currentTimeMillis() + 30000;
+
+        testing().onEvent(create(EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
+        testing().onEvent(create(newest, EventType.REGISTER, "realmId", "clientId", "userId", "127.0.0.1", "error"));
+        testing().onEvent(create(newest, EventType.REGISTER, "realmId", "clientId", "userId2", "127.0.0.1", "error"));
+        testing().onEvent(create(EventType.LOGIN, "realmId2", "clientId", "userId", "127.0.0.1", "error"));
+        testing().onEvent(create(oldest, EventType.LOGIN, "realmId", "clientId2", "userId", "127.0.0.1", "error"));
+        testing().onEvent(create(EventType.LOGIN, "realmId", "clientId", "userId2", "127.0.0.1", "error"));
+
+        Assert.assertEquals(5, testing().queryEvents(null, null, "clientId", null, null, null, null, null, null).size());
+        Assert.assertEquals(5, testing().queryEvents("realmId", null, null, null, null, null, null, null, null).size());
+        Assert.assertEquals(4, testing().queryEvents(null, toList(EventType.LOGIN), null, null, null, null, null, null, null).size());
+        Assert.assertEquals(6, testing().queryEvents(null, toList(EventType.LOGIN, EventType.REGISTER), null, null, null, null, null, null, null).size());
+        Assert.assertEquals(4, testing().queryEvents(null, null, null, "userId", null, null, null, null, null).size());
+
+        Assert.assertEquals(1, testing().queryEvents(null, toList(EventType.REGISTER), null, "userId", null, null, null, null, null).size());
+
+        Assert.assertEquals(2, testing().queryEvents(null, null, null, null, null, null, null, null, 2).size());
+        Assert.assertEquals(1, testing().queryEvents(null, null, null, null, null, null, null, 5, null).size());
+
+        Assert.assertEquals(newest, testing().queryEvents(null, null, null, null, null, null, null, null, 1).get(0).getTime());
+        Assert.assertEquals(oldest, testing().queryEvents(null, null, null, null, null, null, null, 5, 1).get(0).getTime());
+
+        testing().clearEventStore("realmId");
+        testing().clearEventStore("realmId2");
+
+        Assert.assertEquals(0, testing().queryEvents(null, null, null, null, null, null, null, null, null).size());
+
+        String d1 = new String("2015-03-04");
+        String d2 = new String("2015-03-05");
+        String d3 = new String("2015-03-06");
+        String d4 = new String("2015-03-07");
+
+        String d5 = new String("2015-03-01");
+        String d6 = new String("2015-03-03");
+        String d7 = new String("2015-03-08");
+        String d8 = new String("2015-03-10");
+
+        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
+        Date date1 = null, date2 = null, date3 = null, date4 = null;
+
+        try {
+            date1 = formatter.parse(d1);
+            date2 = formatter.parse(d2);
+            date3 = formatter.parse(d3);
+            date4 = formatter.parse(d4);
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+
+        testing().onEvent(create(date1, EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
+        testing().onEvent(create(date1, EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
+        testing().onEvent(create(date2, EventType.REGISTER, "realmId", "clientId", "userId", "127.0.0.1", "error"));
+        testing().onEvent(create(date2, EventType.REGISTER, "realmId", "clientId", "userId", "127.0.0.1", "error"));
+        testing().onEvent(create(date3, EventType.CODE_TO_TOKEN, "realmId", "clientId", "userId2", "127.0.0.1", "error"));
+        testing().onEvent(create(date3, EventType.LOGOUT, "realmId", "clientId", "userId2", "127.0.0.1", "error"));
+        testing().onEvent(create(date4, EventType.UPDATE_PROFILE, "realmId2", "clientId2", "userId2", "127.0.0.1", "error"));
+        testing().onEvent(create(date4, EventType.UPDATE_EMAIL, "realmId2", "clientId2", "userId2", "127.0.0.1", "error"));
+
+        Assert.assertEquals(6, testing().queryEvents(null, null, "clientId", null, null, null, null, null, null).size());
+        Assert.assertEquals(2, testing().queryEvents(null, null, "clientId2", null, null, null, null, null, null).size());
+
+        Assert.assertEquals(6, testing().queryEvents("realmId", null, null, null, null, null, null, null, null).size());
+        Assert.assertEquals(2, testing().queryEvents("realmId2", null, null, null, null, null, null, null, null).size());
+
+        Assert.assertEquals(4, testing().queryEvents(null, null, null, "userId", null, null, null, null, null).size());
+        Assert.assertEquals(4, testing().queryEvents(null, null, null, "userId2", null, null, null, null, null).size());
+
+        Assert.assertEquals(2, testing().queryEvents(null, toList(EventType.LOGIN), null, null, null, null, null, null, null).size());
+        Assert.assertEquals(2, testing().queryEvents(null, toList(EventType.REGISTER), null, null, null, null, null, null, null).size());
+        Assert.assertEquals(4, testing().queryEvents(null, toList(EventType.LOGIN, EventType.REGISTER), null, null, null, null, null, null, null).size());
+        Assert.assertEquals(1, testing().queryEvents(null, toList(EventType.CODE_TO_TOKEN), null, null, null, null, null, null, null).size());
+        Assert.assertEquals(1, testing().queryEvents(null, toList(EventType.LOGOUT), null, null, null, null, null, null, null).size());
+        Assert.assertEquals(1, testing().queryEvents(null, toList(EventType.UPDATE_PROFILE), null, null, null, null, null, null, null).size());
+        Assert.assertEquals(1, testing().queryEvents(null, toList(EventType.UPDATE_EMAIL), null, null, null, null, null, null, null).size());
+
+        Assert.assertEquals(8, testing().queryEvents(null, null, null, null, d1, null, null, null, null).size());
+        Assert.assertEquals(8, testing().queryEvents(null, null, null, null, null, d4, null, null, null).size());
+
+        Assert.assertEquals(4, testing().queryEvents(null, null, null, null, d3, null, null, null, null).size());
+        Assert.assertEquals(4, testing().queryEvents(null, null, null, null, null, d2, null, null, null).size());
+
+        Assert.assertEquals(0, testing().queryEvents(null, null, null, null, d7, null, null, null, null).size());
+        Assert.assertEquals(0, testing().queryEvents(null, null, null, null, null, d6, null, null, null).size());
+
+        Assert.assertEquals(8, testing().queryEvents(null, null, null, null, d1, d4, null, null, null).size());
+        Assert.assertEquals(6, testing().queryEvents(null, null, null, null, d2, d4, null, null, null).size());
+        Assert.assertEquals(4, testing().queryEvents(null, null, null, null, d1, d2, null, null, null).size());
+        Assert.assertEquals(4, testing().queryEvents(null, null, null, null, d3, d4, null, null, null).size());
+
+        Assert.assertEquals(0, testing().queryEvents(null, null, null, null, d5, d6, null, null, null).size());
+        Assert.assertEquals(0, testing().queryEvents(null, null, null, null, d7, d8, null, null, null).size());
+    }
+
+    @Test
+    public void clear() {
+        testing().onEvent(create(System.currentTimeMillis() - 30000, EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
+        testing().onEvent(create(System.currentTimeMillis() - 20000, EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
+        testing().onEvent(create(System.currentTimeMillis(), EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
+        testing().onEvent(create(System.currentTimeMillis(), EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
+        testing().onEvent(create(System.currentTimeMillis() - 30000, EventType.LOGIN, "realmId2", "clientId", "userId", "127.0.0.1", "error"));
+
+        testing().clearEventStore("realmId");
+
+        Assert.assertEquals(1, testing().queryEvents(null, null, null, null, null, null, null, null, null).size());
+    }
+
+    @Test
+    public void lengthExceedLimit(){
+        testing().onEvent(create(System.currentTimeMillis() - 30000, EventType.LOGIN, "realmId", StringUtils.repeat("clientId", 100), "userId", "127.0.0.1", "error"));
+        testing().onEvent(create(System.currentTimeMillis() - 30000, EventType.LOGIN, StringUtils.repeat("realmId", 100), "clientId", "userId", "127.0.0.1", "error"));
+        testing().onEvent(create(System.currentTimeMillis() - 30000, EventType.LOGIN, "realmId", "clientId", StringUtils.repeat("userId", 100), "127.0.0.1", "error"));
+
+    }
+
+    @Test
+    public void maxLengthWithNull(){
+        testing().onEvent(create(System.currentTimeMillis() - 30000, EventType.LOGIN, null, null, null, "127.0.0.1", "error"));
+    }
+
+    @Test
+    public void clearOld() {
+        testing().onEvent(create(System.currentTimeMillis() - 30000, EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
+        testing().onEvent(create(System.currentTimeMillis() - 20000, EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
+        testing().onEvent(create(System.currentTimeMillis(), EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
+        testing().onEvent(create(System.currentTimeMillis(), EventType.LOGIN, "realmId", "clientId", "userId", "127.0.0.1", "error"));
+        testing().onEvent(create(System.currentTimeMillis() - 30000, EventType.LOGIN, "realmId2", "clientId", "userId", "127.0.0.1", "error"));
+
+        testing().clearEventStore("realmId", System.currentTimeMillis() - 10000);
+
+        Assert.assertEquals(3, testing().queryEvents(null, null, null, null, null, null, null, null, null).size());
+    }
+
+    private EventRepresentation create(EventType event, String realmId, String clientId, String userId, String ipAddress, String error) {
+        return create(System.currentTimeMillis(), event, realmId, clientId, userId, ipAddress, error);
+    }
+
+    private EventRepresentation create(Date date, EventType event, String realmId, String clientId, String userId, String ipAddress, String error) {
+        return create(date.getTime(), event, realmId, clientId, userId, ipAddress, error);
+    }
+
+    private EventRepresentation create(long time, EventType event, String realmId, String clientId, String userId, String ipAddress, String error) {
+        EventRepresentation e = new EventRepresentation();
+        e.setTime(time);
+        e.setType(event.toString());
+        e.setRealmId(realmId);
+        e.setClientId(clientId);
+        e.setUserId(userId);
+        e.setIpAddress(ipAddress);
+        e.setError(error);
+
+        Map<String, String> details = new HashMap<String, String>();
+        details.put("key1", "value1");
+        details.put("key2", "value2");
+
+        e.setDetails(details);
+
+        return e;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportTest.java
new file mode 100755
index 0000000..6abaf97
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportTest.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.exportimport;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.exportimport.ExportImportConfig;
+import org.keycloak.exportimport.dir.DirExportProvider;
+import org.keycloak.exportimport.dir.DirExportProviderFactory;
+import org.keycloak.exportimport.singlefile.SingleFileExportProviderFactory;
+import org.keycloak.representations.idm.ComponentRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+
+import java.io.File;
+import java.net.URL;
+import java.util.List;
+import java.util.regex.Matcher;
+import org.jboss.arquillian.container.spi.client.container.LifecycleException;
+import org.junit.After;
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.util.UserBuilder;
+
+import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
+
+/**
+ *
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
+ */
+public class ExportImportTest extends AbstractExportImportTest {
+
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+        RealmRepresentation testRealm1 = loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class);
+        testRealm1.getUsers().add(makeUser("user1"));
+        testRealm1.getUsers().add(makeUser("user2"));
+        testRealm1.getUsers().add(makeUser("user3"));
+        testRealms.add(testRealm1);
+
+        RealmRepresentation testRealm2 = loadJson(getClass().getResourceAsStream("/model/testrealm.json"), RealmRepresentation.class);
+        testRealm2.setId("test-realm");
+        testRealms.add(testRealm2);
+    }
+
+    private UserRepresentation makeUser(String userName) {
+        return UserBuilder.create()
+                .username(userName)
+                .email(userName + "@test.com")
+                .password("password")
+                .build();
+    }
+
+    @After
+    public void clearExportImportProps() throws LifecycleException {
+        clearExportImportProperties();
+    }
+
+    @Test
+    public void testDirFullExportImport() throws Throwable {
+        testingClient.testing().setProvider(DirExportProviderFactory.PROVIDER_ID);
+        String targetDirPath = testingClient.testing().getExportImportTestDirectory()+ File.separator + "dirExport";
+        DirExportProvider.recursiveDeleteDir(new File(targetDirPath));
+        testingClient.testing().setDir(targetDirPath);
+        testingClient.testing().setUsersPerFile(ExportImportConfig.DEFAULT_USERS_PER_FILE);
+
+        testFullExportImport();
+
+        // There should be 6 files in target directory (3 realm, 3 user)
+        Assert.assertEquals(6, new File(targetDirPath).listFiles().length);
+    }
+
+    @Test
+    public void testDirRealmExportImport() throws Throwable {
+        testingClient.testing().setProvider(DirExportProviderFactory.PROVIDER_ID);
+        String targetDirPath = testingClient.testing().getExportImportTestDirectory() + File.separator + "dirRealmExport";
+        DirExportProvider.recursiveDeleteDir(new File(targetDirPath));
+        testingClient.testing().setDir(targetDirPath);
+        testingClient.testing().setUsersPerFile(3);
+
+        testRealmExportImport();
+
+        // There should be 3 files in target directory (1 realm, 3 user)
+        File[] files = new File(targetDirPath).listFiles();
+        Assert.assertEquals(4, files.length);
+    }
+
+    @Test
+    public void testSingleFileFullExportImport() throws Throwable {
+        testingClient.testing().setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
+        String targetFilePath = testingClient.testing().getExportImportTestDirectory() + File.separator + "singleFile-full.json";
+        testingClient.testing().setFile(targetFilePath);
+
+        testFullExportImport();
+    }
+
+    @Test
+    public void testSingleFileRealmExportImport() throws Throwable {
+        testingClient.testing().setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
+        String targetFilePath = testingClient.testing().getExportImportTestDirectory() + File.separator + "singleFile-realm.json";
+        testingClient.testing().setFile(targetFilePath);
+
+        testRealmExportImport();
+    }
+
+    @Test
+    public void testSingleFileRealmWithoutBuiltinsImport() throws Throwable {
+        // Remove test realm
+        removeRealm("test-realm");
+
+        // Set the realm, which doesn't have builtin clients/roles inside JSON
+        testingClient.testing().setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
+        URL url = ExportImportTest.class.getResource("/model/testrealm.json");
+        String targetFilePath = new File(url.getFile()).getAbsolutePath();
+        testingClient.testing().setFile(targetFilePath);
+
+        testingClient.testing().setAction(ExportImportConfig.ACTION_IMPORT);
+
+        testingClient.testing().runImport();
+
+        RealmResource testRealmRealm = adminClient.realm("test-realm");
+
+        ExportImportUtil.assertDataImportedInRealm(adminClient, testingClient, testRealmRealm.toRepresentation());
+    }
+
+    @Test
+    public void testComponentExportImport() throws Throwable {
+        RealmRepresentation realmRep = new RealmRepresentation();
+        realmRep.setRealm("component-realm");
+        adminClient.realms().create(realmRep);
+        Assert.assertEquals(4, adminClient.realms().findAll().size());
+        RealmResource realm = adminClient.realm("component-realm");
+        realmRep = realm.toRepresentation();
+        ComponentRepresentation component = new ComponentRepresentation();
+        component.setProviderId("dummy");
+        component.setProviderType("dummyType");
+        component.setName("dummy-name");
+        component.setParentId(realmRep.getId());
+        component.setConfig(new MultivaluedHashMap<>());
+        component.getConfig().add("name", "value");
+        realm.components().add(component);
+
+
+        testingClient.testing().setProvider(SingleFileExportProviderFactory.PROVIDER_ID);
+
+        String targetFilePath = testingClient.testing().getExportImportTestDirectory() + File.separator + "singleFile-realm.json";
+        testingClient.testing().setFile(targetFilePath);
+        testingClient.testing().setAction(ExportImportConfig.ACTION_EXPORT);
+        testingClient.testing().setRealmName("component-realm");
+
+        testingClient.testing().runExport();
+
+        // Delete some realm (and some data in admin realm)
+        adminClient.realm("component-realm").remove();
+
+        Assert.assertEquals(3, adminClient.realms().findAll().size());
+
+        // Configure import
+        testingClient.testing().setAction(ExportImportConfig.ACTION_IMPORT);
+
+        testingClient.testing().runImport();
+
+        realmRep = realm.toRepresentation();
+
+        List<ComponentRepresentation> components = realm.components().query();
+
+        Assert.assertEquals(1, components.size());
+
+        component = components.get(0);
+
+        Assert.assertEquals("dummy-name", component.getName());
+        Assert.assertEquals("dummyType", component.getProviderType());
+        Assert.assertEquals("dummy", component.getProviderId());
+        Assert.assertEquals(realmRep.getId(), component.getParentId());
+        Assert.assertEquals(1, component.getConfig().size());
+        Assert.assertEquals("value", component.getConfig().getFirst("name"));
+
+        adminClient.realm("component-realm").remove();
+    }
+
+
+
+
+    private void removeRealm(String realmName) {
+        adminClient.realm(realmName).remove();
+    }
+
+    private void testFullExportImport() throws LifecycleException {
+        testingClient.testing().setAction(ExportImportConfig.ACTION_EXPORT);
+        testingClient.testing().setRealmName("");
+
+        testingClient.testing().runExport();
+
+        removeRealm("test");
+        removeRealm("test-realm");
+        Assert.assertEquals(1, adminClient.realms().findAll().size());
+
+        assertNotAuthenticated("test", "test-user@localhost", "password");
+        assertNotAuthenticated("test", "user1", "password");
+        assertNotAuthenticated("test", "user2", "password");
+        assertNotAuthenticated("test", "user3", "password");
+
+        // Configure import
+        testingClient.testing().setAction(ExportImportConfig.ACTION_IMPORT);
+
+        testingClient.testing().runImport();
+
+        // Ensure data are imported back
+        Assert.assertEquals(3, adminClient.realms().findAll().size());
+
+        assertAuthenticated("test", "test-user@localhost", "password");
+        assertAuthenticated("test", "user1", "password");
+        assertAuthenticated("test", "user2", "password");
+        assertAuthenticated("test", "user3", "password");
+    }
+
+    private void testRealmExportImport() throws LifecycleException {
+        testingClient.testing().setAction(ExportImportConfig.ACTION_EXPORT);
+        testingClient.testing().setRealmName("test");
+
+        testingClient.testing().runExport();
+
+        // Delete some realm (and some data in admin realm)
+        adminClient.realm("test").remove();
+
+        Assert.assertEquals(2, adminClient.realms().findAll().size());
+
+        assertNotAuthenticated("test", "test-user@localhost", "password");
+        assertNotAuthenticated("test", "user1", "password");
+        assertNotAuthenticated("test", "user2", "password");
+        assertNotAuthenticated("test", "user3", "password");
+
+        // Configure import
+        testingClient.testing().setAction(ExportImportConfig.ACTION_IMPORT);
+
+        testingClient.testing().runImport();
+
+        // Ensure data are imported back, but just for "test" realm
+        Assert.assertEquals(3, adminClient.realms().findAll().size());
+
+        assertAuthenticated("test", "test-user@localhost", "password");
+        assertAuthenticated("test", "user1", "password");
+        assertAuthenticated("test", "user2", "password");
+        assertAuthenticated("test", "user3", "password");
+    }
+
+    private void assertAuthenticated(String realmName, String username, String password) {
+        assertAuth(true, realmName, username, password);
+    }
+
+    private void assertNotAuthenticated(String realmName, String username, String password) {
+        assertAuth(false, realmName, username, password);
+    }
+
+    private void assertAuth(boolean expectedResult, String realmName, String username, String password) {
+        Assert.assertEquals(expectedResult, testingClient.testing().validCredentials(realmName, username, password));
+    }
+
+    private static String getExportImportTestDirectory() {
+        String dirPath = null;
+        String relativeDirExportImportPath = "testsuite" + File.separator +
+                                             "integration-arquillian" + File.separator +
+                                             "tests" + File.separator +
+                                             "base" + File.separator +
+                                             "target" + File.separator +
+                                             "export-import";
+
+        if (System.getProperties().containsKey("maven.home")) {
+            dirPath = System.getProperty("user.dir").replaceFirst("testsuite.integration.*", Matcher.quoteReplacement(relativeDirExportImportPath));
+        } else {
+            for (String c : System.getProperty("java.class.path").split(File.pathSeparator)) {
+                if (c.contains(File.separator + "testsuite" + File.separator + "integration-arquillian" + File.separator)) {
+                    dirPath = c.replaceFirst("testsuite.integration-arquillian.*", Matcher.quoteReplacement(relativeDirExportImportPath));
+                }
+            }
+        }
+
+        String absolutePath = new File(dirPath).getAbsolutePath();
+        return absolutePath;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java
new file mode 100644
index 0000000..19aee3f
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java
@@ -0,0 +1,642 @@
+/*
+ * Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.keycloak.testsuite.exportimport;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Predicate;
+
+import org.junit.Assert;
+import org.keycloak.admin.client.Keycloak;
+import org.keycloak.admin.client.resource.AuthorizationResource;
+import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.admin.client.resource.ClientTemplateResource;
+import org.keycloak.admin.client.resource.RealmResource;
+import org.keycloak.admin.client.resource.UserResource;
+import org.keycloak.common.constants.KerberosConstants;
+import org.keycloak.federation.ldap.mappers.FullNameLDAPFederationMapper;
+import org.keycloak.federation.ldap.mappers.FullNameLDAPFederationMapperFactory;
+import org.keycloak.models.Constants;
+import org.keycloak.models.LDAPConstants;
+import org.keycloak.models.utils.DefaultAuthenticationFlows;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
+import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
+import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
+import org.keycloak.representations.idm.ClientMappingsRepresentation;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.ClientTemplateRepresentation;
+import org.keycloak.representations.idm.FederatedIdentityRepresentation;
+import org.keycloak.representations.idm.IdentityProviderRepresentation;
+import org.keycloak.representations.idm.ProtocolMapperRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.UserFederationMapperRepresentation;
+import org.keycloak.representations.idm.UserFederationProviderRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.representations.idm.authorization.PolicyRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceRepresentation;
+import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
+import org.keycloak.representations.idm.authorization.ScopeRepresentation;
+import org.keycloak.testsuite.admin.ApiUtil;
+import org.keycloak.testsuite.client.KeycloakTestingClient;
+import org.keycloak.testsuite.util.RealmRepUtil;
+
+/**
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
+ */
+public class ExportImportUtil {
+
+    // In the old testsuite, this method exists as a public method of ImportTest from the model package.
+    // However, model package is not ready to be migrated yet.
+    public static void assertDataImportedInRealm(Keycloak adminClient, KeycloakTestingClient testingClient, RealmRepresentation realm) {
+        Assert.assertTrue(realm.isVerifyEmail());
+        Assert.assertEquals((Integer)3600000, realm.getOfflineSessionIdleTimeout());
+        Assert.assertEquals((Integer)1500, realm.getAccessTokenLifespanForImplicitFlow());
+
+        Set<String> creds = realm.getRequiredCredentials();
+        Assert.assertEquals(1, creds.size());
+        String cred = (String)creds.iterator().next();
+        Assert.assertEquals("password", cred);
+        Assert.assertEquals(4, realm.getDefaultRoles().size());
+
+        Assert.assertNotNull(RealmRepUtil.findDefaultRole(realm, "foo"));
+        Assert.assertNotNull(RealmRepUtil.findDefaultRole(realm, "bar"));
+
+        RealmResource realmRsc = adminClient.realm(realm.getRealm());
+
+        /* See KEYCLOAK-3104*/
+        UserRepresentation user = findByUsername(realmRsc, "loginclient");
+        Assert.assertNotNull(user);
+
+        UserResource userRsc = realmRsc.users().get(user.getId());
+        Assert.assertEquals(0, userRsc.getFederatedIdentity().size());
+
+        List<ClientRepresentation> resources = realmRsc.clients().findAll();
+        Assert.assertEquals(9, resources.size());
+
+        // Test applications imported
+        ClientRepresentation application = ApiUtil.findClientByClientId(realmRsc, "Application").toRepresentation();
+        ClientRepresentation otherApp = ApiUtil.findClientByClientId(realmRsc, "OtherApp").toRepresentation();
+        ClientRepresentation accountApp = ApiUtil.findClientByClientId(realmRsc, Constants.ACCOUNT_MANAGEMENT_CLIENT_ID).toRepresentation();
+        ClientResource nonExisting = ApiUtil.findClientByClientId(realmRsc, "NonExisting");
+        Assert.assertNotNull(application);
+        Assert.assertNotNull(otherApp);
+        Assert.assertNull(nonExisting);
+        List<ClientRepresentation> clients = realmRsc.clients().findAll();
+        Assert.assertEquals(9, clients.size());
+        Assert.assertTrue(hasClient(clients, application));
+        Assert.assertTrue(hasClient(clients, otherApp));
+        Assert.assertTrue(hasClient(clients, accountApp));
+
+        Assert.assertEquals("Applicationn", application.getName());
+        Assert.assertEquals((Integer)50, application.getNodeReRegistrationTimeout());
+        Map<String, Integer> appRegisteredNodes = application.getRegisteredNodes();
+        Assert.assertEquals(2, appRegisteredNodes.size());
+        Assert.assertTrue(10 == appRegisteredNodes.get("node1"));
+        Assert.assertTrue(20 == appRegisteredNodes.get("172.10.15.20"));
+
+        // test clientAuthenticatorType
+        Assert.assertEquals("client-secret", application.getClientAuthenticatorType());
+        Assert.assertEquals("client-jwt", otherApp.getClientAuthenticatorType());
+
+        // Test finding applications by ID
+        Assert.assertNull(ApiUtil.findClientResourceById(realmRsc, "982734"));
+        Assert.assertEquals(application.getId(), ApiUtil.findClientResourceById(realmRsc, application.getId()).toRepresentation().getId());
+
+
+        // Test role mappings
+        UserRepresentation admin = findByUsername(realmRsc, "admin");
+        // user without creation timestamp in import
+        Assert.assertNull(admin.getCreatedTimestamp());
+        Set<RoleRepresentation> allRoles = allRoles(realmRsc, admin);
+        Assert.assertEquals(3, allRoles.size());
+        Assert.assertTrue(containsRole(allRoles, findRealmRole(realmRsc, "admin")));
+        Assert.assertTrue(containsRole(allRoles, findClientRole(realmRsc, application.getId(), "app-admin")));
+        Assert.assertTrue(containsRole(allRoles, findClientRole(realmRsc, otherApp.getId(), "otherapp-admin")));
+
+        Assert.assertTrue(findClientRole(realmRsc, application.getId(), "app-admin").isScopeParamRequired());
+        Assert.assertFalse(findClientRole(realmRsc, otherApp.getId(), "otherapp-admin").isScopeParamRequired());
+        Assert.assertFalse(findClientRole(realmRsc, otherApp.getId(), "otherapp-user").isScopeParamRequired());
+
+        UserRepresentation wburke = findByUsername(realmRsc, "wburke");
+        // user with creation timestamp in import
+        Assert.assertEquals(new Long(123654), wburke.getCreatedTimestamp());
+        allRoles = allRoles(realmRsc, wburke);
+        Assert.assertEquals(2, allRoles.size());
+        Assert.assertFalse(containsRole(allRoles, findRealmRole(realmRsc, "admin")));
+        Assert.assertTrue(containsRole(allRoles, findClientRole(realmRsc, application.getId(), "app-user")));
+        Assert.assertTrue(containsRole(allRoles, findClientRole(realmRsc, otherApp.getId(), "otherapp-user")));
+
+        Assert.assertNull(realmRsc.users().get(wburke.getId()).roles().getAll().getRealmMappings());
+
+        UserRepresentation loginclient = findByUsername(realmRsc, "loginclient");
+        // user with creation timestamp as string in import
+        Assert.assertEquals(new Long(123655), loginclient.getCreatedTimestamp());
+
+        List<RoleRepresentation> realmRoles = realmRolesForUser(realmRsc, admin);
+        Assert.assertEquals(1, realmRoles.size());
+        Assert.assertEquals("admin", realmRoles.iterator().next().getName());
+
+        List<RoleRepresentation> appRoles = clientRolesForUser(realmRsc, application, admin);
+        Assert.assertEquals(1, appRoles.size());
+        Assert.assertEquals("app-admin", appRoles.iterator().next().getName());
+
+        // Test attributes
+        Map<String, List<String>> attrs = wburke.getAttributesAsListValues();
+        Assert.assertEquals(1, attrs.size());
+        List<String> attrVals = attrs.get("email");
+        Assert.assertEquals(1, attrVals.size());
+        Assert.assertEquals("bburke@redhat.com", attrVals.get(0));
+
+        attrs = admin.getAttributesAsListValues();
+        Assert.assertEquals(2, attrs.size());
+        attrVals = attrs.get("key1");
+        Assert.assertEquals(1, attrVals.size());
+        Assert.assertEquals("val1", attrVals.get(0));
+        attrVals = attrs.get("key2");
+        Assert.assertEquals(2, attrVals.size());
+        Assert.assertTrue(attrVals.contains("val21") && attrVals.contains("val22"));
+
+        // Test client
+        ClientResource oauthClient = ApiUtil.findClientResourceByClientId(realmRsc, "oauthclient");
+        ClientRepresentation oauthClientRep = oauthClient.toRepresentation();
+        Assert.assertEquals("clientpassword", oauthClient.getSecret().getValue());
+        Assert.assertTrue(oauthClientRep.isEnabled());
+        Assert.assertNotNull(oauthClientRep);
+
+        // Test scope relationship
+        Set<RoleRepresentation> allScopes = allScopeMappings(oauthClient);
+        Assert.assertEquals(2, allScopes.size());
+        Assert.assertTrue(containsRole(allScopes, findRealmRole(realmRsc, "admin")));
+        Assert.assertTrue(containsRole(allScopes, findClientRole(realmRsc, application.getId(), "app-user")));
+
+        List<RoleRepresentation> realmScopes = realmScopeMappings(oauthClient);
+        Assert.assertTrue(containsRole(realmScopes, findRealmRole(realmRsc, "admin")));
+
+        List<RoleRepresentation> appScopes = clientScopeMappings(oauthClient);
+        Assert.assertTrue(containsRole(appScopes, findClientRole(realmRsc, application.getId(), "app-user")));
+
+        // Test social linking
+        UserResource socialUser = realmRsc.users().get(findByUsername(realmRsc, "mySocialUser").getId());
+        List<FederatedIdentityRepresentation> socialLinks = socialUser.getFederatedIdentity();
+        Assert.assertEquals(3, socialLinks.size());
+        boolean facebookFound = false;
+        boolean googleFound = false;
+        boolean twitterFound = false;
+        FederatedIdentityRepresentation facebookIdentityRep = null;
+        for (FederatedIdentityRepresentation federatedIdentityRep : socialLinks) {
+            if ("facebook1".equals(federatedIdentityRep.getIdentityProvider())) {
+                facebookFound = true;
+                facebookIdentityRep = federatedIdentityRep;
+                Assert.assertEquals("facebook1",federatedIdentityRep.getUserId());
+                Assert.assertEquals("fbuser1", federatedIdentityRep.getUserName());
+            } else if ("google1".equals(federatedIdentityRep.getIdentityProvider())) {
+                googleFound = true;
+                Assert.assertEquals("google1", federatedIdentityRep.getUserId());
+                Assert.assertEquals("mysocialuser@gmail.com", federatedIdentityRep.getUserName());
+            } else if ("twitter1".equals(federatedIdentityRep.getIdentityProvider())) {
+                twitterFound = true;
+                Assert.assertEquals("twitter1", federatedIdentityRep.getUserId());
+                Assert.assertEquals("twuser1", federatedIdentityRep.getUserName());
+            }
+        }
+        Assert.assertTrue(facebookFound && twitterFound && googleFound);
+
+        UserRepresentation foundSocialUser =  testingClient.testing().getUserByFederatedIdentity(realm.getRealm(), "facebook1", "facebook1", "fbuser1");
+        Assert.assertEquals(foundSocialUser.getUsername(), socialUser.toRepresentation().getUsername());
+        Assert.assertNull(testingClient.testing().getUserByFederatedIdentity(realm.getRealm(), "facebook", "not-existing", "not-existing"));
+
+        Assert.assertEquals("facebook1", facebookIdentityRep.getUserId());
+        Assert.assertEquals("fbuser1", facebookIdentityRep.getUserName());
+        Assert.assertEquals("facebook1", facebookIdentityRep.getIdentityProvider());
+
+        // Test remove/add social link
+        socialUser.removeFederatedIdentity("facebook1");
+        Assert.assertEquals(2, socialUser.getFederatedIdentity().size());
+        socialUser.addFederatedIdentity("facebook1", facebookIdentityRep);
+        Assert.assertEquals(3, socialUser.getFederatedIdentity().size());
+
+        // Test smtp config
+        Map<String, String> smtpConfig = realm.getSmtpServer();
+        Assert.assertTrue(smtpConfig.size() == 3);
+        Assert.assertEquals("auto@keycloak.org", smtpConfig.get("from"));
+        Assert.assertEquals("localhost", smtpConfig.get("host"));
+        Assert.assertEquals("3025", smtpConfig.get("port"));
+
+        // Test identity providers
+        List<IdentityProviderRepresentation> identityProviders = realm.getIdentityProviders();
+        Assert.assertEquals(3, identityProviders.size());
+        IdentityProviderRepresentation google = null;
+        for (IdentityProviderRepresentation idpRep : identityProviders) {
+            if (idpRep.getAlias().equals("google1")) google = idpRep;
+        }
+        Assert.assertNotNull(google);
+        Assert.assertEquals("google1", google.getAlias());
+        Assert.assertEquals("google", google.getProviderId());
+        Assert.assertTrue(google.isEnabled());
+        Assert.assertEquals("googleId", google.getConfig().get("clientId"));
+        Assert.assertEquals("googleSecret", google.getConfig().get("clientSecret"));
+
+        // Test federation providers
+        List<UserFederationProviderRepresentation> fedProviders = realm.getUserFederationProviders();
+        Assert.assertTrue(fedProviders.size() == 2);
+        UserFederationProviderRepresentation ldap1 = fedProviders.get(0);
+        Assert.assertEquals("MyLDAPProvider1", ldap1.getDisplayName());
+        Assert.assertEquals("ldap", ldap1.getProviderName());
+        Assert.assertEquals(1, ldap1.getPriority());
+        Assert.assertEquals("ldap://foo", ldap1.getConfig().get(LDAPConstants.CONNECTION_URL));
+
+        UserFederationProviderRepresentation ldap2 = fedProviders.get(1);
+        Assert.assertEquals("MyLDAPProvider2", ldap2.getDisplayName());
+        Assert.assertEquals("ldap://bar", ldap2.getConfig().get(LDAPConstants.CONNECTION_URL));
+
+        // Test federation mappers
+        List<UserFederationMapperRepresentation> fedMappers1 = realmRsc.userFederation().get(ldap1.getId()).getMappers();
+        Assert.assertTrue(fedMappers1.size() == 1);
+        UserFederationMapperRepresentation fullNameMapper = fedMappers1.iterator().next();
+        Assert.assertEquals("FullNameMapper", fullNameMapper.getName());
+        Assert.assertEquals(FullNameLDAPFederationMapperFactory.PROVIDER_ID, fullNameMapper.getFederationMapperType());
+        //Assert.assertEquals(ldap1.getId(), fullNameMapper.getFederationProviderId());
+        Assert.assertEquals("cn", fullNameMapper.getConfig().get(FullNameLDAPFederationMapper.LDAP_FULL_NAME_ATTRIBUTE));
+
+        // All builtin LDAP mappers should be here
+        List<UserFederationMapperRepresentation> fedMappers2 = realmRsc.userFederation().get(ldap2.getId()).getMappers();
+        Assert.assertTrue(fedMappers2.size() > 3);
+        List<UserFederationMapperRepresentation> allMappers = realm.getUserFederationMappers();
+        Assert.assertEquals(allMappers.size(), fedMappers1.size() + fedMappers2.size());
+
+        // Assert that federation link wasn't created during import
+        Assert.assertNull(testingClient.testing().getUserByUsernameFromFedProviderFactory(realm.getRealm(), "wburke"));
+
+        // Test builtin authentication flows
+        AuthenticationFlowRepresentation clientFlow = testingClient.testing().getClientAuthFlow(realm.getRealm());
+        Assert.assertEquals(DefaultAuthenticationFlows.CLIENT_AUTHENTICATION_FLOW, clientFlow.getAlias());
+        Assert.assertNotNull(realmRsc.flows().getFlow(clientFlow.getId()));
+        Assert.assertTrue(realmRsc.flows().getExecutions(clientFlow.getAlias()).size() > 0);
+
+        AuthenticationFlowRepresentation resetFlow = testingClient.testing().getResetCredFlow(realm.getRealm());
+        Assert.assertEquals(DefaultAuthenticationFlows.RESET_CREDENTIALS_FLOW, resetFlow.getAlias());
+        Assert.assertNotNull(realmRsc.flows().getFlow(resetFlow.getId()));
+        Assert.assertTrue(realmRsc.flows().getExecutions(resetFlow.getAlias()).size() > 0);
+
+        // Test protocol mappers. Default application has all the builtin protocol mappers. OtherApp just gss credential
+        List<ProtocolMapperRepresentation> applicationMappers = application.getProtocolMappers();
+        Assert.assertNotNull(findMapperByName(applicationMappers, OIDCLoginProtocol.LOGIN_PROTOCOL, "username"));//application.getProtocolMapperByName(OIDCLoginProtocol.LOGIN_PROTOCOL, "username"));
+        Assert.assertNotNull(findMapperByName(applicationMappers, OIDCLoginProtocol.LOGIN_PROTOCOL, "email"));
+        Assert.assertNotNull(findMapperByName(applicationMappers, OIDCLoginProtocol.LOGIN_PROTOCOL, "given name"));
+        Assert.assertNull(findMapperByName(applicationMappers, OIDCLoginProtocol.LOGIN_PROTOCOL, KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME));
+
+        Assert.assertEquals(1, otherApp.getProtocolMappers().size());
+        List<ProtocolMapperRepresentation> otherAppMappers = otherApp.getProtocolMappers();
+        Assert.assertNull(findMapperByName(otherAppMappers, OIDCLoginProtocol.LOGIN_PROTOCOL, "username"));
+        ProtocolMapperRepresentation gssCredentialMapper = findMapperByName(otherAppMappers, OIDCLoginProtocol.LOGIN_PROTOCOL, KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME);
+        assertGssProtocolMapper(gssCredentialMapper);
+
+        // Test clientTemplates
+        List<ClientTemplateRepresentation> clientTemplates = realmRsc.clientTemplates().findAll();
+        Assert.assertEquals(1, clientTemplates.size());
+        ClientTemplateRepresentation clientTemplate = clientTemplates.get(0);
+        Assert.assertEquals("foo-template", clientTemplate.getName());
+        Assert.assertEquals("foo-template-desc", clientTemplate.getDescription());
+        Assert.assertEquals(OIDCLoginProtocol.LOGIN_PROTOCOL, clientTemplate.getProtocol());
+        Assert.assertEquals(1, clientTemplate.getProtocolMappers().size());
+        List<ProtocolMapperRepresentation> clientTemplateMappers = clientTemplate.getProtocolMappers();
+        ProtocolMapperRepresentation templateGssCredentialMapper = findMapperByName(clientTemplateMappers, OIDCLoginProtocol.LOGIN_PROTOCOL, KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME);
+        assertGssProtocolMapper(templateGssCredentialMapper);
+
+        // Test client template scopes
+        Set<RoleRepresentation> allClientTemplateScopes = allScopeMappings(realmRsc.clientTemplates().get(clientTemplate.getId()));
+        Assert.assertEquals(3, allClientTemplateScopes.size());
+        Assert.assertTrue(containsRole(allClientTemplateScopes, findRealmRole(realmRsc, "admin")));//allClientTemplateScopes.contains(realm.getRole("admin")));
+        Assert.assertTrue(containsRole(allClientTemplateScopes, findClientRole(realmRsc, application.getId(), "app-user")));//allClientTemplateScopes.contains(application.getRole("app-user")));
+        Assert.assertTrue(containsRole(allClientTemplateScopes, findClientRole(realmRsc, application.getId(), "app-admin")));//allClientTemplateScopes.contains(application.getRole("app-admin")));
+
+        List<RoleRepresentation> clientTemplateRealmScopes = realmScopeMappings(realmRsc.clientTemplates().get(clientTemplate.getId()));
+        Assert.assertTrue(containsRole(clientTemplateRealmScopes, findRealmRole(realmRsc, "admin")));//clientTemplateRealmScopes.contains(realm.getRole("admin")));
+
+        List<RoleRepresentation> clientTemplateAppScopes = clientScopeMappings(realmRsc.clientTemplates().get(clientTemplate.getId()));//application.getClientScopeMappings(oauthClient);
+        Assert.assertTrue(containsRole(clientTemplateAppScopes, findClientRole(realmRsc, application.getId(), "app-user")));//clientTemplateAppScopes.contains(application.getRole("app-user")));
+        Assert.assertTrue(containsRole(clientTemplateAppScopes, findClientRole(realmRsc, application.getId(), "app-admin")));//clientTemplateAppScopes.contains(application.getRole("app-admin")));
+
+        // Test user consents
+        //admin =  session.users().getUserByUsername("admin", realm);
+
+        UserResource adminRsc = realmRsc.users().get(admin.getId());
+        List<Map<String, Object>> consents = adminRsc.getConsents();
+        Assert.assertEquals(2, consents.size());//.getConsents().size());
+
+        Map<String, Object> appAdminConsent = findConsentByClientId(consents, application.getClientId());
+        Assert.assertEquals(2, calcNumberGrantedRoles(appAdminConsent));
+        Assert.assertTrue(getGrantedProtocolMappers(appAdminConsent) == null || getGrantedProtocolMappers(appAdminConsent).isEmpty());
+        Assert.assertTrue(isRealmRoleGranted(appAdminConsent, "admin"));//appAdminConsent.isRoleGranted(realm.getRole("admin")));
+        Assert.assertTrue(isClientRoleGranted(appAdminConsent, application.getClientId(), "app-admin"));//appAdminConsent.isRoleGranted(application.getRole("app-admin")));
+
+        Map<String, Object> otherAppAdminConsent = findConsentByClientId(consents, otherApp.getClientId());//admin.getConsentByClient(otherApp.getId());
+        Assert.assertEquals(1, calcNumberGrantedRoles(otherAppAdminConsent));
+        Assert.assertEquals(1, getGrantedProtocolMappers(otherAppAdminConsent).size());//otherAppAdminConsent.getGrantedProtocolMappers().size());
+        Assert.assertTrue(isRealmRoleGranted(otherAppAdminConsent, "admin"));//otherAppAdminConsent.isRoleGranted(realm.getRole("admin")));
+        Assert.assertFalse(isClientRoleGranted(otherAppAdminConsent, application.getClientId(), "app-admin"));//otherAppAdminConsent.isRoleGranted(application.getRole("app-admin")));
+        Assert.assertTrue(isProtocolMapperGranted(otherAppAdminConsent, gssCredentialMapper));
+
+        Assert.assertTrue(application.isStandardFlowEnabled());
+        Assert.assertTrue(application.isImplicitFlowEnabled());
+        Assert.assertTrue(application.isDirectAccessGrantsEnabled());
+        Assert.assertFalse(otherApp.isStandardFlowEnabled());
+        Assert.assertFalse(otherApp.isImplicitFlowEnabled());
+        Assert.assertFalse(otherApp.isDirectAccessGrantsEnabled());
+
+        // Test service accounts
+        Assert.assertFalse(application.isServiceAccountsEnabled());
+        Assert.assertTrue(otherApp.isServiceAccountsEnabled());
+        Assert.assertNull(testingClient.testing().getUserByServiceAccountClient(realm.getRealm(), application.getClientId()));//session.users().getUserByServiceAccountClient(application));
+        UserRepresentation linked = testingClient.testing().getUserByServiceAccountClient(realm.getRealm(), otherApp.getClientId());//session.users().getUserByServiceAccountClient(otherApp);
+        Assert.assertNotNull(linked);
+        Assert.assertEquals("my-service-user", linked.getUsername());
+
+        assertAuthorizationSettings(realmRsc);
+    }
+
+    private static boolean isProtocolMapperGranted(Map<String, Object> consent, ProtocolMapperRepresentation mapperRep) {
+        Map<String, List> grantedMappers = (Map<String, List>)consent.get("grantedProtocolMappers");
+        if (grantedMappers == null) return false;
+        List<String> mappers = grantedMappers.get(mapperRep.getProtocol());
+        if (mappers == null) return false;
+        return mappers.contains(mapperRep.getName());
+    }
+
+    private static boolean isRealmRoleGranted(Map<String, Object> consent, String roleName) {
+        if (consent.get("grantedRealmRoles") == null) return false;
+        return ((List)consent.get("grantedRealmRoles")).contains(roleName);
+    }
+
+    private static boolean isClientRoleGranted(Map<String, Object> consent, String clientId, String roleName) {
+        if (consent.get("grantedClientRoles") == null) return false;
+        Map<String, List> grantedClientRoles = (Map<String, List>)consent.get("grantedClientRoles");
+        List rolesForClient = grantedClientRoles.get(clientId);
+        if (rolesForClient == null) return false;
+        return rolesForClient.contains(roleName);
+    }
+
+    private static Map<String, List<String>> getGrantedProtocolMappers(Map<String, Object> consent) {
+        return (Map<String, List<String>>)consent.get("grantedProtocolMappers");
+    }
+
+    private static int calcNumberGrantedRoles(Map<String, Object> consent) {
+        int numGranted = 0;
+        List realmRoles = (List)consent.get("grantedRealmRoles");
+        if (realmRoles != null) numGranted += realmRoles.size();
+        Map clientRoles = (Map)consent.get("grantedClientRoles");
+        if (clientRoles != null) numGranted += clientRoles.size();
+        return numGranted;
+    }
+
+    private static Map<String, Object> findConsentByClientId(List<Map<String, Object>> consents, String clientId) {
+        for (Map<String, Object> consent : consents) {
+            if (clientId.equals(consent.get("clientId"))) return consent;
+        }
+        return null;
+    }
+
+    private static void assertGssProtocolMapper(ProtocolMapperRepresentation gssCredentialMapper) {
+        Assert.assertEquals(KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME, gssCredentialMapper.getName());
+        Assert.assertEquals( OIDCLoginProtocol.LOGIN_PROTOCOL, gssCredentialMapper.getProtocol());
+        Assert.assertEquals(UserSessionNoteMapper.PROVIDER_ID, gssCredentialMapper.getProtocolMapper());
+        String includeInAccessToken = gssCredentialMapper.getConfig().get(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN);
+        String includeInIdToken = gssCredentialMapper.getConfig().get(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN);
+        Assert.assertTrue(includeInAccessToken.equalsIgnoreCase("true"));
+        Assert.assertTrue(includeInIdToken == null || Boolean.parseBoolean(includeInIdToken) == false);
+    }
+
+    private static ProtocolMapperRepresentation findMapperByName(List<ProtocolMapperRepresentation> mappers, String type, String name) {
+        for (ProtocolMapperRepresentation mapper : mappers) {
+            if (mapper.getProtocol().equals(type) &&
+                mapper.getName().equals(name)) {
+                return mapper;
+            }
+        }
+        return null;
+    }
+
+    private static boolean hasClient(List<ClientRepresentation> clients, ClientRepresentation client) {
+        for (ClientRepresentation clientRep : clients) {
+            if (client.getId().equals(clientRep.getId())) return true;
+        }
+        return false;
+    }
+
+    // Workaround for KEYCLOAK-3104.  For this realm, search() only works if username is null.
+    private static UserRepresentation findByUsername(RealmResource realmRsc, String username) {
+        for (UserRepresentation user : realmRsc.users().search(null, 0, Integer.MAX_VALUE)) {
+            if (user.getUsername().equalsIgnoreCase(username)) return user;
+        }
+        return null;
+    }
+
+    private static Set<RoleRepresentation> allScopeMappings(ClientResource client) {
+        Set<RoleRepresentation> allRoles = new HashSet<>();
+        List<RoleRepresentation> realmRoles = realmScopeMappings(client);
+        if (realmRoles != null) allRoles.addAll(realmRoles);
+
+        allRoles.addAll(clientScopeMappings(client));
+
+        return allRoles;
+    }
+
+    private static Set<RoleRepresentation> allScopeMappings(ClientTemplateResource client) {
+        Set<RoleRepresentation> allRoles = new HashSet<>();
+        List<RoleRepresentation> realmRoles = realmScopeMappings(client);
+        if (realmRoles != null) allRoles.addAll(realmRoles);
+
+        allRoles.addAll(clientScopeMappings(client));
+
+        return allRoles;
+    }
+
+    private static List<RoleRepresentation> clientScopeMappings(ClientResource client) {
+        List<RoleRepresentation> clientScopeMappings = new LinkedList<>();
+        Map<String, ClientMappingsRepresentation> clientRoles = client.getScopeMappings().getAll().getClientMappings();
+        if (clientRoles == null) return clientScopeMappings;
+
+        for (String clientKey : clientRoles.keySet()) {
+            List<RoleRepresentation> clientRoleScopeMappings = clientRoles.get(clientKey).getMappings();
+            if (clientRoleScopeMappings != null) clientScopeMappings.addAll(clientRoleScopeMappings);
+        }
+
+        return clientScopeMappings;
+    }
+
+    private static List<RoleRepresentation> clientScopeMappings(ClientTemplateResource client) {
+        List<RoleRepresentation> clientScopeMappings = new LinkedList<>();
+        Map<String, ClientMappingsRepresentation> clientRoles = client.getScopeMappings().getAll().getClientMappings();
+        if (clientRoles == null) return clientScopeMappings;
+
+        for (String clientKey : clientRoles.keySet()) {
+            List<RoleRepresentation> clientRoleScopeMappings = clientRoles.get(clientKey).getMappings();
+            if (clientRoleScopeMappings != null) clientScopeMappings.addAll(clientRoleScopeMappings);
+        }
+
+        return clientScopeMappings;
+    }
+
+    private static List<RoleRepresentation> realmScopeMappings(ClientResource client) {
+        return client.getScopeMappings().realmLevel().listAll();
+    }
+
+    private static List<RoleRepresentation> realmScopeMappings(ClientTemplateResource client) {
+        return client.getScopeMappings().realmLevel().listAll();
+    }
+
+    private static Set<RoleRepresentation> allRoles(RealmResource realmRsc, UserRepresentation user) {
+        UserResource userRsc = realmRsc.users().get(user.getId());
+        Set<RoleRepresentation> roles = new HashSet<>();
+
+        List<RoleRepresentation> realmRoles = userRsc.roles().getAll().getRealmMappings();
+        if (realmRoles != null) roles.addAll(realmRoles);
+
+        roles.addAll(allClientRolesForUser(realmRsc, user));
+
+        return roles;
+    }
+
+    private static List<RoleRepresentation> realmRolesForUser(RealmResource realmRsc, UserRepresentation user) {
+        return realmRsc.users().get(user.getId()).roles().getAll().getRealmMappings();
+    }
+
+    private static List<RoleRepresentation> allClientRolesForUser(RealmResource realmRsc, UserRepresentation user) {
+        UserResource userRsc = realmRsc.users().get(user.getId());
+        List<RoleRepresentation> roles = new LinkedList<>();
+        for(String client : userRsc.roles().getAll().getClientMappings().keySet()) {
+            List<RoleRepresentation> clientRoles = userRsc.roles().getAll().getClientMappings().get(client).getMappings();
+            if (clientRoles != null) roles.addAll(clientRoles);
+        }
+        return roles;
+    }
+
+    private static List<RoleRepresentation> clientRolesForUser(RealmResource realmRsc, ClientRepresentation client, UserRepresentation user) {
+        UserResource userRsc = realmRsc.users().get(user.getId());
+        return userRsc.roles().clientLevel(client.getId()).listAll();
+    }
+
+    private static RoleRepresentation findRealmRole(RealmResource realmRsc, String roleName) {
+        return realmRsc.roles().get(roleName).toRepresentation();
+    }
+
+    private static RoleRepresentation findClientRole(RealmResource realmRsc, String clientDbId, String roleName) {
+        return realmRsc.clients().get(clientDbId).roles().get(roleName).toRepresentation();
+    }
+
+    private static boolean containsRole(Collection<RoleRepresentation> roles, RoleRepresentation role) {
+        for (RoleRepresentation setRole : roles) {
+            if (setRole.getId().equals(role.getId())) return true;
+        }
+        return false;
+    }
+
+    private static void assertAuthorizationSettings(RealmResource realmRsc) {
+        AuthorizationResource authzResource = ApiUtil.findAuthorizationSettings(realmRsc, "test-app-authz");
+
+        Assert.assertNotNull(authzResource);
+
+        List<ResourceRepresentation> resources = authzResource.resources().resources();
+        Assert.assertEquals(4, resources.size());
+        ResourceServerRepresentation authzSettings = authzResource.getSettings();
+        List<Predicate<ResourceRepresentation>> resourcePredicates = new ArrayList<>();
+        resourcePredicates.add(resourceRep -> {
+            if ("Admin Resource".equals(resourceRep.getName())) {
+                Assert.assertEquals(authzSettings.getClientId(), resourceRep.getOwner().getId());
+                Assert.assertEquals("/protected/admin/*", resourceRep.getUri());
+                Assert.assertEquals("http://test-app-authz/protected/admin", resourceRep.getType());
+                Assert.assertEquals("http://icons.com/icon-admin", resourceRep.getIconUri());
+                Assert.assertEquals(1, resourceRep.getScopes().size());
+                return true;
+            }
+            return false;
+        });
+        resourcePredicates.add(resourceRep -> {
+            if ("Protected Resource".equals(resourceRep.getName())) {
+                Assert.assertEquals(authzSettings.getClientId(), resourceRep.getOwner().getId());
+                Assert.assertEquals("/*", resourceRep.getUri());
+                Assert.assertEquals("http://test-app-authz/protected/resource", resourceRep.getType());
+                Assert.assertEquals("http://icons.com/icon-resource", resourceRep.getIconUri());
+                Assert.assertEquals(1, resourceRep.getScopes().size());
+                return true;
+            }
+            return false;
+        });
+        resourcePredicates.add(resourceRep -> {
+            if ("Premium Resource".equals(resourceRep.getName())) {
+                Assert.assertEquals(authzSettings.getClientId(), resourceRep.getOwner().getId());
+                Assert.assertEquals("/protected/premium/*", resourceRep.getUri());
+                Assert.assertEquals("urn:test-app-authz:protected:resource", resourceRep.getType());
+                Assert.assertEquals("http://icons.com/icon-premium", resourceRep.getIconUri());
+                Assert.assertEquals(1, resourceRep.getScopes().size());
+                return true;
+            }
+            return false;
+        });
+        resourcePredicates.add(resourceRep -> {
+            if ("Main Page".equals(resourceRep.getName())) {
+                Assert.assertEquals(authzSettings.getClientId(), resourceRep.getOwner().getId());
+                Assert.assertNull(resourceRep.getUri());
+                Assert.assertEquals("urn:test-app-authz:protected:resource", resourceRep.getType());
+                Assert.assertEquals("http://icons.com/icon-main-page", resourceRep.getIconUri());
+                Assert.assertEquals(3, resourceRep.getScopes().size());
+                return true;
+            }
+            return false;
+        });
+        assertPredicate(resources, resourcePredicates);
+
+        List<ScopeRepresentation> scopes = authzResource.scopes().scopes();
+        Assert.assertEquals(6, scopes.size());
+        List<Predicate<ScopeRepresentation>> scopePredicates = new ArrayList<>();
+        scopePredicates.add(scopeRepresentation -> "admin-access".equals(scopeRepresentation.getName()));
+        scopePredicates.add(scopeRepresentation -> "resource-access".equals(scopeRepresentation.getName()));
+        scopePredicates.add(scopeRepresentation -> "premium-access".equals(scopeRepresentation.getName()));
+        scopePredicates.add(scopeRepresentation -> "urn:test-app-authz:page:main:actionForAdmin".equals(scopeRepresentation.getName()));
+        scopePredicates.add(scopeRepresentation -> "urn:test-app-authz:page:main:actionForUser".equals(scopeRepresentation.getName()));
+        scopePredicates.add(scopeRepresentation -> "urn:test-app-authz:page:main:actionForPremiumUser".equals(scopeRepresentation.getName()));
+        assertPredicate(scopes, scopePredicates);
+
+        List<PolicyRepresentation> policies = authzResource.policies().policies();
+        Assert.assertEquals(10, policies.size());
+        List<Predicate<PolicyRepresentation>> policyPredicates = new ArrayList<>();
+        policyPredicates.add(policyRepresentation -> "Any Admin Policy".equals(policyRepresentation.getName()));
+        policyPredicates.add(policyRepresentation -> "Any User Policy".equals(policyRepresentation.getName()));
+        policyPredicates.add(policyRepresentation -> "Only Premium User Policy".equals(policyRepresentation.getName()));
+        policyPredicates.add(policyRepresentation -> "All Users Policy".equals(policyRepresentation.getName()));
+        policyPredicates.add(policyRepresentation -> "Premium Resource Permission".equals(policyRepresentation.getName()));
+        policyPredicates.add(policyRepresentation -> "Administrative Resource Permission".equals(policyRepresentation.getName()));
+        policyPredicates.add(policyRepresentation -> "Protected Resource Permission".equals(policyRepresentation.getName()));
+        policyPredicates.add(policyRepresentation -> "Action 1 on Main Page Resource Permission".equals(policyRepresentation.getName()));
+        policyPredicates.add(policyRepresentation -> "Action 2 on Main Page Resource Permission".equals(policyRepresentation.getName()));
+        policyPredicates.add(policyRepresentation -> "Action 3 on Main Page Resource Permission".equals(policyRepresentation.getName()));
+        assertPredicate(policies, policyPredicates);
+    }
+
+    private static <D> void assertPredicate(List<D> source, List<Predicate<D>> predicate) {
+        Assert.assertTrue(!source.stream().filter(object -> !predicate.stream().filter(predicate1 -> predicate1.test(object)).findFirst().isPresent()).findAny().isPresent());
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java
index a22c359..90178a9 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java
@@ -26,24 +26,22 @@ import org.keycloak.models.Constants;
 import org.keycloak.models.utils.TimeBasedOTP;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.testsuite.AssertEvents;
+import org.keycloak.testsuite.AssertEvents.ExpectedEvent;
 import org.keycloak.testsuite.pages.AppPage;
 import org.keycloak.testsuite.pages.AppPage.RequestType;
 import org.keycloak.testsuite.pages.LoginPage;
 import org.keycloak.testsuite.pages.LoginTotpPage;
 import org.keycloak.testsuite.pages.RegisterPage;
 
-import javax.ws.rs.client.Client;
-import javax.ws.rs.client.ClientBuilder;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.Response;
 import java.net.MalformedURLException;
 import org.jboss.arquillian.graphene.page.Page;
-import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.testsuite.TestRealmKeycloakTest;
 import org.keycloak.testsuite.util.GreenMailRule;
 import org.keycloak.testsuite.util.OAuthClient;
+import org.keycloak.testsuite.util.UserBuilder;
+import org.keycloak.testsuite.util.RealmRepUtil;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -53,7 +51,7 @@ public class BruteForceTest extends TestRealmKeycloakTest {
 
     @Override
     public void configureTestRealm(RealmRepresentation testRealm) {
-        UserRepresentation user = findUserInRealmRep(testRealm, "test-user@localhost");
+        UserRepresentation user = RealmRepUtil.findUser(testRealm, "test-user@localhost");
         CredentialRepresentation credRep = new CredentialRepresentation();
         credRep.setType(CredentialRepresentation.TOTP);
         credRep.setValue("totpSecret");
@@ -63,7 +61,8 @@ public class BruteForceTest extends TestRealmKeycloakTest {
         testRealm.setBruteForceProtected(true);
         testRealm.setFailureFactor(2);
 
-        findClientInRealmRep(testRealm, "test-app").setDirectAccessGrantsEnabled(true);
+        RealmRepUtil.findClientByClientId(testRealm, "test-app").setDirectAccessGrantsEnabled(true);
+        testRealm.getUsers().add(UserBuilder.create().username("user2").email("user2@localhost").password("password").build());
     }
 
     @Before
@@ -110,33 +109,11 @@ public class BruteForceTest extends TestRealmKeycloakTest {
     }
 
     protected void clearUserFailures() throws Exception {
-        String token = getAdminToken();
-        Client client = ClientBuilder.newClient();
-        Response response = client.target(AppPage.AUTH_SERVER_URL)
-                .path("admin/realms/test/attack-detection/brute-force/usernames/test-user@localhost")
-                .request()
-                .header(HttpHeaders.AUTHORIZATION, "Bearer " + token)
-                .delete();
-        Assert.assertEquals(204, response.getStatus());
-        response.close();
-        client.close();
-
-
+        adminClient.realm("test").attackDetection().clearBruteForceForUser(findUser("test-user@localhost").getId());
     }
 
     protected void clearAllUserFailures() throws Exception {
-        String token = getAdminToken();
-        Client client = ClientBuilder.newClient();
-        Response response = client.target(AppPage.AUTH_SERVER_URL)
-                .path("admin/realms/test/attack-detection/brute-force/usernames")
-                .request()
-                .header(HttpHeaders.AUTHORIZATION, "Bearer " + token)
-                .delete();
-        Assert.assertEquals(204, response.getStatus());
-        response.close();
-        client.close();
-
-
+        adminClient.realm("test").attackDetection().clearAllBruteForce();
     }
 
     @Test
@@ -169,8 +146,8 @@ public class BruteForceTest extends TestRealmKeycloakTest {
             OAuthClient.AccessTokenResponse response = getTestToken("password", totpSecret);
             Assert.assertNull(response.getAccessToken());
             Assert.assertNotNull(response.getError());
-            Assert.assertEquals(response.getError(), "invalid_grant");
-            Assert.assertEquals(response.getErrorDescription(), "Account temporarily disabled");
+            Assert.assertEquals("invalid_grant", response.getError());
+            Assert.assertEquals("Account temporarily disabled", response.getErrorDescription());
             events.clear();
         }
         clearUserFailures();
@@ -293,6 +270,17 @@ public class BruteForceTest extends TestRealmKeycloakTest {
     }
 
     @Test
+    public void testEmail() throws Exception {
+        String userId = adminClient.realm("test").users().search("user2", null, null, null, 0, 1).get(0).getId();
+
+        loginSuccess("user2@localhost");
+        loginInvalidPassword("user2@localhost");
+        loginInvalidPassword("user2@localhost");
+        expectTemporarilyDisabled("user2@localhost", userId);
+        clearAllUserFailures();
+    }
+
+    @Test
     public void testBrowserMissingPassword() throws Exception {
         loginSuccess();
         loginMissingPassword();
@@ -334,20 +322,25 @@ public class BruteForceTest extends TestRealmKeycloakTest {
     }
 
     public void expectTemporarilyDisabled() throws Exception {
-        expectTemporarilyDisabled("test-user@localhost");
+        expectTemporarilyDisabled("test-user@localhost", null);
     }
 
-    public void expectTemporarilyDisabled(String username) throws Exception {
+    public void expectTemporarilyDisabled(String username, String userId) throws Exception {
         loginPage.open();
         loginPage.login(username, "password");
 
         loginPage.assertCurrent();
         String src = driver.getPageSource();
         Assert.assertEquals("Invalid username or password.", loginPage.getError());
-        events.expectLogin().session((String) null).error(Errors.USER_TEMPORARILY_DISABLED)
-                .detail(Details.USERNAME, "test-user@localhost")
-                .removeDetail(Details.CONSENT)
-                .assertEvent();
+        ExpectedEvent event = events.expectLogin()
+                .session((String) null)
+                .error(Errors.USER_TEMPORARILY_DISABLED)
+                .detail(Details.USERNAME, username)
+                .removeDetail(Details.CONSENT);
+        if(userId != null) {
+            event.user(userId);
+        }
+        event.assertEvent();
     }
 
     public void loginSuccess() throws Exception {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/CustomFlowTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/CustomFlowTest.java
index d9f2182..73b2af4 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/CustomFlowTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/CustomFlowTest.java
@@ -45,6 +45,7 @@ import org.keycloak.testsuite.util.ClientBuilder;
 import org.keycloak.testsuite.util.ExecutionBuilder;
 import org.keycloak.testsuite.util.FlowBuilder;
 import org.keycloak.testsuite.util.OAuthClient;
+import org.keycloak.testsuite.util.RealmRepUtil;
 import org.keycloak.testsuite.util.UserBuilder;
 
 import static org.junit.Assert.assertEquals;
@@ -73,7 +74,7 @@ public class CustomFlowTest extends AbstractFlowTest {
                                               .build();
         testRealm.getClients().add(dummyClient);
 
-        ClientRepresentation testApp = findClientInRealmRep(testRealm, "test-app");
+        ClientRepresentation testApp = RealmRepUtil.findClientByClientId(testRealm, "test-app");
         testApp.setClientAuthenticatorType(PassThroughClientAuthenticator.PROVIDER_ID);
         testApp.setDirectAccessGrantsEnabled(true);
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginHotpTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginHotpTest.java
index 8964040..43c6153 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginHotpTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginHotpTest.java
@@ -36,6 +36,7 @@ import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.testsuite.TestRealmKeycloakTest;
 import org.keycloak.testsuite.util.GreenMailRule;
+import org.keycloak.testsuite.util.RealmRepUtil;
 import org.keycloak.testsuite.util.UserBuilder;
 
 /**
@@ -48,7 +49,7 @@ public class LoginHotpTest extends TestRealmKeycloakTest {
 
     @Override
     public void configureTestRealm(RealmRepresentation testRealm) {
-        UserRepresentation user = findUserInRealmRep(testRealm, "test-user@localhost");
+        UserRepresentation user = RealmRepUtil.findUser(testRealm, "test-user@localhost");
         UserBuilder.edit(user)
                    .hotpSecret("hotpSecret")
                    .otpEnabled();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
index ae84f89..accbd37 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
@@ -306,22 +306,25 @@ public class LoginTest extends TestRealmKeycloakTest {
     }
 
     @Test
-    public void loginPromptNone() {
-        driver.navigate().to(oauth.getLoginFormUrl().toString() + "&prompt=none");
-
-        assertFalse(loginPage.isCurrent());
-        assertTrue(appPage.isCurrent());
-
+    public void loginWithWhitespaceSuccess() {
         loginPage.open();
-        loginPage.login("login-test", "password");
+        loginPage.login(" login-test \t ", "password");
+
         Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
+        Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
 
         events.expectLogin().user(userId).detail(Details.USERNAME, "login-test").assertEvent();
+    }
+
+    @Test
+    public void loginWithEmailWhitespaceSuccess() {
+        loginPage.open();
+        loginPage.login("    login@test.com    ", "password");
 
-        driver.navigate().to(oauth.getLoginFormUrl().toString() + "&prompt=none");
         Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
+        Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
 
-        events.expectLogin().user(userId).removeDetail(Details.USERNAME).assertEvent();
+        events.expectLogin().user(userId).assertEvent();
     }
 
     private void setPasswordPolicy(String policy) {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
index 1c04847..66e6bad 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
@@ -34,6 +34,7 @@ import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.testsuite.TestRealmKeycloakTest;
 import org.keycloak.testsuite.util.GreenMailRule;
+import org.keycloak.testsuite.util.RealmRepUtil;
 import org.keycloak.testsuite.util.UserBuilder;
 
 /**
@@ -44,7 +45,7 @@ public class LoginTotpTest extends TestRealmKeycloakTest {
 
     @Override
     public void configureTestRealm(RealmRepresentation testRealm) {
-        UserRepresentation user = findUserInRealmRep(testRealm, "test-user@localhost");
+        UserRepresentation user = RealmRepUtil.findUser(testRealm, "test-user@localhost");
         UserBuilder.edit(user)
                    .totpSecret("totpSecret")
                    .otpEnabled();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java
index dda7540..ff1f66a 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/RegisterTest.java
@@ -23,11 +23,15 @@ import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.testsuite.AssertEvents;
 import org.keycloak.testsuite.TestRealmKeycloakTest;
+import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
 import org.keycloak.testsuite.pages.AppPage;
 import org.keycloak.testsuite.pages.AppPage.RequestType;
 import org.keycloak.testsuite.pages.LoginPage;
 import org.keycloak.testsuite.pages.RegisterPage;
+import org.keycloak.testsuite.util.RealmBuilder;
+import org.keycloak.testsuite.util.UserBuilder;
 
+import static org.jgroups.util.Util.assertTrue;
 import static org.junit.Assert.assertEquals;
 
 /**
@@ -48,6 +52,9 @@ public class RegisterTest extends TestRealmKeycloakTest {
     @Page
     protected RegisterPage registerPage;
 
+    @Page
+    protected AccountUpdateProfilePage accountPage;
+
     @Override
     public void configureTestRealm(RealmRepresentation testRealm) {
     }
@@ -253,15 +260,61 @@ public class RegisterTest extends TestRealmKeycloakTest {
         assertEquals("lastName", user.getLastName());
     }
 
-    /*protected UserModel getUser(String userId) {
-        KeycloakSession samlServerSession = keycloakRule.startSession();
-        try {
-            RealmModel brokerRealm = samlServerSession.realms().getRealm("test");
-            return samlServerSession.users().getUserById(userId, brokerRealm);
-        } finally {
-            keycloakRule.stopSession(samlServerSession, false);
-        }
-    }*/
+    @Test
+    public void registerUserUmlats() {
+        loginPage.open();
+
+        assertTrue(loginPage.isCurrent());
+
+        loginPage.clickRegister();
+        registerPage.assertCurrent();
+
+        registerPage.register("Äǜṳǚǘǖ", "Öṏṏ", "registeruserumlats@email", "registeruserumlats", "password", "password");
+
+        String userId = events.expectRegister("registeruserumlats", "registeruserumlats@email").assertEvent().getUserId();
+        events.expectLogin().detail("username", "registeruserumlats").user(userId).assertEvent();
+
+        accountPage.open();
+        assertTrue(accountPage.isCurrent());
+
+        UserRepresentation user = getUser(userId);
+        Assert.assertNotNull(user);
+        assertEquals("Äǜṳǚǘǖ", user.getFirstName());
+        assertEquals("Öṏṏ", user.getLastName());
+
+        assertEquals("Äǜṳǚǘǖ", accountPage.getFirstName());
+        assertEquals("Öṏṏ", accountPage.getLastName());
+    }
+
+    // KEYCLOAK-3266
+    @Test
+    public void registerUserNotUsernamePasswordPolicy() {
+        adminClient.realm("test").update(RealmBuilder.create().passwordPolicy("notUsername").build());
+
+        loginPage.open();
+
+        assertTrue(loginPage.isCurrent());
+
+        loginPage.clickRegister();
+        registerPage.assertCurrent();
+
+        registerPage.register("firstName", "lastName", "registerUserNotUsername@email", "registerUserNotUsername", "registerUserNotUsername", "registerUserNotUsername");
+
+        assertTrue(registerPage.isCurrent());
+        assertEquals("Invalid password: must not be equal to the username.", registerPage.getError());
+
+        adminClient.realm("test").users().create(UserBuilder.create().username("registerUserNotUsername").build());
+
+        registerPage.register("firstName", "lastName", "registerUserNotUsername@email", "registerUserNotUsername", "registerUserNotUsername", "registerUserNotUsername");
+
+        assertTrue(registerPage.isCurrent());
+        assertEquals("Username already exists.", registerPage.getError());
+
+        registerPage.register("firstName", "lastName", "registerUserNotUsername@email", null, "password", "password");
+
+        assertTrue(registerPage.isCurrent());
+        assertEquals("Please specify username.", registerPage.getError());
+    }
 
     protected UserRepresentation getUser(String userId) {
         return testRealm().users().get(userId).toRepresentation();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
index 98a3fe6..78d20d9 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/ResetPasswordTest.java
@@ -314,6 +314,7 @@ public class ResetPasswordTest extends TestRealmKeycloakTest {
 
         assertTrue(updatePasswordPage.isCurrent());
         assertEquals(error, updatePasswordPage.getError());
+        events.expectRequiredAction(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).user(userId).detail(Details.USERNAME, "login-test").assertEvent().getSessionId();
     }
 
     @Test
@@ -544,6 +545,8 @@ public class ResetPasswordTest extends TestRealmKeycloakTest {
 
         assertEquals("Invalid password: minimum length 8.", resetPasswordPage.getErrorMessage());
 
+        events.expectRequiredAction(EventType.UPDATE_PASSWORD_ERROR).error(Errors.PASSWORD_REJECTED).user(userId).detail(Details.USERNAME, "login-test").assertEvent().getSessionId();
+
         updatePasswordPage.changePassword("resetPasswordWithPasswordPolicy", "resetPasswordWithPasswordPolicy");
 
         String sessionId = events.expectRequiredAction(EventType.UPDATE_PASSWORD).user(userId).detail(Details.USERNAME, "login-test").assertEvent().getSessionId();
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/SSOTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/SSOTest.java
index 7a693c7..17cd717 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/SSOTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/forms/SSOTest.java
@@ -23,6 +23,7 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.keycloak.OAuth2Constants;
 import org.keycloak.events.Details;
+import org.keycloak.representations.IDToken;
 import org.keycloak.representations.idm.EventRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.testsuite.AssertEvents;
@@ -73,7 +74,11 @@ public class SSOTest extends TestRealmKeycloakTest {
         assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
         Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
 
-        String sessionId = events.expectLogin().assertEvent().getSessionId();
+        EventRepresentation loginEvent = events.expectLogin().assertEvent();
+        String sessionId = loginEvent.getSessionId();
+
+        IDToken idToken = sendTokenRequestAndGetIDToken(loginEvent);
+        Assert.assertEquals("1", idToken.getAcr());
 
         appPage.open();
 
@@ -81,13 +86,17 @@ public class SSOTest extends TestRealmKeycloakTest {
 
         assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
 
-        profilePage.open();
+        loginEvent = events.expectLogin().removeDetail(Details.USERNAME).client("test-app").assertEvent();
+        String sessionId2 = loginEvent.getSessionId();
 
-        assertTrue(profilePage.isCurrent());
+        assertEquals(sessionId, sessionId2);
 
-        String sessionId2 = events.expectLogin().removeDetail(Details.USERNAME).client("test-app").assertEvent().getSessionId();
+        // acr is 0 as we authenticated through SSO cookie
+        idToken = sendTokenRequestAndGetIDToken(loginEvent);
+        Assert.assertEquals("0", idToken.getAcr());
 
-        assertEquals(sessionId, sessionId2);
+        profilePage.open();
+        assertTrue(profilePage.isCurrent());
 
         // Expire session
         testingClient.testing().removeUserSession("test", sessionId);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
index 48b0275..dfade95 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AccessTokenTest.java
@@ -16,6 +16,8 @@
  */
 package org.keycloak.testsuite.oauth;
 
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.http.NameValuePair;
 import org.apache.http.client.entity.UrlEncodedFormEntity;
 import org.apache.http.client.methods.HttpPost;
@@ -34,6 +36,7 @@ import org.keycloak.admin.client.resource.UserResource;
 import org.keycloak.common.enums.SslRequired;
 import org.keycloak.events.Details;
 import org.keycloak.events.Errors;
+import org.keycloak.jose.jws.JWSHeader;
 import org.keycloak.jose.jws.JWSInput;
 import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.models.ProtocolMapperModel;
@@ -59,6 +62,7 @@ import org.keycloak.testsuite.util.OAuthClient;
 import org.keycloak.testsuite.util.RealmManager;
 import org.keycloak.testsuite.util.RoleBuilder;
 import org.keycloak.testsuite.util.UserBuilder;
+import org.keycloak.testsuite.util.UserInfoClientUtil;
 import org.keycloak.testsuite.util.UserManager;
 import org.keycloak.util.BasicAuthHelper;
 
@@ -69,6 +73,8 @@ import javax.ws.rs.core.Form;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
+
+import java.io.IOException;
 import java.net.URI;
 import java.util.Arrays;
 import java.util.LinkedList;
@@ -155,6 +161,26 @@ public class AccessTokenTest extends AbstractKeycloakTest {
 
         assertEquals("bearer", response.getTokenType());
 
+        String expectedKid = oauth.doCertsRequest("test").getKeys()[0].getKeyId();
+
+        JWSHeader header = new JWSInput(response.getAccessToken()).getHeader();
+        assertEquals("RS256", header.getAlgorithm().name());
+        assertEquals("JWT", header.getType());
+        assertEquals(expectedKid, header.getKeyId());
+        assertNull(header.getContentType());
+
+        header = new JWSInput(response.getIdToken()).getHeader();
+        assertEquals("RS256", header.getAlgorithm().name());
+        assertEquals("JWT", header.getType());
+        assertEquals(expectedKid, header.getKeyId());
+        assertNull(header.getContentType());
+
+        header = new JWSInput(response.getRefreshToken()).getHeader();
+        assertEquals("RS256", header.getAlgorithm().name());
+        assertEquals("JWT", header.getType());
+        assertEquals(expectedKid, header.getKeyId());
+        assertNull(header.getContentType());
+
         AccessToken token = oauth.verifyToken(response.getAccessToken());
 
         assertEquals(findUserByUsername(adminClient.realm("test"), "test-user@localhost").getId(), token.getSubject());
@@ -297,7 +323,7 @@ public class AccessTokenTest extends AbstractKeycloakTest {
     }
 
     @Test
-    public void accessTokenCodeUsed() {
+    public void accessTokenCodeUsed() throws IOException {
         oauth.doLogin("test-user@localhost", "password");
 
         EventRepresentation loginEvent = events.expectLogin().assertEvent();
@@ -308,23 +334,53 @@ public class AccessTokenTest extends AbstractKeycloakTest {
         String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
         OAuthClient.AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
         Assert.assertEquals(200, response.getStatusCode());
+        String accessToken = response.getAccessToken();
 
-        events.clear();
-
-        response = oauth.doAccessTokenRequest(code, "password");
-        Assert.assertEquals(400, response.getStatusCode());
-
-        AssertEvents.ExpectedEvent expectedEvent = events.expectCodeToToken(codeId, null);
-        expectedEvent.error("invalid_code")
-                .removeDetail(Details.TOKEN_ID)
-                .removeDetail(Details.REFRESH_TOKEN_ID)
-                .removeDetail(Details.REFRESH_TOKEN_TYPE)
-                .user((String) null);
-        expectedEvent.assertEvent();
-
-        events.clear();
-
-        RealmManager.realm(adminClient.realm("test")).accessCodeLifeSpan(60);
+        Client jaxrsClient = javax.ws.rs.client.ClientBuilder.newClient();
+        try {
+            // Check that userInfo can be invoked
+            Response userInfoResponse = UserInfoClientUtil.executeUserInfoRequest_getMethod(jaxrsClient, accessToken);
+            UserInfoClientUtil.testSuccessfulUserInfoResponse(userInfoResponse, "test-user@localhost", "test-user@localhost");
+
+            // Check that tokenIntrospection can be invoked
+            String introspectionResponse = oauth.introspectAccessTokenWithClientCredential("test-app", "password", accessToken);
+            ObjectMapper objectMapper = new ObjectMapper();
+            JsonNode jsonNode = objectMapper.readTree(introspectionResponse);
+            Assert.assertEquals(true, jsonNode.get("active").asBoolean());
+            Assert.assertEquals("test-user@localhost", jsonNode.get("email").asText());
+
+            events.clear();
+
+            // Repeating attempt to exchange code should be refused and invalidate previous clientSession
+            response = oauth.doAccessTokenRequest(code, "password");
+            Assert.assertEquals(400, response.getStatusCode());
+
+            AssertEvents.ExpectedEvent expectedEvent = events.expectCodeToToken(codeId, null);
+            expectedEvent.error("invalid_code")
+                    .removeDetail(Details.TOKEN_ID)
+                    .removeDetail(Details.REFRESH_TOKEN_ID)
+                    .removeDetail(Details.REFRESH_TOKEN_TYPE)
+                    .user((String) null);
+            expectedEvent.assertEvent();
+
+            // Check that userInfo can't be invoked with invalidated accessToken
+            userInfoResponse = UserInfoClientUtil.executeUserInfoRequest_getMethod(jaxrsClient, accessToken);
+            assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), userInfoResponse.getStatus());
+            userInfoResponse.close();
+
+            // Check that tokenIntrospection can't be invoked with invalidated accessToken
+            introspectionResponse = oauth.introspectAccessTokenWithClientCredential("test-app", "password", accessToken);
+            objectMapper = new ObjectMapper();
+            jsonNode = objectMapper.readTree(introspectionResponse);
+            Assert.assertEquals(false, jsonNode.get("active").asBoolean());
+            Assert.assertNull(jsonNode.get("email"));
+
+            events.clear();
+
+            RealmManager.realm(adminClient.realm("test")).accessCodeLifeSpan(60);
+        } finally {
+            jaxrsClient.close();
+        }
     }
 
     @Test
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
index 3fc08b4..99ee7c6 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AuthorizationCodeTest.java
@@ -18,12 +18,15 @@ package org.keycloak.testsuite.oauth;
 
 import org.jboss.arquillian.graphene.page.Page;
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.keycloak.OAuth2Constants;
+import org.keycloak.OAuthErrorException;
 import org.keycloak.events.Details;
 import org.keycloak.events.Errors;
 import org.keycloak.models.Constants;
+import org.keycloak.protocol.oidc.utils.OIDCResponseMode;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.testsuite.AbstractKeycloakTest;
 import org.keycloak.testsuite.AssertEvents;
@@ -65,15 +68,21 @@ public class AuthorizationCodeTest extends AbstractKeycloakTest {
 
     }
 
+    @Before
+    public void clientConfiguration() {
+        oauth.responseType(OAuth2Constants.CODE);
+        oauth.responseMode(null);
+    }
+
     @Test
     public void authorizationRequest() throws IOException {
-        oauth.state("mystate");
+        oauth.state("OpenIdConnect.AuthenticationProperties=2302984sdlk");
 
-        OAuthClient.AuthorizationCodeResponse response = oauth.doLogin("test-user@localhost", "password");
+        OAuthClient.AuthorizationEndpointResponse response = oauth.doLogin("test-user@localhost", "password");
 
         Assert.assertTrue(response.isRedirected());
         Assert.assertNotNull(response.getCode());
-        assertEquals("mystate", response.getState());
+        assertEquals("OpenIdConnect.AuthenticationProperties=2302984sdlk", response.getState());
         Assert.assertNull(response.getError());
 
         testingClient.testing().verifyCode("test", response.getCode());
@@ -107,7 +116,7 @@ public class AuthorizationCodeTest extends AbstractKeycloakTest {
 
         oauth.state("mystate");
 
-        OAuthClient.AuthorizationCodeResponse response = oauth.doLogin("test-user@localhost", "password");
+        OAuthClient.AuthorizationEndpointResponse response = oauth.doLogin("test-user@localhost", "password");
 
         Assert.assertTrue(response.isRedirected());
         Assert.assertNotNull(response.getCode());
@@ -122,7 +131,7 @@ public class AuthorizationCodeTest extends AbstractKeycloakTest {
     public void authorizationRequestNoState() throws IOException {
         oauth.state(null);
 
-        OAuthClient.AuthorizationCodeResponse response = oauth.doLogin("test-user@localhost", "password");
+        OAuthClient.AuthorizationEndpointResponse response = oauth.doLogin("test-user@localhost", "password");
 
         Assert.assertTrue(response.isRedirected());
         Assert.assertNotNull(response.getCode());
@@ -136,21 +145,36 @@ public class AuthorizationCodeTest extends AbstractKeycloakTest {
     }
 
     @Test
-    public void authorizationRequestImplicitFlowDisabled() throws IOException {
+    public void authorizationRequestInvalidResponseType() throws IOException {
+        oauth.responseType("tokenn");
         UriBuilder b = UriBuilder.fromUri(oauth.getLoginFormUrl());
-        b.replaceQueryParam(OAuth2Constants.RESPONSE_TYPE, "token id_token");
         driver.navigate().to(b.build().toURL());
-        assertEquals("Client is not allowed to initiate browser login with given response_type. Implicit flow is disabled for the client.", errorPage.getError());
-        events.expectLogin().error(Errors.NOT_ALLOWED).user((String) null).session((String) null).clearDetails().detail(Details.RESPONSE_TYPE, "token id_token").assertEvent();
+
+        OAuthClient.AuthorizationEndpointResponse errorResponse = new OAuthClient.AuthorizationEndpointResponse(oauth);
+        Assert.assertTrue(errorResponse.isRedirected());
+        Assert.assertEquals(errorResponse.getError(), OAuthErrorException.UNSUPPORTED_RESPONSE_TYPE);
+
+        events.expectLogin().error(Errors.INVALID_REQUEST).user((String) null).session((String) null).clearDetails().detail(Details.RESPONSE_TYPE, "tokenn").assertEvent();
     }
 
+    // KEYCLOAK-3281
     @Test
-    public void authorizationRequestInvalidResponseType() throws IOException {
-        UriBuilder b = UriBuilder.fromUri(oauth.getLoginFormUrl());
-        b.replaceQueryParam(OAuth2Constants.RESPONSE_TYPE, "tokenn");
-        driver.navigate().to(b.build().toURL());
-        assertEquals("Invalid parameter: response_type", errorPage.getError());
-        events.expectLogin().error(Errors.INVALID_REQUEST).client((String) null).user((String) null).session((String) null).clearDetails().detail(Details.RESPONSE_TYPE, "tokenn").assertEvent();
+    public void authorizationRequestFormPostResponseMode() throws IOException {
+        oauth.responseMode(OIDCResponseMode.FORM_POST.toString().toLowerCase());
+        oauth.state("OpenIdConnect.AuthenticationProperties=2302984sdlk");
+        oauth.doLoginGrant("test-user@localhost", "password");
+
+        String sources = driver.getPageSource();
+        System.out.println(sources);
+
+        String code = driver.findElement(By.id("code")).getText();
+        String state = driver.findElement(By.id("state")).getText();
+
+        assertEquals("OpenIdConnect.AuthenticationProperties=2302984sdlk", state);
+
+        testingClient.testing().verifyCode("test", code);
+        String codeId = events.expectLogin().assertEvent().getDetails().get(Details.CODE_ID);
+        assertCode(codeId, code);
     }
 
     private void assertCode(String expectedCodeId, String actualCode) {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientAuthPostMethodTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientAuthPostMethodTest.java
new file mode 100644
index 0000000..a7d395a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientAuthPostMethodTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.oauth;
+
+import java.io.UnsupportedEncodingException;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.http.NameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.message.BasicNameValuePair;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.events.Details;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.idm.EventRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.AbstractKeycloakTest;
+import org.keycloak.testsuite.AssertEvents;
+import org.keycloak.testsuite.admin.AbstractAdminTest;
+import org.keycloak.testsuite.util.OAuthClient;
+
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.lessThanOrEqualTo;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test for "client_secret_post" client authentication (clientID + clientSecret sent in the POST body instead of in "Authorization: Basic" header)
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class ClientAuthPostMethodTest extends AbstractKeycloakTest {
+
+    @Rule
+    public AssertEvents events = new AssertEvents(this);
+
+
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+        RealmRepresentation realm = AbstractAdminTest.loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class);
+        testRealms.add(realm);
+    }
+
+
+    @Test
+    public void testPostAuthentication() {
+        oauth.doLogin("test-user@localhost", "password");
+
+        EventRepresentation loginEvent = events.expectLogin().assertEvent();
+
+        String sessionId = loginEvent.getSessionId();
+        String codeId = loginEvent.getDetails().get(Details.CODE_ID);
+
+        String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
+        OAuthClient.AccessTokenResponse response = doAccessTokenRequestPostAuth(code, "password");
+
+        assertEquals(200, response.getStatusCode());
+
+        Assert.assertThat(response.getExpiresIn(), allOf(greaterThanOrEqualTo(250), lessThanOrEqualTo(300)));
+        Assert.assertThat(response.getRefreshExpiresIn(), allOf(greaterThanOrEqualTo(1750), lessThanOrEqualTo(1800)));
+
+        AccessToken token = oauth.verifyToken(response.getAccessToken());
+
+        EventRepresentation event = events.expectCodeToToken(codeId, sessionId).assertEvent();
+        assertEquals(token.getId(), event.getDetails().get(Details.TOKEN_ID));
+        assertEquals(oauth.verifyRefreshToken(response.getRefreshToken()).getId(), event.getDetails().get(Details.REFRESH_TOKEN_ID));
+        assertEquals(sessionId, token.getSessionState());
+    }
+
+
+    private OAuthClient.AccessTokenResponse doAccessTokenRequestPostAuth(String code, String clientSecret) {
+        CloseableHttpClient client = new DefaultHttpClient();
+        try {
+            HttpPost post = new HttpPost(oauth.getAccessTokenUrl());
+
+            List<NameValuePair> parameters = new LinkedList<NameValuePair>();
+            parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.AUTHORIZATION_CODE));
+            parameters.add(new BasicNameValuePair(OAuth2Constants.CODE, code));
+            parameters.add(new BasicNameValuePair(OAuth2Constants.REDIRECT_URI, oauth.getRedirectUri()));
+
+            parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, oauth.getClientId()));
+            parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_SECRET, clientSecret));
+
+
+            UrlEncodedFormEntity formEntity;
+            try {
+                formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
+            } catch (UnsupportedEncodingException e) {
+                throw new RuntimeException(e);
+            }
+            post.setEntity(formEntity);
+
+            try {
+                return new OAuthClient.AccessTokenResponse(client.execute(post));
+            } catch (Exception e) {
+                throw new RuntimeException("Failed to retrieve access token", e);
+            }
+        } finally {
+            oauth.closeClient(client);
+        }
+    }
+
+
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java
index 8a890df..087a1e6 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java
@@ -613,7 +613,7 @@ public class ClientAuthSignedJWTTest extends AbstractKeycloakTest {
     }
 
     @Test
-    @Ignore // Waiting for KEYCLOAK-2986 to be implemented
+    // KEYCLOAK-2986
     public void testMissingExpirationClaim() throws Exception {
         // Missing only exp; the lifespan should be calculated from issuedAt
         OAuthClient.AccessTokenResponse response = testMissingClaim("expiration");
@@ -840,9 +840,7 @@ public class ClientAuthSignedJWTTest extends AbstractKeycloakTest {
 
             int now = Time.currentTime();
             if (isClaimEnabled("issuedAt")) reqToken.issuedAt(now);
-            // For the time being there's no getter for tokenTimeout in JWTClientCredentialsProvider
-            // This is fine because KC doesn't care when exp claim is missing (see KEYCLOAK-2986)
-            /*if (isClaimEnabled("expiration")) reqToken.expiration(now + getTokenTimeout());*/
+            if (isClaimEnabled("expiration")) reqToken.expiration(now + getTokenTimeout());
             if (isClaimEnabled("notBefore")) reqToken.notBefore(now);
 
             return reqToken;
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/LoginStatusIframeEndpointTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/LoginStatusIframeEndpointTest.java
index 5386141..958362a 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/LoginStatusIframeEndpointTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/LoginStatusIframeEndpointTest.java
@@ -36,6 +36,7 @@ import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.testsuite.AbstractKeycloakTest;
 
 import java.io.IOException;
+import java.net.URLEncoder;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.regex.Matcher;
@@ -54,8 +55,11 @@ public class LoginStatusIframeEndpointTest extends AbstractKeycloakTest {
 
         CloseableHttpClient client = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
         try {
+            String redirectUri = URLEncoder.encode(suiteContext.getAuthServerInfo().getContextRoot() + "/auth/admin/master/console", "UTF-8");
+
             HttpGet get = new HttpGet(
-                    suiteContext.getAuthServerInfo().getContextRoot() + "/auth/realms/master/protocol/openid-connect/auth?response_type=code&client_id=" + Constants.ADMIN_CONSOLE_CLIENT_ID);
+                    suiteContext.getAuthServerInfo().getContextRoot() + "/auth/realms/master/protocol/openid-connect/auth?response_type=code&client_id=" + Constants.ADMIN_CONSOLE_CLIENT_ID +
+                            "&redirect_uri=" + redirectUri);
 
             CloseableHttpResponse response = client.execute(get);
             String s = IOUtils.toString(response.getEntity().getContent());
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/LogoutTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/LogoutTest.java
new file mode 100644
index 0000000..38dde74
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/LogoutTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.oauth;
+
+import org.apache.http.HttpResponse;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.common.util.Time;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.AbstractKeycloakTest;
+import org.keycloak.testsuite.AssertEvents;
+import org.keycloak.testsuite.util.ClientManager;
+import org.keycloak.testsuite.util.OAuthClient;
+import org.keycloak.testsuite.util.RealmBuilder;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class LogoutTest extends AbstractKeycloakTest {
+
+    @Rule
+    public AssertEvents events = new AssertEvents(this);
+
+    @Override
+    public void beforeAbstractKeycloakTest() throws Exception {
+        super.beforeAbstractKeycloakTest();
+    }
+
+    @Before
+    public void clientConfiguration() {
+        ClientManager.realm(adminClient.realm("test")).clientId("test-app").directAccessGrant(true);
+    }
+
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+        RealmRepresentation realmRepresentation = loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class);
+        RealmBuilder realm = RealmBuilder.edit(realmRepresentation).testEventListener();
+
+        testRealms.add(realm.build());
+    }
+
+    @Test
+    public void postLogout() throws Exception {
+        oauth.doLogin("test-user@localhost", "password");
+
+        String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
+
+        oauth.clientSessionState("client-session");
+        OAuthClient.AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(code, "password");
+        String refreshTokenString = tokenResponse.getRefreshToken();
+
+        HttpResponse response = oauth.doLogout(refreshTokenString, "password");
+        assertEquals(204, response.getStatusLine().getStatusCode());
+
+        assertNotNull(testingClient.testApp().getAdminLogoutAction());
+    }
+
+    @Test
+    public void postLogoutExpiredRefreshToken() throws Exception {
+        oauth.doLogin("test-user@localhost", "password");
+
+        String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
+
+        oauth.clientSessionState("client-session");
+        OAuthClient.AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(code, "password");
+        String refreshTokenString = tokenResponse.getRefreshToken();
+
+        adminClient.realm("test").update(RealmBuilder.create().notBefore(Time.currentTime() + 1).build());
+
+        // Logout should succeed with expired refresh token, see KEYCLOAK-3302
+        HttpResponse response = oauth.doLogout(refreshTokenString, "password");
+        assertEquals(204, response.getStatusLine().getStatusCode());
+
+        assertNotNull(testingClient.testApp().getAdminLogoutAction());
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java
index 71274a0..f80e789 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/OAuthRedirectUriTest.java
@@ -103,9 +103,9 @@ public class OAuthRedirectUriTest extends AbstractKeycloakTest {
     @Test
     public void testNoParam() throws IOException {
         oauth.redirectUri(null);
-        OAuthClient.AuthorizationCodeResponse response = oauth.doLogin("test-user@localhost", "password");
-        Assert.assertNotNull(response.getCode());
-        assertEquals(oauth.getCurrentRequest(), APP_ROOT + "/auth");
+        oauth.openLoginForm();
+        Assert.assertTrue(errorPage.isCurrent());
+        Assert.assertEquals("Invalid parameter: redirect_uri", errorPage.getError());
     }
 
     @Test
@@ -154,7 +154,7 @@ public class OAuthRedirectUriTest extends AbstractKeycloakTest {
     @Test
     public void testValid() throws IOException {
         oauth.redirectUri(APP_ROOT + "/auth");
-        OAuthClient.AuthorizationCodeResponse response = oauth.doLogin("test-user@localhost", "password");
+        OAuthClient.AuthorizationEndpointResponse response = oauth.doLogin("test-user@localhost", "password");
 
         Assert.assertNotNull(response.getCode());
         URL url = new URL(driver.getCurrentUrl());
@@ -175,7 +175,7 @@ public class OAuthRedirectUriTest extends AbstractKeycloakTest {
     @Test
     public void testWithParams() throws IOException {
         oauth.redirectUri(APP_ROOT + "/auth?key=value");
-        OAuthClient.AuthorizationCodeResponse response = oauth.doLogin("test-user@localhost", "password");
+        OAuthClient.AuthorizationEndpointResponse response = oauth.doLogin("test-user@localhost", "password");
 
         Assert.assertNotNull(response.getCode());
         URL url = new URL(driver.getCurrentUrl());
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java
index ec76062..6796d12 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ResourceOwnerPasswordCredentialsGrantTest.java
@@ -351,8 +351,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest extends AbstractKeycloakT
     public void grantAccessTokenExpiredPassword() throws Exception {
 
         RealmResource realmResource = adminClient.realm("test");
-        RealmManager.realm(realmResource).passwordPolicy(
-                new PasswordPolicy("forceExpiredPasswordChange(1)").toString());
+        RealmManager.realm(realmResource).passwordPolicy("forceExpiredPasswordChange(1)");
 
         try {
             setTimeOffset(60 * 60 * 48);
@@ -376,7 +375,7 @@ public class ResourceOwnerPasswordCredentialsGrantTest extends AbstractKeycloakT
                     .user((String) null)
                     .assertEvent();
         } finally {
-            RealmManager.realm(realmResource).passwordPolicy(new PasswordPolicy("").toString());
+            RealmManager.realm(realmResource).passwordPolicy("");
             UserManager.realm(realmResource).username("test-user@localhost")
                     .removeRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD.toString());
         }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenIntrospectionTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenIntrospectionTest.java
index 74b0516..ec800ed 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenIntrospectionTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/TokenIntrospectionTest.java
@@ -21,12 +21,15 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import org.junit.Rule;
 import org.junit.Test;
 import org.keycloak.OAuth2Constants;
+import org.keycloak.OAuthErrorException;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.representations.idm.EventRepresentation;
+import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
 import org.keycloak.representations.oidc.TokenMetadataRepresentation;
+import org.keycloak.testsuite.Assert;
 import org.keycloak.testsuite.AssertEvents;
 import org.keycloak.testsuite.TestRealmKeycloakTest;
 import org.keycloak.testsuite.util.KeycloakModelUtils;
@@ -112,7 +115,9 @@ public class TokenIntrospectionTest extends TestRealmKeycloakTest {
         AccessTokenResponse accessTokenResponse = oauth.doAccessTokenRequest(code, "password");
         String tokenResponse = oauth.introspectAccessTokenWithClientCredential("confidential-cli", "bad_credential", accessTokenResponse.getAccessToken());
 
-        assertEquals("{\"error_description\":\"Authentication failed.\",\"error\":\"invalid_request\"}", tokenResponse);
+        OAuth2ErrorRepresentation errorRep = JsonSerialization.readValue(tokenResponse, OAuth2ErrorRepresentation.class);
+        Assert.assertEquals("Authentication failed.", errorRep.getErrorDescription());
+        Assert.assertEquals(OAuthErrorException.INVALID_REQUEST, errorRep.getError());
     }
 
     @Test
@@ -122,7 +127,7 @@ public class TokenIntrospectionTest extends TestRealmKeycloakTest {
         EventRepresentation loginEvent = events.expectLogin().assertEvent();
         String sessionId = loginEvent.getSessionId();
         AccessTokenResponse accessTokenResponse = oauth.doAccessTokenRequest(code, "password");
-        String tokenResponse = oauth.introspectAccessTokenWithClientCredential("confidential-cli", "secret1", accessTokenResponse.getAccessToken());
+        String tokenResponse = oauth.introspectRefreshTokenWithClientCredential("confidential-cli", "secret1", accessTokenResponse.getAccessToken());
         ObjectMapper objectMapper = new ObjectMapper();
         JsonNode jsonNode = objectMapper.readTree(tokenResponse);
 
@@ -157,7 +162,9 @@ public class TokenIntrospectionTest extends TestRealmKeycloakTest {
         AccessTokenResponse accessTokenResponse = oauth.doAccessTokenRequest(code, "password");
         String tokenResponse = oauth.introspectAccessTokenWithClientCredential("public-cli", "it_doesnt_matter", accessTokenResponse.getAccessToken());
 
-        assertEquals("{\"error_description\":\"Client not allowed.\",\"error\":\"invalid_request\"}", tokenResponse);
+        OAuth2ErrorRepresentation errorRep = JsonSerialization.readValue(tokenResponse, OAuth2ErrorRepresentation.class);
+        Assert.assertEquals("Client not allowed.", errorRep.getErrorDescription());
+        Assert.assertEquals(OAuthErrorException.INVALID_REQUEST, errorRep.getError());
     }
 
     @Test
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/AbstractOIDCResponseTypeTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/AbstractOIDCResponseTypeTest.java
new file mode 100644
index 0000000..28c6ff5
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/AbstractOIDCResponseTypeTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.oidc.flows;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.List;
+
+import javax.ws.rs.core.UriBuilder;
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.OAuthErrorException;
+import org.keycloak.events.Details;
+import org.keycloak.events.Errors;
+import org.keycloak.jose.jws.Algorithm;
+import org.keycloak.representations.IDToken;
+import org.keycloak.representations.idm.EventRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.AssertEvents;
+import org.keycloak.testsuite.TestRealmKeycloakTest;
+import org.keycloak.testsuite.admin.AbstractAdminTest;
+import org.keycloak.testsuite.pages.AppPage;
+import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.util.ClientManager;
+import org.keycloak.testsuite.util.OAuthClient;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Abstract test for various values of response_type
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public abstract class AbstractOIDCResponseTypeTest extends TestRealmKeycloakTest {
+
+    // Harcoded for now
+    Algorithm jwsAlgorithm = Algorithm.RS256;
+
+    @Rule
+    public AssertEvents events = new AssertEvents(this);
+
+    @Page
+    protected AppPage appPage;
+
+    @Page
+    protected LoginPage loginPage;
+
+    @Override
+    public void configureTestRealm(RealmRepresentation testRealm) {
+    }
+
+
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+        RealmRepresentation realm = AbstractAdminTest.loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class);
+        testRealms.add(realm);
+    }
+
+
+    @Test
+    public void nonceMatches() {
+        EventRepresentation loginEvent = loginUser("abcdef123456");
+        List<IDToken> idTokens = retrieveIDTokens(loginEvent);
+
+        for (IDToken idToken : idTokens) {
+            Assert.assertEquals("abcdef123456", idToken.getNonce());
+        }
+    }
+
+
+    @Test
+    public void authorizationRequestMissingResponseType() throws IOException {
+        oauth.responseType(null);
+        UriBuilder b = UriBuilder.fromUri(oauth.getLoginFormUrl());
+        driver.navigate().to(b.build().toURL());
+
+        // Always read error from the "query"
+        OAuthClient.AuthorizationEndpointResponse errorResponse = new OAuthClient.AuthorizationEndpointResponse(oauth, false);
+        org.junit.Assert.assertTrue(errorResponse.isRedirected());
+        org.junit.Assert.assertEquals(errorResponse.getError(), OAuthErrorException.INVALID_REQUEST);
+
+        events.expectLogin().error(Errors.INVALID_REQUEST).user((String) null).session((String) null).clearDetails().assertEvent();
+    }
+
+
+    protected void validateNonceNotUsedErrorExpected() {
+        oauth.nonce(null);
+        driver.navigate().to(oauth.getLoginFormUrl());
+
+        assertFalse(loginPage.isCurrent());
+        assertTrue(appPage.isCurrent());
+
+        // Assert error response was sent because not logged in
+        OAuthClient.AuthorizationEndpointResponse resp = new OAuthClient.AuthorizationEndpointResponse(oauth);
+        Assert.assertNull(resp.getCode());
+        Assert.assertNull(resp.getIdToken());
+        Assert.assertEquals(OAuthErrorException.INVALID_REQUEST, resp.getError());
+        Assert.assertEquals("Missing parameter: nonce", resp.getErrorDescription());
+    }
+
+
+    protected void validateErrorImplicitFlowNotAllowed() throws Exception {
+        // Disable implicit flow for client
+        clientManagerBuilder().implicitFlow(false);
+
+        UriBuilder b = UriBuilder.fromUri(oauth.getLoginFormUrl());
+        driver.navigate().to(b.build().toURL());
+
+        OAuthClient.AuthorizationEndpointResponse errorResponse = new OAuthClient.AuthorizationEndpointResponse(oauth);
+        Assert.assertTrue(errorResponse.isRedirected());
+        Assert.assertEquals(errorResponse.getError(), OAuthErrorException.UNSUPPORTED_RESPONSE_TYPE);
+        Assert.assertEquals(errorResponse.getErrorDescription(), "Client is not allowed to initiate browser login with given response_type. Implicit flow is disabled for the client.");
+
+        events.expectLogin().error(Errors.NOT_ALLOWED).user((String) null).session((String) null).clearDetails().assertEvent();
+
+        // Revert
+        clientManagerBuilder().implicitFlow(true);
+    }
+
+
+    protected void validateErrorStandardFlowNotAllowed() throws Exception {
+        // Disable standard flow for client
+        clientManagerBuilder().standardFlow(false);
+
+        UriBuilder b = UriBuilder.fromUri(oauth.getLoginFormUrl());
+        driver.navigate().to(b.build().toURL());
+
+        OAuthClient.AuthorizationEndpointResponse errorResponse = new OAuthClient.AuthorizationEndpointResponse(oauth);
+        Assert.assertTrue(errorResponse.isRedirected());
+        Assert.assertEquals(errorResponse.getError(), OAuthErrorException.UNSUPPORTED_RESPONSE_TYPE);
+        Assert.assertEquals(errorResponse.getErrorDescription(), "Client is not allowed to initiate browser login with given response_type. Standard flow is disabled for the client.");
+
+        events.expectLogin().error(Errors.NOT_ALLOWED).user((String) null).session((String) null).clearDetails().assertEvent();
+
+        // Revert
+        clientManagerBuilder().standardFlow(true);
+    }
+
+
+
+    protected EventRepresentation loginUser(String nonce) {
+        if (nonce != null) {
+            oauth.nonce(nonce);
+        }
+
+        driver.navigate().to(oauth.getLoginFormUrl());
+
+        loginPage.assertCurrent();
+        loginPage.login("test-user@localhost", "password");
+        Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
+
+        return events.expectLogin().detail(Details.USERNAME, "test-user@localhost").assertEvent();
+    }
+
+    protected abstract List<IDToken> retrieveIDTokens(EventRepresentation loginEvent);
+
+    protected ClientManager.ClientManagerBuilder clientManagerBuilder() {
+        return ClientManager.realm(adminClient.realm("test")).clientId("test-app");
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCBasicResponseTypeCodeTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCBasicResponseTypeCodeTest.java
new file mode 100644
index 0000000..355aa42
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCBasicResponseTypeCodeTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.oidc.flows;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.events.Details;
+import org.keycloak.protocol.oidc.utils.OIDCResponseType;
+import org.keycloak.representations.IDToken;
+import org.keycloak.representations.idm.EventRepresentation;
+import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.util.ClientManager;
+import org.keycloak.testsuite.util.OAuthClient;
+
+/**
+ * Test for response_type=code
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OIDCBasicResponseTypeCodeTest extends AbstractOIDCResponseTypeTest {
+
+    @Before
+    public void clientConfiguration() {
+        clientManagerBuilder().standardFlow(true).implicitFlow(false);
+
+        oauth.clientId("test-app");
+        oauth.responseType(OIDCResponseType.CODE);
+    }
+
+
+    protected List<IDToken> retrieveIDTokens(EventRepresentation loginEvent) {
+        Assert.assertEquals(OIDCResponseType.CODE, loginEvent.getDetails().get(Details.RESPONSE_TYPE));
+
+        OAuthClient.AuthorizationEndpointResponse authzResponse = new OAuthClient.AuthorizationEndpointResponse(oauth, false);
+        Assert.assertNull(authzResponse.getAccessToken());
+        Assert.assertNull(authzResponse.getIdToken());
+
+        IDToken idToken = sendTokenRequestAndGetIDToken(loginEvent);
+
+        return Collections.singletonList(idToken);
+    }
+
+
+    @Test
+    public void nonceNotUsed() {
+        EventRepresentation loginEvent = loginUser(null);
+
+        List<IDToken> idTokens = retrieveIDTokens(loginEvent);
+        for (IDToken idToken : idTokens) {
+            Assert.assertNull(idToken.getNonce());
+        }
+    }
+
+    @Test
+    public void errorStandardFlowNotAllowed() throws Exception {
+        super.validateErrorStandardFlowNotAllowed();
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTest.java
new file mode 100644
index 0000000..ebad58a
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.oidc.flows;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.events.Details;
+import org.keycloak.jose.jws.crypto.HashProvider;
+import org.keycloak.protocol.oidc.utils.OIDCResponseType;
+import org.keycloak.representations.IDToken;
+import org.keycloak.representations.idm.EventRepresentation;
+import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.util.OAuthClient;
+
+/**
+ * Tests with response_type=code id_token
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OIDCHybridResponseTypeCodeIDTokenTest extends AbstractOIDCResponseTypeTest {
+
+    @Before
+    public void clientConfiguration() {
+        clientManagerBuilder().standardFlow(true).implicitFlow(true);
+
+        oauth.clientId("test-app");
+        oauth.responseType(OIDCResponseType.CODE + " " + OIDCResponseType.ID_TOKEN);
+    }
+
+
+    protected List<IDToken> retrieveIDTokens(EventRepresentation loginEvent) {
+        Assert.assertEquals(OIDCResponseType.CODE + " " + OIDCResponseType.ID_TOKEN, loginEvent.getDetails().get(Details.RESPONSE_TYPE));
+
+        // IDToken from the authorization response
+        OAuthClient.AuthorizationEndpointResponse authzResponse = new OAuthClient.AuthorizationEndpointResponse(oauth, true);
+        Assert.assertNull(authzResponse.getAccessToken());
+        String idTokenStr = authzResponse.getIdToken();
+        IDToken idToken = oauth.verifyIDToken(idTokenStr);
+
+        // Validate "c_hash"
+        Assert.assertNull(idToken.getAccessTokenHash());
+        Assert.assertNotNull(idToken.getCodeHash());
+        Assert.assertEquals(idToken.getCodeHash(), HashProvider.oidcHash(jwsAlgorithm, authzResponse.getCode()));
+
+        // IDToken exchanged for the code
+        IDToken idToken2 = sendTokenRequestAndGetIDToken(loginEvent);
+
+        return Arrays.asList(idToken, idToken2);
+    }
+
+
+    @Test
+    public void nonceNotUsedErrorExpected() {
+        super.validateNonceNotUsedErrorExpected();
+    }
+
+    @Test
+    public void errorStandardFlowNotAllowed() throws Exception {
+        super.validateErrorStandardFlowNotAllowed();
+    }
+
+    @Test
+    public void errorImplicitFlowNotAllowed() throws Exception {
+        super.validateErrorImplicitFlowNotAllowed();
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTokenTest.java
new file mode 100644
index 0000000..dd56c7d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeIDTokenTokenTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.oidc.flows;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.events.Details;
+import org.keycloak.jose.jws.crypto.HashProvider;
+import org.keycloak.protocol.oidc.utils.OIDCResponseType;
+import org.keycloak.representations.IDToken;
+import org.keycloak.representations.idm.EventRepresentation;
+import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.util.OAuthClient;
+
+/**
+ * Tests with response_type=code id_token token
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OIDCHybridResponseTypeCodeIDTokenTokenTest extends AbstractOIDCResponseTypeTest {
+
+    @Before
+    public void clientConfiguration() {
+        clientManagerBuilder().standardFlow(true).implicitFlow(true);
+
+        oauth.clientId("test-app");
+        oauth.responseType(OIDCResponseType.CODE + " " + OIDCResponseType.ID_TOKEN + " "  + OIDCResponseType.TOKEN);
+    }
+
+
+    protected List<IDToken> retrieveIDTokens(EventRepresentation loginEvent) {
+        Assert.assertEquals(OIDCResponseType.CODE + " " + OIDCResponseType.ID_TOKEN + " " + OIDCResponseType.TOKEN, loginEvent.getDetails().get(Details.RESPONSE_TYPE));
+
+        // IDToken from the authorization response
+        OAuthClient.AuthorizationEndpointResponse authzResponse = new OAuthClient.AuthorizationEndpointResponse(oauth, true);
+        Assert.assertNotNull(authzResponse.getAccessToken());
+        String idTokenStr = authzResponse.getIdToken();
+        IDToken idToken = oauth.verifyIDToken(idTokenStr);
+
+        // Validate "at_hash" and "c_hash"
+        Assert.assertNotNull(idToken.getAccessTokenHash());
+        Assert.assertEquals(idToken.getAccessTokenHash(), HashProvider.oidcHash(jwsAlgorithm, authzResponse.getAccessToken()));
+        Assert.assertNotNull(idToken.getCodeHash());
+        Assert.assertEquals(idToken.getCodeHash(), HashProvider.oidcHash(jwsAlgorithm, authzResponse.getCode()));
+
+        // IDToken exchanged for the code
+        IDToken idToken2 = sendTokenRequestAndGetIDToken(loginEvent);
+
+        return Arrays.asList(idToken, idToken2);
+    }
+
+
+    @Test
+    public void nonceNotUsedErrorExpected() {
+        super.validateNonceNotUsedErrorExpected();
+    }
+
+    @Test
+    public void errorStandardFlowNotAllowed() throws Exception {
+        super.validateErrorStandardFlowNotAllowed();
+    }
+
+    @Test
+    public void errorImplicitFlowNotAllowed() throws Exception {
+        super.validateErrorImplicitFlowNotAllowed();
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeTokenTest.java
new file mode 100644
index 0000000..4ce4a28
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCHybridResponseTypeCodeTokenTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.oidc.flows;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.events.Details;
+import org.keycloak.protocol.oidc.utils.OIDCResponseType;
+import org.keycloak.representations.IDToken;
+import org.keycloak.representations.idm.EventRepresentation;
+import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.util.OAuthClient;
+
+/**
+ * Tests with response_type=code token
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OIDCHybridResponseTypeCodeTokenTest extends AbstractOIDCResponseTypeTest  {
+
+    @Before
+    public void clientConfiguration() {
+        clientManagerBuilder().standardFlow(true).implicitFlow(true);
+
+        oauth.clientId("test-app");
+        oauth.responseType(OIDCResponseType.CODE + " " + OIDCResponseType.TOKEN);
+    }
+
+
+    protected List<IDToken> retrieveIDTokens(EventRepresentation loginEvent) {
+        Assert.assertEquals(OIDCResponseType.CODE + " " + OIDCResponseType.TOKEN, loginEvent.getDetails().get(Details.RESPONSE_TYPE));
+
+        OAuthClient.AuthorizationEndpointResponse authzResponse = new OAuthClient.AuthorizationEndpointResponse(oauth, true);
+        Assert.assertNotNull(authzResponse.getAccessToken());
+        Assert.assertNull(authzResponse.getIdToken());
+
+        // IDToken exchanged for the code
+        IDToken idToken2 = sendTokenRequestAndGetIDToken(loginEvent);
+
+        return Collections.singletonList(idToken2);
+    }
+
+
+    @Test
+    public void nonceNotUsedErrorExpected() {
+        super.validateNonceNotUsedErrorExpected();
+    }
+
+    @Test
+    public void errorStandardFlowNotAllowed() throws Exception {
+        super.validateErrorStandardFlowNotAllowed();
+    }
+
+    @Test
+    public void errorImplicitFlowNotAllowed() throws Exception {
+        super.validateErrorImplicitFlowNotAllowed();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCImplicitResponseTypeIDTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCImplicitResponseTypeIDTokenTest.java
new file mode 100644
index 0000000..2a82cd9
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCImplicitResponseTypeIDTokenTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.oidc.flows;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.events.Details;
+import org.keycloak.protocol.oidc.utils.OIDCResponseType;
+import org.keycloak.representations.IDToken;
+import org.keycloak.representations.idm.EventRepresentation;
+import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.util.OAuthClient;
+
+/**
+ * Tests with response_type=id_token
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OIDCImplicitResponseTypeIDTokenTest extends AbstractOIDCResponseTypeTest {
+
+    @Before
+    public void clientConfiguration() {
+        clientManagerBuilder().standardFlow(false).implicitFlow(true);
+
+        oauth.clientId("test-app");
+        oauth.responseType(OIDCResponseType.ID_TOKEN);
+    }
+
+
+    protected List<IDToken> retrieveIDTokens(EventRepresentation loginEvent) {
+        Assert.assertEquals(OIDCResponseType.ID_TOKEN, loginEvent.getDetails().get(Details.RESPONSE_TYPE));
+
+        OAuthClient.AuthorizationEndpointResponse authzResponse = new OAuthClient.AuthorizationEndpointResponse(oauth, true);
+        Assert.assertNull(authzResponse.getAccessToken());
+        String idTokenStr = authzResponse.getIdToken();
+        IDToken idToken = oauth.verifyIDToken(idTokenStr);
+
+        Assert.assertNull(idToken.getAccessTokenHash());
+        Assert.assertNull(idToken.getCodeHash());
+
+        return Collections.singletonList(idToken);
+    }
+
+
+    @Test
+    public void nonceNotUsedErrorExpected() {
+        super.validateNonceNotUsedErrorExpected();
+    }
+
+    @Test
+    public void errorImplicitFlowNotAllowed() throws Exception {
+        super.validateErrorImplicitFlowNotAllowed();
+    }
+
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCImplicitResponseTypeIDTokenTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCImplicitResponseTypeIDTokenTokenTest.java
new file mode 100644
index 0000000..899d406
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/flows/OIDCImplicitResponseTypeIDTokenTokenTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.oidc.flows;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.events.Details;
+import org.keycloak.jose.jws.crypto.HashProvider;
+import org.keycloak.protocol.oidc.utils.OIDCResponseType;
+import org.keycloak.representations.IDToken;
+import org.keycloak.representations.idm.EventRepresentation;
+import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.util.OAuthClient;
+
+/**
+ * Tests with response_type=id_token token
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OIDCImplicitResponseTypeIDTokenTokenTest extends AbstractOIDCResponseTypeTest {
+
+    @Before
+    public void clientConfiguration() {
+        clientManagerBuilder().standardFlow(false).implicitFlow(true);
+
+        oauth.clientId("test-app");
+        oauth.responseType(OIDCResponseType.ID_TOKEN + " " + OIDCResponseType.TOKEN);
+    }
+
+
+    protected List<IDToken> retrieveIDTokens(EventRepresentation loginEvent) {
+        Assert.assertEquals(OIDCResponseType.ID_TOKEN + " " + OIDCResponseType.TOKEN, loginEvent.getDetails().get(Details.RESPONSE_TYPE));
+
+        OAuthClient.AuthorizationEndpointResponse authzResponse = new OAuthClient.AuthorizationEndpointResponse(oauth, true);
+        Assert.assertNotNull(authzResponse.getAccessToken());
+        String idTokenStr = authzResponse.getIdToken();
+        IDToken idToken = oauth.verifyIDToken(idTokenStr);
+
+        // Validate "at_hash"
+        Assert.assertNotNull(idToken.getAccessTokenHash());
+        Assert.assertEquals(idToken.getAccessTokenHash(), HashProvider.oidcHash(jwsAlgorithm, authzResponse.getAccessToken()));
+        Assert.assertNull(idToken.getCodeHash());
+
+        return Collections.singletonList(idToken);
+    }
+
+
+    @Test
+    public void nonceNotUsedErrorExpected() {
+        super.validateNonceNotUsedErrorExpected();
+    }
+
+    @Test
+    public void errorImplicitFlowNotAllowed() throws Exception {
+        super.validateErrorImplicitFlowNotAllowed();
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCAdvancedRequestParamsTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCAdvancedRequestParamsTest.java
new file mode 100644
index 0000000..191581e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCAdvancedRequestParamsTest.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.oidc;
+
+import java.util.List;
+
+
+import org.jboss.arquillian.graphene.page.Page;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.OAuthErrorException;
+import org.keycloak.common.util.Time;
+import org.keycloak.events.Details;
+import org.keycloak.models.Constants;
+import org.keycloak.protocol.oidc.OIDCLoginProtocol;
+import org.keycloak.representations.IDToken;
+import org.keycloak.representations.idm.EventRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.AssertEvents;
+import org.keycloak.testsuite.TestRealmKeycloakTest;
+import org.keycloak.testsuite.admin.AbstractAdminTest;
+import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
+import org.keycloak.testsuite.pages.AppPage;
+import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.pages.OAuthGrantPage;
+import org.keycloak.testsuite.util.ClientManager;
+import org.keycloak.testsuite.util.OAuthClient;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test for supporting advanced parameters of OIDC specs (max_age, prompt, ...)
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OIDCAdvancedRequestParamsTest extends TestRealmKeycloakTest {
+
+    @Rule
+    public AssertEvents events = new AssertEvents(this);
+
+    @Page
+    protected AppPage appPage;
+
+    @Page
+    protected LoginPage loginPage;
+
+    @Page
+    protected AccountUpdateProfilePage profilePage;
+
+    @Page
+    protected OAuthGrantPage grantPage;
+
+
+    @Override
+    public void configureTestRealm(RealmRepresentation testRealm) {
+    }
+
+    @Before
+    public void clientConfiguration() {
+        ClientManager.realm(adminClient.realm("test")).clientId("test-app").directAccessGrant(true);
+        /*
+         * Configure the default client ID. Seems like OAuthClient is keeping the state of clientID
+         * For example: If some test case configure oauth.clientId("sample-public-client"), other tests
+         * will faile and the clientID will always be "sample-public-client
+         * @see AccessTokenTest#testAuthorizationNegotiateHeaderIgnored()
+         */
+        oauth.clientId("test-app");
+        oauth.maxAge(null);
+    }
+
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+        RealmRepresentation realm = AbstractAdminTest.loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class);
+        testRealms.add(realm);
+    }
+
+
+    // Max_age
+
+    @Test
+    public void testMaxAge1() {
+        // Open login form and login successfully
+        oauth.doLogin("test-user@localhost", "password");
+        EventRepresentation loginEvent = events.expectLogin().assertEvent();
+
+        IDToken idToken = sendTokenRequestAndGetIDToken(loginEvent);
+
+        // Check that authTime is available and set to current time
+        int authTime = idToken.getAuthTime();
+        int currentTime = Time.currentTime();
+        Assert.assertTrue(authTime <= currentTime && authTime + 3 >= currentTime);
+
+        // Set time offset
+        setTimeOffset(10);
+
+        // Now open login form with maxAge=1
+        oauth.maxAge("1");
+
+        // Assert I need to login again through the login form
+        oauth.doLogin("test-user@localhost", "password");
+        loginEvent = events.expectLogin().assertEvent();
+
+        idToken = sendTokenRequestAndGetIDToken(loginEvent);
+
+        // Assert that authTime was updated
+        int authTimeUpdated = idToken.getAuthTime();
+        Assert.assertTrue(authTime + 10 <= authTimeUpdated);
+    }
+
+    @Test
+    public void testMaxAge10000() {
+        // Open login form and login successfully
+        oauth.doLogin("test-user@localhost", "password");
+        EventRepresentation loginEvent = events.expectLogin().assertEvent();
+
+        IDToken idToken = sendTokenRequestAndGetIDToken(loginEvent);
+
+        // Check that authTime is available and set to current time
+        int authTime = idToken.getAuthTime();
+        int currentTime = Time.currentTime();
+        Assert.assertTrue(authTime <= currentTime && authTime + 3 >= currentTime);
+
+        // Set time offset
+        setTimeOffset(10);
+
+        // Now open login form with maxAge=10000
+        oauth.maxAge("10000");
+
+        // Assert that I will be automatically logged through cookie
+        oauth.openLoginForm();
+        loginEvent = events.expectLogin().assertEvent();
+
+        idToken = sendTokenRequestAndGetIDToken(loginEvent);
+
+        // Assert that authTime is still the same
+        int authTimeUpdated = idToken.getAuthTime();
+        Assert.assertEquals(authTime, authTimeUpdated);
+    }
+
+
+    // Prompt
+
+    @Test
+    public void promptNoneNotLogged() {
+        // Send request with prompt=none
+        driver.navigate().to(oauth.getLoginFormUrl() + "&prompt=none");
+
+        assertFalse(loginPage.isCurrent());
+        assertTrue(appPage.isCurrent());
+
+        events.assertEmpty();
+
+        // Assert error response was sent because not logged in
+        OAuthClient.AuthorizationEndpointResponse resp = new OAuthClient.AuthorizationEndpointResponse(oauth);
+        Assert.assertNull(resp.getCode());
+        Assert.assertEquals(OAuthErrorException.LOGIN_REQUIRED, resp.getError());
+
+
+    }
+
+    @Test
+    public void promptNoneSuccess() {
+        // Login user
+        loginPage.open();
+        loginPage.login("test-user@localhost", "password");
+        Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
+
+        EventRepresentation loginEvent = events.expectLogin().detail(Details.USERNAME, "test-user@localhost").assertEvent();
+        IDToken idToken = sendTokenRequestAndGetIDToken(loginEvent);
+        int authTime = idToken.getAuthTime();
+
+        // Set time offset
+        setTimeOffset(10);
+
+        // Assert user still logged with previous authTime
+        driver.navigate().to(oauth.getLoginFormUrl() + "&prompt=none");
+        Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
+
+        loginEvent = events.expectLogin().removeDetail(Details.USERNAME).assertEvent();
+        idToken = sendTokenRequestAndGetIDToken(loginEvent);
+        int authTime2 = idToken.getAuthTime();
+
+        Assert.assertEquals(authTime, authTime2);
+    }
+
+
+    // Prompt=none with consent required for client
+    @Test
+    public void promptNoneConsentRequired() throws Exception {
+        // Require consent
+        ClientManager.realm(adminClient.realm("test")).clientId("test-app").consentRequired(true);
+
+        try {
+            // login to account mgmt.
+            profilePage.open();
+            assertTrue(loginPage.isCurrent());
+            loginPage.login("test-user@localhost", "password");
+            profilePage.assertCurrent();
+
+            events.expectLogin().client(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID)
+                    .removeDetail(Details.REDIRECT_URI)
+                    .detail(Details.USERNAME, "test-user@localhost").assertEvent();
+
+            // Assert error shown when trying prompt=none and consent not yet retrieved
+            driver.navigate().to(oauth.getLoginFormUrl() + "&prompt=none");
+            assertTrue(appPage.isCurrent());
+            Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
+
+            OAuthClient.AuthorizationEndpointResponse resp = new OAuthClient.AuthorizationEndpointResponse(oauth);
+            Assert.assertNull(resp.getCode());
+            Assert.assertEquals(OAuthErrorException.INTERACTION_REQUIRED, resp.getError());
+
+            // Confirm consent
+            driver.navigate().to(oauth.getLoginFormUrl());
+            grantPage.assertCurrent();
+            grantPage.accept();
+
+            events.expectLogin()
+                    .detail(Details.USERNAME, "test-user@localhost")
+                    .detail(Details.CONSENT, Details.CONSENT_VALUE_CONSENT_GRANTED)
+                    .assertEvent();
+
+            // Consent not required anymore. Login with prompt=none should success
+            driver.navigate().to(oauth.getLoginFormUrl() + "&prompt=none");
+            Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
+
+            resp = new OAuthClient.AuthorizationEndpointResponse(oauth);
+            Assert.assertNotNull(resp.getCode());
+            Assert.assertNull(resp.getError());
+
+            events.expectLogin()
+                    .detail(Details.USERNAME, "test-user@localhost")
+                    .detail(Details.CONSENT, Details.CONSENT_VALUE_PERSISTED_CONSENT)
+                    .assertEvent();
+
+        } finally {
+            //  revert require consent
+            ClientManager.realm(adminClient.realm("test")).clientId("test-app").consentRequired(false);
+        }
+    }
+
+
+    // prompt=login
+    @Test
+    public void promptLogin() {
+        // Login user
+        loginPage.open();
+        loginPage.login("test-user@localhost", "password");
+        Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
+
+        EventRepresentation loginEvent = events.expectLogin().detail(Details.USERNAME, "test-user@localhost").assertEvent();
+        IDToken idToken = sendTokenRequestAndGetIDToken(loginEvent);
+        int authTime = idToken.getAuthTime();
+
+        // Set time offset
+        setTimeOffset(10);
+
+        // Assert need to re-authenticate with prompt=login
+        driver.navigate().to(oauth.getLoginFormUrl() + "&prompt=login");
+
+        loginPage.assertCurrent();
+        loginPage.login("test-user@localhost", "password");
+        Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
+
+        loginEvent = events.expectLogin().detail(Details.USERNAME, "test-user@localhost").assertEvent();
+        idToken = sendTokenRequestAndGetIDToken(loginEvent);
+        int authTimeUpdated = idToken.getAuthTime();
+
+        // Assert that authTime was updated
+        Assert.assertTrue(authTime + 10 <= authTimeUpdated);
+
+    }
+
+    // DISPLAY & OTHERS
+
+    @Test
+    public void nonSupportedParams() {
+        driver.navigate().to(oauth.getLoginFormUrl() + "&display=popup&foo=foobar&claims_locales=fr");
+
+        loginPage.assertCurrent();
+        loginPage.login("test-user@localhost", "password");
+        Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
+
+        EventRepresentation loginEvent = events.expectLogin().detail(Details.USERNAME, "test-user@localhost").assertEvent();
+        IDToken idToken = sendTokenRequestAndGetIDToken(loginEvent);
+
+        Assert.assertNotNull(idToken);
+    }
+
+    // REQUEST & REQUEST_URI
+
+    @Test
+    public void requestParam() {
+        driver.navigate().to(oauth.getLoginFormUrl() + "&request=abc");
+
+        assertFalse(loginPage.isCurrent());
+        assertTrue(appPage.isCurrent());
+
+        // Assert error response was sent because not logged in
+        OAuthClient.AuthorizationEndpointResponse resp = new OAuthClient.AuthorizationEndpointResponse(oauth);
+        Assert.assertNull(resp.getCode());
+        Assert.assertEquals(OAuthErrorException.REQUEST_NOT_SUPPORTED, resp.getError());
+    }
+
+    @Test
+    public void requestUriParam() {
+        driver.navigate().to(oauth.getLoginFormUrl() + "&request_uri=https%3A%2F%2Flocalhost%3A60784%2Fexport%2FqzHTG11W48.jwt");
+
+        assertFalse(loginPage.isCurrent());
+        assertTrue(appPage.isCurrent());
+
+        // Assert error response was sent because not logged in
+        OAuthClient.AuthorizationEndpointResponse resp = new OAuthClient.AuthorizationEndpointResponse(oauth);
+        Assert.assertNull(resp.getCode());
+        Assert.assertEquals(OAuthErrorException.REQUEST_URI_NOT_SUPPORTED, resp.getError());
+    }
+
+    // LOGIN_HINT
+
+    @Test
+    public void loginHint() {
+        // Assert need to re-authenticate with prompt=login
+        driver.navigate().to(oauth.getLoginFormUrl() + "&" + OIDCLoginProtocol.LOGIN_HINT_PARAM + "=test-user%40localhost");
+
+                loginPage.assertCurrent();
+        Assert.assertEquals("test-user@localhost", loginPage.getUsername());
+        loginPage.login("password");
+        Assert.assertEquals(AppPage.RequestType.AUTH_RESPONSE, appPage.getRequestType());
+
+        events.expectLogin().detail(Details.USERNAME, "test-user@localhost").assertEvent();
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCWellKnownProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCWellKnownProviderTest.java
new file mode 100644
index 0000000..ab5c230
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/OIDCWellKnownProviderTest.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.oidc;
+
+import java.net.URI;
+import java.util.List;
+
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.keycloak.OAuth2Constants;
+import org.keycloak.jose.jws.Algorithm;
+import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
+import org.keycloak.protocol.oidc.OIDCWellKnownProviderFactory;
+import org.keycloak.protocol.oidc.representations.OIDCConfigurationRepresentation;
+import org.keycloak.protocol.oidc.utils.OIDCResponseType;
+import org.keycloak.representations.IDToken;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.services.resources.RealmsResource;
+import org.keycloak.testsuite.AbstractKeycloakTest;
+import org.keycloak.testsuite.Assert;
+import org.keycloak.testsuite.admin.AbstractAdminTest;
+import org.keycloak.testsuite.util.ClientManager;
+import org.keycloak.testsuite.util.OAuthClient;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class OIDCWellKnownProviderTest extends AbstractKeycloakTest {
+
+    @Override
+    public void addTestRealms(List<RealmRepresentation> testRealms) {
+        RealmRepresentation realm = AbstractAdminTest.loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class);
+        testRealms.add(realm);
+    }
+
+    @Before
+    public void clientConfiguration() {
+        ClientManager.realm(adminClient.realm("test")).clientId("test-app").directAccessGrant(true);
+        /*
+         * Configure the default client ID. Seems like OAuthClient is keeping the state of clientID
+         * For example: If some test case configure oauth.clientId("sample-public-client"), other tests
+         * will faile and the clientID will always be "sample-public-client
+         * @see AccessTokenTest#testAuthorizationNegotiateHeaderIgnored()
+         */
+        oauth.clientId("test-app");
+    }
+
+
+    @Test
+    public void testDiscovery() {
+        Client client = ClientBuilder.newClient();
+        try {
+            OIDCConfigurationRepresentation oidcConfig = getOIDCDiscoveryConfiguration(client);
+
+            // URIs are filled
+            Assert.assertEquals(oidcConfig.getAuthorizationEndpoint(), OIDCLoginProtocolService.authUrl(UriBuilder.fromUri(OAuthClient.AUTH_SERVER_ROOT)).build("test").toString());
+            Assert.assertEquals(oidcConfig.getTokenEndpoint(), oauth.getAccessTokenUrl());
+            Assert.assertEquals(oidcConfig.getUserinfoEndpoint(), OIDCLoginProtocolService.userInfoUrl(UriBuilder.fromUri(OAuthClient.AUTH_SERVER_ROOT)).build("test").toString());
+            Assert.assertEquals(oidcConfig.getJwksUri(), oauth.getCertsUrl("test"));
+
+            // Support standard + implicit + hybrid flow
+            assertContains(oidcConfig.getResponseTypesSupported(), OAuth2Constants.CODE, OIDCResponseType.ID_TOKEN, "id_token token", "code id_token", "code token", "code id_token token");
+            assertContains(oidcConfig.getGrantTypesSupported(), OAuth2Constants.AUTHORIZATION_CODE, OAuth2Constants.IMPLICIT);
+            assertContains(oidcConfig.getResponseModesSupported(), "query", "fragment");
+
+            Assert.assertNames(oidcConfig.getSubjectTypesSupported(), "public");
+            Assert.assertNames(oidcConfig.getIdTokenSigningAlgValuesSupported(), Algorithm.RS256.toString());
+
+            // Client authentication
+            Assert.assertNames(oidcConfig.getTokenEndpointAuthMethodsSupported(), "client_secret_basic", "client_secret_post", "private_key_jwt");
+            Assert.assertNames(oidcConfig.getTokenEndpointAuthSigningAlgValuesSupported(), Algorithm.RS256.toString());
+
+            // Claims
+            assertContains(oidcConfig.getClaimsSupported(), IDToken.NAME, IDToken.EMAIL, IDToken.PREFERRED_USERNAME, IDToken.FAMILY_NAME);
+            Assert.assertNames(oidcConfig.getClaimTypesSupported(), "normal");
+            Assert.assertFalse(oidcConfig.getClaimsParameterSupported());
+
+            // Scopes supported
+            Assert.assertNames(oidcConfig.getScopesSupported(), OAuth2Constants.SCOPE_OPENID, OAuth2Constants.OFFLINE_ACCESS);
+
+            // Request and Request_Uri
+            Assert.assertFalse(oidcConfig.getRequestParameterSupported());
+            Assert.assertFalse(oidcConfig.getRequestUriParameterSupported());
+        } finally {
+            client.close();
+        }
+    }
+
+    @Test
+    public void testIssuerMatches() throws Exception {
+        OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest("password", "test-user@localhost", "password");
+        Assert.assertEquals(200, response.getStatusCode());
+        IDToken idToken = oauth.verifyIDToken(response.getIdToken());
+
+        Client client = ClientBuilder.newClient();
+        try {
+            OIDCConfigurationRepresentation oidcConfig = getOIDCDiscoveryConfiguration(client);
+
+            // assert issuer matches
+            Assert.assertEquals(idToken.getIssuer(), oidcConfig.getIssuer());
+        } finally {
+            client.close();
+        }
+    }
+
+    private OIDCConfigurationRepresentation getOIDCDiscoveryConfiguration(Client client) {
+        UriBuilder builder = UriBuilder.fromUri(OAuthClient.AUTH_SERVER_ROOT);
+        URI oidcDiscoveryUri = RealmsResource.wellKnownProviderUrl(builder).build("test", OIDCWellKnownProviderFactory.PROVIDER_ID);
+        WebTarget oidcDiscoveryTarget = client.target(oidcDiscoveryUri);
+
+        Response response = oidcDiscoveryTarget.request().get();
+        return response.readEntity(OIDCConfigurationRepresentation.class);
+    }
+
+    private void assertContains(List<String> actual, String... expected) {
+        for (String exp : expected) {
+            Assert.assertTrue(actual.contains(exp));
+        }
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
index 15cff20..268333f 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oidc/UserInfoTest.java
@@ -16,10 +16,14 @@
  */
 package org.keycloak.testsuite.oidc;
 
+import org.hamcrest.Matchers;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.keycloak.OAuth2Constants;
+import org.keycloak.events.Details;
+import org.keycloak.events.Errors;
+import org.keycloak.events.EventType;
 import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
 import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.representations.UserInfo;
@@ -28,6 +32,7 @@ import org.keycloak.testsuite.AbstractKeycloakTest;
 import org.keycloak.testsuite.AssertEvents;
 import org.keycloak.testsuite.util.ClientManager;
 import org.keycloak.testsuite.util.RealmBuilder;
+import org.keycloak.testsuite.util.UserInfoClientUtil;
 import org.keycloak.util.BasicAuthHelper;
 
 import javax.ws.rs.client.Client;
@@ -43,7 +48,6 @@ import java.net.URI;
 import java.util.List;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
 import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
 import static org.keycloak.testsuite.util.OAuthClient.AUTH_SERVER_ROOT;
 
@@ -75,57 +79,136 @@ public class UserInfoTest extends AbstractKeycloakTest {
     }
 
     @Test
-    public void testSuccessfulUserInfoRequest() throws Exception {
+    public void testSuccess_getMethod_header() throws Exception {
         Client client = ClientBuilder.newClient();
-        UriBuilder builder = UriBuilder.fromUri(AUTH_SERVER_ROOT);
-        URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
-        WebTarget grantTarget = client.target(grantUri);
-        AccessTokenResponse accessTokenResponse = executeGrantAccessTokenRequest(grantTarget);
-        Response response = executeUserInfoRequest(accessTokenResponse.getToken());
 
-        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+        try {
+            AccessTokenResponse accessTokenResponse = executeGrantAccessTokenRequest(client);
+            Response response = UserInfoClientUtil.executeUserInfoRequest_getMethod(client, accessTokenResponse.getToken());
 
-        UserInfo userInfo = response.readEntity(UserInfo.class);
+            testSuccessfulUserInfoResponse(response);
 
-        response.close();
+        } finally {
+            client.close();
+        }
+    }
+
+    @Test
+    public void testSuccess_postMethod_header() throws Exception {
+        Client client = ClientBuilder.newClient();
+
+        try {
+            AccessTokenResponse accessTokenResponse = executeGrantAccessTokenRequest(client);
+
+            WebTarget userInfoTarget = UserInfoClientUtil.getUserInfoWebTarget(client);
+            Response response = userInfoTarget.request()
+                    .header(HttpHeaders.AUTHORIZATION, "bearer " + accessTokenResponse.getToken())
+                    .post(Entity.form(new Form()));
+
+            testSuccessfulUserInfoResponse(response);
+
+        } finally {
+            client.close();
+        }
+    }
+
+    @Test
+    public void testSuccess_postMethod_body() throws Exception {
+        Client client = ClientBuilder.newClient();
+
+        try {
+            AccessTokenResponse accessTokenResponse = executeGrantAccessTokenRequest(client);
+
+            Form form = new Form();
+            form.param("access_token", accessTokenResponse.getToken());
+
+            WebTarget userInfoTarget = UserInfoClientUtil.getUserInfoWebTarget(client);
+            Response response = userInfoTarget.request()
+                    .post(Entity.form(form));
+
+            testSuccessfulUserInfoResponse(response);
+
+        } finally {
+            client.close();
+        }
+    }
+
+    @Test
+    public void testSuccess_postMethod_header_textEntity() throws Exception {
+        Client client = ClientBuilder.newClient();
+
+        try {
+            AccessTokenResponse accessTokenResponse = executeGrantAccessTokenRequest(client);
 
-        assertNotNull(userInfo);
-        assertNotNull(userInfo.getSubject());
-        assertEquals("test-user@localhost", userInfo.getEmail());
-        assertEquals("test-user@localhost", userInfo.getPreferredUsername());
+            WebTarget userInfoTarget = UserInfoClientUtil.getUserInfoWebTarget(client);
+            Response response = userInfoTarget.request()
+                    .header(HttpHeaders.AUTHORIZATION, "bearer " + accessTokenResponse.getToken())
+                    .post(Entity.text(""));
 
-        client.close();
+            testSuccessfulUserInfoResponse(response);
+
+        } finally {
+            client.close();
+        }
     }
 
     @Test
     public void testSessionExpired() throws Exception {
         Client client = ClientBuilder.newClient();
-        UriBuilder builder = UriBuilder.fromUri(AUTH_SERVER_ROOT);
-        URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
-        WebTarget grantTarget = client.target(grantUri);
-        AccessTokenResponse accessTokenResponse = executeGrantAccessTokenRequest(grantTarget);
 
-        testingClient.testing().removeUserSessions("test");
+        try {
+            AccessTokenResponse accessTokenResponse = executeGrantAccessTokenRequest(client);
 
-        Response response = executeUserInfoRequest(accessTokenResponse.getToken());
+            testingClient.testing().removeUserSessions("test");
 
-        assertEquals(Status.FORBIDDEN.getStatusCode(), response.getStatus());
+            Response response = UserInfoClientUtil.executeUserInfoRequest_getMethod(client, accessTokenResponse.getToken());
 
-        response.close();
+            assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
+
+            response.close();
 
-        client.close();
+            events.expect(EventType.USER_INFO_REQUEST_ERROR)
+                    .error(Errors.USER_SESSION_NOT_FOUND)
+                    .client((String) null)
+                    .user(Matchers.nullValue(String.class))
+                    .session(Matchers.nullValue(String.class))
+                    .detail(Details.AUTH_METHOD, Details.VALIDATE_ACCESS_TOKEN)
+                    .assertEvent();
+
+        } finally {
+            client.close();
+        }
     }
 
     @Test
     public void testUnsuccessfulUserInfoRequest() throws Exception {
-        Response response = executeUserInfoRequest("bad");
+        Client client = ClientBuilder.newClient();
 
-        response.close();
+        try {
+            Response response = UserInfoClientUtil.executeUserInfoRequest_getMethod(client, "bad");
 
-        assertEquals(Status.FORBIDDEN.getStatusCode(), response.getStatus());
+            response.close();
+
+            assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
+
+            events.expect(EventType.USER_INFO_REQUEST_ERROR)
+                    .error(Errors.INVALID_TOKEN)
+                    .client((String) null)
+                    .user(Matchers.nullValue(String.class))
+                    .session(Matchers.nullValue(String.class))
+                    .detail(Details.AUTH_METHOD, Details.VALIDATE_ACCESS_TOKEN)
+                    .assertEvent();
+
+        } finally {
+            client.close();
+        }
     }
 
-    private AccessTokenResponse executeGrantAccessTokenRequest(WebTarget grantTarget) {
+    private AccessTokenResponse executeGrantAccessTokenRequest(Client client) {
+        UriBuilder builder = UriBuilder.fromUri(AUTH_SERVER_ROOT);
+        URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test");
+        WebTarget grantTarget = client.target(grantUri);
+
         String header = BasicAuthHelper.createHeader("test-app", "password");
         Form form = new Form();
         form.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD)
@@ -142,18 +225,17 @@ public class UserInfoTest extends AbstractKeycloakTest {
 
         response.close();
 
+        events.clear();
+
         return accessTokenResponse;
     }
 
-    private Response executeUserInfoRequest(String accessToken) {
-        UriBuilder builder = UriBuilder.fromUri(AUTH_SERVER_ROOT);
-        UriBuilder uriBuilder = OIDCLoginProtocolService.tokenServiceBaseUrl(builder);
-        URI userInfoUri = uriBuilder.path(OIDCLoginProtocolService.class, "issueUserInfo").build("test");
-        Client client = ClientBuilder.newClient();
-        WebTarget userInfoTarget = client.target(userInfoUri);
-
-        return userInfoTarget.request()
-                .header(HttpHeaders.AUTHORIZATION, "bearer " + accessToken)
-                .get();
+    private void testSuccessfulUserInfoResponse(Response response) {
+        events.expect(EventType.USER_INFO_REQUEST)
+                .session(Matchers.notNullValue(String.class))
+                .detail(Details.AUTH_METHOD, Details.VALIDATE_ACCESS_TOKEN)
+                .detail(Details.USERNAME, "test-user@localhost")
+                .assertEvent();
+        UserInfoClientUtil.testSuccessfulUserInfoResponse(response, "test-user@localhost", "test-user@localhost");
     }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/TestRealmKeycloakTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/TestRealmKeycloakTest.java
index 0e41cee..040bb4c 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/TestRealmKeycloakTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/TestRealmKeycloakTest.java
@@ -17,39 +17,30 @@
 
 package org.keycloak.testsuite;
 
+import org.keycloak.OAuth2Constants;
+import org.keycloak.common.util.reflections.Reflections;
+import org.keycloak.events.Details;
+import org.keycloak.representations.IDToken;
 import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.EventRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 
+import java.lang.reflect.Field;
 import java.util.List;
 import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.testsuite.util.OAuthClient;
 
 import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
 
 /**
  * This class provides loading of the testRealm called "test".  It also
- * provides an OAuthClient for the testRealm.
+ * provides a few utility methods for the testRealm.
  *
  * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
  */
 public abstract class TestRealmKeycloakTest extends AbstractKeycloakTest {
 
-    protected UserRepresentation findUserInRealmRep(RealmRepresentation testRealm, String userName) {
-        for (UserRepresentation user : testRealm.getUsers()) {
-            if (user.getUsername().equals(userName)) return user;
-        }
-
-        return null;
-    }
-
-    protected ClientRepresentation findClientInRealmRep(RealmRepresentation testRealm, String clientId) {
-        for (ClientRepresentation client : testRealm.getClients()) {
-            if (client.getClientId().equals(clientId)) return client;
-        }
-
-        return null;
-    }
-
     protected RealmResource testRealm() {
         return adminClient.realm("test");
     }
@@ -90,4 +81,23 @@ public abstract class TestRealmKeycloakTest extends AbstractKeycloakTest {
      */
     public abstract void configureTestRealm(RealmRepresentation testRealm);
 
+
+    protected IDToken sendTokenRequestAndGetIDToken(EventRepresentation loginEvent) {
+        String sessionId = loginEvent.getSessionId();
+        String codeId = loginEvent.getDetails().get(Details.CODE_ID);
+
+        String code = new OAuthClient.AuthorizationEndpointResponse(oauth).getCode();
+        OAuthClient.AccessTokenResponse response = oauth.doAccessTokenRequest(code, "password");
+
+        Assert.assertEquals(200, response.getStatusCode());
+        IDToken idToken = oauth.verifyIDToken(response.getIdToken());
+
+        Field eventsField = Reflections.findDeclaredField(this.getClass(), "events");
+        if (eventsField != null) {
+            AssertEvents events = Reflections.getFieldValue(eventsField, this, AssertEvents.class);
+            events.expectCodeToToken(codeId, sessionId).assertEvent();
+        }
+        return idToken;
+    }
+
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AdminEventPaths.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AdminEventPaths.java
index dddc621..eddd171 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AdminEventPaths.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AdminEventPaths.java
@@ -317,6 +317,15 @@ public class AdminEventPaths {
         return uri.toString();
     }
 
+    // CLIENT REGISTRATION TRUSTED HOSTS
+
+    public static String clientRegistrationTrustedHostPath(String hostName) {
+        URI uri = UriBuilder.fromUri("").path(RealmResource.class, "clientRegistrationTrustedHost")
+                .path(ClientInitialAccessResource.class, "delete")
+                .build(hostName);
+        return uri.toString();
+    }
+
     // GROUPS
 
     public static String groupsPath() {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AssertAdminEvents.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AssertAdminEvents.java
index 58f8e9a..c50c022 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AssertAdminEvents.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/AssertAdminEvents.java
@@ -38,6 +38,7 @@ import org.junit.runners.model.Statement;
 import org.keycloak.common.util.ObjectUtil;
 import org.keycloak.common.util.reflections.Reflections;
 import org.keycloak.events.admin.OperationType;
+import org.keycloak.events.admin.ResourceType;
 import org.keycloak.jose.jws.JWSInput;
 import org.keycloak.jose.jws.JWSInputException;
 import org.keycloak.representations.AccessToken;
@@ -106,22 +107,23 @@ public class AssertAdminEvents implements TestRule {
 
 
 
-    public AdminEventRepresentation assertEvent(String realmId, OperationType operationType, String resourcePath) {
-        return assertEvent(realmId, operationType, resourcePath, null);
+    public AdminEventRepresentation assertEvent(String realmId, OperationType operationType, String resourcePath, ResourceType resourceType) {
+        return assertEvent(realmId, operationType, resourcePath, null, resourceType);
     }
 
-    public AdminEventRepresentation assertEvent(String realmId, OperationType operationType, Matcher<String> resourcePath) {
-        return assertEvent(realmId, operationType, resourcePath, null);
+    public AdminEventRepresentation assertEvent(String realmId, OperationType operationType, Matcher<String> resourcePath, ResourceType resourceType) {
+        return assertEvent(realmId, operationType, resourcePath, null, resourceType);
     }
 
-    public AdminEventRepresentation assertEvent(String realmId, OperationType operationType, String resourcePath, Object representation) {
-        return assertEvent(realmId, operationType, Matchers.equalTo(resourcePath), representation);
+    public AdminEventRepresentation assertEvent(String realmId, OperationType operationType, String resourcePath, Object representation, ResourceType resourceType) {
+        return assertEvent(realmId, operationType, Matchers.equalTo(resourcePath), representation, resourceType);
     }
 
-    public AdminEventRepresentation assertEvent(String realmId, OperationType operationType, Matcher<String> resourcePath, Object representation) {
+    public AdminEventRepresentation assertEvent(String realmId, OperationType operationType, Matcher<String> resourcePath, Object representation, ResourceType resourceType) {
         return expect().realmId(realmId)
                 .operationType(operationType)
                 .resourcePath(resourcePath)
+                .resourceType(resourceType)
                 .representation(representation)
                 .assertEvent();
     }
@@ -132,6 +134,7 @@ public class AssertAdminEvents implements TestRule {
 
         private AdminEventRepresentation expected = new AdminEventRepresentation();
         private Matcher<String> resourcePath;
+        private ResourceType resourceType;
         private Object expectedRep;
 
         public ExpectedAdminEvent realmId(String realmId) {
@@ -158,6 +161,11 @@ public class AssertAdminEvents implements TestRule {
             return this;
         }
 
+        public ExpectedAdminEvent resourceType(ResourceType resourceType){
+            expected.setResourceType(resourceType.toString());
+            return this;
+        }
+
         public ExpectedAdminEvent error(String error) {
             expected.setError(error);
             updateOperationTypeIfError();
@@ -191,6 +199,7 @@ public class AssertAdminEvents implements TestRule {
         public AdminEventRepresentation assertEvent(AdminEventRepresentation actual) {
             Assert.assertEquals(expected.getRealmId(), actual.getRealmId());
             Assert.assertThat(actual.getResourcePath(), resourcePath);
+            Assert.assertEquals(expected.getResourceType(), actual.getResourceType());
             Assert.assertEquals(expected.getOperationType(), actual.getOperationType());
 
             Assert.assertTrue(ObjectUtil.isEqualOrBothNull(expected.getError(), actual.getError()));
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientManager.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientManager.java
index 6702ec5..6bc7151 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientManager.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/ClientManager.java
@@ -67,6 +67,20 @@ public class ClientManager {
             clientResource.update(app);
         }
 
+        public ClientManagerBuilder standardFlow(Boolean enable) {
+            ClientRepresentation app = clientResource.toRepresentation();
+            app.setStandardFlowEnabled(enable);
+            clientResource.update(app);
+            return this;
+        }
+
+        public ClientManagerBuilder implicitFlow(Boolean enable) {
+            ClientRepresentation app = clientResource.toRepresentation();
+            app.setImplicitFlowEnabled(enable);
+            clientResource.update(app);
+            return this;
+        }
+
         public void fullScopeAllowed(boolean enable) {
             ClientRepresentation app = clientResource.toRepresentation();
             app.setFullScopeAllowed(enable);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailAssert.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailAssert.java
index 93ae0cc..ac90ea8 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailAssert.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/MailAssert.java
@@ -30,11 +30,15 @@ public class MailAssert {
 
     private static final Logger log = Logger.getLogger(MailAssert.class);
     
-    public static String assertEmailAndGetUrl(String from, String recipient, String content) {
+    public static String assertEmailAndGetUrl(String from, String recipient, String content, Boolean sslEnabled) {
 
         try {
-            MimeMessage message = MailServer.getLastReceivedMessage();
-            assertNotNull("There is no received email.", message);
+            MimeMessage message;
+            if (sslEnabled){
+                message= SslMailServer.getLastReceivedMessage();
+            } else {
+                message = MailServer.getLastReceivedMessage();
+            }            assertNotNull("There is no received email.", message);
             assertEquals(recipient, message.getRecipients(RecipientType.TO)[0].toString());
             assertEquals(from, message.getFrom()[0].toString());
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/RealmBuilder.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/RealmBuilder.java
index b01ba5e..3653065 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/RealmBuilder.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/RealmBuilder.java
@@ -17,6 +17,7 @@
 
 package org.keycloak.testsuite.util;
 
+import java.util.Collections;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
@@ -66,12 +67,18 @@ public class RealmBuilder {
     public RealmBuilder roles(RolesBuilder roles) {
         return roles(roles.build());
     }
-    
+
     public RealmBuilder roles(RolesRepresentation roles) {
         rep.setRoles(roles);
         return this;
     }
 
+    public RealmBuilder events() {
+        rep.setEventsEnabled(true);
+        rep.setEnabledEventTypes(Collections.<String>emptyList()); // enables all types
+        return this;
+    }
+
     public RealmBuilder testMail() {
         Map<String, String> config = new HashMap<>();
         config.put("from", MailServerConfiguration.FROM);
@@ -125,11 +132,26 @@ public class RealmBuilder {
         return this;
     }
 
+    public RealmBuilder notBefore(int i) {
+        rep.setNotBefore(i);
+        return this;
+    }
+
     public RealmBuilder otpLookAheadWindow(int i) {
         rep.setOtpPolicyLookAheadWindow(i);
         return this;
     }
 
+    public RealmBuilder bruteForceProtected(boolean bruteForceProtected) {
+        rep.setBruteForceProtected(bruteForceProtected);
+        return this;
+    }
+
+    public RealmBuilder failureFactor(int failureFactor) {
+        rep.setFailureFactor(failureFactor);
+        return this;
+    }
+
     public RealmBuilder otpDigits(int i) {
         rep.setOtpPolicyDigits(i);
         return this;
@@ -155,6 +177,11 @@ public class RealmBuilder {
         return this;
     }
 
+    public RealmBuilder passwordPolicy(String passwordPolicy) {
+        rep.setPasswordPolicy(passwordPolicy);
+        return this;
+    }
+
     public RealmRepresentation build() {
         return rep;
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/RealmRepUtil.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/RealmRepUtil.java
new file mode 100644
index 0000000..7d5b0c0
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/RealmRepUtil.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2016 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @author tags. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.keycloak.testsuite.util;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.keycloak.representations.idm.ClientRepresentation;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+
+/**
+ *
+ * @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
+ */
+public class RealmRepUtil {
+
+    // don't allow instance
+    private RealmRepUtil() {
+    }
+
+    public static UserRepresentation findUser(RealmRepresentation testRealm, String userName) {
+        for (UserRepresentation user : testRealm.getUsers()) {
+            if (user.getUsername().equals(userName)) return user;
+        }
+
+        return null;
+    }
+
+    public static ClientRepresentation findClientByClientId(RealmRepresentation testRealm, String clientId) {
+        for (ClientRepresentation client : testRealm.getClients()) {
+            if (client.getClientId().equals(clientId)) return client;
+        }
+
+        return null;
+    }
+
+    public static ClientRepresentation findClientById(RealmRepresentation testRealm, String id) {
+        for (ClientRepresentation client : testRealm.getClients()) {
+            if (client.getId().equals(id)) return client;
+        }
+        return null;
+    }
+
+    public static RoleRepresentation findRealmRole(RealmRepresentation realm, String roleName) {
+        if (realm.getRoles() == null) return null;
+        if (realm.getRoles().getRealm() == null) return null;
+        for (RoleRepresentation role : realm.getRoles().getRealm()) {
+            if (role.getName().equals(roleName)) return role;
+        }
+
+        return null;
+    }
+
+    public static RoleRepresentation findClientRole(RealmRepresentation realm, String clientId, String roleName) {
+        if (realm.getRoles() == null) return null;
+        if (realm.getRoles().getClient() == null) return null;
+        if (realm.getRoles().getClient().get(clientId) == null) return null;
+        for (RoleRepresentation role : realm.getRoles().getClient().get(clientId)) {
+            if (roleName.equals(role.getName())) return role;
+        }
+
+        return null;
+    }
+
+    public static String findDefaultRole(RealmRepresentation realm, String roleName) {
+        if (realm.getDefaultRoles() == null) return null;
+        for (String role : realm.getDefaultRoles()) {
+            if (role.equals(roleName)) return role;
+        }
+
+        return null;
+    }
+
+    public static Set<RoleRepresentation> allRoles(RealmRepresentation realm, UserRepresentation user) {
+        Set<RoleRepresentation> allRoles = new HashSet<>();
+        for (String roleName : user.getRealmRoles()) {
+            allRoles.add(findRealmRole(realm, roleName));
+        }
+
+        for (String clientId : user.getClientRoles().keySet()) {
+            for (String roleName : user.getClientRoles().get(clientId)) {
+                allRoles.add(findClientRole(realm, clientId, roleName));
+            }
+        }
+
+        return allRoles;
+    }
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/SslMailServer.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/SslMailServer.java
new file mode 100644
index 0000000..0088e42
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/SslMailServer.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.testsuite.util;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.*;
+import java.security.*;
+import java.security.cert.CertificateException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.mail.internet.MimeMessage;
+import javax.net.ssl.*;
+
+import org.jboss.logging.Logger;
+import org.subethamail.smtp.server.SMTPServer;
+
+import static org.keycloak.testsuite.util.MailServerConfiguration.*;
+import static org.keycloak.testsuite.util.MailServerConfiguration.PORT_SSL;
+import static org.keycloak.testsuite.util.MailServerConfiguration.STARTTLS;
+
+public class SslMailServer {
+
+    private static final Logger log = Logger.getLogger(MailServer.class);
+
+    public static final String PRIVATE_KEY = "keystore/keycloak.jks";
+
+    public static final String TRUSTED_CERTIFICATE = "keystore/keycloak.truststore";
+
+    //private key tested with invalid certificate
+    public static final String INVALID_KEY = "keystore/email_invalid.jks";
+
+    private static MessageHandlerFactoryImpl messageHandlerFactory = new MessageHandlerFactoryImpl();
+
+    private static SMTPServer smtpServer;
+
+    private static Map<String, String> serverConfiguration = new HashMap<>();
+
+
+    public static void start() {
+        smtpServer = new SMTPServer(messageHandlerFactory);
+        smtpServer.setHostName(HOST);
+        smtpServer.setPort(Integer.parseInt(PORT));
+        smtpServer.start();
+
+        log.info("Started mail server (" + smtpServer.getHostName() + ":" + smtpServer.getPort() + ")");
+    }
+
+    public static void stop() {
+        if (smtpServer != null) {
+            log.info("Stopping mail server (" + smtpServer.getHostName() + ":" + smtpServer.getPort() + ")");
+            // Suppress error from SubEthaSmtp on shutdown
+            Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
+                @Override
+                public void uncaughtException(Thread t, Throwable e) {
+                    if (!(e.getCause() instanceof SocketException && e.getStackTrace()[0].getClassName()
+                            .equals("org.subethamail.smtp.server.Session"))) {
+                        log.error("Exception in thread \"" + t.getName() + "\" ");
+                        log.error(e.getMessage(), e);
+                    }
+                }
+            });
+            smtpServer.stop();
+        }
+    }
+
+    public static void startWithSsl(String privateKey){
+        InputStream keyStoreIS = null;
+        try {
+            keyStoreIS = new FileInputStream(privateKey);
+            char[] keyStorePassphrase = "secret".toCharArray();
+            KeyStore ksKeys = null;
+            ksKeys = KeyStore.getInstance("JKS");
+            ksKeys.load(keyStoreIS, keyStorePassphrase);
+
+            // KeyManager decides which key material to use.
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+            kmf.init(ksKeys, keyStorePassphrase);
+
+            // Trust store for client authentication.
+            InputStream trustStoreIS = new FileInputStream(String.valueOf(MailServer.class.getClassLoader().getResource(TRUSTED_CERTIFICATE).getFile()));
+            char[] trustStorePassphrase = "secret".toCharArray();
+            KeyStore ksTrust = KeyStore.getInstance("JKS");
+            ksTrust.load(trustStoreIS, trustStorePassphrase);
+
+            // TrustManager decides which certificate authorities to use.
+            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+            tmf.init(ksTrust);
+
+            final SSLContext sslContext = SSLContext.getInstance("TLS");
+            sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+            smtpServer = new SMTPServer(messageHandlerFactory) {
+                @Override
+                public SSLSocket createSSLSocket(Socket socket) throws IOException {
+                    InetSocketAddress remoteAddress =
+                            (InetSocketAddress) socket.getRemoteSocketAddress();
+                    SSLSocketFactory sf = sslContext.getSocketFactory();
+                    SSLSocket s = (SSLSocket) (sf.createSocket(
+                            socket, remoteAddress.getHostName(), socket.getPort(), true));
+
+                    // we are a server
+                    s.setUseClientMode(false);
+
+                    // select protocols and cipher suites
+                    s.setEnabledProtocols(s.getSupportedProtocols());
+                    s.setEnabledCipherSuites(s.getSupportedCipherSuites());
+                    return s;
+                }
+            };
+        } catch (KeyStoreException | IOException | NoSuchAlgorithmException | UnrecoverableKeyException | KeyManagementException | CertificateException e) {
+            throw new RuntimeException(e);
+        }
+
+        smtpServer.setHostName(HOST);
+        smtpServer.setPort(Integer.parseInt(PORT_SSL));
+        smtpServer.setEnableTLS(true);
+        smtpServer.start();
+
+        log.info("Started mail server (" + smtpServer.getHostName() + ":" + smtpServer.getPort() + ")");
+    }
+
+    public static Map<String, String> getServerConfiguration() {
+        serverConfiguration.put("from", FROM);
+        serverConfiguration.put("host", HOST);
+        serverConfiguration.put("port", PORT_SSL);
+        serverConfiguration.put("starttls", STARTTLS);
+        return serverConfiguration;
+    }
+
+    public static MimeMessage getLastReceivedMessage() throws InterruptedException {
+        return messageHandlerFactory.getMessage();
+    }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/URLAssert.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/URLAssert.java
index 6ef0bbe..573a334 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/URLAssert.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/util/URLAssert.java
@@ -17,8 +17,6 @@
 
 package org.keycloak.testsuite.util;
 
-import javax.ws.rs.core.UriBuilder;
-
 import org.apache.http.Header;
 import org.apache.http.HttpEntity;
 import org.apache.http.client.methods.CloseableHttpResponse;
@@ -27,12 +25,12 @@ import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
 import org.junit.Assert;
 import org.keycloak.testsuite.page.AbstractPage;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import org.keycloak.testsuite.auth.page.login.PageWithLoginUrl;
 import org.openqa.selenium.WebDriver;
 
+import static org.keycloak.testsuite.util.URLUtils.*;
+
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.Reader;
@@ -51,16 +49,9 @@ public class URLAssert {
     }
 
     public static void assertCurrentUrlEquals(WebDriver driver, final AbstractPage page) {
-//        WebDriverWait wait = new WebDriverWait(driver, 1);
-//        ExpectedCondition<Boolean> urlStartsWith = new ExpectedCondition<Boolean>() {
-//
-//            @Override
-//            public Boolean apply(WebDriver wd) {
-//                return startsWithNormalized(wd.getCurrentUrl(), page.toString());
-//            }
-//        };
-//        wait.until(urlStartsWith);
-        assertEqualsNormalized(page.toString(), driver.getCurrentUrl());
+        String expected = page.toString();
+        assertTrue("Expected URL: " + expected + "; actual: " + driver.getCurrentUrl(),
+                currentUrlEqual(driver, page.toString()));
     }
 
     public static void assertCurrentUrlStartsWith(AbstractPage page) {
@@ -68,16 +59,8 @@ public class URLAssert {
     }
 
     public static void assertCurrentUrlStartsWith(WebDriver driver, final String url) {
-//        WebDriverWait wait = new WebDriverWait(driver, 1);
-//        ExpectedCondition<Boolean> urlStartsWith = new ExpectedCondition<Boolean>() {
-//
-//            @Override
-//            public Boolean apply(WebDriver wd) {
-//                return startsWithNormalized(wd.getCurrentUrl(), url);
-//            }
-//        };
-//        wait.until(urlStartsWith);
-        assertTrue("'" + driver.getCurrentUrl() + " does not start with '" + url + "'", startsWithNormalized(driver.getCurrentUrl(), url));
+        assertTrue("URL expected to begin with:" + url + "; actual URL: " + driver.getCurrentUrl(),
+                currentUrlStartWith(driver, url));
     }
 
     public static void assertCurrentUrlDoesntStartWith(AbstractPage page) {
@@ -85,35 +68,10 @@ public class URLAssert {
     }
 
     public static void assertCurrentUrlDoesntStartWith(WebDriver driver, final String url) {
-//        WebDriverWait wait = new WebDriverWait(driver, 1, 250);
-//        ExpectedCondition<Boolean> urlDoesntStartWith = new ExpectedCondition<Boolean>() {
-//
-//            @Override
-//            public Boolean apply(WebDriver wd) {
-//                return !startsWithNormalized(wd.getCurrentUrl(), url);
-//            }
-//        };
-//        wait.until(urlDoesntStartWith);
-        assertFalse(startsWithNormalized(driver.getCurrentUrl(), url));
-    }
-
-    // this normalization is needed because of slash-encoding in uri fragment (the part after #)
-    public static String normalizeUri(String uri) {
-        return UriBuilder.fromUri(uri).build().toASCIIString();
-    }
-
-    public static boolean startsWithNormalized(String str1, String str2) {
-        String uri1 = normalizeUri(str1);
-        String uri2 = normalizeUri(str2);
-        return uri1.startsWith(uri2);
-    }
-
-    public static void assertEqualsNormalized(String str1, String str2) {
-        assertEquals(normalizeUri(str1), normalizeUri(str2));
+        assertTrue("URL expected NOT to begin with:" + url + "; actual URL: " + driver.getCurrentUrl(),
+                currentUrlDoesntStartWith(driver, url));
     }
 
-
-
     public static void assertCurrentUrlStartsWithLoginUrlOf(PageWithLoginUrl page) {
         assertCurrentUrlStartsWithLoginUrlOf(page.getDriver(), page);
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/demorealm.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/demorealm.json
index 79d050a..9a4a7f6 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/demorealm.json
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/demorealm.json
@@ -2,7 +2,7 @@
     "id": "demo",
     "realm": "demo",
     "enabled": true,
-    "accessTokenLifespan": 3000,
+    "accessTokenLifespan": 600,
     "accessCodeLifespan": 10,
     "accessCodeLifespanUserAction": 6000,
     "sslRequired": "external",
@@ -209,6 +209,16 @@
             "secret": "password"
         },
         {
+            "clientId": "token-min-ttl",
+            "enabled": true,
+            "adminUrl": "/token-min-ttl",
+            "baseUrl": "/token-min-ttl",
+            "redirectUris": [
+                "/token-min-ttl/*"
+            ],
+            "secret": "password"
+        },
+        {
             "clientId": "third-party",
             "enabled": true,
             "redirectUris": [
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/jboss-deployment-structure.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/jboss-deployment-structure.xml
index 6f4b9c2..6b5322d 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/jboss-deployment-structure.xml
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/jboss-deployment-structure.xml
@@ -27,7 +27,7 @@
             <module name="org.codehaus.jackson.jackson-mapper-asl" />
             <module name="org.bouncycastle" />
             <module name="org.jboss.xnio" />
-            
+
         </dependencies>
     </deployment>
 </jboss-deployment-structure>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/web.xml
index 44aa653..4207f91 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/web.xml
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/keycloak-saml/web.xml
@@ -23,13 +23,8 @@
 
     <module-name>%CONTEXT_PATH%</module-name>
 
-    <servlet>
-        <servlet-name>Servlet</servlet-name>
-        <servlet-class>org.keycloak.testsuite.adapter.servlet.SendUsernameServlet</servlet-class>
-    </servlet>
-
     <servlet-mapping>
-        <servlet-name>Servlet</servlet-name>
+        <servlet-name>javax.ws.rs.core.Application</servlet-name>
         <url-pattern>/*</url-pattern>
     </servlet-mapping>
 
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/offline-client/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/offline-client/WEB-INF/web.xml
index a329f9a..66acbed 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/offline-client/WEB-INF/web.xml
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/offline-client/WEB-INF/web.xml
@@ -23,6 +23,11 @@
 
     <module-name>offline-client</module-name>
 
+    <filter>
+        <filter-name>AdapterActionsFilter</filter-name>
+        <filter-class>org.keycloak.testsuite.adapter.filter.AdapterActionsFilter</filter-class>
+    </filter>
+
     <servlet>
         <servlet-name>Servlet</servlet-name>
         <servlet-class>org.keycloak.testsuite.adapter.servlet.OfflineTokenServlet</servlet-class>
@@ -33,6 +38,11 @@
         <servlet-class>org.keycloak.testsuite.adapter.servlet.ErrorServlet</servlet-class>
     </servlet>
 
+    <filter-mapping>
+        <filter-name>AdapterActionsFilter</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+
     <servlet-mapping>
         <servlet-name>Servlet</servlet-name>
         <url-pattern>/*</url-pattern>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/token-min-ttl/WEB-INF/jetty-web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/token-min-ttl/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..8c59313
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/token-min-ttl/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8180/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/token-min-ttl/WEB-INF/keycloak.json b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/token-min-ttl/WEB-INF/keycloak.json
new file mode 100644
index 0000000..85eb9a7
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/token-min-ttl/WEB-INF/keycloak.json
@@ -0,0 +1,11 @@
+{
+  "realm": "demo",
+  "resource": "token-min-ttl",
+  "realm-public-key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url": "http://localhost:8180/auth",
+  "ssl-required" : "external",
+  "credentials": {
+    "secret": "password"
+  },
+  "token-minimum-time-to-live": 120
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/token-min-ttl/WEB-INF/web.xml b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/token-min-ttl/WEB-INF/web.xml
new file mode 100644
index 0000000..f8110bc
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/adapter-test/token-min-ttl/WEB-INF/web.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+         version="3.0">
+
+    <module-name>token-min-ttl</module-name>
+
+    <filter>
+        <filter-name>AdapterActionsFilter</filter-name>
+        <filter-class>org.keycloak.testsuite.adapter.filter.AdapterActionsFilter</filter-class>
+    </filter>
+
+    <servlet>
+        <servlet-name>Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.servlet.TokenMinTTLServlet</servlet-class>
+    </servlet>
+
+    <servlet>
+        <servlet-name>Error Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.servlet.ErrorServlet</servlet-class>
+    </servlet>
+
+    <filter-mapping>
+        <filter-name>AdapterActionsFilter</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Error Servlet</servlet-name>
+        <url-pattern>/error.html</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Errors</web-resource-name>
+            <url-pattern>/error.html</url-pattern>
+        </web-resource-collection>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>KEYCLOAK</auth-method>
+        <realm-name>test</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/client-auth-test/publickey.pem b/testsuite/integration-arquillian/tests/base/src/test/resources/client-auth-test/publickey.pem
new file mode 100644
index 0000000..906ff55
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/client-auth-test/publickey.pem
@@ -0,0 +1 @@
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/clientreg-test/jwks.json b/testsuite/integration-arquillian/tests/base/src/test/resources/clientreg-test/jwks.json
new file mode 100644
index 0000000..25ba0dd
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/clientreg-test/jwks.json
@@ -0,0 +1,32 @@
+{"keys": [
+  {
+    "use": "enc",
+    "n": "tx3Hjdbc19lkTiohbJrNj4jf2_90MEE122CRrwtFu6saDywKcG7Bi7w2FMAK2oTkuWfqhWRb5BEGmnSXdiCEPO5d-ytqP3nwlZXHaCDYscpP8bB4YLhvCn7R8Efw6gwQle24QPRP3lYoFeuUbDUq7GKA5SfaZUvWoeWjqyLIaBspKQsC26_Umx1E4IXLrMSL6nkRnrYcVZBAXrYCeTP1XtsV38_lZVJfHSaJaUy4PKaj3yvgm93EV2CXybPti7CCMXZ34VqqWiF64pQjZsPu3ZTr7ha_TTQq499-zYRQNDvIVsBDLQQIgrbctuGqj6lrXb31Jj3JIEYqH_4h5X9d0Q",
+    "e": "AQAB",
+    "kty": "RSA",
+    "kid": "a0"
+  },
+  {
+    "use":"sig",
+    "n":"q1awrk7QK24Gmcy9Yb4dMbS-ZnO6NDaj1Z2F5C74HMIgtwYyxsNbRhBqCWlw7kmkZZaG5udyQYY8d91Db_uc_1DBuJMrQVsYXjVSpy-hoKpTWmzGhXzyzwhfJAICp7Iu_TTKPp-ip0mPGHlJnnP6dr4ztjY7EgFXFhEDFYSd9S8",
+    "e":"AQAB",
+    "kty":"RSA",
+    "kid":"FJ86GcF3jTbNLOco4NvZkUCIUmfYCqoqtOQeMfbhNlE"
+  },
+  {
+    "use": "sig",
+    "crv": "P-256",
+    "kty": "EC",
+    "y": "HtxLgYFXpJSomE8cN7qCEHXvKuLGZMWbK1FiJLCRCW8",
+    "x": "PMtxvxd-owwLzE_cUlA4_nT_bWcdcfnlhFF3wh8Gl5o",
+    "kid": "a2"
+  },
+  {
+    "use": "enc",
+    "crv": "P-256",
+    "kty": "EC",
+    "y": "xJd7r3N8WSjTW7ebZySfYzJtWYHeWjF34u3-BxoPfs4",
+    "x": "KIWYBJU45adk20B99K_93qvVGaqumQKGauW_RTQPazY",
+    "kid": "a3"
+  }
+]}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/keystore/email_invalid.jks b/testsuite/integration-arquillian/tests/base/src/test/resources/keystore/email_invalid.jks
new file mode 100644
index 0000000..e940f19
Binary files /dev/null and b/testsuite/integration-arquillian/tests/base/src/test/resources/keystore/email_invalid.jks differ
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/keystore/keycloak.jks b/testsuite/integration-arquillian/tests/base/src/test/resources/keystore/keycloak.jks
new file mode 100644
index 0000000..81570ab
Binary files /dev/null and b/testsuite/integration-arquillian/tests/base/src/test/resources/keystore/keycloak.jks differ
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/keystore/keycloak.truststore b/testsuite/integration-arquillian/tests/base/src/test/resources/keystore/keycloak.truststore
new file mode 100644
index 0000000..2df5170
Binary files /dev/null and b/testsuite/integration-arquillian/tests/base/src/test/resources/keystore/keycloak.truststore differ
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json b/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json
index 9208927..99e8614 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/META-INF/keycloak-server.json
@@ -23,10 +23,18 @@
         "provider": "${keycloak.user.provider:jpa}"
     },
 
+    "userFederatedStorage": {
+        "provider": "${keycloak.userFederatedStorage.provider:jpa}"
+    },
+
     "userSessionPersister": {
         "provider": "${keycloak.userSessionPersister.provider:jpa}"
     },
 
+    "authorizationPersister": {
+        "provider": "${keycloak.authorization.provider:jpa}"
+    },
+
     "userCache": {
         "provider": "${keycloak.user.cache.provider:default}",
         "default" : {
@@ -117,10 +125,18 @@
 
     "truststore": {
         "file": {
-            "file": "${keycloak.truststore.file:src/main/keystore/keycloak.truststore}",
+            "file": "${keycloak.truststore.file:src/test/resources/keystore/keycloak.truststore}",
             "password": "${keycloak.truststore.password:secret}",
             "hostname-verification-policy": "${keycloak.truststore.policy:WILDCARD}",
-            "disabled": "${keycloak.truststore.disabled:true}"
+            "disabled": "${keycloak.truststore.disabled:false}"
         }
+    },
+
+    "jta-lookup": {
+        "provider": "${keycloak.jta.lookup.provider:jboss}",
+        "jboss" : {
+            "enabled": true
+        }
+
     }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm.json b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm.json
new file mode 100755
index 0000000..6cd3ef6
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm.json
@@ -0,0 +1,459 @@
+{
+    "realm": "test-realm",
+    "enabled": true,
+    "accessTokenLifespan": 6000,
+    "accessTokenLifespanForImplicitFlow": 1500,
+    "accessCodeLifespan": 30,
+    "accessCodeLifespanUserAction": 600,
+    "offlineSessionIdleTimeout": 3600000,
+    "requiredCredentials": [ "password" ],
+    "defaultRoles": [ "foo", "bar" ],
+    "verifyEmail" : "true",
+    "smtpServer": {
+        "from": "auto@keycloak.org",
+        "host": "localhost",
+        "port":"3025"
+    },
+    "identityProviders" : [
+        {
+            "providerId" : "google",
+            "alias" : "google1",
+            "enabled": true,
+            "config": {
+                "clientId": "googleId",
+                "clientSecret": "googleSecret"
+            }
+        },
+        {
+            "providerId" : "facebook",
+            "alias" : "facebook1",
+            "enabled": true,
+            "config": {
+                "clientId": "facebookId",
+                "clientSecret": "facebookSecret"
+            }
+        },
+        {
+            "providerId" : "twitter",
+            "alias" : "twitter1",
+            "enabled": true,
+            "config": {
+                "clientId": "twitterId",
+                "clientSecret": "twitterSecret"
+            }
+        }
+    ],
+    "userFederationProviders": [
+        {
+            "displayName": "MyLDAPProvider1",
+            "providerName": "ldap",
+            "priority": 1,
+            "config": {
+                "connectionUrl": "ldap://foo"
+            }
+        },
+        {
+            "displayName": "MyLDAPProvider2",
+            "providerName": "ldap",
+            "priority": 2,
+            "config": {
+                "connectionUrl": "ldap://bar"
+            }
+        }
+    ],
+    "userFederationMappers": [
+        {
+            "name": "FullNameMapper",
+            "federationProviderDisplayName": "MyLDAPProvider1",
+            "federationMapperType": "full-name-ldap-mapper",
+            "config": {
+                "ldap.full.name.attribute": "cn"
+            }
+        }
+    ],
+    "users": [
+        {
+            "username": "wburke",
+            "enabled": true,
+            "createdTimestamp" : 123654,
+            "attributes": {
+                "email": "bburke@redhat.com"
+            },
+            "credentials": [
+                {
+                    "type": "password",
+                    "value": "userpassword"
+                }
+            ],
+            "applicationRoles": {
+                "Application": [ "app-user" ],
+                "OtherApp": [  "otherapp-user" ]
+            }
+        },
+        {
+            "username": "loginclient",
+            "createdTimestamp" : "123655",
+            "enabled": true,
+            "credentials": [
+                {
+                    "type": "password",
+                    "value": "clientpassword"
+                }
+            ]
+        },
+        {
+            "username": "admin",
+            "enabled": true,
+            "attributes": {
+                "key1": [
+                    "val1"
+                ],
+                "key2": [
+                    "val21",
+                    "val22"
+                ]
+            },
+            "credentials": [
+                {
+                    "type": "password",
+                    "value": "adminpassword"
+                }
+            ],
+            "realmRoles": [ "admin" ],
+            "applicationRoles": {
+                "Application": [ "app-admin" ],
+                "OtherApp": [  "otherapp-admin" ]
+            },
+            "clientConsents": [
+                {
+                    "clientId": "Application",
+                    "grantedRealmRoles": [ "admin" ],
+                    "grantedClientRoles": {
+                        "Application": [ "app-admin" ]
+                    }
+                },
+                {
+                    "clientId": "OtherApp",
+                    "grantedRealmRoles": [ "admin" ],
+                    "grantedProtocolMappers": {
+                        "openid-connect": [ "gss delegation credential" ]
+                    }
+                }
+            ]
+        },
+        {
+            "username": "mySocialUser",
+            "enabled": true,
+            "federatedIdentities": [
+                {
+                    "identityProvider": "facebook1",
+                    "userId": "facebook1",
+                    "userName": "fbuser1"
+                },
+                {
+                    "identityProvider": "twitter1",
+                    "userId": "twitter1",
+                    "userName": "twuser1"
+                },
+                {
+                    "identityProvider": "google1",
+                    "userId": "google1",
+                    "userName": "mySocialUser@gmail.com"
+                }
+            ]
+        },
+        {
+            "username": "my-service-user",
+            "enabled": true,
+            "serviceAccountClientId": "OtherApp"
+        }
+    ],
+    "clients": [
+        {
+            "clientId": "Application",
+            "name": "Applicationn",
+            "enabled": true,
+            "implicitFlowEnabled": true,
+            "directAccessGrantsEnabled": true,
+            "nodeReRegistrationTimeout": 50,
+            "registeredNodes": {
+                "node1": 10,
+                "172.10.15.20": 20
+            }
+        },
+        {
+            "clientId": "OtherApp",
+            "name": "Other Application",
+            "enabled": true,
+            "standardFlowEnabled": false,
+            "directAccessGrantsEnabled": false,
+            "serviceAccountsEnabled": true,
+            "clientAuthenticatorType": "client-jwt",
+            "protocolMappers" : [
+                {
+                    "name" : "gss delegation credential",
+                    "protocol" : "openid-connect",
+                    "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+                    "consentRequired" : true,
+                    "consentText" : "gss delegation credential",
+                    "config" : {
+                        "user.session.note" : "gss_delegation_credential",
+                        "access.token.claim" : "true",
+                        "claim.name" : "gss_delegation_credential",
+                        "Claim JSON Type" : "String"
+                    }
+                }
+            ]
+        },
+        {
+            "clientId": "test-app-authz",
+            "enabled": true,
+            "baseUrl": "/test-app-authz",
+            "adminUrl": "/test-app-authz",
+            "bearerOnly": false,
+            "authorizationSettings": {
+                "allowRemoteResourceManagement": true,
+                "policyEnforcementMode": "ENFORCING",
+                "resources": [
+                    {
+                        "name": "Admin Resource",
+                        "uri": "/protected/admin/*",
+                        "type": "http://test-app-authz/protected/admin",
+                        "icon_uri" : "http://icons.com/icon-admin",
+                        "scopes": [
+                            {
+                                "name": "admin-access"
+                            }
+                        ]
+                    },
+                    {
+                        "name": "Protected Resource",
+                        "uri": "/*",
+                        "type": "http://test-app-authz/protected/resource",
+                        "icon_uri" : "http://icons.com/icon-resource",
+                        "scopes": [
+                            {
+                                "name": "resource-access"
+                            }
+                        ]
+                    },
+                    {
+                        "name": "Premium Resource",
+                        "uri": "/protected/premium/*",
+                        "type": "urn:test-app-authz:protected:resource",
+                        "icon_uri" : "http://icons.com/icon-premium",
+                        "scopes": [
+                            {
+                                "name": "premium-access"
+                            }
+                        ]
+                    },
+                    {
+                        "name": "Main Page",
+                        "type": "urn:test-app-authz:protected:resource",
+                        "icon_uri" : "http://icons.com/icon-main-page",
+                        "scopes": [
+                            {
+                                "name": "urn:test-app-authz:page:main:actionForAdmin"
+                            },
+                            {
+                                "name": "urn:test-app-authz:page:main:actionForUser"
+                            },
+                            {
+                                "name": "urn:test-app-authz:page:main:actionForPremiumUser"
+                            }
+                        ]
+                    }
+                ],
+                "policies": [
+                    {
+                        "name": "Any Admin Policy",
+                        "description": "Defines that adminsitrators can do something",
+                        "type": "role",
+                        "config": {
+                            "roles": "[{\"id\":\"admin\"}]"
+                        }
+                    },
+                    {
+                        "name": "Any User Policy",
+                        "description": "Defines that any user can do something",
+                        "type": "role",
+                        "config": {
+                            "roles": "[{\"id\":\"user\"}]"
+                        }
+                    },
+                    {
+                        "name": "Only Premium User Policy",
+                        "description": "Defines that only premium users can do something",
+                        "type": "role",
+                        "logic": "POSITIVE",
+                        "config": {
+                            "roles": "[{\"id\":\"customer-user-premium\"}]"
+                        }
+                    },
+                    {
+                        "name": "All Users Policy",
+                        "description": "Defines that all users can do something",
+                        "type": "aggregate",
+                        "decisionStrategy": "AFFIRMATIVE",
+                        "config": {
+                            "applyPolicies": "[\"Any User Policy\",\"Any Admin Policy\",\"Only Premium User Policy\"]"
+                        }
+                    },
+                    {
+                        "name": "Premium Resource Permission",
+                        "description": "A policy that defines access to premium resources",
+                        "type": "resource",
+                        "decisionStrategy": "UNANIMOUS",
+                        "config": {
+                            "resources": "[\"Premium Resource\"]",
+                            "applyPolicies": "[\"Only Premium User Policy\"]"
+                        }
+                    },
+                    {
+                        "name": "Administrative Resource Permission",
+                        "description": "A policy that defines access to administrative resources",
+                        "type": "resource",
+                        "decisionStrategy": "UNANIMOUS",
+                        "config": {
+                            "resources": "[\"Admin Resource\"]",
+                            "applyPolicies": "[\"Any Admin Policy\"]"
+                        }
+                    },
+                    {
+                        "name": "Protected Resource Permission",
+                        "description": "A policy that defines access to any protected resource",
+                        "type": "resource",
+                        "decisionStrategy": "AFFIRMATIVE",
+                        "config": {
+                            "resources": "[\"Protected Resource\"]",
+                            "applyPolicies": "[\"All Users Policy\"]"
+                        }
+                    },
+                    {
+                        "name": "Action 1 on Main Page Resource Permission",
+                        "description": "A policy that defines access to action 1 on the main page",
+                        "type": "scope",
+                        "decisionStrategy": "AFFIRMATIVE",
+                        "config": {
+                            "scopes": "[\"urn:test-app-authz:page:main:actionForAdmin\"]",
+                            "applyPolicies": "[\"Any Admin Policy\"]"
+                        }
+                    },
+                    {
+                        "name": "Action 2 on Main Page Resource Permission",
+                        "description": "A policy that defines access to action 2 on the main page",
+                        "type": "scope",
+                        "decisionStrategy": "AFFIRMATIVE",
+                        "config": {
+                            "scopes": "[\"urn:test-app-authz:page:main:actionForUser\"]",
+                            "applyPolicies": "[\"Any User Policy\"]"
+                        }
+                    },
+                    {
+                        "name": "Action 3 on Main Page Resource Permission",
+                        "description": "A policy that defines access to action 3 on the main page",
+                        "type": "scope",
+                        "decisionStrategy": "AFFIRMATIVE",
+                        "config": {
+                            "scopes": "[\"urn:test-app-authz:page:main:actionForPremiumUser\"]",
+                            "applyPolicies": "[\"Only Premium User Policy\"]"
+                        }
+                    }
+                ]
+            },
+            "redirectUris": [
+                "/test-app-authz/*"
+            ],
+            "secret": "secret"
+        }
+    ],
+    "oauthClients" : [
+        {
+            "name" : "oauthclient",
+            "enabled": true,
+            "secret": "clientpassword"
+        }
+    ],
+    "clientTemplates" : [
+        {
+            "name" : "foo-template",
+            "description" : "foo-template-desc",
+            "protocol" : "openid-connect",
+            "protocolMappers" : [
+                {
+                    "name" : "gss delegation credential",
+                    "protocol" : "openid-connect",
+                    "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+                    "consentRequired" : true,
+                    "consentText" : "gss delegation credential",
+                    "config" : {
+                        "user.session.note" : "gss_delegation_credential",
+                        "access.token.claim" : "true",
+                        "claim.name" : "gss_delegation_credential",
+                        "Claim JSON Type" : "String"
+                    }
+                }
+            ]
+        }
+    ],
+    "roles" : {
+        "realm" : [
+            {
+                "name": "admin"
+            },
+            {
+                "name": "user"
+            },
+            {
+                "name": "customer-user-premium",
+                "description": "Have User Premium privileges"
+            }
+        ],
+        "application" : {
+            "Application" : [
+                {
+                    "name": "app-admin",
+                    "scopeParamRequired": true
+                },
+                {
+                    "name": "app-user"
+                }
+            ],
+            "OtherApp" : [
+                {
+                    "name": "otherapp-admin",
+                    "scopeParamRequired": false
+                },
+                {
+                    "name": "otherapp-user"
+                }
+            ]
+        }
+    },
+    "scopeMappings": [
+        {
+            "client": "oauthclient",
+            "roles": ["admin"]
+        },
+        {
+            "clientTemplate": "foo-template",
+            "roles": ["admin"]
+        }
+    ],
+    "applicationScopeMappings": {
+        "Application": [
+            {
+                "client": "oauthclient",
+                "roles": ["app-user"]
+            },
+            {
+                "clientTemplate": "foo-template",
+                "roles": ["app-user", "app-admin" ]
+            }
+        ]
+
+    }
+
+
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm2.json b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm2.json
new file mode 100755
index 0000000..4e3d9fb
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm2.json
@@ -0,0 +1,89 @@
+{
+    "realm": "demo-delete",
+    "enabled": true,
+    "accessTokenLifespan": 3000,
+    "accessCodeLifespan": 10,
+    "accessCodeLifespanUserAction": 6000,
+    "sslRequired": "external",
+    "registrationAllowed": false,
+    "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+    "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+    "requiredCredentials": [ "password" ],
+    "users" : [
+        {
+            "username" : "bburke@redhat.com",
+            "enabled": true,
+            "email" : "bburke@redhat.com",
+            "firstName": "Bill",
+            "lastName": "Burke",
+            "credentials" : [
+                { "type" : "password",
+                  "value" : "password" }
+            ],
+            "realmRoles": ["user"],
+            "applicationRoles": {
+                "account": [ "manage-account" ]
+            }
+
+        }
+    ],
+    "roles" : {
+        "realm" : [
+            {
+                "name": "user",
+                "description": "User privileges"
+            },
+            {
+                "name": "admin",
+                "description": "Administrator privileges"
+            }
+        ]
+    },
+    "scopeMappings": [
+        {
+            "client": "third-party",
+            "roles": ["user"]
+        },
+        {
+            "client": "customer-portal",
+            "roles": ["user"]
+        },
+        {
+            "client": "product-portal",
+            "roles": ["user"]
+        }
+
+    ],
+    "applications": [
+        {
+            "name": "customer-portal",
+            "enabled": true,
+            "adminUrl": "http://localhost:8080/customer-portal",
+            "redirectUris": [
+                "http://localhost:8080/customer-portal/*"
+            ],
+            "secret": "password"
+        },
+        {
+            "name": "product-portal",
+            "enabled": true,
+            "adminUrl": "http://localhost:8080/product-portal",
+            "redirectUris": [
+                "http://localhost:8080/product-portal/*"
+            ],
+            "secret": "password"
+        }
+    ],
+    "oauthClients": [
+        {
+            "name": "third-party",
+            "enabled": true,
+            "redirectUris": [
+                "http://localhost:8080/oauth-client/*",
+                "http://localhost:8080/oauth-client-cdi/*"
+            ],
+            "secret": "password"
+        }
+    ]
+
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm-demo.json b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm-demo.json
new file mode 100755
index 0000000..c98bbf7
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm-demo.json
@@ -0,0 +1,63 @@
+{
+    "realm": "demo",
+    "enabled": true,
+    "accessTokenLifespan": 300,
+    "accessCodeLifespan": 10,
+    "accessCodeLifespanUserAction": 600,
+    "sslRequired": "external",
+    "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+    "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+    "requiredCredentials": [ "password" ],
+    "users" : [
+        {
+            "username" : "bburke@redhat.com",
+            "enabled": true,
+            "email" : "bburke@redhat.com",
+            "credentials" : [
+                { "type" : "Password",
+                  "value" : "password" }
+            ],
+            "realmRoles": [ "user" ]
+        }
+    ],
+    "oauthClients" : [
+        {
+            "name" : "third-party",
+            "enabled": true,
+            "secret": "password"
+        }
+    ],
+    "roles" : {
+        "realm" : [
+            {
+                "name": "user",
+                "description": "Have User privileges"
+            },
+            {
+                "name": "admin",
+                "description": "Have Administrator privileges"
+            }
+        ]
+    },
+
+    "scopeMappings": [
+        {
+            "client": "third-party",
+            "roles": ["user"]
+        }
+    ],
+    "applications": [
+        {
+            "name": "customer-portal",
+            "enabled": true,
+            "adminUrl": "http://localhost:8080/customer-portal/j_admin_request",
+            "secret": "password"
+        },
+        {
+            "name": "product-portal",
+            "enabled": true,
+            "adminUrl": "http://localhost:8080/product-portal/j_admin_request",
+            "secret": "password"
+        }
+    ]
+}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm-noclient-id.json b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm-noclient-id.json
new file mode 100755
index 0000000..4751c7f
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm-noclient-id.json
@@ -0,0 +1,57 @@
+
+{
+    "realm": "demo-no-client-id",
+    "enabled": true,
+    "accessTokenLifespan": 300,
+    "accessCodeLifespan": 10,
+    "accessCodeLifespanUserAction": 600,
+    "sslRequired": "external",
+    "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+    "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+    "requiredCredentials": [ "password" ],
+    "users" : [
+        {
+            "username" : "bburke@redhat.com",
+            "enabled": true,
+            "email" : "bburke@redhat.com",
+            "credentials" : [
+                { "type" : "Password",
+                    "value" : "password" }
+            ],
+            "realmRoles": [ "user" ]
+        }
+    ],
+    "roles" : {
+        "realm" : [
+            {
+                "name": "user",
+                "description": "Have User privileges"
+            },
+            {
+                "name": "admin",
+                "description": "Have Administrator privileges"
+            }
+        ]
+    },
+    "scopeMappings": [
+        {
+            "client": "third-party",
+            "roles": ["user"]
+        }
+    ],
+    "clients": [
+        {
+            "name": "third-party",
+            "enabled": true,
+            "bearerOnly": true
+        }
+    ],
+    "clientScopeMappings": {
+        "realm-management": [
+            {
+                "client": "some-client",
+                "roles": ["create-client"]
+            }
+        ]
+    }
+}
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/testrealm.json b/testsuite/integration-arquillian/tests/base/src/test/resources/testrealm.json
index 5427075..c0b2b6c 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/testrealm.json
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/testrealm.json
@@ -105,7 +105,7 @@
       "redirectUris": [
         "http://localhost:8180/auth/realms/master/app/auth/*"
       ],
-      "adminUrl": "http://localhost:8180/auth/realms/master/app/logout",
+      "adminUrl": "http://localhost:8180/auth/realms/master/app/admin",
       "secret": "password"
     },
     {
@@ -117,6 +117,164 @@
         "http://localhost:8180/auth/realms/master/app/*"
       ],
       "secret": "password"
+    },
+    {
+      "clientId": "test-app-authz",
+      "enabled": true,
+      "baseUrl": "/test-app-authz",
+      "adminUrl": "/test-app-authz",
+      "bearerOnly": false,
+      "authorizationSettings": {
+        "allowRemoteResourceManagement": true,
+        "policyEnforcementMode": "ENFORCING",
+        "resources": [
+          {
+            "name": "Admin Resource",
+            "uri": "/protected/admin/*",
+            "type": "http://test-app-authz/protected/admin",
+            "scopes": [
+              {
+                "name": "admin-access"
+              }
+            ]
+          },
+          {
+            "name": "Protected Resource",
+            "uri": "/*",
+            "type": "http://test-app-authz/protected/resource",
+            "scopes": [
+              {
+                "name": "resource-access"
+              }
+            ]
+          },
+          {
+            "name": "Premium Resource",
+            "uri": "/protected/premium/*",
+            "type": "urn:test-app-authz:protected:resource",
+            "scopes": [
+              {
+                "name": "premium-access"
+              }
+            ]
+          },
+          {
+            "name": "Main Page",
+            "type": "urn:test-app-authz:protected:resource",
+            "scopes": [
+              {
+                "name": "urn:test-app-authz:page:main:actionForAdmin"
+              },
+              {
+                "name": "urn:test-app-authz:page:main:actionForUser"
+              },
+              {
+                "name": "urn:test-app-authz:page:main:actionForPremiumUser"
+              }
+            ]
+          }
+        ],
+        "policies": [
+          {
+            "name": "Any Admin Policy",
+            "description": "Defines that adminsitrators can do something",
+            "type": "role",
+            "config": {
+              "roles": "[{\"id\":\"admin\"}]"
+            }
+          },
+          {
+            "name": "Any User Policy",
+            "description": "Defines that any user can do something",
+            "type": "role",
+            "config": {
+              "roles": "[{\"id\":\"user\"}]"
+            }
+          },
+          {
+            "name": "Only Premium User Policy",
+            "description": "Defines that only premium users can do something",
+            "type": "role",
+            "logic": "POSITIVE",
+            "config": {
+              "roles": "[{\"id\":\"customer-user-premium\"}]"
+            }
+          },
+          {
+            "name": "All Users Policy",
+            "description": "Defines that all users can do something",
+            "type": "aggregate",
+            "decisionStrategy": "AFFIRMATIVE",
+            "config": {
+              "applyPolicies": "[\"Any User Policy\",\"Any Admin Policy\",\"Only Premium User Policy\"]"
+            }
+          },
+          {
+            "name": "Premium Resource Permission",
+            "description": "A policy that defines access to premium resources",
+            "type": "resource",
+            "decisionStrategy": "UNANIMOUS",
+            "config": {
+              "resources": "[\"Premium Resource\"]",
+              "applyPolicies": "[\"Only Premium User Policy\"]"
+            }
+          },
+          {
+            "name": "Administrative Resource Permission",
+            "description": "A policy that defines access to administrative resources",
+            "type": "resource",
+            "decisionStrategy": "UNANIMOUS",
+            "config": {
+              "resources": "[\"Admin Resource\"]",
+              "applyPolicies": "[\"Any Admin Policy\"]"
+            }
+          },
+          {
+            "name": "Protected Resource Permission",
+            "description": "A policy that defines access to any protected resource",
+            "type": "resource",
+            "decisionStrategy": "AFFIRMATIVE",
+            "config": {
+              "resources": "[\"Protected Resource\"]",
+              "applyPolicies": "[\"All Users Policy\"]"
+            }
+          },
+          {
+            "name": "Action 1 on Main Page Resource Permission",
+            "description": "A policy that defines access to action 1 on the main page",
+            "type": "scope",
+            "decisionStrategy": "AFFIRMATIVE",
+            "config": {
+              "scopes": "[\"urn:test-app-authz:page:main:actionForAdmin\"]",
+              "applyPolicies": "[\"Any Admin Policy\"]"
+            }
+          },
+          {
+            "name": "Action 2 on Main Page Resource Permission",
+            "description": "A policy that defines access to action 2 on the main page",
+            "type": "scope",
+            "decisionStrategy": "AFFIRMATIVE",
+            "config": {
+              "scopes": "[\"urn:test-app-authz:page:main:actionForUser\"]",
+              "applyPolicies": "[\"Any User Policy\"]"
+            }
+          },
+          {
+            "name": "Action 3 on Main Page Resource Permission",
+            "description": "A policy that defines access to action 3 on the main page",
+            "type": "scope",
+            "decisionStrategy": "AFFIRMATIVE",
+            "config": {
+              "scopes": "[\"urn:test-app-authz:page:main:actionForPremiumUser\"]",
+              "applyPolicies": "[\"Only Premium User Policy\"]"
+            }
+          }
+        ]
+      },
+      "redirectUris": [
+        "/test-app-authz/*"
+      ],
+      "secret": "secret"
     }
   ],
   "roles" : {
@@ -128,6 +286,10 @@
       {
         "name": "admin",
         "description": "Have Administrator privileges"
+      },
+      {
+        "name": "customer-user-premium",
+        "description": "Have User Premium privileges"
       }
     ],
     "client" : {
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/pom.xml
index e3a882d..d192990 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-adapters-jboss</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-adapters-as7</artifactId>
@@ -33,7 +33,6 @@
     
     <properties>
         <app.server>as7</app.server>
-        <adapter.libs.home>${app.server.home}/modules/org/keycloak</adapter.libs.home>
         
         <app.server.management.protocol>remote</app.server.management.protocol>
         <app.server.management.port>${app.server.management.port.jmx}</app.server.management.port>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/src/test/java/org/keycloak/testsuite/adapter/AS7OIDCAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/src/test/java/org/keycloak/testsuite/adapter/AS7OIDCAdapterTest.java
index 93dec26..bd9843e 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/src/test/java/org/keycloak/testsuite/adapter/AS7OIDCAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/src/test/java/org/keycloak/testsuite/adapter/AS7OIDCAdapterTest.java
@@ -8,7 +8,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-as7")
-//@AdapterLibsLocationProperty("adapter.libs.as7")
 public class AS7OIDCAdapterTest extends AbstractDemoServletsAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/src/test/java/org/keycloak/testsuite/adapter/AS7OIDCSessionAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/src/test/java/org/keycloak/testsuite/adapter/AS7OIDCSessionAdapterTest.java
index 51da714..1d1c632 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/src/test/java/org/keycloak/testsuite/adapter/AS7OIDCSessionAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/src/test/java/org/keycloak/testsuite/adapter/AS7OIDCSessionAdapterTest.java
@@ -8,7 +8,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-as7")
-//@AdapterLibsLocationProperty("adapter.libs.as7")
 public class AS7OIDCSessionAdapterTest extends AbstractSessionServletAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/src/test/java/org/keycloak/testsuite/adapter/example/AS7BasicAuthExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/src/test/java/org/keycloak/testsuite/adapter/example/AS7BasicAuthExampleAdapterTest.java
index 7c62445..280cd61 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/src/test/java/org/keycloak/testsuite/adapter/example/AS7BasicAuthExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/src/test/java/org/keycloak/testsuite/adapter/example/AS7BasicAuthExampleAdapterTest.java
@@ -7,7 +7,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-as7")
-//@AdapterLibsLocationProperty("adapter.libs.as7")
 public class AS7BasicAuthExampleAdapterTest extends AbstractBasicAuthExampleAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/src/test/java/org/keycloak/testsuite/adapter/example/AS7DemoExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/src/test/java/org/keycloak/testsuite/adapter/example/AS7DemoExampleAdapterTest.java
index 53ae0e1..0daaf9a 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/src/test/java/org/keycloak/testsuite/adapter/example/AS7DemoExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/as7/src/test/java/org/keycloak/testsuite/adapter/example/AS7DemoExampleAdapterTest.java
@@ -7,7 +7,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-as7")
-//@AdapterLibsLocationProperty("adapter.libs.as7")
 public class AS7DemoExampleAdapterTest extends AbstractDemoExampleAdapterTest {
 
 }
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/pom.xml
index ad22c37..3c754bc 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-adapters-jboss</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-adapters-eap</artifactId>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/EAPOIDCAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/EAPOIDCAdapterTest.java
index 4912f06..8c663f2 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/EAPOIDCAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/EAPOIDCAdapterTest.java
@@ -1,7 +1,6 @@
 package org.keycloak.testsuite.adapter;
 
 import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
-import org.junit.Ignore;
 import org.keycloak.testsuite.adapter.servlet.AbstractDemoServletsAdapterTest;
 
 /**
@@ -9,8 +8,6 @@ import org.keycloak.testsuite.adapter.servlet.AbstractDemoServletsAdapterTest;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-eap")
-//@AdapterLibsLocationProperty("adapter.libs.eap7")
-//@Ignore //failing tests
 public class EAPOIDCAdapterTest extends AbstractDemoServletsAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/EAPOIDCSessionAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/EAPOIDCSessionAdapterTest.java
index e1db84f..c84f2cb 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/EAPOIDCSessionAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/EAPOIDCSessionAdapterTest.java
@@ -8,7 +8,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-eap")
-//@AdapterLibsLocationProperty("adapter.libs.eap7")
 public class EAPOIDCSessionAdapterTest extends AbstractSessionServletAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/EAPSAMLAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/EAPSAMLAdapterTest.java
index 8852087..33aaab3 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/EAPSAMLAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/EAPSAMLAdapterTest.java
@@ -7,7 +7,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author mhajas
  */
 @AppServerContainer("app-server-eap")
-//@AdapterLibsLocationProperty("adapter.libs.eap7")
 public class EAPSAMLAdapterTest extends AbstractSAMLServletsAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/EAPSAMLFilterAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/EAPSAMLFilterAdapterTest.java
new file mode 100644
index 0000000..bf739a7
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/EAPSAMLFilterAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter;
+
+import org.keycloak.testsuite.adapter.servlet.AbstractSAMLFilterServletAdapterTest;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+import org.keycloak.testsuite.arquillian.annotation.UseServletFilter;
+
+/**
+ * @author mhajas
+ */
+@AppServerContainer("app-server-eap")
+public class EAPSAMLFilterAdapterTest extends AbstractSAMLFilterServletAdapterTest {
+}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/example/EAPBasicAuthExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/example/EAPBasicAuthExampleAdapterTest.java
index 26b7c5f..574ee16 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/example/EAPBasicAuthExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/example/EAPBasicAuthExampleAdapterTest.java
@@ -7,7 +7,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-eap")
-//@AdapterLibsLocationProperty("adapter.libs.eap7")
 public class EAPBasicAuthExampleAdapterTest extends AbstractBasicAuthExampleAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/example/EAPDemoExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/example/EAPDemoExampleAdapterTest.java
index fa22b56..f461222 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/example/EAPDemoExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/example/EAPDemoExampleAdapterTest.java
@@ -7,7 +7,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-eap")
-//@AdapterLibsLocationProperty("adapter.libs.eap7")
 public class EAPDemoExampleAdapterTest extends AbstractDemoExampleAdapterTest {
 
 }
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/example/EAPJSConsoleExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/example/EAPJSConsoleExampleAdapterTest.java
index 0674eea..e9cabc4 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/example/EAPJSConsoleExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/example/EAPJSConsoleExampleAdapterTest.java
@@ -1,13 +1,11 @@
 package org.keycloak.testsuite.adapter.example;
 
-import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
 import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
-import org.junit.Ignore;
+
 /**
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-eap")
-//@AdapterLibsLocationProperty("adapter.libs.eap")
 public class EAPJSConsoleExampleAdapterTest extends AbstractJSConsoleExampleAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/example/EAPSAMLExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/example/EAPSAMLExampleAdapterTest.java
index 4ae0838..b5431ff 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/example/EAPSAMLExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap/src/test/java/org/keycloak/testsuite/adapter/example/EAPSAMLExampleAdapterTest.java
@@ -6,7 +6,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author mhajas
  */
 @AppServerContainer("app-server-eap")
-//@AdapterLibsLocationProperty("adapter.libs.eap7")
 public class EAPSAMLExampleAdapterTest extends AbstractSAMLExampleAdapterTest {
 
 }
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/pom.xml
index 09be582..7820141 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-adapters-jboss</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-adapters-eap6</artifactId>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6OIDCAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6OIDCAdapterTest.java
index 3562370..a834596 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6OIDCAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6OIDCAdapterTest.java
@@ -1,7 +1,6 @@
 package org.keycloak.testsuite.adapter;
 
 import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
-import org.junit.Ignore;
 import org.keycloak.testsuite.adapter.servlet.AbstractDemoServletsAdapterTest;
 
 /**
@@ -9,8 +8,6 @@ import org.keycloak.testsuite.adapter.servlet.AbstractDemoServletsAdapterTest;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-eap6")
-//@AdapterLibsLocationProperty("adapter.libs.eap6")
-//@Ignore //failing tests
 public class EAP6OIDCAdapterTest extends AbstractDemoServletsAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6OIDCSessionAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6OIDCSessionAdapterTest.java
index 82f5926..a3c6bc9 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6OIDCSessionAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6OIDCSessionAdapterTest.java
@@ -8,7 +8,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-eap6")
-//@AdapterLibsLocationProperty("adapter.libs.eap6")
 public class EAP6OIDCSessionAdapterTest extends AbstractSessionServletAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6SAMLAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6SAMLAdapterTest.java
index dff9bc1..ee73379 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6SAMLAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6SAMLAdapterTest.java
@@ -7,7 +7,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author mhajas
  */
 @AppServerContainer("app-server-eap6")
-//@AdapterLibsLocationProperty("adapter.libs.eap6")
 public class EAP6SAMLAdapterTest extends AbstractSAMLServletsAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6SAMLFilterAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6SAMLFilterAdapterTest.java
new file mode 100644
index 0000000..627e5f3
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/EAP6SAMLFilterAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter;
+
+import org.keycloak.testsuite.adapter.servlet.AbstractSAMLFilterServletAdapterTest;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+import org.keycloak.testsuite.arquillian.annotation.UseServletFilter;
+
+/**
+ * @author mhajas
+ */
+@AppServerContainer("app-server-eap6")
+public class EAPSAMLFilterAdapterTest extends AbstractSAMLFilterServletAdapterTest {
+}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/example/EAP6BasicAuthExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/example/EAP6BasicAuthExampleAdapterTest.java
index c293d05..8299093 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/example/EAP6BasicAuthExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/example/EAP6BasicAuthExampleAdapterTest.java
@@ -7,7 +7,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-eap6")
-//@AdapterLibsLocationProperty("adapter.libs.eap6")
 public class EAP6BasicAuthExampleAdapterTest extends AbstractBasicAuthExampleAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/example/EAP6CorsExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/example/EAP6CorsExampleAdapterTest.java
index 8bc4646..80c7dad 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/example/EAP6CorsExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/example/EAP6CorsExampleAdapterTest.java
@@ -7,7 +7,6 @@ import org.junit.Ignore;
  * @author fkiss
  */
 @AppServerContainer("app-server-eap6")
-//@AdapterLibsLocationProperty("adapter.libs.eap6")
 @Ignore //cannot find web.xml in target/examples
 public class EAP6CorsExampleAdapterTest extends AbstractCorsExampleAdapterTest {
 
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/example/EAP6DemoExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/example/EAP6DemoExampleAdapterTest.java
index 9541c14..d0c0c95 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/example/EAP6DemoExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/example/EAP6DemoExampleAdapterTest.java
@@ -7,7 +7,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-eap6")
-//@AdapterLibsLocationProperty("adapter.libs.eap6")
 public class EAP6DemoExampleAdapterTest extends AbstractDemoExampleAdapterTest {
 
 }
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/example/EAP6JSConsoleExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/example/EAP6JSConsoleExampleAdapterTest.java
index 4f167ba..c2911b5 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/example/EAP6JSConsoleExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/example/EAP6JSConsoleExampleAdapterTest.java
@@ -1,13 +1,11 @@
 package org.keycloak.testsuite.adapter.example;
 
-import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
 import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
-import org.junit.Ignore;
+
 /**
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-eap6")
-//@AdapterLibsLocationProperty("adapter.libs.eap6")
 public class EAP6JSConsoleExampleAdapterTest extends AbstractJSConsoleExampleAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/example/EAP6SAMLExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/example/EAP6SAMLExampleAdapterTest.java
index f0977dc..208d430 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/example/EAP6SAMLExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/eap6/src/test/java/org/keycloak/testsuite/adapter/example/EAP6SAMLExampleAdapterTest.java
@@ -6,7 +6,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author mhajas
  */
 @AppServerContainer("app-server-eap6")
-//@AdapterLibsLocationProperty("adapter.libs.eap6")
 public class EAP6SAMLExampleAdapterTest extends AbstractSAMLExampleAdapterTest {
 
 }
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/jboss/pom.xml
index 69869fa..75d1978 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-adapters</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-adapters-jboss</artifactId>
@@ -35,7 +35,6 @@
     
     <properties>
         <common.resources>${project.parent.basedir}/common</common.resources>
-        <adapter.libs.home>${app.server.home}/modules/system/add-ons/keycloak</adapter.libs.home>
         <app.server.type>managed</app.server.type>
     </properties>
 
@@ -46,7 +45,7 @@
                 <artifactId>xml-maven-plugin</artifactId>
                 <executions>
                     <execution>
-                        <id>Configure keycloak subsystem</id>
+                        <id>configure-keycloak-subsystem</id>
                         <phase>process-test-resources</phase>
                         <goals>
                             <goal>transform</goal>
@@ -91,7 +90,7 @@
                         <artifactId>xml-maven-plugin</artifactId>
                         <executions>
                             <execution>
-                                <id>Configure keycloak subsystem</id>
+                                <id>configure-keycloak-subsystem</id>
                                 <phase>process-test-resources</phase>
                                 <goals>
                                     <goal>transform</goal>
@@ -131,7 +130,8 @@
                 <dependency>
                     <groupId>org.wildfly.arquillian</groupId>
                     <artifactId>wildfly-arquillian-container-${app.server.type}</artifactId>
-                </dependency>                
+                    <version>${arquillian-wildfly-container.version}</version>
+                </dependency>
             </dependencies>            
         </profile>
 
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/pom.xml
index 10c3ef4..73aa117 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-adapters-jboss-relative</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-adapters-relative-eap</artifactId>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/example/RelativeEAPBasicAuthExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/example/RelativeEAPBasicAuthExampleAdapterTest.java
index 60b9595..9d77950 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/example/RelativeEAPBasicAuthExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/example/RelativeEAPBasicAuthExampleAdapterTest.java
@@ -4,7 +4,6 @@ package org.keycloak.testsuite.adapter.example;
  *
  * @author tkyjovsk
  */
-//@AdapterLibsLocationProperty("adapter.libs.eap")
 public class RelativeEAPBasicAuthExampleAdapterTest extends AbstractBasicAuthExampleAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/example/RelativeEAPCorsExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/example/RelativeEAPCorsExampleAdapterTest.java
index a718a3b..b96ee75 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/example/RelativeEAPCorsExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/example/RelativeEAPCorsExampleAdapterTest.java
@@ -4,7 +4,6 @@ package org.keycloak.testsuite.adapter.example;
  *
  * @author fkiss
  */
-//@AdapterLibsLocationProperty("adapter.libs.eap")
 public class RelativeEAPCorsExampleAdapterTest extends AbstractCorsExampleAdapterTest {
 
 }
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/example/RelativeEAPDemoExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/example/RelativeEAPDemoExampleAdapterTest.java
index d2775bf..ef94eee 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/example/RelativeEAPDemoExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/example/RelativeEAPDemoExampleAdapterTest.java
@@ -4,7 +4,6 @@ package org.keycloak.testsuite.adapter.example;
  *
  * @author tkyjovsk
  */
-//@AdapterLibsLocationProperty("adapter.libs.eap")
 public class RelativeEAPDemoExampleAdapterTest extends AbstractDemoExampleAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/example/RelativeEAPJSConsoleExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/example/RelativeEAPJSConsoleExampleAdapterTest.java
index d11f68b..465ae45 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/example/RelativeEAPJSConsoleExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/example/RelativeEAPJSConsoleExampleAdapterTest.java
@@ -4,7 +4,6 @@ package org.keycloak.testsuite.adapter.example;
  *
  * @author tkyjovsk
  */
-//@AdapterLibsLocationProperty("adapter.libs.eap")
 public class RelativeEAPJSConsoleExampleAdapterTest extends AbstractJSConsoleExampleAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/example/RelativeEAPSAMLExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/example/RelativeEAPSAMLExampleAdapterTest.java
index 6361e83..2afe238 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/example/RelativeEAPSAMLExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/example/RelativeEAPSAMLExampleAdapterTest.java
@@ -4,7 +4,6 @@ package org.keycloak.testsuite.adapter.example;
  *
  * @author mhajas
  */
-//@AdapterLibsLocationProperty("adapter.libs.eap")
 public class RelativeEAPSAMLExampleAdapterTest extends AbstractSAMLExampleAdapterTest {
 
 }
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/RelativeEAPOIDCAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/RelativeEAPOIDCAdapterTest.java
index 249ec6b..8d0cedc 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/RelativeEAPOIDCAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/RelativeEAPOIDCAdapterTest.java
@@ -6,7 +6,6 @@ import org.keycloak.testsuite.adapter.servlet.AbstractDemoServletsAdapterTest;
  *
  * @author tkyjovsk
  */
-//@AdapterLibsLocationProperty("adapter.libs.eap")
 public class RelativeEAPOIDCAdapterTest extends AbstractDemoServletsAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/RelativeEAPOIDCSessionAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/RelativeEAPOIDCSessionAdapterTest.java
index 9ef19ce..444c758 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/RelativeEAPOIDCSessionAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/RelativeEAPOIDCSessionAdapterTest.java
@@ -6,7 +6,6 @@ import org.keycloak.testsuite.adapter.servlet.AbstractSessionServletAdapterTest;
  *
  * @author tkyjovsk
  */
-//@AdapterLibsLocationProperty("adapter.libs.eap")
 public class RelativeEAPOIDCSessionAdapterTest extends AbstractSessionServletAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/RelativeEAPSAMLAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/RelativeEAPSAMLAdapterTest.java
index cd27bee..9807577 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/RelativeEAPSAMLAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/eap/src/test/java/org/keycloak/testsuite/adapter/RelativeEAPSAMLAdapterTest.java
@@ -5,7 +5,6 @@ import org.keycloak.testsuite.adapter.servlet.AbstractSAMLServletsAdapterTest;
 /**
  * @author mhajas
  */
-//@AdapterLibsLocationProperty("adapter.libs.eap")
 public class RelativeEAPSAMLAdapterTest extends AbstractSAMLServletsAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/pom.xml
index 30fbf6c..d8b3826 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-adapters-jboss</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
     
     <packaging>pom</packaging>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/pom.xml
index cfa7507..21470d6 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-adapters-jboss-relative</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-adapters-relative-wildfly</artifactId>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/RelativeWildflyBasicAuthExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/RelativeWildflyBasicAuthExampleAdapterTest.java
index dc2f293..17dc40c 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/RelativeWildflyBasicAuthExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/RelativeWildflyBasicAuthExampleAdapterTest.java
@@ -4,7 +4,6 @@ package org.keycloak.testsuite.adapter.example;
  *
  * @author tkyjovsk
  */
-//@AdapterLibsLocationProperty("adapter.libs.eap")
 public class RelativeWildflyBasicAuthExampleAdapterTest extends AbstractBasicAuthExampleAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/RelativeWildflyCorsExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/RelativeWildflyCorsExampleAdapterTest.java
index 69a8694..af3bdb8 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/RelativeWildflyCorsExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/RelativeWildflyCorsExampleAdapterTest.java
@@ -4,7 +4,6 @@ package org.keycloak.testsuite.adapter.example;
  *
  * @author fkiss
  */
-//@AdapterLibsLocationProperty("adapter.libs.eap")
 public class RelativeWildflyCorsExampleAdapterTest extends AbstractCorsExampleAdapterTest {
 
 }
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/RelativeWildflyDemoExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/RelativeWildflyDemoExampleAdapterTest.java
index 108fc5b..0abd086 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/RelativeWildflyDemoExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/RelativeWildflyDemoExampleAdapterTest.java
@@ -4,7 +4,6 @@ package org.keycloak.testsuite.adapter.example;
  *
  * @author tkyjovsk
  */
-//@AdapterLibsLocationProperty("adapter.libs.eap")
 public class RelativeWildflyDemoExampleAdapterTest extends AbstractDemoExampleAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/RelativeWildflyJSConsoleExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/RelativeWildflyJSConsoleExampleAdapterTest.java
index 3807997..7bf44bc 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/RelativeWildflyJSConsoleExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/RelativeWildflyJSConsoleExampleAdapterTest.java
@@ -4,7 +4,6 @@ package org.keycloak.testsuite.adapter.example;
  *
  * @author tkyjovsk
  */
-//@AdapterLibsLocationProperty("adapter.libs.eap")
 public class RelativeWildflyJSConsoleExampleAdapterTest extends AbstractJSConsoleExampleAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/RelativeWildflySAMLExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/RelativeWildflySAMLExampleAdapterTest.java
index 303f0b4..56fa580 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/RelativeWildflySAMLExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/RelativeWildflySAMLExampleAdapterTest.java
@@ -4,7 +4,6 @@ package org.keycloak.testsuite.adapter.example;
  *
  * @author mhajas
  */
-//@AdapterLibsLocationProperty("adapter.libs.eap")
 public class RelativeWildflySAMLExampleAdapterTest extends AbstractSAMLExampleAdapterTest {
 
 }
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/RelativeWildflyOIDCAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/RelativeWildflyOIDCAdapterTest.java
index dd7b733..09ed2bc 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/RelativeWildflyOIDCAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/RelativeWildflyOIDCAdapterTest.java
@@ -6,7 +6,6 @@ import org.keycloak.testsuite.adapter.servlet.AbstractDemoServletsAdapterTest;
  *
  * @author tkyjovsk
  */
-//@AdapterLibsLocationProperty("adapter.libs.eap")
 public class RelativeWildflyOIDCAdapterTest extends AbstractDemoServletsAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/RelativeWildflyOIDCSessionAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/RelativeWildflyOIDCSessionAdapterTest.java
index 021d25b..060af61 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/RelativeWildflyOIDCSessionAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/RelativeWildflyOIDCSessionAdapterTest.java
@@ -6,7 +6,6 @@ import org.keycloak.testsuite.adapter.servlet.AbstractSessionServletAdapterTest;
  *
  * @author tkyjovsk
  */
-//@AdapterLibsLocationProperty("adapter.libs.eap")
 public class RelativeWildflyOIDCSessionAdapterTest extends AbstractSessionServletAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/RelativeWildflySAMLAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/RelativeWildflySAMLAdapterTest.java
index 0413cee..ea3afa6 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/RelativeWildflySAMLAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/relative/wildfly/src/test/java/org/keycloak/testsuite/adapter/RelativeWildflySAMLAdapterTest.java
@@ -5,7 +5,6 @@ import org.keycloak.testsuite.adapter.servlet.AbstractSAMLServletsAdapterTest;
 /**
  * @author mhajas
  */
-//@AdapterLibsLocationProperty("adapter.libs.eap")
 public class RelativeWildflySAMLAdapterTest extends AbstractSAMLServletsAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/pom.xml
index 03ee852..b07ae38 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-adapters-jboss</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.1.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-adapters-remote</artifactId>
@@ -49,6 +49,11 @@
             <artifactId>commons-io</artifactId> 
             <version>2.4</version> 
         </dependency> 
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-csv</artifactId>
+            <version>1.2</version>
+        </dependency>
     </dependencies>
     
     <build>
@@ -157,7 +162,7 @@
                                 <warmup.load>1</warmup.load>
                                 <warmup.duration>10</warmup.duration>
                                 <max.iterations>0</max.iterations>
-                                <sleep.between.repeats>30</sleep.between.repeats>
+                                <sleep.between.loops>30</sleep.between.loops>
                             </systemPropertyVariables>
                         </configuration>
                     </plugin>
@@ -166,4 +171,4 @@
         </profile>
     </profiles>
     
-</project>
\ No newline at end of file
+</project>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/README.md b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/README.md
index a9bd7fd..40926cb 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/README.md
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/README.md
@@ -1,2 +1,65 @@
-# 
+# Keycloak Adapter Tests - JBoss Remote
+
+## Performance Tests
+
+### Parameters
+
+* Warmup phase
+ - `warmup.load` Load during warmup phase (# of clients).
+ - `warmup.duration` Duration of warmup phase in seconds.
+* Measuremet iterations
+ - `initial.load` Load for the initial measurement iteration (# of clients).
+ - `load.increase` How many clients to add after each iteration.
+ - `load.increase.rate` How many clients to add per second.
+ - `measurement.duration` Duration of measurement iteration (in seconds).
+* Limits
+ - `max.iterations`
+ - `max.threads`
+* Other
+ - `sleep.between.loops` Sleep period between scenario loops.
+
+### Generated Load
+
+Warmup phase and measurement iterations with load-increase phases in between.
+
+    load
+
+    ^
+    │
+    │                                                                   /
+    │                                                         _________/
+    │                                                       /|         |
+    │                                                      / |         |
+    │                                            _________/  |         |
+    │                                          /|         |  |         |
+    │                                         / |         |  |         |
+    │                               _________/  |         |  |         |
+    │                             /│         |  |         |  |         |
+    │                            / |         |  |         |  |         |
+    │                  _________/  |         |  |         |  |         |
+    │                /|         |  |         |  |         |  |         |
+    │   ____________/ |         |  |         |  |         |  |         |
+    │ /|            | |         |  |         |  |         |  |         |
+    │/ |            | |         |  |         |  |         |  |         |
+    └──|────────────|─|─────────|──|─────────|──|─────────|──|─────────|───────> time
+
+        <--warmup-->   <--it.1->    <--it.2->    <--it.3->    <--it.4->
+
+
+### Login-Logout Test Scenario
+
+#### Collected Statistics
+
+ - ACCESS_REQUEST_TIME
+ - LOGIN_REQUEST_TIME
+ - LOGIN_VERIFY_REQUEST_TIME
+ - LOGOUT_REQUEST_TIME
+ - LOGOUT_VERIFY_REQUEST_TIME
+
+#### Parameters
+
+* Limits
+ - `max.login.time.average` Maximum accepted average value of LOGIN_REQUEST_TIME.
+ - `max.logout.time.average` Maximum accepted average value of LOGOUT_REQUEST_TIME.
+ - `max.timeout.percentage` Maximum accepted timeout percentage for all statistics.
 
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/htmlunit/HtmlUnitLoginLogoutPerfTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/htmlunit/HtmlUnitLoginLogoutPerfTest.java
index b279098..de8e29f 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/htmlunit/HtmlUnitLoginLogoutPerfTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/htmlunit/HtmlUnitLoginLogoutPerfTest.java
@@ -13,18 +13,19 @@ import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
 import org.keycloak.testsuite.performance.page.AppProfileJEE;
 import org.openqa.selenium.By;
-import static org.keycloak.testsuite.performance.LoginLogoutParameters.AVERAGE_LOGIN_TIME_LIMIT;
-import static org.keycloak.testsuite.performance.LoginLogoutParameters.AVERAGE_LOGOUT_TIME_LIMIT;
-import static org.keycloak.testsuite.performance.LoginLogoutParameters.LOGIN_REQUEST_TIME;
-import static org.keycloak.testsuite.performance.LoginLogoutParameters.LOGOUT_REQUEST_TIME;
-import static org.keycloak.testsuite.performance.LoginLogoutParameters.ACCESS_REQUEST_TIME;
-import static org.keycloak.testsuite.performance.LoginLogoutParameters.LOGIN_VERIFY_REQUEST_TIME;
-import static org.keycloak.testsuite.performance.LoginLogoutParameters.LOGOUT_VERIFY_REQUEST_TIME;
+import static org.keycloak.testsuite.performance.LoginLogoutTestParameters.LOGIN_REQUEST_TIME;
+import static org.keycloak.testsuite.performance.LoginLogoutTestParameters.LOGOUT_REQUEST_TIME;
+import static org.keycloak.testsuite.performance.LoginLogoutTestParameters.ACCESS_REQUEST_TIME;
+import static org.keycloak.testsuite.performance.LoginLogoutTestParameters.LOGIN_VERIFY_REQUEST_TIME;
+import static org.keycloak.testsuite.performance.LoginLogoutTestParameters.LOGOUT_VERIFY_REQUEST_TIME;
 import org.keycloak.testsuite.performance.PerformanceTest;
-import static org.junit.Assert.assertTrue;
 import org.keycloak.testsuite.performance.OperationTimeoutException;
-import static org.keycloak.testsuite.util.IOUtil.loadRealm;
 import org.openqa.selenium.TimeoutException;
+import org.keycloak.testsuite.performance.PerformanceMeasurement;
+import org.keycloak.testsuite.performance.LoginLogoutTestParameters;
+import static org.junit.Assert.assertTrue;
+import static org.keycloak.testsuite.performance.LoginLogoutTestParameters.PASSWORD_HASH_ITERATIONS;
+import static org.keycloak.testsuite.util.IOUtil.loadRealm;
 
 /**
  *
@@ -65,7 +66,9 @@ public class HtmlUnitLoginLogoutPerfTest extends HtmlUnitPerformanceTest {
 
     @Override
     public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
-        testRealms.add(loadRealm("/examples-realm.json"));
+        RealmRepresentation examplesRealm = loadRealm("/examples-realm.json");
+        examplesRealm.setPasswordPolicy("hashIterations(" + PASSWORD_HASH_ITERATIONS + ")");
+        testRealms.add(examplesRealm);
     }
 
     @Before
@@ -83,16 +86,15 @@ public class HtmlUnitLoginLogoutPerfTest extends HtmlUnitPerformanceTest {
     }
 
     @Override
-    protected boolean isLatestResultsWithinLimits() {
-        return getLatestResults().get(LOGIN_REQUEST_TIME).getAverage() < AVERAGE_LOGIN_TIME_LIMIT
-                && getLatestResults().get(LOGOUT_REQUEST_TIME).getAverage() < AVERAGE_LOGOUT_TIME_LIMIT;
+    protected boolean isMeasurementWithinLimits(PerformanceMeasurement measurement) {
+        return LoginLogoutTestParameters.isMeasurementWithinLimits(measurement);
     }
 
     public class Runnable extends HtmlUnitPerformanceTest.Runnable {
 
         @Override
         public void performanceScenario() throws Exception {
-            LOG.debug(String.format("Starting login-logout scenario #%s", getRepeatCounter()));
+            LOG.trace(String.format("Starting login-logout scenario #%s", getLoopCounter()));
             driver.manage().deleteAllCookies();
 
             // ACCESS
@@ -104,7 +106,7 @@ public class HtmlUnitLoginLogoutPerfTest extends HtmlUnitPerformanceTest {
             } catch (TimeoutException ex) {
                 throw new OperationTimeoutException(ACCESS_REQUEST_TIME, ex);
             }
-            metrics.addValue(ACCESS_REQUEST_TIME, timer.getElapsedTime());
+            statistics.addValue(ACCESS_REQUEST_TIME, timer.getElapsedTime());
 
             // LOGIN
             LOG.trace("Logging in");
@@ -119,7 +121,7 @@ public class HtmlUnitLoginLogoutPerfTest extends HtmlUnitPerformanceTest {
             } catch (TimeoutException ex) {
                 throw new OperationTimeoutException(LOGIN_REQUEST_TIME, ex);
             }
-            metrics.addValue(LOGIN_REQUEST_TIME, timer.getElapsedTime());
+            statistics.addValue(LOGIN_REQUEST_TIME, timer.getElapsedTime());
 
             // VERIFY LOGIN
             LOG.trace("Verifying login");
@@ -130,7 +132,7 @@ public class HtmlUnitLoginLogoutPerfTest extends HtmlUnitPerformanceTest {
             } catch (TimeoutException ex) {
                 throw new OperationTimeoutException(LOGIN_VERIFY_REQUEST_TIME, ex);
             }
-            metrics.addValue(LOGIN_VERIFY_REQUEST_TIME, timer.getElapsedTime());
+            statistics.addValue(LOGIN_VERIFY_REQUEST_TIME, timer.getElapsedTime());
 
             // LOGOUT
             LOG.trace("Logging out");
@@ -141,7 +143,7 @@ public class HtmlUnitLoginLogoutPerfTest extends HtmlUnitPerformanceTest {
             } catch (TimeoutException ex) {
                 throw new OperationTimeoutException(LOGOUT_REQUEST_TIME, ex);
             }
-            metrics.addValue(LOGOUT_REQUEST_TIME, timer.getElapsedTime());
+            statistics.addValue(LOGOUT_REQUEST_TIME, timer.getElapsedTime());
 
             // VERIFY LOGOUT
             LOG.trace("Verifying logout");
@@ -152,7 +154,7 @@ public class HtmlUnitLoginLogoutPerfTest extends HtmlUnitPerformanceTest {
             } catch (TimeoutException ex) {
                 throw new OperationTimeoutException(LOGOUT_VERIFY_REQUEST_TIME, ex);
             }
-            metrics.addValue(LOGOUT_VERIFY_REQUEST_TIME, timer.getElapsedTime());
+            statistics.addValue(LOGOUT_VERIFY_REQUEST_TIME, timer.getElapsedTime());
 
             LOG.trace("Logged out");
         }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/httpclient/HttpClientLoginLogoutPerfTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/httpclient/HttpClientLoginLogoutPerfTest.java
index 2a6e301..9590958 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/httpclient/HttpClientLoginLogoutPerfTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/httpclient/HttpClientLoginLogoutPerfTest.java
@@ -27,18 +27,19 @@ import org.junit.Before;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
 import org.keycloak.testsuite.performance.page.AppProfileJEE;
-import static org.keycloak.testsuite.performance.LoginLogoutParameters.AVERAGE_LOGIN_TIME_LIMIT;
-import static org.keycloak.testsuite.performance.LoginLogoutParameters.AVERAGE_LOGOUT_TIME_LIMIT;
-import static org.keycloak.testsuite.performance.LoginLogoutParameters.LOGIN_REQUEST_TIME;
-import static org.keycloak.testsuite.performance.LoginLogoutParameters.LOGOUT_REQUEST_TIME;
-import static org.keycloak.testsuite.performance.LoginLogoutParameters.ACCESS_REQUEST_TIME;
-import static org.keycloak.testsuite.performance.LoginLogoutParameters.LOGIN_VERIFY_REQUEST_TIME;
-import static org.keycloak.testsuite.performance.LoginLogoutParameters.LOGOUT_VERIFY_REQUEST_TIME;
+import static org.keycloak.testsuite.performance.LoginLogoutTestParameters.ACCESS_REQUEST_TIME;
+import static org.keycloak.testsuite.performance.LoginLogoutTestParameters.LOGIN_VERIFY_REQUEST_TIME;
+import static org.keycloak.testsuite.performance.LoginLogoutTestParameters.LOGOUT_VERIFY_REQUEST_TIME;
 import org.keycloak.testsuite.performance.PerformanceTest;
 import org.keycloak.testsuite.performance.OperationTimeoutException;
+import static org.keycloak.testsuite.performance.LoginLogoutTestParameters.LOGIN_REQUEST_TIME;
+import static org.keycloak.testsuite.performance.LoginLogoutTestParameters.LOGOUT_REQUEST_TIME;
+import org.keycloak.testsuite.performance.PerformanceMeasurement;
+import org.keycloak.testsuite.performance.LoginLogoutTestParameters;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.keycloak.testsuite.performance.LoginLogoutTestParameters.PASSWORD_HASH_ITERATIONS;
 import static org.keycloak.testsuite.util.IOUtil.loadRealm;
 
 /**
@@ -80,7 +81,9 @@ public class HttpClientLoginLogoutPerfTest extends HttpClientPerformanceTest {
 
     @Override
     public void addAdapterTestRealms(List<RealmRepresentation> testRealms) {
-        testRealms.add(loadRealm("/examples-realm.json"));
+        RealmRepresentation examplesRealm = loadRealm("/examples-realm.json");
+        examplesRealm.setPasswordPolicy("hashIterations(" + PASSWORD_HASH_ITERATIONS + ")");
+        testRealms.add(examplesRealm);
     }
 
     @Before
@@ -98,17 +101,15 @@ public class HttpClientLoginLogoutPerfTest extends HttpClientPerformanceTest {
     }
 
     @Override
-    protected boolean isLatestResultsWithinLimits() {
-        return isLatestTimeoutsWithinLimits()
-                && getLatestResults().get(LOGIN_REQUEST_TIME).getAverage() < AVERAGE_LOGIN_TIME_LIMIT
-                && getLatestResults().get(LOGOUT_REQUEST_TIME).getAverage() < AVERAGE_LOGOUT_TIME_LIMIT;
+    protected boolean isMeasurementWithinLimits(PerformanceMeasurement measurement) {
+        return LoginLogoutTestParameters.isMeasurementWithinLimits(measurement);
     }
 
     public class Runnable extends HttpClientPerformanceTest.Runnable {
 
         @Override
         public void performanceScenario() throws IOException, OperationTimeoutException {
-            LOG.debug(String.format("Starting login-logout scenario #%s", getRepeatCounter()));
+            LOG.trace(String.format("Starting login-logout scenario #%s", getLoopCounter()));
             context.getCookieStore().clear();
 
             // ACCESS
@@ -118,17 +119,17 @@ public class HttpClientLoginLogoutPerfTest extends HttpClientPerformanceTest {
             LOG.trace(getSecuredPageRequest);
             timer.reset();
             try (CloseableHttpResponse r = client.execute(getSecuredPageRequest, context)) {
-                assertEquals(HTTP_OK, r.getStatusLine().getStatusCode());
+                assertEquals("ACCESS_REQUEST OK", HTTP_OK, r.getStatusLine().getStatusCode());
                 logRedirects();
-                assertEquals(1, context.getRedirectLocations().size());
-                assertTrue(getLastRedirect().toASCIIString().startsWith(loginPageUrl));
+                assertEquals("ACCESS_REQUEST has 1 redirect", 1, context.getRedirectLocations().size());
+                assertTrue("ACCESS_REQUEST redirects to login page", getLastRedirect().toASCIIString().startsWith(loginPageUrl));
                 pageContent = EntityUtils.toString(r.getEntity());
             } catch (SocketException ex) {
                 throw new OperationTimeoutException(ACCESS_REQUEST_TIME, ex);
             } catch (SocketTimeoutException ex) {
                 throw new OperationTimeoutException(ACCESS_REQUEST_TIME, ex.bytesTransferred, ex);
             }
-            metrics.addValue(ACCESS_REQUEST_TIME, timer.getElapsedTime());
+            statistics.addValue(ACCESS_REQUEST_TIME, timer.getElapsedTime());
 
             // LOGIN
             final HttpPost loginRequest = new HttpPost(getLoginUrlFromPage(pageContent));
@@ -141,31 +142,31 @@ public class HttpClientLoginLogoutPerfTest extends HttpClientPerformanceTest {
             LOG.trace(loginRequest);
             timer.reset();
             try (CloseableHttpResponse r = client.execute(loginRequest, context)) {
-                assertEquals(HTTP_OK, r.getStatusLine().getStatusCode());
+                assertEquals("LOGIN_REQUEST OK", HTTP_OK, r.getStatusLine().getStatusCode());
                 logRedirects();
-                assertEquals(2, context.getRedirectLocations().size());
-                assertTrue(getLastRedirect().toASCIIString().equals(securedUrl));
+                assertEquals("LOGIN_REQUEST has 2 redirects", 2, context.getRedirectLocations().size());
+                assertTrue("LOGIN_REQUEST redirects to secured page", getLastRedirect().toASCIIString().equals(securedUrl));
             } catch (SocketException ex) {
                 throw new OperationTimeoutException(LOGIN_REQUEST_TIME, ex);
             } catch (SocketTimeoutException ex) {
                 throw new OperationTimeoutException(LOGIN_REQUEST_TIME, ex.bytesTransferred, ex);
             }
-            metrics.addValue(LOGIN_REQUEST_TIME, timer.getElapsedTime());
+            statistics.addValue(LOGIN_REQUEST_TIME, timer.getElapsedTime());
 
             // VERIFY LOGIN
             LOG.trace("Verifying login");
             LOG.trace(getSecuredPageRequest);
             timer.reset();
             try (CloseableHttpResponse r = client.execute(getSecuredPageRequest, context)) {
-                assertEquals(HTTP_OK, r.getStatusLine().getStatusCode());
+                assertEquals("LOGIN_VERIFY_REQUEST OK", HTTP_OK, r.getStatusLine().getStatusCode());
                 logRedirects();
-                assertEquals(0, context.getRedirectLocations().size());
+                assertEquals("LOGIN_VERIFY_REQUEST has 0 redirects", 0, context.getRedirectLocations().size());
             } catch (SocketException ex) {
                 throw new OperationTimeoutException(LOGIN_VERIFY_REQUEST_TIME, ex);
             } catch (SocketTimeoutException ex) {
                 throw new OperationTimeoutException(LOGIN_VERIFY_REQUEST_TIME, ex.bytesTransferred, ex);
             }
-            metrics.addValue(LOGIN_VERIFY_REQUEST_TIME, timer.getElapsedTime());
+            statistics.addValue(LOGIN_VERIFY_REQUEST_TIME, timer.getElapsedTime());
 
             // LOGOUT
             final HttpGet logoutRequest = new HttpGet(logoutUrl);
@@ -173,31 +174,31 @@ public class HttpClientLoginLogoutPerfTest extends HttpClientPerformanceTest {
             LOG.trace(logoutRequest);
             timer.reset();
             try (CloseableHttpResponse r = client.execute(logoutRequest, context)) {
-                assertEquals(HTTP_OK, r.getStatusLine().getStatusCode());
+                assertEquals("LOGOUT_REQUEST OK", HTTP_OK, r.getStatusLine().getStatusCode());
                 logRedirects();
-                assertEquals(0, context.getRedirectLocations().size());
+                assertEquals("LOGOUT_REQUEST has 0 redirects", 0, context.getRedirectLocations().size());
             } catch (SocketException ex) {
                 throw new OperationTimeoutException(LOGOUT_REQUEST_TIME, ex);
             } catch (SocketTimeoutException ex) {
                 throw new OperationTimeoutException(LOGOUT_REQUEST_TIME, ex.bytesTransferred, ex);
             }
-            metrics.addValue(LOGOUT_REQUEST_TIME, timer.getElapsedTime());
+            statistics.addValue(LOGOUT_REQUEST_TIME, timer.getElapsedTime());
 
             // VERIFY LOGOUT
             LOG.trace("Verifying logout");
             LOG.trace(getSecuredPageRequest);
             timer.reset();
             try (CloseableHttpResponse r = client.execute(getSecuredPageRequest, context)) {
-                assertEquals(HTTP_OK, r.getStatusLine().getStatusCode());
+                assertEquals("LOGOUT_VERIFY_REQUEST OK", HTTP_OK, r.getStatusLine().getStatusCode());
                 logRedirects();
-                assertEquals(1, context.getRedirectLocations().size());
-                assertTrue(getLastRedirect().toASCIIString().startsWith(loginPageUrl));
+                assertEquals("LOGOUT_VERIFY_REQUEST has 1 redirect", 1, context.getRedirectLocations().size());
+                assertTrue("LOGOUT_VERIFY_REQUEST redirects to login page", getLastRedirect().toASCIIString().startsWith(loginPageUrl));
             } catch (SocketException ex) {
                 throw new OperationTimeoutException(LOGOUT_VERIFY_REQUEST_TIME, ex);
             } catch (SocketTimeoutException ex) {
                 throw new OperationTimeoutException(LOGOUT_VERIFY_REQUEST_TIME, ex.bytesTransferred, ex);
             }
-            metrics.addValue(LOGOUT_VERIFY_REQUEST_TIME, timer.getElapsedTime());
+            statistics.addValue(LOGOUT_VERIFY_REQUEST_TIME, timer.getElapsedTime());
 
             LOG.trace("Logged out");
 
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/httpclient/HttpClientPerformanceTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/httpclient/HttpClientPerformanceTest.java
index d9aafaf..e6504e5 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/httpclient/HttpClientPerformanceTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/httpclient/HttpClientPerformanceTest.java
@@ -12,6 +12,7 @@ import org.apache.http.client.protocol.HttpClientContext;
 import org.apache.http.config.SocketConfig;
 import org.apache.http.impl.client.BasicCookieStore;
 import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
 import org.apache.http.impl.client.DefaultRedirectStrategy;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
@@ -45,6 +46,7 @@ public abstract class HttpClientPerformanceTest extends PerformanceTest {
                 .setDefaultCookieStore(new BasicCookieStore())
                 .setDefaultRequestConfig(getDefaultRequestConfig())
                 .setRedirectStrategy(new CustomRedirectStrategy())
+                .setRetryHandler(new DefaultHttpRequestRetryHandler(0, false))
                 .build();
     }
 
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/LoginLogoutTestParameters.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/LoginLogoutTestParameters.java
new file mode 100644
index 0000000..70dbaec
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/LoginLogoutTestParameters.java
@@ -0,0 +1,38 @@
+package org.keycloak.testsuite.performance;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class LoginLogoutTestParameters {
+
+    // Statistics
+    public static final String ACCESS_REQUEST_TIME = "ACCESS_REQUEST";
+    public static final String LOGIN_REQUEST_TIME = "LOGIN_REQUEST";
+    public static final String LOGIN_VERIFY_REQUEST_TIME = "LOGIN_VERIFY_REQUEST";
+    public static final String LOGOUT_REQUEST_TIME = "LOGOUT_REQUEST";
+    public static final String LOGOUT_VERIFY_REQUEST_TIME = "LOGOUT_VERIFY_REQUEST";
+
+    // Limits
+    public static final Integer MAX_LOGIN_TIME_AVERAGE = Integer.parseInt(System.getProperty("max.login.time.average", "500"));
+    public static final Integer MAX_LOGOUT_TIME_AVERAGE = Integer.parseInt(System.getProperty("max.logout.time.average", "500"));
+    public static final double MAX_TIMEOUT_PERCENTAGE = Double.parseDouble(System.getProperty("max.timeout.percentage", "0"));
+
+    // Other
+    public static final Integer PASSWORD_HASH_ITERATIONS = Integer.parseInt(System.getProperty("password.hash.iterations", "1"));
+    
+    public static boolean isMeasurementWithinLimits(PerformanceMeasurement measurement) {
+        return isTimeoutPercentageWithinLimits(measurement)
+                && measurement.getStatistics().get(LOGIN_REQUEST_TIME).getAverage() < MAX_LOGIN_TIME_AVERAGE
+                && measurement.getStatistics().get(LOGOUT_REQUEST_TIME).getAverage() < MAX_LOGOUT_TIME_AVERAGE;
+    }
+
+    public static boolean isTimeoutPercentageWithinLimits(PerformanceMeasurement measurement) {
+        boolean withinLimits = true;
+        for (String statistic : measurement.getStatistics().keySet()) {
+            withinLimits = withinLimits && measurement.getTimeoutPercentage(statistic) <= MAX_TIMEOUT_PERCENTAGE;
+        }
+        return withinLimits;
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/OperationTimeoutException.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/OperationTimeoutException.java
index deb5026..c364766 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/OperationTimeoutException.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/OperationTimeoutException.java
@@ -6,21 +6,21 @@ package org.keycloak.testsuite.performance;
  */
 public class OperationTimeoutException extends Exception {
 
-    private final String metric;
+    private final String statistic;
     private final long value;
 
-    public OperationTimeoutException(String metric, Throwable cause) {
-        this(metric, 0, cause);
+    public OperationTimeoutException(String statistic, Throwable cause) {
+        this(statistic, 0, cause);
     }
 
-    public OperationTimeoutException(String metric, long value, Throwable cause) {
+    public OperationTimeoutException(String statistic, long value, Throwable cause) {
         super(cause);
-        this.metric = metric;
+        this.statistic = statistic;
         this.value = value;
     }
 
-    public String getMetric() {
-        return metric;
+    public String getStatistic() {
+        return statistic;
     }
 
     public long getValue() {
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/PerformanceMeasurement.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/PerformanceMeasurement.java
new file mode 100644
index 0000000..32ec4a2
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/PerformanceMeasurement.java
@@ -0,0 +1,145 @@
+package org.keycloak.testsuite.performance;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVPrinter;
+import static org.keycloak.testsuite.performance.PerformanceTest.LOG;
+import org.keycloak.testsuite.performance.statistics.SimpleStatistics;
+import static org.keycloak.testsuite.util.IOUtil.PROJECT_BUILD_DIRECTORY;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class PerformanceMeasurement {
+
+    private final Date started;
+    private final int load;
+    private long durationMillis;
+    private SimpleStatistics statistics;
+    private SimpleStatistics timeoutStatistics;
+
+    public static final DateFormat ISO8601_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXX"); // should be compatible with `date --iso-8601=seconds`
+    public static final DateFormat RFC3339_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ"); // should be compatible with `date --rfc-3339=seconds`
+
+    public PerformanceMeasurement(int load) {
+        this.started = new Date();
+        this.load = load;
+    }
+
+    public SimpleStatistics getStatistics() {
+        return this.statistics;
+    }
+
+    public SimpleStatistics getTimeoutStatistics() {
+        return this.timeoutStatistics;
+    }
+
+    public void setStatistics(SimpleStatistics statistics, SimpleStatistics timeoutStatistics) {
+        this.durationMillis = new Date().getTime() - started.getTime();
+        if (durationMillis < 0) {
+            throw new IllegalStateException("Cannot set a negative duration.");
+        }
+        this.statistics = statistics;
+        this.timeoutStatistics = timeoutStatistics;
+    }
+
+    private void checkStatisticsNotNull() {
+        if (statistics == null || timeoutStatistics == null) {
+            throw new IllegalStateException("Iteration doesn't have any statistics set.");
+        }
+    }
+
+    public double getThroughput(String statistic) {
+        checkStatisticsNotNull();
+        return (double) statistics.get(statistic).getCount() / durationMillis * 1000;
+    }
+
+    public double getTimeoutPercentage(String statistic) {
+        checkStatisticsNotNull();
+        long timeouts = timeoutStatistics.containsKey(statistic) ? timeoutStatistics.get(statistic).getCount() : 0;
+        return (double) timeouts / statistics.get(statistic).getCount();
+    }
+
+    public static final Object[] HEADER = new String[]{
+        "Timestamp",
+        "Load",
+        "Duration",
+        "Count",
+        "Min",
+        "Max",
+        "Average",
+        "Standard Deviation",
+        "Timeout Percentage",
+        "Throughput",};
+
+    public List toRecord(String statistic) {
+        checkStatisticsNotNull();
+        List record = new ArrayList();
+        record.add(ISO8601_DATE_FORMAT.format(started));
+        record.add(load);
+        record.add(durationMillis);
+        record.add(statistics.get(statistic).getCount());
+        record.add(statistics.get(statistic).getMin());
+        record.add(statistics.get(statistic).getMax());
+        record.add(statistics.get(statistic).getAverage());
+        record.add(statistics.get(statistic).getStandardDeviation());
+        record.add(getTimeoutPercentage(statistic));
+        record.add(getThroughput(statistic));
+        return record;
+    }
+
+    public void printToCSV() {
+        printToCSV(null);
+    }
+
+    public void printToCSV(String testName) {
+        checkStatisticsNotNull();
+        for (String statistic : statistics.keySet()) {
+
+            File csvFile = new File(PROJECT_BUILD_DIRECTORY + "/measurements" + (testName == null ? "" : "/" + testName),
+                    statistic + ".csv");
+            boolean csvFileCreated = false;
+            if (!csvFile.exists()) {
+                try {
+                    csvFile.getParentFile().mkdirs();
+                    csvFileCreated = csvFile.createNewFile();
+                } catch (IOException ex) {
+                    throw new RuntimeException(ex);
+                }
+            }
+
+            try (BufferedWriter writer = new BufferedWriter(new FileWriter(csvFile, true))) {
+
+                CSVPrinter printer = new CSVPrinter(writer, CSVFormat.RFC4180);
+
+                if (csvFileCreated) {
+                    printer.printRecord(HEADER);
+                }
+                printer.printRecord(toRecord(statistic));
+
+                printer.flush();
+            } catch (IOException ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+    }
+
+    public void printToLog() {
+        LOG.info("Measurement results:");
+        LOG.info("Operation " + Arrays.toString(HEADER));
+        for (String statistic : statistics.keySet()) {
+            LOG.info(statistic + " " + toRecord(statistic));
+        }
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/PerformanceStatistics.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/PerformanceStatistics.java
new file mode 100644
index 0000000..5209bbb
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/PerformanceStatistics.java
@@ -0,0 +1,56 @@
+package org.keycloak.testsuite.performance;
+
+import java.util.concurrent.ConcurrentHashMap;
+import org.keycloak.testsuite.performance.statistics.DataHoldingUpdatableStatistic;
+import org.keycloak.testsuite.performance.statistics.MovingUpdatableStatistic;
+import org.keycloak.testsuite.performance.statistics.SimpleStatistics;
+import org.keycloak.testsuite.performance.statistics.UpdatableStatistics;
+import org.keycloak.testsuite.performance.statistics.UpdatableStatistic;
+
+/**
+ * PerformanceStatistics. Concurrent hash map of UpdatableStatistic objects, 
+ * type of which can be selected by the "statistic.type" property.
+ *
+ * @author tkyjovsk
+ */
+public class PerformanceStatistics extends ConcurrentHashMap<String, UpdatableStatistic> implements UpdatableStatistics {
+
+    public static final String STATISTIC_TYPE = System.getProperty("statistic.type", MovingUpdatableStatistic.STATISTIC_TYPE_PROPERTY_VALUE);
+
+    @Override
+    public void reset() {
+        clear();
+    }
+
+    private UpdatableStatistic createIfNullAndGet(String statistic) {
+        UpdatableStatistic updatableStatistic = get(statistic);
+        if (updatableStatistic == null) {
+            switch (STATISTIC_TYPE) {
+                case DataHoldingUpdatableStatistic.STATISTIC_TYPE_PROPERTY_VALUE:
+                    updatableStatistic = new DataHoldingUpdatableStatistic();
+                    break;
+                case MovingUpdatableStatistic.STATISTIC_TYPE_PROPERTY_VALUE:
+                    updatableStatistic = new DataHoldingUpdatableStatistic();
+                    break;
+                default:
+                    throw new IllegalStateException(String.format(
+                            "Unknown statistic type: '%s'. Supported values: %s | %s",
+                            STATISTIC_TYPE,
+                            DataHoldingUpdatableStatistic.STATISTIC_TYPE_PROPERTY_VALUE,
+                            MovingUpdatableStatistic.STATISTIC_TYPE_PROPERTY_VALUE));
+            }
+            put(statistic, updatableStatistic);
+        }
+        return updatableStatistic;
+    }
+
+    @Override
+    public void addValue(String statistic, long value) {
+        createIfNullAndGet(statistic).addValue(value);
+    }
+
+    public SimpleStatistics snapshot() {
+        return new SimpleStatistics(this);
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/PerformanceTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/PerformanceTest.java
index a4278e1..24c2d90 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/PerformanceTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/PerformanceTest.java
@@ -11,8 +11,6 @@ import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.keycloak.testsuite.adapter.AbstractExampleAdapterTest;
-import org.keycloak.testsuite.performance.metrics.impl.Results;
-import org.keycloak.testsuite.performance.metrics.impl.ResultsWithThroughput;
 import static org.keycloak.testsuite.util.WaitUtils.pause;
 
 /**
@@ -21,12 +19,12 @@ import static org.keycloak.testsuite.util.WaitUtils.pause;
  * @author tkyjovsk
  */
 public abstract class PerformanceTest extends AbstractExampleAdapterTest {
-
-    private final Logger LOG = Logger.getLogger(PerformanceTest.class);
-
+    
+    public static final Logger LOG = Logger.getLogger(PerformanceTest.class);
+    
     public static final Integer WARMUP_LOAD = Integer.parseInt(System.getProperty("warmup.load", "5"));
     public static final Integer WARMUP_DURATION = Integer.parseInt(System.getProperty("warmup.duration", "30"));
-
+    
     public static final Integer INITIAL_LOAD = Integer.parseInt(System.getProperty("initial.load", "10")); // load for the first iteration
     public static final Integer LOAD_INCREASE = Integer.parseInt(System.getProperty("load.increase", "10")); // how many threads to add before each iteration
     public static final Integer LOAD_INCREASE_RATE = Integer.parseInt(System.getProperty("load.increase.rate", "2")); // how fast to add the new threads per second
@@ -35,76 +33,83 @@ public abstract class PerformanceTest extends AbstractExampleAdapterTest {
 
     public static final Integer MAX_ITERATIONS = Integer.parseInt(System.getProperty("max.iterations", "10"));
     public static final Integer MAX_THREADS = Integer.parseInt(System.getProperty("max.threads", "1000"));
-
-    public static final Integer SLEEP_BETWEEN_REPEATS = Integer.parseInt(System.getProperty("sleep.between.repeats", "0"));
-
-    private final double AVERAGE_TIMEOUT_PERCENTAGE_LIMIT = Double.parseDouble(System.getProperty("average.timeout.percentage.limit", "0.01"));
-
+    
+    public static final Integer SLEEP_BETWEEN_LOOPS = Integer.parseInt(System.getProperty("sleep.between.loops", "0"));
+    public static final Integer THREADPOOL_TERMINATION_TIMEOUT = Integer.parseInt(System.getProperty("threadpool.termination.timeout", "10"));
+    public static final Integer ADDITIONAL_SLEEP_AFTER = Integer.parseInt(System.getProperty("additional.sleep.after", "0"));
+    
+    public static final String SCENARIO_TIME = "SCENARIO";
+    
     private int currentLoad;
-
+    
     private ExecutorService executorService;
+    
+    protected PerformanceStatistics statistics = new PerformanceStatistics();
+    protected PerformanceStatistics timeoutStatistics = new PerformanceStatistics(); // for keeping track of # of conn. timeout exceptions
 
-    protected PerformanceTestMetrics metrics = new PerformanceTestMetrics();
-    protected PerformanceTestMetrics timeouts = new PerformanceTestMetrics();
-
-    protected List<ResultsWithThroughput> resultsList = new ArrayList<>();
-    protected List<ResultsWithThroughput> timeoutResultsList = new ArrayList<>();
-
+    protected List<PerformanceMeasurement> measurements = new ArrayList<>();
+    
     @Before
     public void before() {
         if (WARMUP_LOAD > INITIAL_LOAD) {
             throw new IllegalArgumentException("'warmup.load' cannot be larger than 'initial.load'");
         }
-
+        
         executorService = Executors.newFixedThreadPool(MAX_THREADS);
         currentLoad = 0;
-
-        metrics.clear();
+        
+        statistics.clear();
+        timeoutStatistics.clear();
     }
-
+    
     @After
     public void after() throws IOException, InterruptedException {
         executorService.shutdown();
+        
         LOG.info("Waiting for threadpool termination.");
-        executorService.awaitTermination(10, TimeUnit.SECONDS);
+        executorService.awaitTermination(THREADPOOL_TERMINATION_TIMEOUT, TimeUnit.SECONDS);
+        pause(ADDITIONAL_SLEEP_AFTER * 1000);
+        
+        LOG.info("Logging out all sessions.");
+        testRealmResource().logoutAll();
     }
-
+    
     @Test
     public void test() {
-
+        
         increaseLoadBy(WARMUP_LOAD); // increase to warmup load
         warmup();
-
+        
         for (int i = 0; i < MAX_ITERATIONS; i++) {
-
+            
             int loadIncrease = (i == 0)
                     ? INITIAL_LOAD - WARMUP_LOAD // increase from warmup to initial load
-                    : LOAD_INCREASE; // increase load between iterations
+                    : LOAD_INCREASE; // increase load between measurements
 
             increaseLoadBy(loadIncrease);
             measurePerformance();
-
+            
             if (!isThereEnoughThreadsForNextIteration(LOAD_INCREASE)) {
                 LOG.warn("Threadpool capacity reached. Stopping the test.");
                 break;
             }
-            if (!isLatestResultsWithinLimits()) {
-                LOG.warn("The latest measurement surpassed expected limit. Stopping the test.");
+            if (!isLatestMeasurementWithinLimits()) {
+                LOG.warn("The latest measurement exceeded expected limit. Stopping the test.");
                 break;
             }
         }
-
+        
     }
-
+    
     private void warmup() {
         LOG.info("Warming up for " + WARMUP_DURATION + " s");
         pauseWithErrorChecking(WARMUP_DURATION * 1000);
     }
-
+    
     private boolean isThereEnoughThreadsForNextIteration(int loadIncrease) {
         return currentLoad + loadIncrease <= MAX_THREADS;
     }
-
+    
     private void increaseLoadBy(int loadIncrease) {
         if (loadIncrease < 0) {
             throw new IllegalArgumentException("Cannot increase load by a negative number (" + loadIncrease + ").");
@@ -113,7 +118,7 @@ public abstract class PerformanceTest extends AbstractExampleAdapterTest {
             throw new IllegalArgumentException("Cannot increase load beyond threadpool capacity (" + MAX_THREADS + ").");
         }
         if (loadIncrease > 0) {
-            LOG.info(String.format("Increasing load from %s to %s.", currentLoad, currentLoad + loadIncrease));
+            LOG.info(String.format("Increasing load from %s to %s at +%s clients/s.", currentLoad, currentLoad + loadIncrease, LOAD_INCREASE_RATE));
             for (int t = 0; t < loadIncrease; t++) {
                 executorService.submit(newRunnable());
                 currentLoad++;
@@ -121,95 +126,98 @@ public abstract class PerformanceTest extends AbstractExampleAdapterTest {
             }
         }
     }
-
+    
     private void measurePerformance() {
-        LOG.info("Measuring performance");
-        LOG.info("Iteration: " + (resultsList.size() + 1));
-        LOG.info("Duration: " + MEASUREMENT_DURATION + " s");
-        LOG.info("Load: " + currentLoad);
-
-        metrics.reset();
+        PerformanceMeasurement measurement = new PerformanceMeasurement(currentLoad);
+        statistics.reset();
+        timeoutStatistics.reset();
+        
+        LOG.info(String.format("Measuring performance. Iteration: %s, Load: %s, Duration: %s s", measurements.size() + 1, currentLoad, MEASUREMENT_DURATION));
+        
         pauseWithErrorChecking(MEASUREMENT_DURATION * 1000);
-        resultsList.add(metrics.computeMetrics());
-        timeoutResultsList.add(timeouts.computeMetrics());
-
-        getLatestResults().logResults(); // to file
-        LOG.info("Timeouts: " + getLatestTimeoutResults());
-    }
-
-    protected ResultsWithThroughput getLatestResults() {
-        return resultsList.isEmpty() ? null : resultsList.get(resultsList.size() - 1);
+        
+        measurement.setStatistics(
+                statistics.snapshot(),
+                timeoutStatistics.snapshot());
+        measurements.add(measurement);
+        
+        measurement.printToCSV(getTestName());
+        measurement.printToLog();
     }
-
-    protected Results getLatestTimeoutResults() {
-        return timeoutResultsList.isEmpty() ? null : timeoutResultsList.get(timeoutResultsList.size() - 1);
-    }
-
+    
     private Throwable error = null;
-
+    
     public synchronized Throwable getError() {
         return error;
     }
-
+    
     public synchronized void setError(Throwable error) {
         this.error = error;
     }
-
+    
     protected void pauseWithErrorChecking(long millis) {
         pauseWithErrorChecking(millis, 1000);
     }
-
-    protected void pauseWithErrorChecking(long millis, long checkIntervals) {
-        long count = millis / checkIntervals;
-        long remainder = millis % checkIntervals;
-        for (int i = 0; i < count + 1; i++) { // repeat 'count' times + once for remainder
-            if (i < count || remainder > 0) { // on last iteration check if any remainder
-                pause(checkIntervals);
+    
+    protected void pauseWithErrorChecking(long millis, long checkDurationMillis) {
+        long checkDurationMillisMin = Math.min(millis, checkDurationMillis);
+        long checkCount = millis / checkDurationMillis;
+        long remainder = millis % checkDurationMillis;
+        LOG.debug(String.format("Pause %s ms, checking errors once per %s ms", millis, checkDurationMillisMin));
+        for (int i = 0; i < checkCount + 1; i++) { // loop 'count' times + once for remainder
+            if (i < checkCount || remainder > 0) { // on last iteration check if any remainder
+                pause(checkDurationMillisMin);
                 if (getError() != null) {
                     throw new RuntimeException("PerformanceTestRunnable threw an exception. Stopping the test.", getError());
                 }
             }
         }
     }
-
-    protected abstract boolean isLatestResultsWithinLimits();
-
-    protected boolean isLatestTimeoutsWithinLimits() {
-        boolean socketTimeoutsWithinLimits = true;
-        for (String metric : getLatestResults().keySet()) {
-            long timemoutCount = getLatestTimeoutResults().containsKey(metric) ? getLatestTimeoutResults().get(metric).getCount() : 0;
-            double timeoutPercentage = (double) timemoutCount / getLatestResults().get(metric).getCount();
-            socketTimeoutsWithinLimits = socketTimeoutsWithinLimits && timeoutPercentage < AVERAGE_TIMEOUT_PERCENTAGE_LIMIT;
-        }
-        return socketTimeoutsWithinLimits;
+    
+    protected PerformanceMeasurement getLatestMeasurement() {
+        return measurements.isEmpty() ? null : measurements.get(measurements.size() - 1);
     }
-
+    
+    protected boolean isLatestMeasurementWithinLimits() {
+        return isMeasurementWithinLimits(getLatestMeasurement());
+    }
+    
+    protected abstract boolean isMeasurementWithinLimits(PerformanceMeasurement measurement);
+    
     protected abstract Runnable newRunnable();
-
-    public abstract class Runnable extends RepeatRunnable {
-
-        protected final Timer timer;
+    
+    public abstract class Runnable extends LoopingRunnable {
+        
+        protected final Timer timer; // for timing individual operations/requests
+        private final Timer scenarioTimer; // for timing the whole scenario
 
         public Runnable() {
-            super(SLEEP_BETWEEN_REPEATS * 1000);
+            super(SLEEP_BETWEEN_LOOPS * 1000);
             this.timer = new Timer();
+            this.scenarioTimer = new Timer();
         }
-
+        
         @Override
-        public void repeat() {
+        public void loop() {
             try {
+                scenarioTimer.reset();
                 performanceScenario();
+                statistics.addValue(SCENARIO_TIME, scenarioTimer.getElapsedTime());
             } catch (OperationTimeoutException ex) {
-                timeouts.addValue(ex.getMetric(), ex.getValue());
-                LOG.debug(String.format("Operatin %s timed out. Cause: %s.", ex.getMetric(), ex.getCause()));
+                timeoutStatistics.addValue(ex.getStatistic(), ex.getValue());
+                LOG.debug(String.format("Operation %s timed out. Cause: %s.", ex.getStatistic(), ex.getCause()));
             } catch (AssertionError | Exception ex) {
                 setError(ex);
                 throw new RuntimeException(ex);
             }
         }
-
+        
         public abstract void performanceScenario() throws Exception;
-
+        
     }
-
+    
+    public String getTestName() {
+        return this.getClass().getSimpleName();
+    }
+    
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/statistics/SimpleStatistics.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/statistics/SimpleStatistics.java
new file mode 100644
index 0000000..185e0c6
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/java/org/keycloak/testsuite/performance/statistics/SimpleStatistics.java
@@ -0,0 +1,17 @@
+package org.keycloak.testsuite.performance.statistics;
+
+import java.util.TreeMap;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+public class SimpleStatistics extends TreeMap<String, SimpleStatistic> implements Statistics<SimpleStatistic> {
+
+    public SimpleStatistics(Statistics statistics) {
+        for (Object statistic : statistics.keySet()) {
+            put(statistic.toString(), new SimpleStatistic((Statistic) statistics.get(statistic)));
+        }
+    }
+
+}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/resources/log4j.properties b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/resources/log4j.properties
index 7c833ee..b931f73 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/resources/log4j.properties
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/remote/src/test/resources/log4j.properties
@@ -8,6 +8,7 @@ log4j.appender.DEFAULT.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] [%t] 
 
 log4j.logger.org.keycloak=OFF
 log4j.logger.org.keycloak.testsuite=INFO
+log4j.logger.org.keycloak.testsuite.performance.PerformanceTest=INFO
 
 # HtmlUnit
 log4j.logger.org.keycloak.testsuite.performance.htmlunit.HtmlUnitLoginLogoutPerfTest=${logging.loginlogout}
@@ -17,14 +18,3 @@ log4j.logger.com.gargoylesoftware.htmlunit=OFF
 log4j.logger.org.keycloak.testsuite.performance.httpclient.HttpClientLoginLogoutPerfTest=${logging.loginlogout}
 log4j.logger.org.keycloak.testsuite.performance.httpclient.HttpClientPerformanceTest$CustomRedirectStrategy=OFF
 
-
-# RESULTS 
-
-log4j.appender.RESULTS=org.apache.log4j.FileAppender
-log4j.appender.RESULTS.file=target/results.log
-log4j.appender.RESULTS.immediateFlush=true
-log4j.appender.RESULTS.append=true
-log4j.appender.RESULTS.layout=org.apache.log4j.PatternLayout
-log4j.appender.RESULTS.layout.ConversionPattern=%d{HHmmss} %m%n
-
-log4j.logger.org.keycloak.testsuite.performance.metrics.impl.ResultsWithThroughput=INFO, RESULTS
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/pom.xml
index f2b6752..d120357 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-adapters-jboss</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-adapters-wildfly</artifactId>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/authorization/WildflyPhotozExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/authorization/WildflyPhotozExampleAdapterTest.java
new file mode 100644
index 0000000..f35217c
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/authorization/WildflyPhotozExampleAdapterTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.adapter.example.authorization;
+
+import org.keycloak.testsuite.adapter.example.authorization.AbstractPhotozExampleAdapterTest;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-wildfly")
+//@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflyPhotozExampleAdapterTest extends AbstractPhotozExampleAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/authorization/WildflyServletAuthzAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/authorization/WildflyServletAuthzAdapterTest.java
new file mode 100644
index 0000000..d50cf29
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/authorization/WildflyServletAuthzAdapterTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.adapter.example.authorization;
+
+import org.jboss.arquillian.container.test.api.RunAsClient;
+import org.keycloak.testsuite.adapter.example.authorization.AbstractDefaultAuthzConfigAdapterTest;
+import org.keycloak.testsuite.adapter.example.authorization.AbstractServletAuthzAdapterTest;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@RunAsClient
+@AppServerContainer("app-server-wildfly")
+//@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class WildflyServletAuthzAdapterTest extends AbstractServletAuthzAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflyBasicAuthExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflyBasicAuthExampleAdapterTest.java
index 6fda250..878f337 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflyBasicAuthExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflyBasicAuthExampleAdapterTest.java
@@ -7,7 +7,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-wildfly")
-//@AdapterLibsLocationProperty("adapter.libs.wildfly")
 public class WildflyBasicAuthExampleAdapterTest extends AbstractBasicAuthExampleAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflyDemoExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflyDemoExampleAdapterTest.java
index 41d53cb..588c28d 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflyDemoExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflyDemoExampleAdapterTest.java
@@ -7,7 +7,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-wildfly")
-//@AdapterLibsLocationProperty("adapter.libs.wildfly")
 public class WildflyDemoExampleAdapterTest extends AbstractDemoExampleAdapterTest {
 
 }
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflyJSConsoleExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflyJSConsoleExampleAdapterTest.java
index 7834461..bc9c7ae 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflyJSConsoleExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflyJSConsoleExampleAdapterTest.java
@@ -1,16 +1,13 @@
 
 package org.keycloak.testsuite.adapter.example;
 
-import org.keycloak.testsuite.arquillian.annotation.AdapterLibsLocationProperty;
 import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
 
-
 /**
  *
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-wildfly")
-//@AdapterLibsLocationProperty("adapter.libs.wildfly")
 public class WildflyJSConsoleExampleAdapterTest extends AbstractJSConsoleExampleAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflySAMLExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflySAMLExampleAdapterTest.java
index e8627aa..e118da1 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflySAMLExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/example/WildflySAMLExampleAdapterTest.java
@@ -6,7 +6,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author mhajas
  */
 @AppServerContainer("app-server-wildfly")
-//@AdapterLibsLocationProperty("adapter.libs.wildfly")
 public class WildflySAMLExampleAdapterTest extends AbstractSAMLExampleAdapterTest {
 
 }
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/WildflyOIDCAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/WildflyOIDCAdapterTest.java
index cd4ca90..51ba75e 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/WildflyOIDCAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/WildflyOIDCAdapterTest.java
@@ -8,7 +8,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-wildfly")
-//@AdapterLibsLocationProperty("adapter.libs.wildfly")
 public class WildflyOIDCAdapterTest extends AbstractDemoServletsAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/WildflyOIDCSessionAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/WildflyOIDCSessionAdapterTest.java
index e6324fa..0b3c03e 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/WildflyOIDCSessionAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/WildflyOIDCSessionAdapterTest.java
@@ -8,7 +8,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-wildfly")
-//@AdapterLibsLocationProperty("adapter.libs.wildfly")
 public class WildflyOIDCSessionAdapterTest extends AbstractSessionServletAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/WildflySAMLAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/WildflySAMLAdapterTest.java
index 8e00445..4ffed54 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/WildflySAMLAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/WildflySAMLAdapterTest.java
@@ -7,7 +7,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author mhajas
  */
 @AppServerContainer("app-server-wildfly")
-//@AdapterLibsLocationProperty("adapter.libs.wildfly")
 public class WildflySAMLAdapterTest extends AbstractSAMLServletsAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/WildflySAMLFilterAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/WildflySAMLFilterAdapterTest.java
new file mode 100644
index 0000000..d5e837d
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly/src/test/java/org/keycloak/testsuite/adapter/WildflySAMLFilterAdapterTest.java
@@ -0,0 +1,11 @@
+package org.keycloak.testsuite.adapter;
+
+import org.keycloak.testsuite.adapter.servlet.AbstractSAMLFilterServletAdapterTest;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ * @author mhajas
+ */
+@AppServerContainer("app-server-wildfly")
+public class WildflySAMLFilterAdapterTest extends AbstractSAMLFilterServletAdapterTest {
+}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/pom.xml
index 9adb331..41f3469 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-adapters-jboss</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-adapters-wildfly8</artifactId>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly8BasicAuthExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly8BasicAuthExampleAdapterTest.java
index 03aa572..dc4e7cc 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly8BasicAuthExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly8BasicAuthExampleAdapterTest.java
@@ -7,7 +7,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-wildfly8")
-//@AdapterLibsLocationProperty("adapter.libs.wildfly8")
 public class Wildfly8BasicAuthExampleAdapterTest extends AbstractBasicAuthExampleAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly8DefaultAuthzConfigAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly8DefaultAuthzConfigAdapterTest.java
new file mode 100644
index 0000000..110c53e
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly8DefaultAuthzConfigAdapterTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.adapter.example.authorization.AbstractDefaultAuthzConfigAdapterTest;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-wildfly8")
+//@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class Wildfly8DefaultAuthzConfigAdapterTest extends AbstractDefaultAuthzConfigAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly8DemoExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly8DemoExampleAdapterTest.java
index 9c6dd6c..8bb20d8 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly8DemoExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly8DemoExampleAdapterTest.java
@@ -7,7 +7,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-wildfly8")
-//@AdapterLibsLocationProperty("adapter.libs.wildfly8")
 public class Wildfly8DemoExampleAdapterTest extends AbstractDemoExampleAdapterTest {
 
 }
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly8PhotozExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly8PhotozExampleAdapterTest.java
new file mode 100644
index 0000000..86f4e4f
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly8PhotozExampleAdapterTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.adapter.example.authorization.AbstractPhotozExampleAdapterTest;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-wildfly8")
+//@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class Wildfly8PhotozExampleAdapterTest extends AbstractPhotozExampleAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/Wildfly8OIDCAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/Wildfly8OIDCAdapterTest.java
index 10f3d8d..f853f0d 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/Wildfly8OIDCAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/Wildfly8OIDCAdapterTest.java
@@ -8,7 +8,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-wildfly8")
-//@AdapterLibsLocationProperty("adapter.libs.wildfly8")
 public class Wildfly8OIDCAdapterTest extends AbstractDemoServletsAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/Wildfly8OIDCSessionAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/Wildfly8OIDCSessionAdapterTest.java
index 06f2df7..b78adbd 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/Wildfly8OIDCSessionAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly8/src/test/java/org/keycloak/testsuite/adapter/Wildfly8OIDCSessionAdapterTest.java
@@ -8,7 +8,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-wildfly8")
-//@AdapterLibsLocationProperty("adapter.libs.wildfly8")
 public class Wildfly8OIDCSessionAdapterTest extends AbstractSessionServletAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/pom.xml
index 4049cd3..220ffa8 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-adapters-jboss</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-adapters-wildfly9</artifactId>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly9BasicAuthExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly9BasicAuthExampleAdapterTest.java
index bb70e9e..9d68c8a 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly9BasicAuthExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly9BasicAuthExampleAdapterTest.java
@@ -7,7 +7,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-wildfly9")
-//@AdapterLibsLocationProperty("adapter.libs.wildfly9")
 public class Wildfly9BasicAuthExampleAdapterTest extends AbstractBasicAuthExampleAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly9DemoExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly9DemoExampleAdapterTest.java
index d1af7fa..26ce953 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly9DemoExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly9DemoExampleAdapterTest.java
@@ -7,7 +7,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-wildfly9")
-//@AdapterLibsLocationProperty("adapter.libs.wildfly9")
 public class Wildfly9DemoExampleAdapterTest extends AbstractDemoExampleAdapterTest {
 
 }
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly9SAMLExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly9SAMLExampleAdapterTest.java
index 7f55123..e5e5c27 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly9SAMLExampleAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/example/Wildfly9SAMLExampleAdapterTest.java
@@ -6,7 +6,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author mhajas
  */
 @AppServerContainer("app-server-wildfly9")
-//@AdapterLibsLocationProperty("adapter.libs.wildfly9")
 public class Wildfly9SAMLExampleAdapterTest extends AbstractSAMLExampleAdapterTest {
 
 }
\ No newline at end of file
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/Wildfly9OIDCAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/Wildfly9OIDCAdapterTest.java
index 621cd20..8c92df2 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/Wildfly9OIDCAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/Wildfly9OIDCAdapterTest.java
@@ -8,7 +8,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-wildfly9")
-//@AdapterLibsLocationProperty("adapter.libs.wildfly9")
 public class Wildfly9OIDCAdapterTest extends AbstractDemoServletsAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/Wildfly9OIDCSessionAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/Wildfly9OIDCSessionAdapterTest.java
index 3f7ddce..61436ea 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/Wildfly9OIDCSessionAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/Wildfly9OIDCSessionAdapterTest.java
@@ -8,7 +8,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author tkyjovsk
  */
 @AppServerContainer("app-server-wildfly9")
-//@AdapterLibsLocationProperty("adapter.libs.wildfly9")
 public class Wildfly9OIDCSessionAdapterTest extends AbstractSessionServletAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/Wildfly9SAMLAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/Wildfly9SAMLAdapterTest.java
index 77f8eb1..a042c78 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/Wildfly9SAMLAdapterTest.java
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/Wildfly9SAMLAdapterTest.java
@@ -7,7 +7,6 @@ import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
  * @author mhajas
  */
 @AppServerContainer("app-server-wildfly9")
-//@AdapterLibsLocationProperty("adapter.libs.wildfly9")
 public class Wildfly9SAMLAdapterTest extends AbstractSAMLServletsAdapterTest {
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/Wildfly9SAMLFilterAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/Wildfly9SAMLFilterAdapterTest.java
new file mode 100644
index 0000000..230cafa
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/jboss/wildfly9/src/test/java/org/keycloak/testsuite/adapter/Wildfly9SAMLFilterAdapterTest.java
@@ -0,0 +1,12 @@
+package org.keycloak.testsuite.adapter;
+
+import org.keycloak.testsuite.adapter.servlet.AbstractSAMLFilterServletAdapterTest;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+import org.keycloak.testsuite.arquillian.annotation.UseServletFilter;
+
+/**
+ * @author mhajas
+ */
+@AppServerContainer("app-server-wildfly9")
+public class Wildfly9SAMLFilterAdapterTest extends AbstractSAMLFilterServletAdapterTest {
+}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/karaf/fuse61/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/karaf/fuse61/pom.xml
index 1a88d93..226355f 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/karaf/fuse61/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/karaf/fuse61/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-adapters-karaf</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-adapters-fuse61</artifactId>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/karaf/fuse62/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/karaf/fuse62/pom.xml
index dfe0540..cb262de 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/karaf/fuse62/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/karaf/fuse62/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-adapters-karaf</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-adapters-fuse62</artifactId>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/karaf/fuse63/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/karaf/fuse63/pom.xml
index e438d44..14c3bb8 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/karaf/fuse63/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/karaf/fuse63/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-adapters-karaf</artifactId>
-        <version>1.9.3.Final-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-adapters-fuse63</artifactId>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/karaf/karaf3/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/karaf/karaf3/pom.xml
index 12479a5..20cc009 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/karaf/karaf3/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/karaf/karaf3/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-adapters-karaf</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-adapters-karaf3</artifactId>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/karaf/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/karaf/pom.xml
index 5942fe3..1bef4ae 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/karaf/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/karaf/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-adapters</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-adapters-karaf</artifactId>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/pom.xml
index 08e0638..9c49390 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-other</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-adapters</artifactId>
@@ -66,8 +66,7 @@
         </adapter.test.props>
         
         <app.server.home>${containers.home}/app-server-${app.server}</app.server.home>
-        <adapter.libs.mode>bundled</adapter.libs.mode>
-        <adapter.config.mode>bundled</adapter.config.mode>
+        <adapter.config.bundled>true</adapter.config.bundled>
         
     </properties>
         
@@ -169,9 +168,7 @@
 
                                 <adapter.test.props>${adapter.test.props}</adapter.test.props>
 
-                                <adapter.libs.home>${adapter.libs.home}</adapter.libs.home>
-                                <adapter.libs.mode>${adapter.libs.mode}</adapter.libs.mode>
-                                <adapter.config.mode>${adapter.config.mode}</adapter.config.mode>
+                                <adapter.config.bundled>${adapter.config.bundled}</adapter.config.bundled>
                             </systemPropertyVariables>
                         </configuration>
                     </plugin>
@@ -180,18 +177,6 @@
         </profile>
         
         <profile>
-            <id>adapter-libs-provided</id>
-            <activation>    
-                <property>
-                    <name>!adapter.libs.bundled</name>
-                </property>
-            </activation>
-            <properties>
-                <adapter.libs.mode>provided</adapter.libs.mode>
-            </properties>
-        </profile>
-        
-        <profile>
             <id>examples</id>
             <activation>
                 <property>
@@ -214,22 +199,22 @@
                                         <artifactItems>
                                             <artifactItem>
                                                 <groupId>org.keycloak.example.demo</groupId>
-                                                <artifactId>product-portal-example</artifactId>        
+                                                <artifactId>product-portal-example</artifactId>
                                                 <version>${project.version}</version>
                                                 <type>war</type>
                                             </artifactItem>
                                             <artifactItem>
                                                 <groupId>org.keycloak.example.demo</groupId>
-                                                <artifactId>customer-portal-example</artifactId>        
+                                                <artifactId>customer-portal-example</artifactId>
                                                 <version>${project.version}</version>
                                                 <type>war</type>
-                                            </artifactItem>                                        
+                                            </artifactItem>
                                             <artifactItem>
                                                 <groupId>org.keycloak.example.demo</groupId>
-                                                <artifactId>database-service</artifactId>        
+                                                <artifactId>database-service</artifactId>
                                                 <version>${project.version}</version>
                                                 <type>war</type>
-                                            </artifactItem>       
+                                            </artifactItem>
                                             <artifactItem>
                                                 <groupId>org.keycloak.testsuite</groupId>
                                                 <artifactId>integration-arquillian-test-apps-js-console</artifactId>
@@ -237,14 +222,20 @@
                                                 <type>war</type>
                                             </artifactItem>
                                             <artifactItem>
+                                                <groupId>org.keycloak.testsuite</groupId>
+                                                <artifactId>integration-arquillian-test-apps-js-database</artifactId>
+                                                <version>${project.version}</version>
+                                                <type>war</type>
+                                            </artifactItem>
+                                            <artifactItem>
                                                 <groupId>org.keycloak</groupId>
-                                                <artifactId>examples-multitenant</artifactId>        
+                                                <artifactId>examples-multitenant</artifactId>
                                                 <version>${project.version}</version>
                                                 <type>war</type>
-                                            </artifactItem>                    
+                                            </artifactItem>
                                             <artifactItem>
                                                 <groupId>org.keycloak</groupId>
-                                                <artifactId>examples-basicauth</artifactId>        
+                                                <artifactId>examples-basicauth</artifactId>
                                                 <version>${project.version}</version>
                                                 <type>war</type>
                                             </artifactItem>
@@ -278,6 +269,30 @@
                                                 <version>${project.version}</version>
                                                 <type>war</type>
                                             </artifactItem>
+                                            <artifactItem>
+                                                <groupId>org.keycloak.testsuite</groupId>
+                                                <artifactId>hello-world-authz-service</artifactId>
+                                                <version>${project.version}</version>
+                                                <type>war</type>
+                                            </artifactItem>
+                                            <artifactItem>
+                                                <groupId>org.keycloak.testsuite</groupId>
+                                                <artifactId>photoz-html5-client</artifactId>
+                                                <version>${project.version}</version>
+                                                <type>war</type>
+                                            </artifactItem>
+                                            <artifactItem>
+                                                <groupId>org.keycloak.testsuite</groupId>
+                                                <artifactId>photoz-restful-api</artifactId>
+                                                <version>${project.version}</version>
+                                                <type>war</type>
+                                            </artifactItem>
+                                            <artifactItem>
+                                                <groupId>org.keycloak.testsuite</groupId>
+                                                <artifactId>servlet-authz-app</artifactId>
+                                                <version>${project.version}</version>
+                                                <type>war</type>
+                                            </artifactItem>
                                         </artifactItems>
                                         <outputDirectory>${examples.home}</outputDirectory>
                                         <overWriteIfNewer>true</overWriteIfNewer>
@@ -293,7 +308,7 @@
                                         <artifactItems>
                                             <artifactItem>
                                                 <groupId>org.keycloak</groupId>
-                                                <artifactId>keycloak-examples-dist</artifactId>        
+                                                <artifactId>keycloak-examples-dist</artifactId>
                                                 <version>${project.version}</version>
                                                 <type>zip</type>
                                                 <includes>**/*realm.json,**/testsaml.json</includes>
@@ -303,7 +318,7 @@
                                                 <artifactId>integration-arquillian-test-apps-dist</artifactId>
                                                 <version>${project.version}</version>
                                                 <type>zip</type>
-                                                <includes>**/*realm.json,**/testsaml.json</includes>
+                                                <includes>**/*realm.json,**/*authz-service.json,**/testsaml.json</includes>
                                             </artifactItem>
                                         </artifactItems>
                                         <outputDirectory>${examples.home}</outputDirectory>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/tomcat/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/tomcat/pom.xml
index 462d4ff..b965bed 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/tomcat/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/tomcat/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-adapters</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-adapters-tomcat</artifactId>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/tomcat/tomcat7/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/tomcat/tomcat7/pom.xml
index 10162d8..2813c4d 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/tomcat/tomcat7/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/tomcat/tomcat7/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-adapters-tomcat</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-adapters-tomcat7</artifactId>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/tomcat/tomcat8/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/tomcat/tomcat8/pom.xml
index 5b75f65..b3c5578 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/tomcat/tomcat8/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/tomcat/tomcat8/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-adapters-tomcat</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-adapters-tomcat8</artifactId>
diff --git a/testsuite/integration-arquillian/tests/other/adapters/tomcat/tomcat8/src/test/java/org/keycloak/testsuite/adapter/example/Tomcat8DefaultAuthzConfigAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/tomcat/tomcat8/src/test/java/org/keycloak/testsuite/adapter/example/Tomcat8DefaultAuthzConfigAdapterTest.java
new file mode 100644
index 0000000..a7f900b
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/tomcat/tomcat8/src/test/java/org/keycloak/testsuite/adapter/example/Tomcat8DefaultAuthzConfigAdapterTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.adapter.example.authorization.AbstractDefaultAuthzConfigAdapterTest;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-tomcat8")
+//@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class Tomcat8DefaultAuthzConfigAdapterTest extends AbstractDefaultAuthzConfigAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/tomcat/tomcat8/src/test/java/org/keycloak/testsuite/adapter/example/Tomcat8PhotozExampleAdapterTest.java b/testsuite/integration-arquillian/tests/other/adapters/tomcat/tomcat8/src/test/java/org/keycloak/testsuite/adapter/example/Tomcat8PhotozExampleAdapterTest.java
new file mode 100644
index 0000000..33349aa
--- /dev/null
+++ b/testsuite/integration-arquillian/tests/other/adapters/tomcat/tomcat8/src/test/java/org/keycloak/testsuite/adapter/example/Tomcat8PhotozExampleAdapterTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite.adapter.example;
+
+import org.keycloak.testsuite.adapter.example.authorization.AbstractPhotozExampleAdapterTest;
+import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
+
+/**
+ *
+ * @author tkyjovsk
+ */
+@AppServerContainer("app-server-tomcat8")
+//@AdapterLibsLocationProperty("adapter.libs.wildfly")
+public class Tomcat8PhotozExampleAdapterTest extends AbstractPhotozExampleAdapterTest {
+
+}
diff --git a/testsuite/integration-arquillian/tests/other/adapters/tomcat/tomcat9/pom.xml b/testsuite/integration-arquillian/tests/other/adapters/tomcat/tomcat9/pom.xml
index 5de892f..c139409 100644
--- a/testsuite/integration-arquillian/tests/other/adapters/tomcat/tomcat9/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/adapters/tomcat/tomcat9/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-adapters-tomcat</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-adapters-tomcat9</artifactId>
diff --git a/testsuite/integration-arquillian/tests/other/clean-start/pom.xml b/testsuite/integration-arquillian/tests/other/clean-start/pom.xml
index 1fb3ff9..65e00bd 100644
--- a/testsuite/integration-arquillian/tests/other/clean-start/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/clean-start/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-other</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.1.0-SNAPSHOT</version>
     </parent>
     
     <artifactId>integration-arquillian-tests-smoke-clean-start</artifactId>
diff --git a/testsuite/integration-arquillian/tests/other/console/pom.xml b/testsuite/integration-arquillian/tests/other/console/pom.xml
index 2ddd65d..d9232e8 100644
--- a/testsuite/integration-arquillian/tests/other/console/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/console/pom.xml
@@ -24,13 +24,17 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-other</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-console</artifactId>
 
     <name>Admin Console UI Tests</name>
 
+    <properties>
+        <keycloak.theme.dir>${auth.server.home}/themes</keycloak.theme.dir>
+    </properties>
+
     <build>
         <pluginManagement>
             <plugins>
@@ -54,6 +58,14 @@
                         </execution>
                     </executions>
                 </plugin>
+                <plugin>
+                    <artifactId>maven-surefire-plugin</artifactId>
+                    <configuration>
+                        <systemProperties>
+                            <keycloak.theme.dir>${keycloak.theme.dir}</keycloak.theme.dir>
+                        </systemProperties>
+                    </configuration>
+                </plugin>
             </plugins>
         </pluginManagement>
     </build>
diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/authentication/PasswordPolicy.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/authentication/PasswordPolicy.java
index 39ce3f0..aef6e93 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/authentication/PasswordPolicy.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/authentication/PasswordPolicy.java
@@ -52,7 +52,9 @@ public class PasswordPolicy extends Authentication {
 
     public void removePolicy(Type policy) {
         getPolicyRow(policy).findElement(By.cssSelector("td.kc-action-cell")).click();
-        primaryButton.click();
+        if (!primaryButton.isDisplayed()) {
+            primaryButton.click();
+        }
     }
 
     public void editPolicy(Type policy, int value) {
@@ -75,10 +77,10 @@ public class PasswordPolicy extends Authentication {
 
     public enum Type {
 
-        HASH_ITERATIONS("HashIterations"), LENGTH("Length"), DIGITS("Digits"), LOWER_CASE("LowerCase"),
-        UPPER_CASE("UpperCase"), SPECIAL_CHARS("SpecialChars"), NOT_USERNAME("NotUsername"),
-        REGEX_PATTERN("RegexPattern"), PASSWORD_HISTORY("PasswordHistory"),
-        FORCE_EXPIRED_PASSWORD_CHANGE("ForceExpiredPasswordChange");
+        HASH_ITERATIONS("Hashing Iterations"), LENGTH("Minimum Length"), DIGITS("Digits"), LOWER_CASE("Lowercase Characters"),
+        UPPER_CASE("Uppercase Characters"), SPECIAL_CHARS("Special Characters"), NOT_USERNAME("Not Username"),
+        REGEX_PATTERN("Regular Expression"), PASSWORD_HISTORY("Not Recently Used"),
+        FORCE_EXPIRED_PASSWORD_CHANGE("Expire Password"), HASH_ALGORITHM("Hashing Algorithm");
 
         private String name;
 
diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java
index 945e72f..8f52163 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/Clients.java
@@ -62,32 +62,26 @@ public class Clients extends AdminConsoleRealm {
         }
 
         public void createClient() {
-            waitForBody();
             clickHeaderLink(CREATE);
         }
 
         public void importClient() {
-            waitForBody();
             clickHeaderLink(IMPORT);
         }
 
         public void clickClient(ClientRepresentation client) {
-            waitForBody();
             clickClient(client.getClientId());
         }
 
         public void clickClient(String clientId) {
-            waitForBody();
             body().findElement(linkText(clientId)).click();
         }
 
         public void editClient(String clientId) {
-            waitForBody();
             clickRowActionButton(getRowByLinkText(clientId), EDIT);
         }
 
         public void deleteClient(String clientId) {
-            waitForBody();
             clickRowActionButton(getRowByLinkText(clientId), DELETE);
         }
 
diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/credentials/ClientCredentialsForm.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/credentials/ClientCredentialsForm.java
index 51d1b24..d105a01 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/credentials/ClientCredentialsForm.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/credentials/ClientCredentialsForm.java
@@ -56,15 +56,18 @@ public class ClientCredentialsForm extends Form {
     public void regenerateSecret() {
         waitUntilElement(regenerateSecretButton).is().visible();
         regenerateSecretButton.click();
+        waitForPageToLoad(driver);
     }
 
     public void regenerateRegistrationAccessToken() {
         waitUntilElement(regenerateRegistrationAccessTokenButton).is().visible();
         regenerateRegistrationAccessTokenButton.click();
+        waitForPageToLoad(driver);
     }
 
     public void generateNewKeysAndCert() {
         waitUntilElement(generateNewKeysAndCert).is().visible();
         generateNewKeysAndCert.click();
+        waitForPageToLoad(driver);
     }
 }
diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/installation/ClientInstallationForm.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/installation/ClientInstallationForm.java
index 6ed4d9e..fbd415a 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/installation/ClientInstallationForm.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/installation/ClientInstallationForm.java
@@ -22,6 +22,7 @@
 package org.keycloak.testsuite.console.page.clients.installation;
 
 import org.keycloak.testsuite.page.Form;
+import org.keycloak.testsuite.util.WaitUtils;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
 import org.openqa.selenium.support.ui.Select;
@@ -40,6 +41,7 @@ public class ClientInstallationForm extends Form {
 
     public void setConfigFormat(String value) {
         configFormatsSelect.selectByVisibleText(value);
+        WaitUtils.waitForPageToLoad(driver);
     }
     
     public String getTextareaContent() {
diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/mappers/ClientMappers.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/mappers/ClientMappers.java
index 20634b7..98eead5 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/mappers/ClientMappers.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/mappers/ClientMappers.java
@@ -42,17 +42,14 @@ public class ClientMappers extends Client {
         }
 
         public void createMapper() {
-            waitForBody();
             clickHeaderLink(CREATE);
         }
 
         public void addBuiltin() {
-            waitForBody();
             clickHeaderLink(ADD_BUILTIN);
         }
 
         public void clickMapper(String mapperName) {
-            waitForBody();
             body().findElement(By.linkText(mapperName)).click();
         }
 
@@ -61,7 +58,6 @@ public class ClientMappers extends Client {
         }
 
         private void clickMapperActionButton(String mapperName, String buttonText) {
-            waitForBody();
             clickRowActionButton(getRowByLinkText(mapperName), buttonText);
         }
 
diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/mappers/CreateClientMappersForm.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/mappers/CreateClientMappersForm.java
index 9eae0be..70e4316 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/mappers/CreateClientMappersForm.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/clients/mappers/CreateClientMappersForm.java
@@ -1,8 +1,11 @@
 package org.keycloak.testsuite.console.page.clients.mappers;
 
+import org.jboss.arquillian.drone.api.annotation.Drone;
 import org.keycloak.testsuite.console.page.fragment.OnOffSwitch;
 import org.keycloak.testsuite.page.Form;
-import static org.keycloak.testsuite.util.WaitUtils.pause;
+
+import org.keycloak.testsuite.util.WaitUtils;
+import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
 import org.openqa.selenium.support.ui.Select;
@@ -44,40 +47,40 @@ public class CreateClientMappersForm extends Form {
     @FindBy(id = "mapperTypeCreate")
     private Select mapperTypeSelect;
 
-    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Property']//following-sibling::node()//input[@type='text']")
+    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Property')]//following-sibling::node()//input[@type='text']")
     private WebElement propertyInput;
 
-    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='User Attribute']//following-sibling::node()//input[@type='text']")
+    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'User Attribute')]//following-sibling::node()//input[@type='text']")
     private WebElement userAttributeInput;
 
-    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='User Session Note']//following-sibling::node()//input[@type='text']")
+    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'User Session Note')]//following-sibling::node()//input[@type='text']")
     private WebElement userSessionNoteInput;
 
-    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Multivalued']//following-sibling::node()//div[@class='onoffswitch']")
+    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Multivalued')]//following-sibling::node()//div[@class='onoffswitch']")
     private OnOffSwitch multivaluedInput;
 
     @FindBy(xpath = ".//button[text() = 'Select Role']/../..//input")
     private WebElement roleInput;
 
-    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='New Role Name']//following-sibling::node()//input[@type='text']")
+    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'New Role Name')]//following-sibling::node()//input[@type='text']")
     private WebElement newRoleInput;
 
-    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Token Claim Name']//following-sibling::node()//input[@type='text']")
+    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Token Claim Name')]//following-sibling::node()//input[@type='text']")
     private WebElement tokenClaimNameInput;
 
-    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Claim value']//following-sibling::node()//input[@type='text']")
+    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Claim value')]//following-sibling::node()//input[@type='text']")
     private WebElement tokenClaimValueInput;
 
-    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Claim JSON Type']//following-sibling::node()//select")
+    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Claim JSON Type')]//following-sibling::node()//select")
     private Select claimJSONTypeInput;
 
-    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Add to ID token']//following-sibling::node()//div[@class='onoffswitch']")
+    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Add to ID token')]//following-sibling::node()//div[@class='onoffswitch']")
     private OnOffSwitch addToIDTokenInput;
 
-    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Add to access token']//following-sibling::node()//div[@class='onoffswitch']")
+    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Add to access token')]//following-sibling::node()//div[@class='onoffswitch']")
     private OnOffSwitch addToAccessTokenInput;
     
-    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Full group path']//following-sibling::node()//div[@class='onoffswitch']")
+    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Full group path')]//following-sibling::node()//div[@class='onoffswitch']")
     private OnOffSwitch fullGroupPath;
 
     @FindBy(xpath = ".//button[text() = 'Select Role']")
@@ -87,16 +90,19 @@ public class CreateClientMappersForm extends Form {
     private RoleSelectorModalDialog roleSelectorModalDialog;
 
     public class RoleSelectorModalDialog {
+        @Drone
+        private WebDriver driver;
+
         @FindBy(id = "available")
         private Select realmAvailable;
-        @FindBy(xpath = ".//button[@tooltip='Select realm role']")
+        @FindBy(xpath = ".//button[@tooltip='Select realm role' and not(@disabled)]")
         private WebElement selectRealmRoleButton;
         
         @FindBy(id = "available-client")
         private Select clientAvailable;
         @FindBy(id = "clients")
         private Select clientSelect;
-        @FindBy(xpath = ".//button[@tooltip='Select client role']")
+        @FindBy(xpath = ".//button[@tooltip='Select client role' and not(@disabled)]")
         private WebElement selectClientRoleButton;
         @FindBy(xpath = ".//button[@class='close']")
         private WebElement closeButton;
@@ -109,8 +115,9 @@ public class CreateClientMappersForm extends Form {
             if (roleName != null) {
                 realmAvailable.selectByVisibleText(roleName);
             }
+            WaitUtils.pause(1000);
             selectRealmRoleButton.click();
-            pause(500); // wait for the modal dialog to fade out
+            WaitUtils.waitForModalFadeOut(driver);
         }
         
         public void selectClientRole(String clientName, String roleName) {
@@ -118,8 +125,9 @@ public class CreateClientMappersForm extends Form {
                 clientSelect.selectByVisibleText(clientName);
                 clientAvailable.selectByVisibleText(roleName);
             }
+            WaitUtils.pause(1000);
             selectClientRoleButton.click();
-            pause(500); // wait for the modal dialog to fade out
+            WaitUtils.waitForModalFadeOut(driver);
         }
     }
     
@@ -263,25 +271,25 @@ public class CreateClientMappersForm extends Form {
     }
     
     //SAML
-    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Role attribute name']//following-sibling::node()//input[@type='text']")
+    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Role attribute name')]//following-sibling::node()//input[@type='text']")
     private WebElement roleAttributeNameInput;
     
-    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Friendly Name']//following-sibling::node()//input[@type='text']")
+    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Friendly Name')]//following-sibling::node()//input[@type='text']")
     private WebElement friendlyNameInput;
     
-    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='SAML Attribute NameFormat']//following-sibling::node()//select")
+    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'SAML Attribute NameFormat')]//following-sibling::node()//select")
     private Select samlAttributeNameFormatSelect;
     
-    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Single Role Attribute']//following-sibling::node()//div[@class='onoffswitch']")
+    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Single Role Attribute')]//following-sibling::node()//div[@class='onoffswitch']")
     private OnOffSwitch singleRoleAttributeSwitch;
     
-    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Attribute value']//following-sibling::node()//input[@type='text']")
+    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Attribute value')]//following-sibling::node()//input[@type='text']")
     private WebElement attributeValueInput;
     
-    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Group attribute name']//following-sibling::node()//input[@type='text']")
+    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Group attribute name')]//following-sibling::node()//input[@type='text']")
     private WebElement groupAttributeNameInput;
     
-    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[text()='Single Group Attribute']//following-sibling::node()//div[@class='onoffswitch']")
+    @FindBy(xpath = ".//div[@properties='model.mapperType.properties']//label[contains(text(),'Single Group Attribute')]//following-sibling::node()//div[@class='onoffswitch']")
     private OnOffSwitch singleGroupAttributeSwitch;
     
     public void setRoleAttributeName(String value) {
diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/realm/ThemeSettings.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/realm/ThemeSettings.java
index 2392c7c..4095cc9 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/realm/ThemeSettings.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/realm/ThemeSettings.java
@@ -51,7 +51,6 @@ public class ThemeSettings extends RealmSettings {
     private OnOffSwitch internatEnabledSwitch;
 
     public void changeLoginTheme(String themeName) {
-        waitUntilElement(By.id("loginTheme")).is().present();
         loginThemeSelect.selectByVisibleText(themeName);
     }
 
diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/roles/RoleCompositeRoles.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/roles/RoleCompositeRoles.java
index b4ab777..eabaf02 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/roles/RoleCompositeRoles.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/roles/RoleCompositeRoles.java
@@ -3,7 +3,6 @@ package org.keycloak.testsuite.console.page.roles;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -11,12 +10,12 @@ import java.util.Map;
 import java.util.Set;
 import org.keycloak.representations.idm.RoleRepresentation.Composites;
 import org.keycloak.testsuite.page.Form;
-import static org.keycloak.testsuite.util.WaitUtils.pause;
+
 import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
+
+import org.keycloak.testsuite.util.UIUtils;
 import org.openqa.selenium.By;
 import org.openqa.selenium.WebElement;
-import org.openqa.selenium.logging.LogEntries;
-import org.openqa.selenium.logging.LogEntry;
 import org.openqa.selenium.support.FindBy;
 import org.openqa.selenium.support.ui.Select;
 
@@ -156,22 +155,12 @@ public class RoleCompositeRoles extends Form {
 
     public boolean isAssignedRole(String role) {
         waitUntilElement(By.id("assigned")).is().present();
-        try {
-            assignedRealmRolesSelect.selectByVisibleText(role);
-        } catch (Exception ex) {
-            return false;
-        }
-        return true;
+        return UIUtils.selectContainsOption(assignedRealmRolesSelect, role);
     }
 
     public boolean isAssignedClientRole(String role) {
         waitUntilElement(By.id("assigned")).is().present();
-        try {
-            assignedClientRolesSelect.selectByVisibleText(role);
-        } catch (Exception ex) {
-            return false;
-        }
-        return true;
+        return UIUtils.selectContainsOption(assignedClientRolesSelect, role);
     }
 
     public void selectClientRole(String client) {
diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/roles/RolesTable.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/roles/RolesTable.java
index 3bec08d..e0a9a51 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/roles/RolesTable.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/roles/RolesTable.java
@@ -28,7 +28,6 @@ public class RolesTable extends DataTable {
     }
 
     public void clickRole(String name) {
-        waitForBody();
         clickRowByLinkText(name);
     }
 
diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/UserCredentials.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/UserCredentials.java
index 0652fa4..277dd67 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/UserCredentials.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/UserCredentials.java
@@ -42,7 +42,6 @@ public class UserCredentials extends User {
     }
 
     public void clickResetPasswordAndConfirm() {
-        waitUntilElement(resetPasswordButton);
         resetPasswordButton.click();
         modalDialog.ok();
     }
diff --git a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/Users.java b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/Users.java
index 82a4906..87bd600 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/Users.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/main/java/org/keycloak/testsuite/console/page/users/Users.java
@@ -17,7 +17,10 @@
  */
 package org.keycloak.testsuite.console.page.users;
 
+import org.jboss.arquillian.drone.api.annotation.Drone;
+import org.keycloak.testsuite.util.URLUtils;
 import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
 
@@ -27,6 +30,8 @@ import org.keycloak.representations.idm.UserRepresentation;
 
 import org.keycloak.testsuite.console.page.AdminConsoleRealm;
 import org.keycloak.testsuite.console.page.fragment.DataTable;
+
+import static org.keycloak.testsuite.util.WaitUtils.waitForPageToLoad;
 import static org.keycloak.testsuite.util.WaitUtils.waitUntilElement;
 import static org.openqa.selenium.By.*;
 
@@ -59,6 +64,9 @@ public class Users extends AdminConsoleRealm {
 
     public class UsersTable extends DataTable {
 
+        @Drone
+        private WebDriver driver;
+
         public List<UserRepresentation> searchUsers(String searchPattern) {
             search(searchPattern);
             return getUsersFromTableRows();
@@ -73,19 +81,18 @@ public class Users extends AdminConsoleRealm {
         }
 
         public void clickUser(String username) {
-            waitUntilElement(body()).is().present();
-            WebElement link = body().findElement(
-                    By.xpath(".//tr/td[./following::td[text()='" + username + "']]/a")
-            );
-            link.click();
+            URLUtils.navigateToUri(driver, getRowByUsername(username).findElement(By.xpath("./td[position()=1]/a")).getAttribute("href"), true);
+            waitForPageToLoad(driver);
         }
 
         public void editUser(String username) {
             clickRowActionButton(getRowByUsername(username), EDIT);
+            waitForPageToLoad(driver);
         }
 
         public void impersonateUser(String username) {
             clickRowActionButton(getRowByUsername(username), IMPERSONATE);
+            waitForPageToLoad(driver);
         }
 
         public void deleteUser(String username) {
@@ -137,11 +144,9 @@ public class Users extends AdminConsoleRealm {
         }
 
         protected WebElement getRowByUsername(String userName) {
-            WebElement row = body().findElement(
-                    By.xpath(".//tr[./td/following::td[text()='" + userName + "']]")
+            return body().findElement(
+                    By.xpath(".//tr[./td[position()=2 and text()='" + userName + "']]")
             );
-            waitUntilElement(row).is().present();
-            return row;
         }
 
     }
diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java
index d061210..dc81e13 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/AbstractConsoleTest.java
@@ -106,14 +106,12 @@ public abstract class AbstractConsoleTest extends AbstractAuthTest {
     }
 
     public void assertAlertSuccess() {
-        alert.waitUntilPresentAndClassSet();
-        assertTrue("Is not success; @class=" + alert.getAttributeClass(), alert.isSuccess());
+        assertTrue(alert.isSuccess());
         alert.close();
     }
 
     public void assertAlertDanger() {
-        alert.waitUntilPresentAndClassSet();
-        assertTrue("Is not danger; @class=" + alert.getAttributeClass(), alert.isDanger());
+        assertTrue(alert.isDanger());
         alert.close();
     }
 
diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authentication/PasswordPolicyTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authentication/PasswordPolicyTest.java
index f904613..e70acd4 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authentication/PasswordPolicyTest.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/authentication/PasswordPolicyTest.java
@@ -25,6 +25,7 @@ import org.keycloak.testsuite.console.AbstractConsoleTest;
 import org.keycloak.testsuite.console.page.authentication.PasswordPolicy;
 import org.keycloak.testsuite.console.page.users.UserCredentials;
 
+import static org.keycloak.testsuite.console.page.authentication.PasswordPolicy.Type.DIGITS;
 import static org.keycloak.testsuite.console.page.authentication.PasswordPolicy.Type.HASH_ITERATIONS;
 import static org.keycloak.testsuite.console.page.authentication.PasswordPolicy.Type.REGEX_PATTERN;
 
@@ -48,17 +49,17 @@ public class PasswordPolicyTest extends AbstractConsoleTest {
     @Test
     public void testAddAndRemovePolicy() {
         passwordPolicyPage.navigateTo();
-        passwordPolicyPage.addPolicy(HASH_ITERATIONS, 5);
-        passwordPolicyPage.removePolicy(HASH_ITERATIONS);
+        passwordPolicyPage.addPolicy(DIGITS, 5);
+        passwordPolicyPage.removePolicy(DIGITS);
         assertAlertSuccess();
     }
 
     @Test
     public void testInvalidPolicyValues() {
         passwordPolicyPage.navigateTo();
-        passwordPolicyPage.addPolicy(HASH_ITERATIONS, "asd");
+        passwordPolicyPage.addPolicy(DIGITS, "asd");
         assertAlertDanger();
-        passwordPolicyPage.removePolicy(HASH_ITERATIONS);
+        passwordPolicyPage.removePolicy(DIGITS);
 
         passwordPolicyPage.addPolicy(REGEX_PATTERN, "([");
         assertAlertDanger();
@@ -177,6 +178,12 @@ public class PasswordPolicyTest extends AbstractConsoleTest {
 
         testUserCredentialsPage.resetPassword("firstPassword");
         assertAlertDanger();
+
+        testUserCredentialsPage.resetPassword("thirdPassword");
+        assertAlertSuccess();
+
+        testUserCredentialsPage.resetPassword("firstPassword");
+        assertAlertSuccess();
     }
 
 }
diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java
index 877aa3f..5ba0484 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/clients/AbstractClientTest.java
@@ -53,7 +53,6 @@ public abstract class AbstractClientTest extends AbstractConsoleTest {
     }
 
     public void createClient(ClientRepresentation client) {
-        WaitUtils.waitUntilElement(By.tagName("body")).is().present();
         assertCurrentUrlEquals(clientsPage);
         clientsPage.table().createClient();
         createClientPage.form().setValues(client);
diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/ConfigTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/ConfigTest.java
index 2c44e5a..fabd63b 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/ConfigTest.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/ConfigTest.java
@@ -25,7 +25,9 @@ public class ConfigTest extends AbstractConsoleTest {
     @Test
     public void configLoginEventsTest() {
         configPage.form().setSaveEvents(true);
-        configPage.form().addSaveType("REGISTER_NODE");
+        // IE webdriver has problem with clicking not visible (scrolling is needed) items in the menu,
+        // so we need to select some type from the beginning of the menu
+        configPage.form().addSaveType("CLIENT_INFO");
         //after removeSavedType method stay input focused -> in phantomjs drop menu doesn't appear after first click
         configPage.form().removeSaveType("LOGIN");
         configPage.form().setExpiration("50", "Days");
@@ -35,7 +37,7 @@ public class ConfigTest extends AbstractConsoleTest {
         RealmRepresentation realm = testRealmResource().toRepresentation();
         assertTrue(realm.isEventsEnabled());
         assertFalse(realm.getEnabledEventTypes().contains("LOGIN"));
-        assertTrue(realm.getEnabledEventTypes().contains("REGISTER_NODE"));
+        assertTrue(realm.getEnabledEventTypes().contains("CLIENT_INFO"));
         assertEquals(4320000L, realm.getEventsExpiration().longValue());
     }
 
diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/LoginEventsTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/LoginEventsTest.java
index f53beef..f573e8f 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/LoginEventsTest.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/events/LoginEventsTest.java
@@ -40,6 +40,7 @@ public class LoginEventsTest extends AbstractConsoleTest {
 
     @Test
     public void userAccessEventsTest() {
+        deleteAllCookiesForTestRealm();
         testRealmAdminConsolePage.navigateTo();
         Users.setPasswordFor(testUser, "Wrong_password");
         testRealmLoginPage.form().login(testUser);
diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/realm/InternationalizationTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/realm/InternationalizationTest.java
index 785158d..090288b 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/realm/InternationalizationTest.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/realm/InternationalizationTest.java
@@ -11,7 +11,6 @@ import org.openqa.selenium.By;
 import org.openqa.selenium.WebElement;
 import org.openqa.selenium.support.FindBy;
 import static org.junit.Assert.*;
-import static org.keycloak.testsuite.util.WaitUtils.*;
 import static org.keycloak.testsuite.util.URLAssert.*;
 
 /**
@@ -32,7 +31,6 @@ public class InternationalizationTest extends AbstractRealmTest {
         themeSettingsPage.saveTheme();
         assertAlertSuccess();
         realmSettingsPage.setAdminRealm(AuthRealm.TEST);
-        accountPage.setAuthRealm(testRealmPage);
         deleteAllCookiesForTestRealm();
         deleteAllCookiesForMasterRealm();
     }
@@ -55,7 +53,7 @@ public class InternationalizationTest extends AbstractRealmTest {
         loginToTestRealmConsoleAs(testUser);
         assertConsoleLocale("Temas");
 
-        accountPage.navigateTo();
+        testRealmAccountPage.navigateTo();
         assertAccountLocale("Cuenta");
     }
 
@@ -64,11 +62,11 @@ public class InternationalizationTest extends AbstractRealmTest {
      */
     @Test
     public void accountInternationalization() {
-        accountPage.navigateTo();
+        testRealmAccountPage.navigateTo();
         loginPage.form().login(testUser);
 
         localeDropdown.selectByText("Français");
-        accountPage.navigateTo();
+        testRealmAccountPage.navigateTo();
         assertAccountLocale("Compte");
 
         deleteAllCookiesForTestRealm();
@@ -78,14 +76,12 @@ public class InternationalizationTest extends AbstractRealmTest {
     }
 
     private void assertConsoleLocale(String expected) {
-        pause(500);
         assertCurrentUrlEquals(realmSettingsPage);
         assertLocale(".//a[contains(@href,'/theme-settings')]", expected); // Themes
     }
 
     private void assertAccountLocale(String expected) {
-        pause(500);
-        assertCurrentUrlEquals(accountPage);
+        assertCurrentUrlEquals(testRealmAccountPage);
         assertLocale(".//div[contains(@class,'bs-sidebar')]/ul/li", expected); // Account
     }
 
@@ -95,7 +91,6 @@ public class InternationalizationTest extends AbstractRealmTest {
     }
 
     private void assertLocale(WebElement element, String expected) {
-        waitUntilElement(element);
         assertEquals(expected, element.getText());
     }
 }
diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/realm/LoginSettingsTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/realm/LoginSettingsTest.java
index 0a6b6a5..75f86a2 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/realm/LoginSettingsTest.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/realm/LoginSettingsTest.java
@@ -75,7 +75,6 @@ public class LoginSettingsTest extends AbstractRealmTest {
     public void beforeLoginSettingsTest() {
 //        tabs().login();
         loginSettingsPage.navigateTo();
-        assertCurrentUrlEquals(loginSettingsPage);
     }
     
     @Test
diff --git a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/realm/SecurityDefensesTest.java b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/realm/SecurityDefensesTest.java
index 9537661..1f47c1e 100644
--- a/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/realm/SecurityDefensesTest.java
+++ b/testsuite/integration-arquillian/tests/other/console/src/test/java/org/keycloak/testsuite/console/realm/SecurityDefensesTest.java
@@ -73,7 +73,7 @@ public class SecurityDefensesTest extends AbstractRealmTest {
 
     @Test
     public void maxLoginFailuresTest() throws InterruptedException {
-        final short secondsToWait = 3;
+        final short secondsToWait = 10; // For slower browsers/webdrivers (like IE) we need higher value
         final short maxLoginFailures = 2;
 
         bruteForceDetectionPage.form().setProtectionEnabled(true);
@@ -89,7 +89,7 @@ public class SecurityDefensesTest extends AbstractRealmTest {
 
     @Test
     public void quickLoginCheck() throws InterruptedException {
-        final short secondsToWait = 3;
+        final short secondsToWait = 10;
 
         bruteForceDetectionPage.form().setProtectionEnabled(true);
         bruteForceDetectionPage.form().setMaxLoginFailures("100");
@@ -104,7 +104,7 @@ public class SecurityDefensesTest extends AbstractRealmTest {
 
     @Test
     public void maxWaitLoginFailures() throws InterruptedException {
-        final short secondsToWait = 5;
+        final short secondsToWait = 15;
 
         bruteForceDetectionPage.form().setProtectionEnabled(true);
         bruteForceDetectionPage.form().setMaxLoginFailures("1");
@@ -120,7 +120,7 @@ public class SecurityDefensesTest extends AbstractRealmTest {
     @Test
     public void failureResetTime() throws InterruptedException {
         final short failureResetTime = 3;
-        final short waitIncrement = 3;
+        final short waitIncrement = 5;
 
         bruteForceDetectionPage.form().setProtectionEnabled(true);
         bruteForceDetectionPage.form().setMaxLoginFailures("1");
@@ -199,8 +199,8 @@ public class SecurityDefensesTest extends AbstractRealmTest {
 
         wait *= 1000;
 
-        log.debug("Wait: " + wait);
-        Thread.sleep(wait);
+        log.info("Wait: " + wait);
+        pause(wait);
 
         if (finalLogin) {
             testRealmLoginPage.form().login(testUser);
diff --git a/testsuite/integration-arquillian/tests/other/console_no_users/pom.xml b/testsuite/integration-arquillian/tests/other/console_no_users/pom.xml
index 9b70e76..63b1d5e 100644
--- a/testsuite/integration-arquillian/tests/other/console_no_users/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/console_no_users/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-other</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-console-no-users</artifactId>
diff --git a/testsuite/integration-arquillian/tests/other/jpa-performance/pom.xml b/testsuite/integration-arquillian/tests/other/jpa-performance/pom.xml
index 95bdc57..4876094 100644
--- a/testsuite/integration-arquillian/tests/other/jpa-performance/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/jpa-performance/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-other</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-jpa-performance</artifactId>
diff --git a/testsuite/integration-arquillian/tests/other/mod_auth_mellon/pom.xml b/testsuite/integration-arquillian/tests/other/mod_auth_mellon/pom.xml
index 4327228..247d622 100644
--- a/testsuite/integration-arquillian/tests/other/mod_auth_mellon/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/mod_auth_mellon/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests-other</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-other-mod_auth_mellon</artifactId>
diff --git a/testsuite/integration-arquillian/tests/other/pom.xml b/testsuite/integration-arquillian/tests/other/pom.xml
index 73c3205..bb238bf 100644
--- a/testsuite/integration-arquillian/tests/other/pom.xml
+++ b/testsuite/integration-arquillian/tests/other/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian-tests</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>integration-arquillian-tests-other</artifactId>
diff --git a/testsuite/integration-arquillian/tests/pom.xml b/testsuite/integration-arquillian/tests/pom.xml
index c3b3ccd..6c25059 100755
--- a/testsuite/integration-arquillian/tests/pom.xml
+++ b/testsuite/integration-arquillian/tests/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.keycloak.testsuite</groupId>
         <artifactId>integration-arquillian</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <packaging>pom</packaging>
@@ -173,6 +173,7 @@
                             <browser>${browser}</browser>
                             <firefox_binary>${firefox_binary}</firefox_binary>
 
+                            <project.version>${project.version}</project.version>
                         </systemPropertyVariables>
                         <properties>
                             <property>
@@ -736,6 +737,16 @@
                         </exclusion>
                     </exclusions>
                 </dependency>
+                <dependency>
+                    <groupId>org.subethamail</groupId>
+                    <artifactId>subethasmtp</artifactId>
+                    <exclusions>
+                        <exclusion>
+                            <groupId>org.slf4j</groupId>
+                            <artifactId>slf4j-api</artifactId>
+                        </exclusion>
+                    </exclusions>
+                </dependency>
 
                 <!-- Keycloak deps for tests -->
 
diff --git a/testsuite/jetty/jetty81/pom.xml b/testsuite/jetty/jetty81/pom.xml
index 6985589..e5c6058 100755
--- a/testsuite/jetty/jetty81/pom.xml
+++ b/testsuite/jetty/jetty81/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-testsuite-pom</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/testsuite/jetty/jetty91/pom.xml b/testsuite/jetty/jetty91/pom.xml
index b4a465f..6488eac 100755
--- a/testsuite/jetty/jetty91/pom.xml
+++ b/testsuite/jetty/jetty91/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-testsuite-pom</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/testsuite/jetty/jetty92/pom.xml b/testsuite/jetty/jetty92/pom.xml
index d109be0..384920c 100755
--- a/testsuite/jetty/jetty92/pom.xml
+++ b/testsuite/jetty/jetty92/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-testsuite-pom</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/testsuite/jetty/jetty93/src/test/java/org/keycloak/testsuite/Jetty9Test.java b/testsuite/jetty/jetty93/src/test/java/org/keycloak/testsuite/Jetty9Test.java
new file mode 100644
index 0000000..00603de
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/java/org/keycloak/testsuite/Jetty9Test.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite;
+
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.HandlerCollection;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.testsuite.adapter.AdapterTestStrategy;
+import org.keycloak.testsuite.rule.AbstractKeycloakRule;
+
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class Jetty9Test {
+    @ClassRule
+    public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() {
+        @Override
+        protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
+            AdapterTestStrategy.baseAdapterTestInitialization(session, manager, adminRealm, getClass());
+        }
+    };
+
+    public static Server server = null;
+
+
+    @BeforeClass
+    public static void initJetty() throws Exception {
+        server = new Server(8082);
+        List<Handler> list = new ArrayList<Handler>();
+        System.setProperty("app.server.base.url", "http://localhost:8082");
+        System.setProperty("my.host.name", "localhost");
+        URL dir = Jetty9Test.class.getResource("/adapter-test/demorealm.json");
+        File base = new File(dir.getFile()).getParentFile();
+        list.add(new WebAppContext(new File(base, "customer-portal").toString(), "/customer-portal"));
+        list.add(new WebAppContext(new File(base, "customer-db").toString(), "/customer-db"));
+        list.add(new WebAppContext(new File(base, "customer-db-error-page").toString(), "/customer-db-error-page"));
+        list.add(new WebAppContext(new File(base, "product-portal").toString(), "/product-portal"));
+        list.add(new WebAppContext(new File(base, "session-portal").toString(), "/session-portal"));
+        list.add(new WebAppContext(new File(base, "input-portal").toString(), "/input-portal"));
+        list.add(new WebAppContext(new File(base, "secure-portal").toString(), "/secure-portal"));
+
+
+
+        HandlerCollection handlers = new HandlerCollection();
+        handlers.setHandlers(list.toArray(new Handler[list.size()]));
+        server.setHandler(handlers);
+
+        server.start();
+    }
+
+
+
+    @AfterClass
+    public static void shutdownJetty() throws Exception {
+        try {
+            server.stop();
+            server.destroy();
+            Thread.sleep(100);
+        } catch (Exception e) {}
+    }
+
+    @Rule
+    public AdapterTestStrategy testStrategy = new AdapterTestStrategy("http://localhost:8081/auth", "http://localhost:8082", keycloakRule, true);
+
+    @Test
+    public void testLoginSSOAndLogout() throws Exception {
+        testStrategy.testLoginSSOAndLogout();
+    }
+
+    @Test
+    public void testSavedPostRequest() throws Exception {
+        testStrategy.testSavedPostRequest();
+    }
+
+    @Test
+    public void testServletRequestLogout() throws Exception {
+        testStrategy.testServletRequestLogout();
+    }
+
+    @Test
+    public void testLoginSSOIdle() throws Exception {
+        testStrategy.testLoginSSOIdle();
+
+    }
+
+    @Test
+    public void testLoginSSOIdleRemoveExpiredUserSessions() throws Exception {
+        testStrategy.testLoginSSOIdleRemoveExpiredUserSessions();
+    }
+
+    @Test
+    public void testLoginSSOMax() throws Exception {
+        testStrategy.testLoginSSOMax();
+    }
+
+    /**
+     * KEYCLOAK-518
+     * @throws Exception
+     */
+    @Test
+    public void testNullBearerToken() throws Exception {
+        testStrategy.testNullBearerToken();
+    }
+
+    /**
+     * KEYCLOAK-1368
+     * @throws Exception
+     */
+    @Test
+    public void testNullBearerTokenCustomErrorPage() throws Exception {
+        testStrategy.testNullBearerTokenCustomErrorPage();
+    }
+
+    /**
+     * KEYCLOAK-518
+     * @throws Exception
+     */
+    @Test
+    public void testBadUser() throws Exception {
+        testStrategy.testBadUser();
+    }
+
+    @Test
+    public void testVersion() throws Exception {
+        testStrategy.testVersion();
+    }
+
+
+    /**
+     * KEYCLOAK-732
+     *
+     * @throws Throwable
+     */
+    @Test
+    public void testSingleSessionInvalidated() throws Throwable {
+        testStrategy.testSingleSessionInvalidated();
+    }
+
+    /**
+     * KEYCLOAK-741
+     */
+    @Test
+    public void testSessionInvalidatedAfterFailedRefresh() throws Throwable {
+        testStrategy.testSessionInvalidatedAfterFailedRefresh();
+
+    }
+
+    /**
+     * KEYCLOAK-942
+     */
+    @Test
+    public void testAdminApplicationLogout() throws Throwable {
+        testStrategy.testAdminApplicationLogout();
+    }
+
+    /**
+     * KEYCLOAK-1216
+     */
+    @Test
+    public void testAccountManagementSessionsLogout() throws Throwable {
+        testStrategy.testAccountManagementSessionsLogout();
+    }
+}
diff --git a/testsuite/jetty/jetty93/src/test/java/org/keycloak/testsuite/JettySamlTest.java b/testsuite/jetty/jetty93/src/test/java/org/keycloak/testsuite/JettySamlTest.java
new file mode 100644
index 0000000..7f1ec98
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/java/org/keycloak/testsuite/JettySamlTest.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.testsuite;
+
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.HandlerCollection;
+import org.eclipse.jetty.webapp.WebAppContext;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.testsuite.keycloaksaml.SamlAdapterTestStrategy;
+import org.keycloak.testsuite.rule.AbstractKeycloakRule;
+import org.openqa.selenium.WebDriver;
+
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class JettySamlTest {
+    @Rule
+    public SamlAdapterTestStrategy testStrategy = new SamlAdapterTestStrategy("http://localhost:8081/auth", "http://localhost:8082", keycloakRule);
+    @ClassRule
+    public static AbstractKeycloakRule keycloakRule = new AbstractKeycloakRule() {
+        @Override
+        protected void configure(KeycloakSession session, RealmManager manager, RealmModel adminRealm) {
+            SamlAdapterTestStrategy.baseAdapterTestInitialization(session, manager, adminRealm, getClass());
+        }
+    };
+
+    public static Server server = null;
+
+
+    @BeforeClass
+    public static void initJetty() throws Exception {
+        server = new Server(8082);
+        List<Handler> list = new ArrayList<Handler>();
+        System.setProperty("app.server.base.url", "http://localhost:8082");
+        System.setProperty("my.host.name", "localhost");
+        URL dir = JettySamlTest.class.getResource("/keycloak-saml/testsaml.json");
+        File base = new File(dir.getFile()).getParentFile();
+        //list.add(new WebAppContext(new File(base, "customer-portal").toString(), "/customer-portal"));
+        list.add(new WebAppContext(new File(base, "simple-post").toString(), "/sales-post"));
+        list.add(new WebAppContext(new File(base, "simple-post2").toString(), "/sales-post2"));
+        list.add(new WebAppContext(new File(base, "simple-input").toString(), "/input-portal"));
+        list.add(new WebAppContext(new File(base, "signed-post").toString(), "/sales-post-sig"));
+        list.add(new WebAppContext(new File(base, "signed-post-email").toString(), "/sales-post-sig-email"));
+        list.add(new WebAppContext(new File(base, "signed-post-transient").toString(), "/sales-post-sig-transient"));
+        list.add(new WebAppContext(new File(base, "signed-post-persistent").toString(), "/sales-post-sig-persistent"));
+        list.add(new WebAppContext(new File(base, "signed-metadata").toString(), "/sales-metadata"));
+        list.add(new WebAppContext(new File(base, "signed-get").toString(), "/employee-sig"));
+        list.add(new WebAppContext(new File(base, "mappers").toString(), "/employee2"));
+        list.add(new WebAppContext(new File(base, "signed-front-get").toString(), "/employee-sig-front"));
+        list.add(new WebAppContext(new File(base, "bad-client-signed-post").toString(), "/bad-client-sales-post-sig"));
+        list.add(new WebAppContext(new File(base, "bad-realm-signed-post").toString(), "/bad-realm-sales-post-sig"));
+        list.add(new WebAppContext(new File(base, "encrypted-post").toString(), "/sales-post-enc"));
+        SamlAdapterTestStrategy.uploadSP("http://localhost:8081/auth");
+
+
+
+        HandlerCollection handlers = new HandlerCollection();
+        handlers.setHandlers(list.toArray(new Handler[list.size()]));
+        server.setHandler(handlers);
+
+        server.start();
+    }
+
+
+
+    @AfterClass
+    public static void shutdownJetty() throws Exception {
+        try {
+            server.stop();
+            server.destroy();
+            Thread.sleep(100);
+        } catch (Exception e) {}
+    }
+
+    @Test
+    public void testSavedPostRequest() throws Exception {
+        testStrategy.testSavedPostRequest();
+    }
+    @Test
+    public void testPostSimpleLoginLogoutIdpInitiatedRedirectTo() {
+        testStrategy.testPostSimpleLoginLogoutIdpInitiatedRedirectTo();
+    }
+
+
+    @Test
+    public void testErrorHandling() throws Exception {
+        testStrategy.testErrorHandling();
+    }
+
+    @Test
+    public void testPostSimpleLoginLogout() {
+        testStrategy.testPostSimpleLoginLogout();
+    }
+
+    @Test
+    public void testPostSimpleLoginLogoutIdpInitiated() {
+        testStrategy.testPostSimpleLoginLogoutIdpInitiated();
+    }
+
+    @Test
+    public void testPostSignedLoginLogout() {
+        testStrategy.testPostSignedLoginLogout();
+    }
+
+    @Test
+    public void testPostSignedLoginLogoutTransientNameID() {
+        testStrategy.testPostSignedLoginLogoutTransientNameID();
+    }
+
+    @Test
+    public void testPostSignedLoginLogoutPersistentNameID() {
+        testStrategy.testPostSignedLoginLogoutPersistentNameID();
+    }
+
+    @Test
+    public void testPostSignedLoginLogoutEmailNameID() {
+        testStrategy.testPostSignedLoginLogoutEmailNameID();
+    }
+
+    @Test
+    public void testAttributes() throws Exception {
+        testStrategy.testAttributes();
+    }
+
+    @Test
+    public void testRedirectSignedLoginLogout() {
+        testStrategy.testRedirectSignedLoginLogout();
+    }
+
+    @Test
+    public void testRedirectSignedLoginLogoutFrontNoSSO() {
+        testStrategy.testRedirectSignedLoginLogoutFrontNoSSO();
+    }
+
+    @Test
+    public void testRedirectSignedLoginLogoutFront() {
+        testStrategy.testRedirectSignedLoginLogoutFront();
+    }
+
+    @Test
+    public void testPostEncryptedLoginLogout() {
+        testStrategy.testPostEncryptedLoginLogout();
+    }
+
+    @Test
+    public void testPostBadClientSignature() {
+        testStrategy.testPostBadClientSignature();
+    }
+
+    @Test
+    public void testPostBadRealmSignature() {
+        testStrategy.testPostBadRealmSignature( );
+    }
+
+    @Test
+    public void testPostSimpleUnauthorized() {
+        testStrategy.testPostSimpleUnauthorized( new SamlAdapterTestStrategy.CheckAuthError() {
+            @Override
+            public void check(WebDriver driver) {
+                Assert.assertTrue(driver.getPageSource().contains("Error 403 !role"));
+            }
+        });
+    }
+
+    @Test
+    public void testMetadataPostSignedLoginLogout() throws Exception {
+        testStrategy.testMetadataPostSignedLoginLogout();
+    }
+
+
+
+}
diff --git a/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-db/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-db/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..737eeb8
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-db/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak.json b/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak.json
new file mode 100644
index 0000000..38d1179
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-db/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+  "realm" : "demo",
+  "resource" : "customer-db",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url": "http://localhost:8081/auth",
+  "ssl-required" : "external",
+  "bearer-only" : true,
+  "enable-cors" : true
+
+}
diff --git a/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-db/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-db/WEB-INF/web.xml
new file mode 100644
index 0000000..81924fb
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-db/WEB-INF/web.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.CustomerDatabaseServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..737eeb8
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json b/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json
new file mode 100644
index 0000000..38d1179
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+  "realm" : "demo",
+  "resource" : "customer-db",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url": "http://localhost:8081/auth",
+  "ssl-required" : "external",
+  "bearer-only" : true,
+  "enable-cors" : true
+
+}
diff --git a/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml
new file mode 100644
index 0000000..b5e700a
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-db-error-page/WEB-INF/web.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.CustomerDatabaseServlet</servlet-class>
+    </servlet>
+    <servlet>
+        <servlet-name>Error Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.rule.ErrorServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Error Servlet</servlet-name>
+        <url-pattern>/error.html</url-pattern>
+    </servlet-mapping>
+
+    <error-page>
+        <error-code>400</error-code>
+        <location>/error.html</location>
+    </error-page>
+
+    <error-page>
+        <error-code>401</error-code>
+        <location>/error.html</location>
+    </error-page>
+
+    <error-page>
+        <error-code>403</error-code>
+        <location>/error.html</location>
+    </error-page>
+
+    <error-page>
+        <error-code>500</error-code>
+        <location>/error.html</location>
+    </error-page>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Errors</web-resource-name>
+            <url-pattern>/error.html</url-pattern>
+        </web-resource-collection>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>FORM</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-portal/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-portal/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..737eeb8
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-portal/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-portal/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-portal/WEB-INF/web.xml
new file mode 100644
index 0000000..8d05b66
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/adapter-test/customer-portal/WEB-INF/web.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.CustomerServlet</servlet-class>
+    </servlet>
+    <servlet>
+        <servlet-name>Error Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.rule.ErrorServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Error Servlet</servlet-name>
+        <url-pattern>/error.html</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Errors</web-resource-name>
+            <url-pattern>/error.html</url-pattern>
+        </web-resource-collection>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>FORM</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty93/src/test/resources/adapter-test/demorealm.json b/testsuite/jetty/jetty93/src/test/resources/adapter-test/demorealm.json
new file mode 100644
index 0000000..b0a8888
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/adapter-test/demorealm.json
@@ -0,0 +1,164 @@
+{
+    "id": "demo",
+    "realm": "demo",
+    "enabled": true,
+    "accessTokenLifespan": 3000,
+    "accessCodeLifespan": 10,
+    "accessCodeLifespanUserAction": 6000,
+    "sslRequired": "external",
+    "registrationAllowed": false,
+    "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+    "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+    "requiredCredentials": [ "password" ],
+    "users" : [
+        {
+            "username" : "bburke@redhat.com",
+            "enabled": true,
+            "email" : "bburke@redhat.com",
+            "firstName": "Bill",
+            "lastName": "Burke",
+            "credentials" : [
+                { "type" : "password",
+                    "value" : "password" }
+            ],
+            "realmRoles": [ "user" ],
+            "applicationRoles": {
+                "account": [ "manage-account" ]
+            }
+        },
+        {
+            "username" : "mposolda",
+            "enabled": true,
+            "email" : "mposolda@redhat.com",
+            "firstName": "Marek",
+            "lastName": "Posolda",
+            "credentials" : [
+                { "type" : "password",
+                  "value" : "password" }
+            ],
+            "realmRoles": [ "user" ],
+            "applicationRoles": {
+                "account": [ "manage-account" ]
+            }
+        }
+    ],
+    "roles" : {
+        "realm" : [
+            {
+                "name": "user",
+                "description": "User privileges"
+            },
+            {
+                "name": "admin",
+                "description": "Administrator privileges"
+            }
+        ]
+    },
+    "scopeMappings": [
+        {
+            "client": "third-party",
+            "roles": ["user"]
+        },
+        {
+            "client": "customer-portal",
+            "roles": ["user"]
+        },
+        {
+            "client": "product-portal",
+            "roles": ["user"]
+        }
+
+    ],
+    "applications": [
+        {
+            "name": "customer-portal",
+            "enabled": true,
+            "adminUrl": "http://localhost:8082/customer-portal",
+            "baseUrl": "http://localhost:8082/customer-portal",
+            "directAccessGrantsEnabled": true,
+            "redirectUris": [
+                "http://localhost:8082/customer-portal/*"
+            ],
+            "secret": "password"
+        },
+        {
+            "name": "customer-cookie-portal",
+            "enabled": true,
+            "baseUrl": "http://localhost:8082/customer-cookie-portal",
+            "redirectUris": [
+                "http://localhost:8082/customer-cookie-portal/*"
+            ],
+            "secret": "password"
+        },
+        {
+            "name": "customer-portal-js",
+            "enabled": true,
+            "publicClient": true,
+            "adminUrl": "http://localhost:8082/customer-portal-js",
+            "baseUrl": "http://localhost:8082/customer-portal-js",
+            "redirectUris": [
+                "http://localhost:8080/customer-portal-js/*"
+            ]
+        },
+        {
+            "name": "customer-portal-cli",
+            "enabled": true,
+            "publicClient": true,
+            "redirectUris": [
+                "urn:ietf:wg:oauth:2.0:oob",
+                "http://localhost"
+            ]
+        },
+        {
+            "name": "product-portal",
+            "enabled": true,
+            "adminUrl": "http://localhost:8082/product-portal",
+            "baseUrl": "http://localhost:8082/product-portal",
+            "redirectUris": [
+                "http://localhost:8082/product-portal/*"
+            ],
+            "secret": "password"
+        },
+        {
+            "name": "secure-portal",
+            "enabled": true,
+            "adminUrl": "http://localhost:8082/secure-portal",
+            "baseUrl": "http://localhost:8082/secure-portal",
+            "redirectUris": [
+                "http://localhost:8082/secure-portal/*"
+            ],
+            "secret": "password"
+        },
+        {
+            "name": "session-portal",
+            "enabled": true,
+            "adminUrl": "http://localhost:8082/session-portal",
+            "baseUrl": "http://localhost:8082/session-portal",
+            "redirectUris": [
+                "http://localhost:8082/session-portal/*"
+            ],
+            "secret": "password"
+        },
+        {
+            "name": "input-portal",
+            "enabled": true,
+            "adminUrl": "http://localhost:8082/input-portal",
+            "baseUrl": "http://localhost:8082/input-portal",
+            "redirectUris": [
+                "http://localhost:8082/input-portal/*"
+            ],
+            "secret": "password"
+        }
+    ],
+    "oauthClients": [
+        {
+            "name": "third-party",
+            "enabled": true,
+            "redirectUris": [
+                "http://localhost:8082/oauth-client/*",
+                "http://localhost:8082/oauth-client-cdi/*"
+            ],
+            "secret": "password"
+        }
+    ]
+}
diff --git a/testsuite/jetty/jetty93/src/test/resources/adapter-test/input-portal/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty93/src/test/resources/adapter-test/input-portal/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..737eeb8
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/adapter-test/input-portal/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/adapter-test/input-portal/WEB-INF/keycloak.json b/testsuite/jetty/jetty93/src/test/resources/adapter-test/input-portal/WEB-INF/keycloak.json
new file mode 100644
index 0000000..0b4b165
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/adapter-test/input-portal/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+  "realm" : "demo",
+  "resource" : "input-portal",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url" : "http://${my.host.name}:8081/auth",
+  "ssl-required" : "external",
+  "credentials" : {
+      "secret": "password"
+   }
+}
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/adapter-test/input-portal/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/adapter-test/input-portal/WEB-INF/web.xml
new file mode 100644
index 0000000..4ac67c4
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/adapter-test/input-portal/WEB-INF/web.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.InputServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/secured/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty93/src/test/resources/adapter-test/product-portal/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty93/src/test/resources/adapter-test/product-portal/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..737eeb8
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/adapter-test/product-portal/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/adapter-test/product-portal/WEB-INF/keycloak.json b/testsuite/jetty/jetty93/src/test/resources/adapter-test/product-portal/WEB-INF/keycloak.json
new file mode 100644
index 0000000..3cfd478
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/adapter-test/product-portal/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+  "realm" : "demo",
+  "resource" : "product-portal",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url" : "http://localhost:8081/auth",
+  "ssl-required" : "external",
+  "credentials" : {
+      "secret": "password"
+   }
+}
diff --git a/testsuite/jetty/jetty93/src/test/resources/adapter-test/product-portal/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/adapter-test/product-portal/WEB-INF/web.xml
new file mode 100644
index 0000000..59c6d3f
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/adapter-test/product-portal/WEB-INF/web.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.ProductServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty93/src/test/resources/adapter-test/secure-portal/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty93/src/test/resources/adapter-test/secure-portal/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..737eeb8
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/adapter-test/secure-portal/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/adapter-test/secure-portal/WEB-INF/keycloak.json b/testsuite/jetty/jetty93/src/test/resources/adapter-test/secure-portal/WEB-INF/keycloak.json
new file mode 100644
index 0000000..dd38f24
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/adapter-test/secure-portal/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+  "realm" : "demo",
+  "resource" : "secure-portal",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url" : "http://localhost:8080/auth",
+  "ssl-required" : "external",
+  "credentials" : {
+      "secret": "password"
+   }
+}
diff --git a/testsuite/jetty/jetty93/src/test/resources/adapter-test/secure-portal/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/adapter-test/secure-portal/WEB-INF/web.xml
new file mode 100644
index 0000000..859407b
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/adapter-test/secure-portal/WEB-INF/web.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.CallAuthenticatedServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty93/src/test/resources/adapter-test/session-portal/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty93/src/test/resources/adapter-test/session-portal/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..737eeb8
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/adapter-test/session-portal/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.jetty.KeycloakJettyAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/adapter-test/session-portal/WEB-INF/keycloak.json b/testsuite/jetty/jetty93/src/test/resources/adapter-test/session-portal/WEB-INF/keycloak.json
new file mode 100644
index 0000000..6a7f60b
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/adapter-test/session-portal/WEB-INF/keycloak.json
@@ -0,0 +1,10 @@
+{
+  "realm" : "demo",
+  "resource" : "session-portal",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url" : "http://${my.host.name}:8081/auth",
+  "ssl-required" : "external",
+  "credentials" : {
+      "secret": "password"
+   }
+}
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/adapter-test/session-portal/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/adapter-test/session-portal/WEB-INF/web.xml
new file mode 100644
index 0000000..be1549f
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/adapter-test/session-portal/WEB-INF/web.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.adapter.SessionServlet</servlet-class>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>Servlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>user</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+    </login-config>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..c583350
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.saml.jetty.KeycloakSamlAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keycloak-saml.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keycloak-saml.xml
new file mode 100644
index 0000000..ecc7469
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,62 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<keycloak-saml-adapter>
+    <SP entityID="http://localhost:8082/bad-client-sales-post-sig/"
+        sslPolicy="EXTERNAL"
+        nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+        logoutPage="/logout.jsp"
+        forceAuthentication="false">
+        <Keys>
+            <Key signing="true" >
+                <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                    <PrivateKey alias="http://localhost:8081/bad-client-sales-post-sig/" password="test123"/>
+                    <Certificate alias="http://localhost:8081/bad-client-sales-post-sig/"/>
+                </KeyStore>
+            </Key>
+        </Keys>
+        <PrincipalNameMapping policy="FROM_NAME_ID"/>
+        <RoleIdentifiers>
+            <Attribute name="Role"/>
+        </RoleIdentifiers>
+        <IDP entityID="idp">
+            <SingleSignOnService signRequest="true"
+                                 validateResponseSignature="true"
+                                 requestBinding="POST"
+                                 bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+
+            <SingleLogoutService
+                    validateRequestSignature="true"
+                    validateResponseSignature="true"
+                    signRequest="true"
+                    signResponse="true"
+                    requestBinding="POST"
+                    responseBinding="POST"
+                    postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+            <Keys>
+                <Key signing="true">
+                    <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                        <Certificate alias="demo"/>
+                    </KeyStore>
+                </Key>
+            </Keys>
+        </IDP>
+     </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keystore.jks b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keystore.jks
new file mode 100644
index 0000000..6a3e3ba
Binary files /dev/null and b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/keystore.jks differ
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
new file mode 100644
index 0000000..f1cdbea
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-client-signed-post/WEB-INF/web.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>manager</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>manager</role-name>
+    </security-role>
+    <security-role>
+        <role-name>el-jefe</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..c583350
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.saml.jetty.KeycloakSamlAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/keycloak-saml.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/keycloak-saml.xml
new file mode 100644
index 0000000..fee4cfe
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,62 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<keycloak-saml-adapter>
+    <SP entityID="http://localhost:8082/bad-realm-sales-post-sig/"
+        sslPolicy="EXTERNAL"
+        nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+        logoutPage="/logout.jsp"
+        forceAuthentication="false">
+        <Keys>
+            <Key signing="true" >
+                <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                    <PrivateKey alias="http://localhost:8081/bad-realm-sales-post-sig/" password="test123"/>
+                    <Certificate alias="http://localhost:8081/bad-realm-sales-post-sig/"/>
+                </KeyStore>
+            </Key>
+        </Keys>
+        <PrincipalNameMapping policy="FROM_NAME_ID"/>
+        <RoleIdentifiers>
+            <Attribute name="Role"/>
+        </RoleIdentifiers>
+        <IDP entityID="idp">
+            <SingleSignOnService signRequest="true"
+                                 validateResponseSignature="true"
+                                 requestBinding="POST"
+                                 bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+
+            <SingleLogoutService
+                    validateRequestSignature="true"
+                    validateResponseSignature="true"
+                    signRequest="true"
+                    signResponse="true"
+                    requestBinding="POST"
+                    responseBinding="POST"
+                    postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+            <Keys>
+                <Key signing="true">
+                    <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                        <Certificate alias="demo"/>
+                    </KeyStore>
+                </Key>
+            </Keys>
+        </IDP>
+     </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/keystore.jks b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/keystore.jks
new file mode 100644
index 0000000..215384c
Binary files /dev/null and b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/keystore.jks differ
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
new file mode 100644
index 0000000..42a7f77
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/bad-realm-signed-post/WEB-INF/web.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+    </servlet>
+    <servlet>
+        <servlet-name>Error Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.rule.ErrorServlet</servlet-class>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Error Servlet</servlet-name>
+        <url-pattern>/error.html</url-pattern>
+    </servlet-mapping>
+
+    <error-page>
+        <error-code>400</error-code>
+        <location>/error.html</location>
+    </error-page>
+
+    <error-page>
+        <error-code>401</error-code>
+        <location>/error.html</location>
+    </error-page>
+
+    <error-page>
+        <error-code>403</error-code>
+        <location>/error.html</location>
+    </error-page>
+
+    <error-page>
+        <error-code>500</error-code>
+        <location>/error.html</location>
+    </error-page>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>manager</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>manager</role-name>
+    </security-role>
+    <security-role>
+        <role-name>el-jefe</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..c583350
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.saml.jetty.KeycloakSamlAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/keycloak-saml.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/keycloak-saml.xml
new file mode 100644
index 0000000..eebd481
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,62 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<keycloak-saml-adapter>
+    <SP entityID="http://localhost:8082/sales-post-enc/"
+        sslPolicy="EXTERNAL"
+        nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+        logoutPage="/logout.jsp"
+        forceAuthentication="false">
+        <Keys>
+            <Key signing="true" encryption="true">
+                <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                    <PrivateKey alias="http://localhost:8080/sales-post-enc/" password="test123"/>
+                    <Certificate alias="http://localhost:8080/sales-post-enc/"/>
+                </KeyStore>
+            </Key>
+        </Keys>
+        <PrincipalNameMapping policy="FROM_NAME_ID"/>
+        <RoleIdentifiers>
+            <Attribute name="Role"/>
+        </RoleIdentifiers>
+        <IDP entityID="idp">
+            <SingleSignOnService signRequest="true"
+                                 validateResponseSignature="true"
+                                 requestBinding="POST"
+                                 bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+
+            <SingleLogoutService
+                    validateRequestSignature="true"
+                    validateResponseSignature="true"
+                    signRequest="true"
+                    signResponse="true"
+                    requestBinding="POST"
+                    responseBinding="POST"
+                    postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+            <Keys>
+                <Key signing="true" >
+                    <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                        <Certificate alias="demo"/>
+                    </KeyStore>
+                </Key>
+            </Keys>
+        </IDP>
+     </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/keystore.jks b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/keystore.jks
new file mode 100644
index 0000000..822162c
Binary files /dev/null and b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/keystore.jks differ
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
new file mode 100644
index 0000000..f1cdbea
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/encrypted-post/WEB-INF/web.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>manager</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>manager</role-name>
+    </security-role>
+    <security-role>
+        <role-name>el-jefe</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/mappers/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/mappers/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..c583350
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/mappers/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.saml.jetty.KeycloakSamlAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/mappers/WEB-INF/keycloak-saml.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/mappers/WEB-INF/keycloak-saml.xml
new file mode 100644
index 0000000..0495c3d
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/mappers/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,42 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<keycloak-saml-adapter>
+    <SP entityID="http://localhost:8082/employee2/"
+        sslPolicy="EXTERNAL"
+        nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+        logoutPage="/logout.jsp"
+        forceAuthentication="false">
+        <PrincipalNameMapping policy="FROM_NAME_ID"/>
+        <RoleIdentifiers>
+            <Attribute name="memberOf"/>
+            <Attribute name="Role"/>
+        </RoleIdentifiers>
+        <IDP entityID="idp">
+            <SingleSignOnService requestBinding="POST"
+                                 bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+
+            <SingleLogoutService
+                    requestBinding="POST"
+                    responseBinding="POST"
+                    postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+        </IDP>
+     </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
new file mode 100644
index 0000000..124a5ca
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/mappers/WEB-INF/web.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>manager</role-name>
+            <role-name>el-jefe</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>manager</role-name>
+    </security-role>
+    <security-role>
+        <role-name>el-jefe</role-name>
+    </security-role>
+    <security-role>
+        <role-name>user</role-name>
+    </security-role>
+    <security-role>
+        <role-name>employee</role-name>
+    </security-role>
+    <security-role>
+        <role-name>pee-on</role-name>
+    </security-role>
+    <security-role>
+        <role-name>hardcoded-role</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..c583350
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.saml.jetty.KeycloakSamlAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/keycloak-saml.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/keycloak-saml.xml
new file mode 100644
index 0000000..993277d
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,61 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<keycloak-saml-adapter>
+    <SP entityID="http://localhost:8082/employee-sig-front/"
+        sslPolicy="EXTERNAL"
+        logoutPage="/logout.jsp"
+        nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+        forceAuthentication="false">
+        <Keys>
+            <Key signing="true" >
+                <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                    <PrivateKey alias="http://localhost:8080/employee-sig/" password="test123"/>
+                    <Certificate alias="http://localhost:8080/employee-sig/"/>
+                </KeyStore>
+            </Key>
+        </Keys>
+        <PrincipalNameMapping policy="FROM_NAME_ID"/>
+        <RoleIdentifiers>
+            <Attribute name="Role"/>
+        </RoleIdentifiers>
+        <IDP entityID="idp">
+            <SingleSignOnService signRequest="true"
+                                 validateResponseSignature="true"
+                                 requestBinding="REDIRECT"
+                                 bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+
+            <SingleLogoutService
+                    validateRequestSignature="true"
+                    validateResponseSignature="true"
+                    signRequest="true"
+                    signResponse="true"
+                    requestBinding="REDIRECT"
+                    responseBinding="REDIRECT"
+                    redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+            <Keys>
+                <Key signing="true">
+                    <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                        <Certificate alias="demo"/>
+                    </KeyStore>
+                </Key>
+            </Keys>
+        </IDP>
+     </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/keystore.jks b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/keystore.jks
new file mode 100644
index 0000000..4daad21
Binary files /dev/null and b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/keystore.jks differ
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
new file mode 100644
index 0000000..f1cdbea
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-front-get/WEB-INF/web.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>manager</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>manager</role-name>
+    </security-role>
+    <security-role>
+        <role-name>el-jefe</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-get/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-get/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..c583350
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-get/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.saml.jetty.KeycloakSamlAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-get/WEB-INF/keycloak-saml.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-get/WEB-INF/keycloak-saml.xml
new file mode 100644
index 0000000..5e8dca8
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-get/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,61 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<keycloak-saml-adapter>
+    <SP entityID="http://localhost:8082/employee-sig/"
+        sslPolicy="EXTERNAL"
+        logoutPage="/logout.jsp"
+        nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+        forceAuthentication="false">
+        <Keys>
+            <Key signing="true" >
+                <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                    <PrivateKey alias="http://localhost:8080/employee-sig/" password="test123"/>
+                    <Certificate alias="http://localhost:8080/employee-sig/"/>
+                </KeyStore>
+            </Key>
+        </Keys>
+        <PrincipalNameMapping policy="FROM_NAME_ID"/>
+        <RoleIdentifiers>
+            <Attribute name="Role"/>
+        </RoleIdentifiers>
+        <IDP entityID="idp">
+            <SingleSignOnService signRequest="true"
+                                 validateResponseSignature="true"
+                                 requestBinding="REDIRECT"
+                                 bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+
+            <SingleLogoutService
+                    validateRequestSignature="true"
+                    validateResponseSignature="true"
+                    signRequest="true"
+                    signResponse="true"
+                    requestBinding="REDIRECT"
+                    responseBinding="REDIRECT"
+                    redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+            <Keys>
+                <Key signing="true">
+                    <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                        <Certificate alias="demo"/>
+                    </KeyStore>
+                </Key>
+            </Keys>
+        </IDP>
+     </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-get/WEB-INF/keystore.jks b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-get/WEB-INF/keystore.jks
new file mode 100644
index 0000000..4daad21
Binary files /dev/null and b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-get/WEB-INF/keystore.jks differ
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
new file mode 100644
index 0000000..42a7f77
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-get/WEB-INF/web.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+    </servlet>
+    <servlet>
+        <servlet-name>Error Servlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.rule.ErrorServlet</servlet-class>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Error Servlet</servlet-name>
+        <url-pattern>/error.html</url-pattern>
+    </servlet-mapping>
+
+    <error-page>
+        <error-code>400</error-code>
+        <location>/error.html</location>
+    </error-page>
+
+    <error-page>
+        <error-code>401</error-code>
+        <location>/error.html</location>
+    </error-page>
+
+    <error-page>
+        <error-code>403</error-code>
+        <location>/error.html</location>
+    </error-page>
+
+    <error-page>
+        <error-code>500</error-code>
+        <location>/error.html</location>
+    </error-page>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>manager</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>manager</role-name>
+    </security-role>
+    <security-role>
+        <role-name>el-jefe</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..c583350
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.saml.jetty.KeycloakSamlAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/keycloak-saml.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/keycloak-saml.xml
new file mode 100644
index 0000000..16a4d75
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,62 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<keycloak-saml-adapter>
+    <SP entityID="http://localhost:8082/sales-metadata/"
+        sslPolicy="EXTERNAL"
+        nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+        logoutPage="/logout.jsp"
+        forceAuthentication="false">
+        <Keys>
+            <Key signing="true" >
+                <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                    <PrivateKey alias="http://localhost:8080/sales-post-sig/" password="test123"/>
+                    <Certificate alias="http://localhost:8080/sales-post-sig/"/>
+                </KeyStore>
+            </Key>
+        </Keys>
+        <PrincipalNameMapping policy="FROM_NAME_ID"/>
+        <RoleIdentifiers>
+            <Attribute name="Role"/>
+        </RoleIdentifiers>
+        <IDP entityID="idp">
+            <SingleSignOnService signRequest="true"
+                                 validateResponseSignature="true"
+                                 requestBinding="POST"
+                                 bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+
+            <SingleLogoutService
+                    validateRequestSignature="true"
+                    validateResponseSignature="true"
+                    signRequest="true"
+                    signResponse="true"
+                    requestBinding="POST"
+                    responseBinding="POST"
+                    postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+            <Keys>
+                <Key signing="true">
+                    <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                        <Certificate alias="demo"/>
+                    </KeyStore>
+                </Key>
+            </Keys>
+        </IDP>
+     </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/keystore.jks b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/keystore.jks
new file mode 100644
index 0000000..144830b
Binary files /dev/null and b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/keystore.jks differ
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
new file mode 100644
index 0000000..f1cdbea
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-metadata/WEB-INF/web.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>manager</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>manager</role-name>
+    </security-role>
+    <security-role>
+        <role-name>el-jefe</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..c583350
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.saml.jetty.KeycloakSamlAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post/WEB-INF/keycloak-saml.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post/WEB-INF/keycloak-saml.xml
new file mode 100644
index 0000000..32bb6b0
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,62 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<keycloak-saml-adapter>
+    <SP entityID="http://localhost:8082/sales-post-sig/"
+        sslPolicy="EXTERNAL"
+        nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+        logoutPage="/logout.jsp"
+        forceAuthentication="false">
+        <Keys>
+            <Key signing="true" >
+                <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                    <PrivateKey alias="http://localhost:8080/sales-post-sig/" password="test123"/>
+                    <Certificate alias="http://localhost:8080/sales-post-sig/"/>
+                </KeyStore>
+            </Key>
+        </Keys>
+        <PrincipalNameMapping policy="FROM_NAME_ID"/>
+        <RoleIdentifiers>
+            <Attribute name="Role"/>
+        </RoleIdentifiers>
+        <IDP entityID="idp">
+            <SingleSignOnService signRequest="true"
+                                 validateResponseSignature="true"
+                                 requestBinding="POST"
+                                 bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+
+            <SingleLogoutService
+                    validateRequestSignature="true"
+                    validateResponseSignature="true"
+                    signRequest="true"
+                    signResponse="true"
+                    requestBinding="POST"
+                    responseBinding="POST"
+                    postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+            <Keys>
+                <Key signing="true">
+                    <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                        <Certificate alias="demo"/>
+                    </KeyStore>
+                </Key>
+            </Keys>
+        </IDP>
+     </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post/WEB-INF/keystore.jks b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post/WEB-INF/keystore.jks
new file mode 100644
index 0000000..144830b
Binary files /dev/null and b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post/WEB-INF/keystore.jks differ
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
new file mode 100644
index 0000000..f1cdbea
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post/WEB-INF/web.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>manager</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>manager</role-name>
+    </security-role>
+    <security-role>
+        <role-name>el-jefe</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..c583350
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.saml.jetty.KeycloakSamlAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/keycloak-saml.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/keycloak-saml.xml
new file mode 100644
index 0000000..ff82567
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,61 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<keycloak-saml-adapter>
+    <SP entityID="http://localhost:8082/sales-post-sig-email/"
+        sslPolicy="EXTERNAL"
+        logoutPage="/logout.jsp"
+        forceAuthentication="false">
+        <Keys>
+            <Key signing="true" >
+                <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                    <PrivateKey alias="http://localhost:8080/sales-post-sig/" password="test123"/>
+                    <Certificate alias="http://localhost:8080/sales-post-sig/"/>
+                </KeyStore>
+            </Key>
+        </Keys>
+        <PrincipalNameMapping policy="FROM_NAME_ID"/>
+        <RoleIdentifiers>
+            <Attribute name="Role"/>
+        </RoleIdentifiers>
+        <IDP entityID="idp">
+            <SingleSignOnService signRequest="true"
+                                 validateResponseSignature="true"
+                                 requestBinding="POST"
+                                 bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+
+            <SingleLogoutService
+                    validateRequestSignature="true"
+                    validateResponseSignature="true"
+                    signRequest="true"
+                    signResponse="true"
+                    requestBinding="POST"
+                    responseBinding="POST"
+                    postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+            <Keys>
+                <Key signing="true">
+                    <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                        <Certificate alias="demo"/>
+                    </KeyStore>
+                </Key>
+            </Keys>
+        </IDP>
+     </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/keystore.jks b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/keystore.jks
new file mode 100644
index 0000000..144830b
Binary files /dev/null and b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/keystore.jks differ
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
new file mode 100644
index 0000000..f1cdbea
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-email/WEB-INF/web.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>manager</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>manager</role-name>
+    </security-role>
+    <security-role>
+        <role-name>el-jefe</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..c583350
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.saml.jetty.KeycloakSamlAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/keycloak-saml.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/keycloak-saml.xml
new file mode 100644
index 0000000..626d239
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,62 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<keycloak-saml-adapter>
+    <SP entityID="http://localhost:8082/sales-post-sig-persistent/"
+        sslPolicy="EXTERNAL"
+        nameIDPolicyFormat="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
+        logoutPage="/logout.jsp"
+        forceAuthentication="false">
+        <Keys>
+            <Key signing="true" >
+                <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                    <PrivateKey alias="http://localhost:8080/sales-post-sig/" password="test123"/>
+                    <Certificate alias="http://localhost:8080/sales-post-sig/"/>
+                </KeyStore>
+            </Key>
+        </Keys>
+        <PrincipalNameMapping policy="FROM_NAME_ID"/>
+        <RoleIdentifiers>
+            <Attribute name="Role"/>
+        </RoleIdentifiers>
+        <IDP entityID="idp">
+            <SingleSignOnService signRequest="true"
+                                 validateResponseSignature="true"
+                                 requestBinding="POST"
+                                 bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+
+            <SingleLogoutService
+                    validateRequestSignature="true"
+                    validateResponseSignature="true"
+                    signRequest="true"
+                    signResponse="true"
+                    requestBinding="POST"
+                    responseBinding="POST"
+                    postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+            <Keys>
+                <Key signing="true">
+                    <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                        <Certificate alias="demo"/>
+                    </KeyStore>
+                </Key>
+            </Keys>
+        </IDP>
+     </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/keystore.jks b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/keystore.jks
new file mode 100644
index 0000000..144830b
Binary files /dev/null and b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/keystore.jks differ
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
new file mode 100644
index 0000000..f1cdbea
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-persistent/WEB-INF/web.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>manager</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>manager</role-name>
+    </security-role>
+    <security-role>
+        <role-name>el-jefe</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..c583350
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.saml.jetty.KeycloakSamlAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/keycloak-saml.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/keycloak-saml.xml
new file mode 100644
index 0000000..3182dc0
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,62 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<keycloak-saml-adapter>
+    <SP entityID="http://localhost:8082/sales-post-sig-transient/"
+        sslPolicy="EXTERNAL"
+        nameIDPolicyFormat="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
+        logoutPage="/logout.jsp"
+        forceAuthentication="false">
+        <Keys>
+            <Key signing="true" >
+                <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                    <PrivateKey alias="http://localhost:8080/sales-post-sig/" password="test123"/>
+                    <Certificate alias="http://localhost:8080/sales-post-sig/"/>
+                </KeyStore>
+            </Key>
+        </Keys>
+        <PrincipalNameMapping policy="FROM_NAME_ID"/>
+        <RoleIdentifiers>
+            <Attribute name="Role"/>
+        </RoleIdentifiers>
+        <IDP entityID="idp">
+            <SingleSignOnService signRequest="true"
+                                 validateResponseSignature="true"
+                                 requestBinding="POST"
+                                 bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+
+            <SingleLogoutService
+                    validateRequestSignature="true"
+                    validateResponseSignature="true"
+                    signRequest="true"
+                    signResponse="true"
+                    requestBinding="POST"
+                    responseBinding="POST"
+                    postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+            <Keys>
+                <Key signing="true">
+                    <KeyStore resource="/WEB-INF/keystore.jks" password="store123">
+                        <Certificate alias="demo"/>
+                    </KeyStore>
+                </Key>
+            </Keys>
+        </IDP>
+     </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/keystore.jks b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/keystore.jks
new file mode 100644
index 0000000..144830b
Binary files /dev/null and b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/keystore.jks differ
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
new file mode 100644
index 0000000..f1cdbea
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/signed-post-transient/WEB-INF/web.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>manager</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>manager</role-name>
+    </security-role>
+    <security-role>
+        <role-name>el-jefe</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-input/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-input/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..c583350
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-input/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.saml.jetty.KeycloakSamlAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-input/WEB-INF/keycloak-saml.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-input/WEB-INF/keycloak-saml.xml
new file mode 100644
index 0000000..1af3a86
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-input/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,41 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<keycloak-saml-adapter>
+    <SP entityID="http://localhost:8082/input-portal/"
+        sslPolicy="EXTERNAL"
+        nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+        logoutPage="/logout.jsp"
+        forceAuthentication="false">
+        <PrincipalNameMapping policy="FROM_NAME_ID"/>
+        <RoleIdentifiers>
+            <Attribute name="Role"/>
+        </RoleIdentifiers>
+        <IDP entityID="idp">
+            <SingleSignOnService requestBinding="POST"
+                                 bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+
+            <SingleLogoutService
+                    requestBinding="POST"
+                    responseBinding="POST"
+                    postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+        </IDP>
+     </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
new file mode 100644
index 0000000..0be7a74
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-input/WEB-INF/web.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.keycloaksaml.InputServlet</servlet-class>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/secured/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>manager</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>manager</role-name>
+    </security-role>
+    <security-role>
+        <role-name>el-jefe</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..c583350
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.saml.jetty.KeycloakSamlAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post/WEB-INF/keycloak-saml.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post/WEB-INF/keycloak-saml.xml
new file mode 100644
index 0000000..f4cb21c
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,41 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<keycloak-saml-adapter>
+    <SP entityID="http://localhost:8082/sales-post/"
+        sslPolicy="EXTERNAL"
+        nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+        logoutPage="/logout.jsp"
+        forceAuthentication="false">
+        <PrincipalNameMapping policy="FROM_NAME_ID"/>
+        <RoleIdentifiers>
+            <Attribute name="Role"/>
+        </RoleIdentifiers>
+        <IDP entityID="idp">
+            <SingleSignOnService requestBinding="POST"
+                                 bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+
+            <SingleLogoutService
+                    requestBinding="POST"
+                    responseBinding="POST"
+                    postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+        </IDP>
+     </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
new file mode 100644
index 0000000..f1cdbea
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post/WEB-INF/web.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>manager</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>manager</role-name>
+    </security-role>
+    <security-role>
+        <role-name>el-jefe</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post2/WEB-INF/jetty-web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post2/WEB-INF/jetty-web.xml
new file mode 100644
index 0000000..c583350
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post2/WEB-INF/jetty-web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+<Configure class="org.eclipse.jetty.webapp.WebAppContext">
+    <Get name="securityHandler">
+        <Set name="authenticator">
+            <New class="org.keycloak.adapters.saml.jetty.KeycloakSamlAuthenticator">
+                <!--
+                <Set name="adapterConfig">
+                    <New class="org.keycloak.representations.adapters.config.AdapterConfig">
+                        <Set name="realm">tomcat</Set>
+                        <Set name="resource">customer-portal</Set>
+                        <Set name="authServerUrl">http://localhost:8081/auth</Set>
+                        <Set name="sslRequired">external</Set>
+                        <Set name="credentials">
+                            <Map>
+                                <Entry>
+                                    <Item>secret</Item>
+                                    <Item>password</Item>
+                                </Entry>
+                            </Map>
+                        </Set>
+                        <Set name="realmKey">MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB</Set>
+                    </New>
+                </Set>
+                -->
+            </New>
+        </Set>
+    </Get>
+</Configure>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post2/WEB-INF/keycloak-saml.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post2/WEB-INF/keycloak-saml.xml
new file mode 100644
index 0000000..3f447c6
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post2/WEB-INF/keycloak-saml.xml
@@ -0,0 +1,41 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<keycloak-saml-adapter>
+    <SP entityID="http://localhost:8082/sales-post2/"
+        sslPolicy="EXTERNAL"
+        nameIDPolicyFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
+        logoutPage="/logout.jsp"
+        forceAuthentication="false">
+        <PrincipalNameMapping policy="FROM_NAME_ID"/>
+        <RoleIdentifiers>
+            <Attribute name="Role"/>
+        </RoleIdentifiers>
+        <IDP entityID="idp">
+            <SingleSignOnService requestBinding="POST"
+                                 bindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+
+            <SingleLogoutService
+                    requestBinding="POST"
+                    responseBinding="POST"
+                    postBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    redirectBindingUrl="http://localhost:8081/auth/realms/demo/protocol/saml"
+                    />
+        </IDP>
+     </SP>
+</keycloak-saml-adapter>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
new file mode 100644
index 0000000..f1cdbea
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/simple-post2/WEB-INF/web.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>adapter-test</module-name>
+
+    <servlet>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <servlet-class>org.keycloak.testsuite.keycloaksaml.SendUsernameServlet</servlet-class>
+    </servlet>
+    <servlet-mapping>
+        <servlet-name>SendUsernameServlet</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Users</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>manager</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>demo</realm-name>
+        <form-login-config>
+            <form-login-page>/error.html</form-login-page>
+            <form-error-page>/error.html</form-error-page>
+        </form-login-config>
+    </login-config>
+
+    <security-role>
+        <role-name>manager</role-name>
+    </security-role>
+    <security-role>
+        <role-name>el-jefe</role-name>
+    </security-role>
+</web-app>
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/sp-metadata.xml b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/sp-metadata.xml
new file mode 100644
index 0000000..853a6b2
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/sp-metadata.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<EntitiesDescriptor Name="urn:mace:shibboleth:testshib:two"
+                    xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+        >
+    <EntityDescriptor entityID="http://localhost:8082/sales-metadata/">
+        <SPSSODescriptor AuthnRequestsSigned="true"
+                protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol urn:oasis:names:tc:SAML:1.1:protocol http://schemas.xmlsoap.org/ws/2003/07/secext">
+            <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+            </NameIDFormat>
+            <SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:8082/sales-metadata/saml"/>
+            <AssertionConsumerService
+                    Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost:8082/sales-metadata/saml"
+                    index="1" isDefault="true" />
+            <KeyDescriptor use="signing">
+                <dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
+                    <dsig:X509Data>
+                        <dsig:X509Certificate>
+                            MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw==
+                        </dsig:X509Certificate>
+                    </dsig:X509Data>
+                </dsig:KeyInfo>
+            </KeyDescriptor>
+        </SPSSODescriptor>
+        <Organization>
+            <OrganizationName xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+                              xml:lang="en">JBoss</OrganizationName>
+            <OrganizationDisplayName xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+                                     xml:lang="en">JBoss by Red Hat</OrganizationDisplayName>
+            <OrganizationURL xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+                             xml:lang="en">http://localhost:8080/sales-metadata/</OrganizationURL>
+        </Organization>
+        <ContactPerson contactType="technical">
+            <GivenName>The</GivenName>
+            <SurName>Admin</SurName>
+            <EmailAddress>admin@mycompany.com</EmailAddress>
+        </ContactPerson>
+    </EntityDescriptor>
+</EntitiesDescriptor>
\ No newline at end of file
diff --git a/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/testsaml.json b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/testsaml.json
new file mode 100644
index 0000000..71cde71
--- /dev/null
+++ b/testsuite/jetty/jetty93/src/test/resources/keycloak-saml/testsaml.json
@@ -0,0 +1,452 @@
+{
+    "id": "demo",
+    "realm": "demo",
+    "enabled": true,
+    "sslRequired": "external",
+    "registrationAllowed": true,
+    "resetPasswordAllowed": true,
+    "privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
+    "publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+    "requiredCredentials": [ "password" ],
+    "defaultRoles": [ "user" ],
+    "smtpServer": {
+        "from": "auto@keycloak.org",
+        "host": "localhost",
+        "port":"3025"
+    },
+    "users" : [
+        {
+            "username" : "bburke",
+            "enabled": true,
+            "email" : "bburke@redhat.com",
+            "credentials" : [
+                { "type" : "password",
+                  "value" : "password" }
+            ],
+            "attributes" : {
+                "phone": "617"
+            },
+            "realmRoles": ["manager", "user"],
+            "applicationRoles": {
+                "http://localhost:8082/employee/": [ "employee" ],
+                "http://localhost:8082/employee2/": [ "employee" ]
+            }
+        } ,
+        {
+            "username" : "unauthorized",
+            "enabled": true,
+            "email" : "unauthorized@redhat.com",
+            "credentials" : [
+                { "type" : "password",
+                    "value" : "password" }
+            ]
+        },
+        {
+            "username" : "topGroupUser",
+            "enabled": true,
+            "email" : "top@redhat.com",
+            "credentials" : [
+                { "type" : "password",
+                    "value" : "password" }
+            ],
+            "groups": [
+                "/top"
+            ]
+        },
+        {
+            "username" : "level2GroupUser",
+            "enabled": true,
+            "email" : "level2@redhat.com",
+            "credentials" : [
+                { "type" : "password",
+                    "value" : "password" }
+            ],
+            "groups": [
+                "/top/level2"
+            ]
+        }
+    ],
+    "applications": [
+        {
+            "name": "http://localhost:8082/sales-post/",
+            "enabled": true,
+            "fullScopeAllowed": true,
+            "protocol": "saml",
+            "baseUrl": "http://localhost:8082/sales-post",
+            "redirectUris": [
+                "http://localhost:8082/sales-post/*"
+            ],
+            "attributes": {
+                "saml.authnstatement": "true",
+                "saml_assertion_consumer_url_post": "http://localhost:8082/sales-post/saml",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8082/sales-post/saml",
+                "saml_single_logout_service_url_post": "http://localhost:8082/sales-post/saml",
+                "saml_single_logout_service_url_redirect": "http://localhost:8082/sales-post/saml",
+                "saml_idp_initiated_sso_url_name": "sales-post"
+            }
+        },
+        {
+            "name": "http://localhost:8082/sales-post2/",
+            "enabled": true,
+            "fullScopeAllowed": true,
+            "protocol": "saml",
+            "baseUrl": "http://localhost:8082/sales-post2",
+            "redirectUris": [
+                "http://localhost:8082/sales-post2/*"
+            ],
+            "attributes": {
+                "saml.authnstatement": "true",
+                "saml_assertion_consumer_url_post": "http://localhost:8082/sales-post2/saml",
+                "saml_single_logout_service_url_post": "http://localhost:8082/sales-post2/saml",
+                "saml_idp_initiated_sso_url_name": "sales-post2",
+                "saml_idp_initiated_sso_relay_state": "redirectTo=/foo"
+            }
+        },
+        {
+            "name": "http://localhost:8082/input-portal/",
+            "enabled": true,
+            "fullScopeAllowed": true,
+            "protocol": "saml",
+            "baseUrl": "http://localhost:8082/input-portal/",
+            "redirectUris": [
+                "http://localhost:8082/input-portal/*"
+            ],
+            "attributes": {
+                "saml.authnstatement": "true",
+                "saml_assertion_consumer_url_post": "http://localhost:8082/input-portal/saml",
+                "saml_single_logout_service_url_post": "http://localhost:8082/input-portal/saml"
+            }
+        },
+        {
+            "name": "http://localhost:8082/sales-post-sig/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8082/sales-post-sig",
+            "redirectUris": [
+                "http://localhost:8082/sales-post-sig/*"
+            ],
+            "attributes": {
+                "saml_assertion_consumer_url_post": "http://localhost:8082/sales-post-sig/saml",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8082/sales-post-sig/saml",
+                "saml_single_logout_service_url_post": "http://localhost:8082/sales-post-sig/saml",
+                "saml_single_logout_service_url_redirect": "http://localhost:8082/sales-post-sig/saml",
+                "saml.server.signature": "true",
+                "saml.signature.algorithm": "RSA_SHA256",
+                "saml.client.signature": "true",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
+            }
+        },
+        {
+            "name": "http://localhost:8082/sales-post-sig-transient/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8082/sales-post-sig-transient",
+            "adminUrl": "http://localhost:8082/sales-post-sig-transient/saml",
+            "redirectUris": [
+                "http://localhost:8082/sales-post-sig-transient/*"
+            ],
+            "attributes": {
+                "saml_assertion_consumer_url_post": "http://localhost:8082/sales-post-sig-transient/saml",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8082/sales-post-sig-transient/saml",
+                "saml_single_logout_service_url_post": "http://localhost:8082/sales-post-sig-transient/saml",
+                "saml_single_logout_service_url_redirect": "http://localhost:8082/sales-post-sig-transient/saml",
+                "saml.server.signature": "true",
+                "saml.signature.algorithm": "RSA_SHA256",
+                "saml.client.signature": "true",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
+            }
+        },
+        {
+            "name": "http://localhost:8082/sales-post-sig-persistent/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8082/sales-post-sig-persistent",
+            "redirectUris": [
+                "http://localhost:8082/sales-post-sig-persistent/*"
+            ],
+            "attributes": {
+                "saml_assertion_consumer_url_post": "http://localhost:8082/sales-post-sig-persistent/saml",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8082/sales-post-sig-persistent/saml",
+                "saml_single_logout_service_url_post": "http://localhost:8082/sales-post-sig-persistent/saml",
+                "saml_single_logout_service_url_redirect": "http://localhost:8082/sales-post-sig-persistent/saml",
+                "saml.server.signature": "true",
+                "saml.signature.algorithm": "RSA_SHA256",
+                "saml.client.signature": "true",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
+            }
+        },
+        {
+            "name": "http://localhost:8082/sales-post-sig-email/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8082/sales-post-sig-email",
+            "adminUrl": "http://localhost:8082/sales-post-sig-email/saml",
+            "redirectUris": [
+                "http://localhost:8082/sales-post-sig-email/*"
+            ],
+            "attributes": {
+                "saml_force_name_id_format": "true",
+                "saml_name_id_format": "email",
+                "saml_assertion_consumer_url_post": "http://localhost:8082/sales-post-sig-email/saml",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8082/sales-post-sig-email/saml",
+                "saml_single_logout_service_url_post": "http://localhost:8082/sales-post-sig-email/saml",
+                "saml_single_logout_service_url_redirect": "http://localhost:8082/sales-post-sig-email/saml",
+                "saml.server.signature": "true",
+                "saml.signature.algorithm": "RSA_SHA256",
+                "saml.client.signature": "true",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
+            }
+        },
+        {
+            "name": "http://localhost:8082/bad-realm-sales-post-sig/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8082/bad-realm-sales-post-sig/",
+            "adminUrl": "http://localhost:8082/bad-realm-sales-post-sig/saml",
+            "redirectUris": [
+                "http://localhost:8082/bad-realm-sales-post-sig/*"
+            ],
+            "attributes": {
+                "saml.server.signature": "true",
+                "saml.client.signature": "true",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB1DCCAT0CBgFJGP5dZDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1zaWcvMB4XDTE0MTAxNjEyNDQyM1oXDTI0MTAxNjEyNDYwM1owMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3Qtc2lnLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1RvGu8RjemSJA23nnMksoHA37MqY1DDTxOECY4rPAd9egr7GUNIXE0y1MokaR5R2crNpN8RIRwR8phQtQDjXL82c6W+NLQISxztarQJ7rdNJIYwHY0d5ri1XRpDP8zAuxubPYiMAVYcDkIcvlbBpwh/dRM5I2eElRK+eSiaMkCUCAwEAATANBgkqhkiG9w0BAQsFAAOBgQCLms6htnPaY69k1ntm9a5jgwSn/K61cdai8R8B0ccY7zvinn9AfRD7fiROQpFyY29wKn8WCLrJ86NBXfgFUGyR5nLNHVy3FghE36N2oHy53uichieMxffE6vhkKJ4P8ChfJMMOZlmCPsQPDvjoAghHt4mriFiQgRdPgIy/zDjSNw=="
+            }
+        },
+        {
+            "name": "http://localhost:8082/bad-client-sales-post-sig/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8082/bad-client-sales-post-sig/",
+            "adminUrl": "http://localhost:8082/bad-client-sales-post-sig/saml",
+            "redirectUris": [
+                "http://localhost:8082/bad-client-sales-post-sig/*"
+            ],
+            "attributes": {
+                "saml.server.signature": "true",
+                "saml.client.signature": "true",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g=="
+            }
+        },
+        {
+            "name": "http://localhost:8082/sales-post-enc/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8082/sales-post-enc",
+            "redirectUris": [
+                "http://localhost:8082/sales-post-enc/*"
+            ],
+            "attributes": {
+                "saml_assertion_consumer_url_post": "http://localhost:8082/sales-post-enc/saml",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8082/sales-post-enc/saml",
+                "saml_single_logout_service_url_post": "http://localhost:8082/sales-post-enc/saml",
+                "saml_single_logout_service_url_redirect": "http://localhost:8082/sales-post-enc/saml",
+                "saml.server.signature": "true",
+                "saml.signature.algorithm": "RSA_SHA512",
+                "saml.client.signature": "true",
+                "saml.encrypt": "true",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g==",
+                "saml.encryption.certificate": "MIIB1DCCAT0CBgFJGVacCDANBgkqhkiG9w0BAQsFADAwMS4wLAYDVQQDEyVodHRwOi8vbG9jYWxob3N0OjgwODAvc2FsZXMtcG9zdC1lbmMvMB4XDTE0MTAxNjE0MjA0NloXDTI0MTAxNjE0MjIyNlowMDEuMCwGA1UEAxMlaHR0cDovL2xvY2FsaG9zdDo4MDgwL3NhbGVzLXBvc3QtZW5jLzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2+5MCT5BnVN+IYnKZcH6ev1pjXGi4feE0nOycq/VJ3aeaZMi4G9AxOxCBPupErOC7Kgm/Bw5AdJyw+Q12wSRXfJ9FhqCrLXpb7YOhbVSTJ8De5O8mW35DxAlh/cxe9FXjqPb286wKTUZ3LfGYR+X235UQeCTAPS/Ufi21EXaEikCAwEAATANBgkqhkiG9w0BAQsFAAOBgQBMrfGD9QFfx5v7ld/OAto5rjkTe3R1Qei8XRXfcs83vLaqEzjEtTuLGrJEi55kXuJgBpVmQpnwCCkkjSy0JxbqLDdVi9arfWUxEGmOr01ZHycELhDNaQcFqVMPr5kRHIHgktT8hK2IgCvd3Fy9/JCgUgCPxKfhwecyEOKxUc857g=="
+            }
+        },
+        {
+            "name": "http://localhost:8082/employee-sig/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8082/employee-sig",
+            "redirectUris": [
+                "http://localhost:8082/employee-sig/*"
+            ],
+            "adminUrl": "http://localhost:8082/employee-sig/saml",
+            "attributes": {
+                "saml.server.signature": "true",
+                "saml.client.signature": "true",
+                "saml.signature.algorithm": "RSA_SHA256",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB0DCCATkCBgFJH5u0EDANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNodHRwOi8vbG9jYWxob3N0OjgwODAvZW1wbG95ZWUtc2lnLzAeFw0xNDEwMTcxOTMzNThaFw0yNDEwMTcxOTM1MzhaMC4xLDAqBgNVBAMTI2h0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9lbXBsb3llZS1zaWcvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACKyPLGqMX8GsIrCfJU8eVnpaqzTXMglLVo/nTcfAnWe9UAdVe8N3a2PXpDBvuqNA/DEAhVcQgxdlOTWnB6s8/yLTRuH0bZgb3qGdySif+lU+E7zZ/SiDzavAvn+ABqemnzHcHyhYO+hNRGHvUbW5OAii9Vdjhm8BI32YF1NwhKp"
+            }
+        },
+        {
+            "name": "http://localhost:8082/employee/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8082/employee/",
+            "redirectUris": [
+                "http://localhost:8082/employee/*"
+            ],
+            "adminUrl": "http://localhost:8082/employee/saml",
+            "attributes": {
+                "saml.authnstatement": "true"
+            },
+            "protocolMappers": [
+                {
+                    "name": "email",
+                    "protocol": "saml",
+                    "protocolMapper": "saml-user-property-mapper",
+                    "consentRequired": false,
+                    "config": {
+                        "user.attribute": "email",
+                        "friendly.name": "email",
+                        "attribute.name": "urn:oid:1.2.840.113549.1.9.1",
+                        "attribute.nameformat": "URI Reference"
+                    }
+                },
+                {
+                    "name": "phone",
+                    "protocol": "saml",
+                    "protocolMapper": "saml-user-attribute-mapper",
+                    "consentRequired": false,
+                    "config": {
+                        "user.attribute": "phone",
+                        "attribute.name": "phone",
+                        "attribute.nameformat": "Basic"
+                    }
+                },
+                {
+                    "name": "role-list",
+                    "protocol": "saml",
+                    "protocolMapper": "saml-role-list-mapper",
+                    "consentRequired": false,
+                    "config": {
+                        "attribute.name": "Role",
+                        "attribute.nameformat": "Basic",
+                        "single": "false"
+                    }
+                }
+            ]
+        },
+        {
+            "name": "http://localhost:8082/employee2/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "baseUrl": "http://localhost:8082/employee2/",
+            "redirectUris": [
+                "http://localhost:8082/employee2/*"
+            ],
+            "adminUrl": "http://localhost:8082/employee2/saml",
+            "attributes": {
+                "saml.authnstatement": "true"
+            },
+            "protocolMappers": [
+                {
+                    "name": "email",
+                    "protocol": "saml",
+                    "protocolMapper": "saml-user-property-mapper",
+                    "consentRequired": false,
+                    "config": {
+                        "user.attribute": "email",
+                        "friendly.name": "email",
+                        "attribute.name": "urn:oid:1.2.840.113549.1.9.1",
+                        "attribute.nameformat": "URI Reference"
+                    }
+                },
+                {
+                    "name": "phone",
+                    "protocol": "saml",
+                    "protocolMapper": "saml-user-attribute-mapper",
+                    "consentRequired": false,
+                    "config": {
+                        "user.attribute": "phone",
+                        "attribute.name": "phone",
+                        "attribute.nameformat": "Basic"
+                    }
+                },
+                {
+                    "name": "role-list",
+                    "protocol": "saml",
+                    "protocolMapper": "saml-role-list-mapper",
+                    "consentRequired": false,
+                    "config": {
+                        "attribute.name": "Role",
+                        "attribute.nameformat": "Basic",
+                        "single": "false"
+                    }
+                }
+            ]
+        },
+        {
+            "name": "http://localhost:8082/employee-sig-front/",
+            "enabled": true,
+            "protocol": "saml",
+            "fullScopeAllowed": true,
+            "frontchannelLogout": true,
+            "baseUrl": "http://localhost:8082/employee-sig-front/",
+            "redirectUris": [
+                "http://localhost:8082/employee-sig-front/*"
+            ],
+            "attributes": {
+                "saml_assertion_consumer_url_post": "http://localhost:8082/employee-sig-front/saml",
+                "saml_assertion_consumer_url_redirect": "http://localhost:8082/employee-sig-front/saml",
+                "saml_single_logout_service_url_post": "http://localhost:8082/employee-sig-front/saml",
+                "saml_single_logout_service_url_redirect": "http://localhost:8082/employee-sig-front/saml",
+                "saml.server.signature": "true",
+                "saml.client.signature": "true",
+                "saml.signature.algorithm": "RSA_SHA1",
+                "saml.authnstatement": "true",
+                "saml.signing.certificate": "MIIB0DCCATkCBgFJH5u0EDANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNodHRwOi8vbG9jYWxob3N0OjgwODAvZW1wbG95ZWUtc2lnLzAeFw0xNDEwMTcxOTMzNThaFw0yNDEwMTcxOTM1MzhaMC4xLDAqBgNVBAMTI2h0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9lbXBsb3llZS1zaWcvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+9kVgPFpshjS2aT2g52lqTv2lqb1jgvXZVk7iFF4LAO6SdCXKXRZI4SuzIRkVNpE1a42V1kQRlaozoFklgvX5sje8tkpa9ylq+bxGXM9RRycqRu2B+oWUV7Aqq7Bs0Xud0WeHQYRcEoCjqsFKGy65qkLRDdT70FTJgpSHts+gDwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBACKyPLGqMX8GsIrCfJU8eVnpaqzTXMglLVo/nTcfAnWe9UAdVe8N3a2PXpDBvuqNA/DEAhVcQgxdlOTWnB6s8/yLTRuH0bZgb3qGdySif+lU+E7zZ/SiDzavAvn+ABqemnzHcHyhYO+hNRGHvUbW5OAii9Vdjhm8BI32YF1NwhKp"
+            }
+        }
+    ],
+    "groups" : [
+        {
+            "name": "top",
+            "attributes": {
+                "topAttribute": ["true"]
+
+            },
+            "realmRoles": ["manager"],
+            "subGroups": [
+                {
+                    "name": "level2",
+                    "realmRoles": ["user"],
+                    "attributes": {
+                        "level2Attribute": ["true"]
+
+                    }
+                }
+            ]
+        }
+    ],
+    "roles" : {
+        "realm" : [
+            {
+                "name": "manager",
+                "description": "Have Manager privileges"
+            },
+            {
+                "name": "user",
+                "description": "Have User privileges"
+            }
+        ],
+        "application" : {
+            "http://localhost:8082/employee/" : [
+                {
+                    "name": "employee",
+                    "description": "Have Employee privileges"
+                }
+            ],
+            "http://localhost:8082/employee2/" : [
+                {
+                    "name": "employee",
+                    "description": "Have Employee privileges"
+                }
+            ]
+        }
+    }
+}
diff --git a/testsuite/jetty/pom.xml b/testsuite/jetty/pom.xml
index e6951dc..55fa3b4 100755
--- a/testsuite/jetty/pom.xml
+++ b/testsuite/jetty/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-testsuite-pom</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <name>Keycloak SAML Jetty Testsuite Integration</name>
@@ -34,5 +34,6 @@
         <module>jetty81</module>
         <module>jetty91</module>
         <module>jetty92</module>
+        <module>jetty93</module>
     </modules>
 </project>
diff --git a/testsuite/pom.xml b/testsuite/pom.xml
index 83eaa85..6e2a3c3 100755
--- a/testsuite/pom.xml
+++ b/testsuite/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
@@ -56,8 +56,6 @@
         <module>tomcat7</module>
         <module>tomcat8</module>
         <module>jetty</module>
-        <module>performance</module>
-        <module>stress</module>
         <module>integration-arquillian</module>
     </modules>
         
diff --git a/testsuite/proxy/pom.xml b/testsuite/proxy/pom.xml
index a8a50c4..8399b22 100755
--- a/testsuite/proxy/pom.xml
+++ b/testsuite/proxy/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-testsuite-pom</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/testsuite/tomcat6/pom.xml b/testsuite/tomcat6/pom.xml
index 1e8f51c..72297a5 100755
--- a/testsuite/tomcat6/pom.xml
+++ b/testsuite/tomcat6/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-testsuite-pom</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/testsuite/tomcat7/pom.xml b/testsuite/tomcat7/pom.xml
index a424eeb..d7e5613 100755
--- a/testsuite/tomcat7/pom.xml
+++ b/testsuite/tomcat7/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-testsuite-pom</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/testsuite/tomcat8/pom.xml b/testsuite/tomcat8/pom.xml
index 64643f7..2b76dfa 100755
--- a/testsuite/tomcat8/pom.xml
+++ b/testsuite/tomcat8/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-testsuite-pom</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>

themes/pom.xml 2(+1 -1)

diff --git a/themes/pom.xml b/themes/pom.xml
index 48e9831..5338312 100755
--- a/themes/pom.xml
+++ b/themes/pom.xml
@@ -4,7 +4,7 @@
 	<parent>
 		<artifactId>keycloak-parent</artifactId>
 		<groupId>org.keycloak</groupId>
-		<version>2.0.0.CR1-SNAPSHOT</version>
+		<version>2.2.0-SNAPSHOT</version>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
 
diff --git a/themes/src/main/resources/theme/base/account/account.ftl b/themes/src/main/resources/theme/base/account/account.ftl
index 34c3e84..87cd198 100755
--- a/themes/src/main/resources/theme/base/account/account.ftl
+++ b/themes/src/main/resources/theme/base/account/account.ftl
@@ -3,7 +3,7 @@
 
     <div class="row">
         <div class="col-md-10">
-            <h2>${msg("editAccountHtmlTtile")}</h2>
+            <h2>${msg("editAccountHtmlTitle")}</h2>
         </div>
         <div class="col-md-2 subtitle">
             <span class="subtitle"><span class="required">*</span> ${msg("requiredFields")}</span>
diff --git a/themes/src/main/resources/theme/base/account/messages/messages_ca.properties b/themes/src/main/resources/theme/base/account/messages/messages_ca.properties
index 4b148ab..5820c4f 100644
--- a/themes/src/main/resources/theme/base/account/messages/messages_ca.properties
+++ b/themes/src/main/resources/theme/base/account/messages/messages_ca.properties
@@ -5,7 +5,7 @@ doRemove=Elimina
 doAdd=Afegeix
 doSignOut=Desconnectar
 
-editAccountHtmlTtile=Edita compte
+editAccountHtmlTitle=Edita compte
 federatedIdentitiesHtmlTitle=Identitats federades
 accountLogHtmlTitle=Registre del compte
 changePasswordHtmlTitle=Canvia contrasenya
diff --git a/themes/src/main/resources/theme/base/account/messages/messages_de.properties b/themes/src/main/resources/theme/base/account/messages/messages_de.properties
index 20ea9cc..f9d27e9 100644
--- a/themes/src/main/resources/theme/base/account/messages/messages_de.properties
+++ b/themes/src/main/resources/theme/base/account/messages/messages_de.properties
@@ -5,7 +5,7 @@ doRemove=Entfernen
 doAdd=Hinzuf\u00FCgen
 doSignOut=Abmelden
 
-editAccountHtmlTtile=Benutzerkonto Bearbeiten
+editAccountHtmlTitle=Benutzerkonto Bearbeiten
 federatedIdentitiesHtmlTitle=Federated Identities
 accountLogHtmlTitle=Benutzerkonto Log
 changePasswordHtmlTitle=Passwort \u00C4ndern
diff --git a/themes/src/main/resources/theme/base/account/messages/messages_en.properties b/themes/src/main/resources/theme/base/account/messages/messages_en.properties
index 8c0727f..5c7ff81 100755
--- a/themes/src/main/resources/theme/base/account/messages/messages_en.properties
+++ b/themes/src/main/resources/theme/base/account/messages/messages_en.properties
@@ -5,7 +5,7 @@ doRemove=Remove
 doAdd=Add
 doSignOut=Sign Out
 
-editAccountHtmlTtile=Edit Account
+editAccountHtmlTitle=Edit Account
 federatedIdentitiesHtmlTitle=Federated Identities
 accountLogHtmlTitle=Account Log
 changePasswordHtmlTitle=Change Password
@@ -53,6 +53,7 @@ role_view-profile=View profile
 role_manage-account=Manage account
 role_read-token=Read token
 role_offline-access=Offline access
+role_uma_authorization=Obtain permissions
 client_account=Account
 client_security-admin-console=Security Admin Console
 client_admin-cli=Admin CLI
@@ -156,4 +157,5 @@ locale_en=English
 locale_es=Espa\u00F1ol
 locale_fr=Fran\u00e7ais
 locale_it=Italian
-locale_pt-BR=Portugu\u00EAs (Brasil)
\ No newline at end of file
+locale_pt-BR=Portugu\u00EAs (Brasil)
+locale_ru=\u0420\u0443\u0441\u0441\u043A\u0438\u0439
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/account/messages/messages_es.properties b/themes/src/main/resources/theme/base/account/messages/messages_es.properties
index ce04c52..24dfa1a 100644
--- a/themes/src/main/resources/theme/base/account/messages/messages_es.properties
+++ b/themes/src/main/resources/theme/base/account/messages/messages_es.properties
@@ -5,7 +5,7 @@ doRemove=Eliminar
 doAdd=A\u00F1adir
 doSignOut=Desconectar
 
-editAccountHtmlTtile=Editar cuenta
+editAccountHtmlTitle=Editar cuenta
 federatedIdentitiesHtmlTitle=Identidades federadas
 accountLogHtmlTitle=Registro de la cuenta
 changePasswordHtmlTitle=Cambiar contrase\u00F1a
diff --git a/themes/src/main/resources/theme/base/account/messages/messages_fr.properties b/themes/src/main/resources/theme/base/account/messages/messages_fr.properties
index ccd3bcb..34680a3 100644
--- a/themes/src/main/resources/theme/base/account/messages/messages_fr.properties
+++ b/themes/src/main/resources/theme/base/account/messages/messages_fr.properties
@@ -8,7 +8,7 @@ doRemove=Supprimer
 doAdd=Ajouter
 doSignOut=D\u00e9connexion
 
-editAccountHtmlTtile=Edition du compte
+editAccountHtmlTitle=Edition du compte
 federatedIdentitiesHtmlTitle=Identit\u00e9s f\u00e9d\u00e9r\u00e9es
 accountLogHtmlTitle=Acc\u00e8s au compte
 changePasswordHtmlTitle=Changer de mot de passe
diff --git a/themes/src/main/resources/theme/base/account/messages/messages_it.properties b/themes/src/main/resources/theme/base/account/messages/messages_it.properties
index e14064f..a7e2931 100755
--- a/themes/src/main/resources/theme/base/account/messages/messages_it.properties
+++ b/themes/src/main/resources/theme/base/account/messages/messages_it.properties
@@ -5,7 +5,7 @@ doRemove=Elimina
 doAdd=Aggiungi
 doSignOut=Sign Out
 
-editAccountHtmlTtile=Gestisci Account
+editAccountHtmlTitle=Gestisci Account
 federatedIdentitiesHtmlTitle=Federated Identities
 accountLogHtmlTitle=Account Log
 changePasswordHtmlTitle=Cambia Password
diff --git a/themes/src/main/resources/theme/base/account/messages/messages_pt_BR.properties b/themes/src/main/resources/theme/base/account/messages/messages_pt_BR.properties
index e2e8743..5c4c5b8 100644
--- a/themes/src/main/resources/theme/base/account/messages/messages_pt_BR.properties
+++ b/themes/src/main/resources/theme/base/account/messages/messages_pt_BR.properties
@@ -5,7 +5,7 @@ doRemove=Remover
 doAdd=Adicionar
 doSignOut=Sair
 
-editAccountHtmlTtile=Editar Conta
+editAccountHtmlTitle=Editar Conta
 federatedIdentitiesHtmlTitle=Identidades Federadas
 accountLogHtmlTitle=Log da conta
 changePasswordHtmlTitle=Alterar senha
@@ -53,6 +53,7 @@ role_view-profile=Visualiza perfil
 role_manage-account=Gerencia conta
 role_read-token=L\u00EA token
 role_offline-access=Acesso Offline
+role_uma_authorization=Obter permiss\u00F5es
 client_account=Conta
 client_security-admin-console=Console de Administra\u00E7\u00E3o de Seguran\u00E7a
 client_admin-cli=Admin CLI
diff --git a/themes/src/main/resources/theme/base/account/messages/messages_ru.properties b/themes/src/main/resources/theme/base/account/messages/messages_ru.properties
new file mode 100644
index 0000000..b7d892a
--- /dev/null
+++ b/themes/src/main/resources/theme/base/account/messages/messages_ru.properties
@@ -0,0 +1,151 @@
+doSave=\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C
+doCancel=\u041E\u0442\u043C\u0435\u043D\u0430
+doLogOutAllSessions=\u0412\u044B\u0439\u0442\u0438 \u0438\u0437 \u0432\u0441\u0435\u0445 \u0441\u0435\u0441\u0441\u0438\u0439
+doRemove=\u0423\u0434\u0430\u043B\u0438\u0442\u044C
+doAdd=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C
+doSignOut=\u0412\u044B\u0445\u043E\u0434
+
+editAccountHtmlTitle=\u0418\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0435 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u0438
+federatedIdentitiesHtmlTitle=\u0424\u0435\u0434\u0435\u0440\u0430\u0442\u0438\u0432\u043D\u044B\u0435 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u044B
+accountLogHtmlTitle=\u041B\u043E\u0433 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u0438
+changePasswordHtmlTitle=\u0421\u043C\u0435\u043D\u0430 \u043F\u0430\u0440\u043E\u043B\u044F
+sessionsHtmlTitle=\u0421\u0435\u0441\u0441\u0438\u0438
+accountManagementTitle=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u044C\u044E
+authenticatorTitle=\u0410\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440
+applicationsHtmlTitle=\u041F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F
+
+authenticatorCode=\u041E\u0434\u043D\u043E\u0440\u0430\u0437\u043E\u0432\u044B\u0439 \u043A\u043E\u0434
+email=\u042D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u0430\u044F \u043F\u043E\u0447\u0442\u0430
+firstName=\u0418\u043C\u044F
+givenName=\u0412\u044B\u0434\u0430\u043D\u043D\u043E\u0435 \u0438\u043C\u044F
+fullName=\u041F\u043E\u043B\u043D\u043E\u0435 \u0438\u043C\u044F
+lastName=\u0424\u0430\u043C\u0438\u043B\u0438\u044F
+familyName=\u0424\u0430\u043C\u0438\u043B\u0438\u044F
+password=\u041F\u0430\u0440\u043E\u043B\u044C
+passwordConfirm=\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u043F\u0430\u0440\u043E\u043B\u044F
+passwordNew=\u041D\u043E\u0432\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C
+username=\u0418\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
+address=\u0410\u0434\u0440\u0435\u0441
+street=\u0423\u043B\u0438\u0446\u0430
+locality=\u0413\u043E\u0440\u043E\u0434
+region=\u0420\u0435\u0433\u0438\u043E\u043D
+postal_code=\u041F\u043E\u0447\u0442\u043E\u0432\u044B\u0439 \u0438\u043D\u0434\u0435\u043A\u0441
+country=\u0421\u0442\u0440\u0430\u043D\u0430
+emailVerified=\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u043F\u043E\u0447\u0442\u043E\u0432\u043E\u0433\u043E \u0430\u0434\u0440\u0435\u0441\u0430
+gssDelegationCredential=\u0414\u0435\u043B\u0435\u0433\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0434\u0430\u043D\u043D\u044B\u0445 \u0447\u0435\u0440\u0435\u0437 GSS
+
+role_admin=\u0410\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440
+role_realm-admin=\u0410\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440 realm
+role_create-realm=\u0421\u043E\u0437\u0434\u0430\u0442\u044C realm
+role_view-realm=\u041F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 realm
+role_view-users=\u041F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439
+role_view-applications=\u041F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0439
+role_view-clients=\u041F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u043A\u043B\u0438\u0435\u043D\u0442\u043E\u0432
+role_view-events=\u041F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u0441\u043E\u0431\u044B\u0442\u0438\u0439
+role_view-identity-providers=\u041F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440\u043E\u0432 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439
+role_manage-realm=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 realm
+role_manage-users=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F\u043C\u0438
+role_manage-applications=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F\u043C\u0438
+role_manage-identity-providers=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440\u0430\u043C\u0438 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439
+role_manage-clients=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043A\u043B\u0438\u0435\u043D\u0442\u0430\u043C\u0438
+role_manage-events=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0441\u043E\u0431\u044B\u0442\u0438\u044F\u043C\u0438
+role_view-profile=\u041F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u043F\u0440\u043E\u0444\u0438\u043B\u044F
+role_manage-account=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u044C\u044E
+role_read-token=\u0427\u0442\u0435\u043D\u0438\u0435 \u0442\u043E\u043A\u0435\u043D\u0430
+role_offline-access=\u0414\u043E\u0441\u0442\u0443\u043F \u043E\u0444\u0444\u043B\u0430\u0439\u043D
+client_account=\u0423\u0447\u0435\u0442\u043D\u0430\u044F \u0437\u0430\u043F\u0438\u0441\u044C
+client_security-admin-console=\u041A\u043E\u043D\u0441\u043E\u043B\u044C \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430 \u0431\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u043E\u0441\u0442\u0438
+client_admin-cli=\u041A\u043E\u043C\u0430\u043D\u0434\u043D\u044B\u0439 \u0438\u043D\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430
+client_realm-management=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 Realm
+client_broker=\u0411\u0440\u043E\u043A\u0435\u0440
+
+
+requiredFields=\u041E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u043F\u043E\u043B\u044F
+allFieldsRequired=\u0412\u0441\u0435 \u043F\u043E\u043B\u044F \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u0435
+
+backToApplication=&laquo; \u041D\u0430\u0437\u0430\u0434 \u0432 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435
+backTo=\u041D\u0430\u0437\u0430\u0434 \u0432 {0}
+
+date=\u0414\u0430\u0442\u0430
+event=\u0421\u043E\u0431\u044B\u0442\u0438\u0435
+ip=IP
+client=\u041A\u043B\u0438\u0435\u043D\u0442
+clients=\u041A\u043B\u0438\u0435\u043D\u0442\u044B
+details=\u0414\u0435\u0442\u0430\u043B\u0438
+started=\u041D\u0430\u0447\u0430\u0442\u0430
+lastAccess=\u041F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u0439 \u0434\u043E\u0441\u0442\u0443\u043F
+expires=\u0418\u0441\u0442\u0435\u043A\u0430\u0435\u0442
+applications=\u041F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F
+
+account=\u0423\u0447\u0435\u0442\u043D\u0430\u044F \u0437\u0430\u043F\u0438\u0441\u044C
+federatedIdentity=\u0424\u0435\u0434\u0435\u0440\u0430\u0442\u0438\u0432\u043D\u044B\u0439 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440
+authenticator=\u0410\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440
+sessions=\u0421\u0435\u0441\u0441\u0438\u0438
+log=\u041B\u043E\u0433
+
+application=\u041F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435
+availablePermissions=\u0414\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u0438\u044F
+grantedPermissions=\u0421\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u043D\u044B\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u0438\u044F
+grantedPersonalInfo=\u0421\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u043D\u0430\u044F \u043F\u0435\u0440\u0441\u043E\u043D\u0430\u043B\u044C\u043D\u0430\u044F \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F
+additionalGrants=\u0414\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u0438\u044F
+action=\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0435
+inResource=\u0432
+fullAccess=\u041F\u043E\u043B\u043D\u044B\u0439 \u0434\u043E\u0441\u0442\u0443\u043F
+offlineToken=\u041E\u0444\u0444\u043B\u0430\u0439\u043D \u0442\u043E\u043A\u0435\u043D
+revoke=\u041E\u0442\u043E\u0437\u0432\u0430\u0442\u044C \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u0438\u0435
+
+configureAuthenticators=\u0421\u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0435 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u044B
+mobile=\u041C\u043E\u0431\u0438\u043B\u044C\u043D\u043E\u0435 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435
+totpStep1=\u0423\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0435 <a href="https://fedorahosted.org/freeotp/" target="_blank">FreeOTP</a> \u0438\u043B\u0438 Google Authenticator. \u041E\u0431\u0430 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B \u043D\u0430 <a href="https://play.google.com">Google Play</a> \u0438 \u0432 Apple App Store.
+totpStep2=\u041E\u0442\u043A\u0440\u043E\u0439\u0442\u0435 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u0438 \u043F\u0440\u043E\u0441\u043A\u0430\u043D\u0438\u0440\u0443\u0439\u0442\u0435 \u0431\u0430\u0440\u043A\u043E\u0434, \u043B\u0438\u0431\u043E \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u043A\u043B\u044E\u0447.
+totpStep3=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043E\u0434\u043D\u043E\u0440\u0430\u0437\u043E\u0432\u044B\u0439 \u043A\u043E\u0434, \u0432\u044B\u0434\u0430\u043D\u043D\u044B\u0439 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435\u043C, \u0438 \u043D\u0430\u0436\u043C\u0438\u0442\u0435 \u0441\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C \u0434\u043B\u044F \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0438\u044F \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438.
+
+missingUsernameMessage=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0438\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F.
+missingFirstNameMessage=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0438\u043C\u044F.
+invalidEmailMessage=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u044B\u0439 \u0430\u0434\u0440\u0435\u0441.
+missingLastNameMessage=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0444\u0430\u043C\u0438\u043B\u0438\u044E.
+missingEmailMessage=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u044B\u0439 \u0430\u0434\u0440\u0435\u0441.
+missingPasswordMessage=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043F\u0430\u0440\u043E\u043B\u044C.
+notMatchPasswordMessage=\u041F\u0430\u0440\u043E\u043B\u0438 \u043D\u0435 \u0441\u043E\u0432\u043F\u0430\u0434\u0430\u044E\u0442.
+
+missingTotpMessage=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043A\u043E\u0434 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u0430.
+invalidPasswordExistingMessage=\u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0439 \u043F\u0430\u0440\u043E\u043B\u044C \u043D\u0435\u0432\u0435\u0440\u043D\u044B\u0439.
+invalidPasswordConfirmMessage=\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u043F\u0430\u0440\u043E\u043B\u044F \u043D\u0435 \u0441\u043E\u0432\u043F\u0430\u0434\u0430\u0435\u0442.
+invalidTotpMessage=\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u043A\u043E\u0434 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u0430.
+
+usernameExistsMessage=\u0418\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442.
+emailExistsMessage=\u042D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u044B\u0439 \u0430\u0434\u0440\u0435\u0441 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442.
+
+readOnlyUserMessage=\u0412\u044B \u043D\u0435 \u043C\u043E\u0436\u0435\u0442\u0435 \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044E \u0432\u0430\u0448\u0435\u0439 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u0438, \u0442.\u043A. \u043E\u043D\u0430 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0430 \u0442\u043E\u043B\u044C\u043A\u043E \u0434\u043B\u044F \u0447\u0442\u0435\u043D\u0438\u044F.
+readOnlyPasswordMessage=\u0412\u044B \u043D\u0435 \u043C\u043E\u0436\u0435\u0442\u0435 \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u043F\u0430\u0440\u043E\u043B\u044C \u0432\u0430\u0448\u0435\u0439 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u0438, \u0442.\u043A. \u043E\u043D \u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D \u0442\u043E\u043B\u044C\u043A\u043E \u0434\u043B\u044F \u0447\u0442\u0435\u043D\u0438\u044F.
+
+successTotpMessage=\u0410\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u0432 \u043C\u043E\u0431\u0438\u043B\u044C\u043D\u043E\u043C \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0438 \u0441\u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043E\u0432\u0430\u043D.
+successTotpRemovedMessage=\u0410\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u0432 \u043C\u043E\u0431\u0438\u043B\u044C\u043D\u043E\u043C \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0438 \u0443\u0434\u0430\u043B\u0435\u043D.
+
+successGrantRevokedMessage=\u0421\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u0438\u0435 \u043E\u0442\u043E\u0437\u0432\u0430\u043D\u043E \u0443\u0441\u043F\u0435\u0448\u043D\u043E.
+
+accountUpdatedMessage=\u0412\u0430\u0448\u0430 \u0443\u0447\u0435\u0442\u043D\u0430\u044F \u0437\u0430\u043F\u0438\u0441\u044C \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0430.
+accountPasswordUpdatedMessage=\u0412\u0430\u0448\u0430 \u043F\u0430\u0440\u043E\u043B\u044C \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D.
+
+missingIdentityProviderMessage=\u041F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439 \u043D\u0435 \u0437\u0430\u0434\u0430\u043D.
+invalidFederatedIdentityActionMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u043E\u0435 \u0438\u043B\u0438 \u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435.
+identityProviderNotFoundMessage=\u0417\u0430\u0434\u0430\u043D\u043D\u044B\u0439 \u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D.
+federatedIdentityLinkNotActiveMessage=\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0435 \u0430\u043A\u0442\u0438\u0432\u0435\u043D.
+federatedIdentityRemovingLastProviderMessage=\u0412\u044B \u043D\u0435 \u043C\u043E\u0436\u0435\u0442\u0435 \u0443\u0434\u0430\u043B\u0438\u0442\u044C \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u0439 \u0444\u0435\u0434\u0435\u0440\u0430\u0442\u0438\u0432\u043D\u044B\u0439 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440, \u0442.\u043A. \u0412\u044B \u043D\u0435 \u0438\u043C\u0435\u0435\u0442\u0435 \u043F\u0430\u0440\u043E\u043B\u044F.
+identityProviderRedirectErrorMessage=\u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0435\u0440\u0435\u043D\u0430\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u044F \u0432 \u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439.
+identityProviderRemovedMessage=\u041F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439 \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u0443\u0434\u0430\u043B\u0435\u043D.
+identityProviderAlreadyLinkedMessage=\u0424\u0435\u0434\u0435\u0440\u0430\u0442\u0438\u0432\u043D\u044B\u0439 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440, \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0435\u043D\u043D\u044B\u0439 {0} \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D \u043A \u0434\u0440\u0443\u0433\u043E\u043C\u0443 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E.
+staleCodeAccountMessage=\u0421\u0442\u0440\u0430\u043D\u0438\u0446\u0430 \u0443\u0441\u0442\u0430\u0440\u0435\u043B\u0430. \u041F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0435 \u0440\u0430\u0437.
+consentDenied=\u0412 \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u0438\u0438 \u043E\u0442\u043A\u0430\u0437\u0430\u043D\u043E.
+
+accountDisabledMessage=\u0423\u0447\u0435\u0442\u043D\u0430\u044F \u0437\u0430\u043F\u0438\u0441\u044C \u0437\u0430\u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u0430\u043D\u0430, \u043E\u0431\u0440\u0430\u0442\u0438\u0442\u0435\u0441\u044C \u043A \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0443.
+
+accountTemporarilyDisabledMessage=\u0423\u0447\u0435\u0442\u043D\u0430\u044F \u0437\u0430\u043F\u0438\u0441\u044C \u0432\u0440\u0435\u043C\u0435\u043D\u043D\u043E \u0437\u0430\u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u0430\u043D\u0430, \u043E\u0431\u0440\u0430\u0442\u0438\u0442\u0435\u0441\u044C \u043A \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0443 \u0438\u043B\u0438 \u043F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u043F\u043E\u0437\u0436\u0435.
+invalidPasswordMinLengthMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u043C\u0438\u043D\u0438\u043C\u0430\u043B\u044C\u043D\u0430\u044F \u0434\u043B\u0438\u043D\u0430 {0}.
+invalidPasswordMinLowerCaseCharsMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u0441\u0438\u043C\u0432\u043E\u043B\u044B \u0432 \u043D\u0438\u0436\u043D\u0435\u043C \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0435 \u043D\u0435 \u043C\u0435\u043D\u0435\u0435 {0}.
+invalidPasswordMinDigitsMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u043D\u0435 \u043C\u0435\u043D\u0435\u0435 {0} \u0446\u0438\u0444\u0440(\u044B).
+invalidPasswordMinUpperCaseCharsMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u043D\u0435 \u043C\u0435\u043D\u0435\u0435 {0} \u0441\u0438\u043C\u0432\u043E\u043B\u0430(\u043E\u0432) \u0432 \u0432\u0435\u0440\u0445\u043D\u0435\u043C \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0435.
+invalidPasswordMinSpecialCharsMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u043D\u0435 \u043C\u0435\u043D\u0435\u0435 {0} \u0441\u043F\u0435\u0446\u0441\u0438\u043C\u0432\u043E\u043B\u0430(\u043E\u0432).
+invalidPasswordNotUsernameMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u043F\u0430\u0440\u043E\u043B\u044C \u043D\u0435 \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0432\u043F\u0430\u0434\u0430\u0442\u044C \u0441 \u0438\u043C\u0435\u043D\u0435\u043C \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F.
+invalidPasswordRegexPatternMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u043F\u0430\u0440\u043E\u043B\u044C \u043D\u0435 \u0443\u0434\u043E\u0432\u043B\u0435\u0442\u0432\u043E\u0440\u044F\u0435\u0442 \u0440\u0435\u0433\u0443\u043B\u044F\u0440\u043D\u043E\u043C\u0443 \u0432\u044B\u0440\u0430\u0436\u0435\u043D\u0438\u044E.
+invalidPasswordHistoryMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u043F\u0430\u0440\u043E\u043B\u044C \u043D\u0435 \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0432\u043F\u0430\u0434\u0430\u0442\u044C \u0441 \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u043C(\u0438) {0} \u043F\u0430\u0440\u043E\u043B\u044F\u043C\u0438.
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/account/theme.properties b/themes/src/main/resources/theme/base/account/theme.properties
index 27f59f5..503eda7 100644
--- a/themes/src/main/resources/theme/base/account/theme.properties
+++ b/themes/src/main/resources/theme/base/account/theme.properties
@@ -1 +1 @@
-locales=ca,de,en,es,fr,it,pt-BR
\ No newline at end of file
+locales=ca,de,en,es,fr,it,pt-BR,ru
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/index.ftl b/themes/src/main/resources/theme/base/admin/index.ftl
index e4db6f9..a352281 100755
--- a/themes/src/main/resources/theme/base/admin/index.ftl
+++ b/themes/src/main/resources/theme/base/admin/index.ftl
@@ -36,6 +36,10 @@
     <script src="${resourceUrl}/lib/angular/select2.js" type="text/javascript"></script>
     <script src="${resourceUrl}/lib/fileupload/angular-file-upload.min.js"></script>
     <script src="${resourceUrl}/lib/filesaver/FileSaver.js"></script>
+    <script src="${resourceUrl}/lib/ui-ace/src-min-noconflict/ace.js"></script>
+    <script src="${resourceUrl}/lib/ui-ace/src-min-noconflict/theme-github.js"></script>
+    <script src="${resourceUrl}/lib/ui-ace/src-min-noconflict/mode-javascript.js"></script>
+    <script src="${resourceUrl}/lib/ui-ace/ui-ace.min.js"></script>
 
     <script src="${authUrl}/js/${resourceVersion}/keycloak.js" type="text/javascript"></script>
 
@@ -46,6 +50,20 @@
     <script src="${resourceUrl}/js/controllers/groups.js" type="text/javascript"></script>
     <script src="${resourceUrl}/js/loaders.js" type="text/javascript"></script>
     <script src="${resourceUrl}/js/services.js" type="text/javascript"></script>
+
+    <!-- Authorization -->
+    <script src="${resourceUrl}/js/authz/lib/ace/ace.js" type="text/javascript"></script>
+    <script src="${resourceUrl}/js/authz/lib/ace/mode-javascript.js" type="text/javascript"></script>
+    <script src="${resourceUrl}/js/authz/lib/ace/ui-ace.min.js" type="text/javascript"></script>
+    <script src="${resourceUrl}/js/authz/authz-app.js" type="text/javascript"></script>
+    <script src="${resourceUrl}/js/authz/authz-controller.js" type="text/javascript"></script>
+    <script src="${resourceUrl}/js/authz/authz-services.js" type="text/javascript"></script>
+
+    <#if properties.scripts?has_content>
+        <#list properties.scripts?split(' ') as script>
+            <script type="text/javascript" src="${resourceUrl}/${script}"></script>
+        </#list>
+    </#if>
 </head>
 <body data-ng-controller="GlobalCtrl" data-ng-cloak data-ng-show="auth.user">
 
diff --git a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
index 6658b51..02c7a70 100644
--- a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
+++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties
@@ -17,9 +17,11 @@ selectOne=Select One...
 true=True
 false=False
 
+endpoints=Endpoints
 
 # Realm settings
 realm-detail.enabled.tooltip=Users and clients can only access a realm if it's enabled
+realm-detail.oidc-endpoints.tooltip=Shows the configuration of the OpenID Connect endpoints
 registrationAllowed=User registration
 registrationAllowed.tooltip=Enable/disable the registration page. A link for registration will show on login page too.
 registrationEmailAsUsername=Email as username
@@ -154,7 +156,14 @@ includeInIdToken.label=Add to ID token
 includeInIdToken.tooltip=Should the claim be added to the ID token?
 includeInAccessToken.label=Add to access token
 includeInAccessToken.tooltip=Should the claim be added to the access token?
-
+includeInUserInfo.label=Add to userinfo
+includeInUserInfo.tooltip=Should the claim be added to the userinfo?
+usermodel.clientRoleMapping.clientId.label=Client ID
+usermodel.clientRoleMapping.clientId.tooltip=Client ID for role mappings
+usermodel.clientRoleMapping.rolePrefix.label=Client Role prefix
+usermodel.clientRoleMapping.rolePrefix.tooltip=A prefix for each client role (optional).
+usermodel.realmRoleMapping.rolePrefix.label=Realm Role prefix
+usermodel.realmRoleMapping.rolePrefix.tooltip=A prefix for each Realm Role (optional).
 
 # client details
 clients.tooltip=Clients are trusted browser apps and web services in a realm. These clients can request a login. You can also define client specific roles.
@@ -174,7 +183,7 @@ select-file=Select file
 view-details=View details
 clear-import=Clear import
 client-id.tooltip=Specifies ID referenced in URI and tokens. For example 'my-client'. For SAML this is also the expected issuer value from authn requests
-client.name.tooltip=Specifies display name of the client. For example 'My Client'. Supports keys for localized values as well. For example\\: ${my_client}
+client.name.tooltip=Specifies display name of the client. For example 'My Client'. Supports keys for localized values as well. For example\: ${my_client}
 client.enabled.tooltip=Disabled clients cannot initiate a login or have obtain access tokens.
 consent-required=Consent Required
 consent-required.tooltip=If enabled users have to consent to client access.
@@ -266,6 +275,7 @@ service-account-roles.tooltip=Allows you to authenticate role mappings for the s
 client-authenticator=Client Authenticator
 client-authenticator.tooltip=Client Authenticator used for authentication this client against Keycloak server
 certificate.tooltip=Client Certificate for validate JWT issued by client and signed by Client private key from your keystore.
+publicKey.tooltip=Public Key for validate JWT issued by client and signed by Client private key.
 no-client-certificate-configured=No client certificate configured
 gen-new-keys-and-cert=Generate new keys and certificate
 import-certificate=Import Certificate
@@ -491,7 +501,7 @@ realm=Realm
 identity-provider-mappers=Identity Provider Mappers
 create-identity-provider-mapper=Create Identity Provider Mapper
 add-identity-provider-mapper=Add Identity Provider Mapper
-client.description.tooltip=Specifies description of the client. For example 'My Client for TimeSheets'. Supports keys for localized values as well. For example\\: ${my_client_description}
+client.description.tooltip=Specifies description of the client. For example 'My Client for TimeSheets'. Supports keys for localized values as well. For example\: ${my_client_description}
 
 expires=Expires
 expiration=Expiration
@@ -502,12 +512,25 @@ remainingCount=Remaining Count
 created=Created
 back=Back
 initial-access-tokens=Initial Access Tokens
+initial-access-tokens.tooltip=Initial Access Tokens for dynamic registrations of clients. Request with those tokens can be sent from any host.
 add-initial-access-tokens=Add Initial Access Token
 initial-access-token=Initial Access Token
 initial-access.copyPaste.tooltip=Copy/paste the initial access token before navigating away from this page as it's not posible to retrieve later
 continue=Continue
 initial-access-token.confirm.title=Copy Initial Access Token
 initial-access-token.confirm.text=Please copy and paste the initial access token before confirming as it can't be retrieved later
+no-initial-access-available=No Initial Access Tokens available
+
+trusted-hosts-legend=Trusted Hosts For Client Registrations
+trusted-hosts-legend.tooltip=Hosts, which are trusted for client registrations. Client registration requests from those hosts can be sent even without initial access token. The amount of client registrations from particular host can be limited to specified count.
+no-client-trusted-hosts-available=No Trusted Hosts available
+add-client-reg-trusted-host=Add Trusted Host
+hostname=Hostname
+client-reg-hostname.tooltip=Fully-Qualified Hostname or IP Address. Client registration requests from this host/address will be trusted and allowed to register new client.
+client-reg-count.tooltip=Allowed count of client registration requests from particular host. You need to restart this once the limit is reached.
+client-reg-remainingCount.tooltip=Remaining count of client registration requests from this host. You need to restart this once the limit is reached.
+reset-remaining-count=Reset Remaining Count
+
 
 client-templates=Client Templates
 client-templates.tooltip=Client templates allow you to define common configuration that is shared between multiple clients
@@ -576,6 +599,7 @@ add-client-template=Add client template
 manage=Manage
 authentication=Authentication
 user-federation=User Federation
+user-storage=User Storage
 events=Events
 realm-settings=Realm Settings
 configure=Configure
@@ -587,6 +611,7 @@ client-template.description.tooltip=Description of the client template
 client-template.protocol.tooltip=Which SSO protocol configuration is being supplied by this client template
 
 add-user-federation-provider=Add user federation provider
+add-user-storage-provider=Add user storage provider
 required-settings=Required Settings
 provider-id=Provider ID
 console-display-name=Console Display Name
@@ -678,6 +703,7 @@ create-user-federation-mapper=Create user federation mapper
 add-user-federation-mapper=Add user federation mapper
 provider-name=Provider Name
 no-user-federation-providers-configured=No user federation providers configured
+no-user-storage-providers-configured=No user storage providers configured
 add-identity-provider=Add identity provider
 add-identity-provider-link=Add identity provider link
 identity-provider=Identity Provider
@@ -733,7 +759,9 @@ filter=Filter
 update=Update
 reset=Reset
 operation-types=Operation Types
+resource-types=Resource Types
 select-operations.placeholder=Select operations...
+select-resource-types.placeholder=Select resource types...
 resource-path=Resource Path
 resource-path.tooltip=Filter by resource path. Supports wildcards '*' to match a single part of the path and '**' matches multiple parts. For example 'realms/*/clients/asbc' matches client with id asbc in any realm, while or 'realms/master/**' matches anything in the master realm.
 date-(from)=Date (From)
@@ -742,6 +770,7 @@ authentication-details=Authentication Details
 ip-address=IP Address
 time=Time
 operation-type=Operation Type
+resource-type=Resource Type
 auth=Auth
 representation=Representation
 register=Register
@@ -913,3 +942,178 @@ saved-types=Saved Types
 clear-admin-events=Clear admin events
 clear-changes=Clear changes
 error=Error
+
+# Authz
+# Authz Common
+authz-authorization=Authorization
+authz-owner=Owner
+authz-uri=URI
+authz-scopes=Scopes
+authz-resource=Resource
+authz-resource-type=Resource Type
+authz-resources=Resources
+authz-scope=Scope
+authz-authz-scopes=Authorization Scopes
+authz-policies=Policies
+authz-permissions=Permissions
+authz-evaluate=Evaluate
+authz-icon-uri=Icon URI
+authz-icon-uri.tooltip=An URI pointing to an icon.
+authz-select-scope=Select a scope
+authz-select-resource=Select a resource
+authz-associated-policies=Associated Policies
+authz-any-resource=Any resource
+authz-any-scope=Any scope
+authz-any-role=Any role
+authz-policy-evaluation=Policy Evaluation
+authz-select-client=Select a client
+authz-select-user=Select an user
+authz-entitlements=Entitlements
+authz-no-resources=No resources
+authz-result=Result
+authz-authorization-services-enabled=Authorization Enabled
+authz-authorization-services-enabled.tooltip=Enable/Disable fine-grained authorization support for a client
+authz-required=Required
+
+# Authz Settings
+authz-import-config.tooltip=Import a JSON file containing authorization settings for this resource server.
+
+authz-policy-enforcement-mode=Policy Enforcement Mode
+authz-policy-enforcement-mode.tooltip=The policy enforcement mode dictates how policies are enforced when evaluating authorization requests. 'Enforcing' means requests are denied by default even when there is no policy associated with a given resource. 'Permissive' means requests are allowed even when there is no policy associated with a given resource. 'Disabled' completely disables the evaluation of policies and allow access to any resource.
+authz-policy-enforcement-mode-enforcing=Enforcing
+authz-policy-enforcement-mode-permissive=Permissive
+authz-policy-enforcement-mode-disabled=Disabled
+
+authz-remote-resource-management=Remote Resource Management
+authz-remote-resource-management.tooltip=Should resources be managed remotely by the resource server? If false, resources can only be managed from this admin console.
+
+authz-export-settings=Export Settings
+authz-export-settings.tooltip=Export and download all authorization settings for this resource server.
+
+# Authz Resource List
+authz-no-resources-available=No resources available.
+authz-no-scopes-assigned=No scopes assigned.
+authz-no-type-defined=No type defined.
+authz-no-permission-assigned=No permission assigned.
+authz-no-policy-assigned=No policy assigned.
+authz-create-permission=Create permission
+
+# Authz Resource Detail
+authz-add-resource=Add Resource
+authz-resource-name.tooltip=An unique name for this resource. The name can be used to uniquely identify a resource, useful when querying for a specific resource.
+authz-resource-owner.tooltip=The owner of this resource.
+authz-resource-type.tooltip=The type of this resource. It can be used to group different resource instances with the same type.
+authz-resource-uri.tooltip=An URI that can also be used to uniquely identify this resource.
+authz-resource-scopes.tooltip=The scopes associated with this resource.
+
+# Authz Scope List
+authz-add-scope=Add Scope
+authz-no-scopes-available=No scopes available.
+
+# Authz Scope Detail
+authz-scope-name.tooltip=An unique name for this scope. The name can be used to uniquely identify a scope, useful when querying for a specific scope.
+
+# Authz Policy List
+authz-all-types=All types
+authz-create-policy=Create policy
+authz-no-policies-available=No policies available.
+
+# Authz Policy Detail
+authz-policy-name.tooltip=The name of this policy.
+authz-policy-description.tooltip=A description for this policy.
+authz-policy-logic=Logic
+authz-policy-logic-positive=Positive
+authz-policy-logic-negative=Negative
+authz-policy-logic.tooltip=The logic dictates how the policy decision should be made. If 'Positive', the resulting effect (permit or deny) obtained during the evaluation of this policy will be used to perform a decision. If 'Negative', the resulting effect will be negated, in other words, a permit becomes a deny and vice-versa.
+authz-policy-apply-policy=Apply Policy
+authz-policy-apply-policy.tooltip=Specifies all the policies that must be applied to the scopes defined by this policy or permission.
+authz-policy-decision-strategy=Decision Strategy
+authz-policy-decision-strategy.tooltip=The decision strategy dictates how the policies associated with a given policy are evaluated and how a final decision is obtained. 'Affirmative' means that at least one policy must evaluate to a positive decision in order to the overall decision be also positive. 'Unanimous' means that all policies must evaluate to a positive decision in order to the overall decision be also positive. 'Consensus' means that the number of positive decisions must be greater than the number of negative decisions. If the number of positive and negative is the same, the final decision will be negative.
+authz-policy-decision-strategy-affirmative=Affirmative
+authz-policy-decision-strategy-unanimous=Unanimous
+authz-policy-decision-strategy-consensus=Consensus
+authz-select-a-policy=Select a policy
+
+# Authz Role Policy Detail
+authz-add-role-policy=Add Role Policy
+authz-no-roles-assigned=No roles assigned.
+authz-policy-role-realm-roles.tooltip=Specifies the *realm* roles allowed by this policy.
+authz-policy-role-clients.tooltip=Selects a client in order to filter the client roles that can be applied to this policy.
+authz-policy-role-client-roles.tooltip=Specifies the client roles allowed by this policy.
+
+# Authz User Policy Detail
+authz-add-user-policy=Add User Policy
+authz-no-users-assigned=No users assigned.
+authz-policy-user-users.tooltip=Specifies which user(s) are allowed by this policy.
+
+# Authz Time Policy Detail
+authz-add-time-policy=Add Time Policy
+authz-policy-time-not-before.tooltip=Defines the time before which the policy MUST NOT be granted. Only granted if current date/time is after or equal to this value.
+authz-policy-time-not-on-after=Not On or After
+authz-policy-time-not-on-after.tooltip=Defines the time after which the policy MUST NOT be granted. Only granted if current date/time is before or equal to this value.
+
+# Authz Drools Policy Detail
+authz-add-drools-policy=Add Drools Policy
+authz-policy-drools-maven-artifact-resolve=Resolve
+authz-policy-drools-maven-artifact=Policy Maven Artifact
+authz-policy-drools-maven-artifact.tooltip=A Maven GAV pointing to an artifact from where the rules would be loaded from. Once you have provided the GAV, you can click *Resolve* to load both *Module* and *Session* fields.
+authz-policy-drools-module=Module
+authz-policy-drools-module.tooltip=The module used by this policy. You must provide a module in order to select a specific session from where rules will be loaded from.
+authz-policy-drools-session=Session
+authz-policy-drools-session.tooltip=The session used by this policy. The session provides all the rules to evaluate when processing the policy.
+authz-policy-drools-update-period=Update Period
+authz-policy-drools-update-period.tooltip=Specifies an interval for scanning for artifact updates.
+
+# Authz JS Policy Detail
+authz-add-js-policy=Add JavaScript Policy
+authz-policy-js-code=Code
+authz-policy-js-code.tooltip=The JavaScript code providing the conditions for this policy.
+
+
+# Authz Aggregated Policy Detail
+authz-aggregated=Aggregated
+authz-add-aggregated-policy=Add Aggregated Policy
+
+# Authz Permission List
+authz-no-permissions-available=No permissions available.
+
+# Authz Permission Detail
+authz-permission-name.tooltip=The name of this permission.
+authz-permission-description.tooltip=A description for this permission.
+
+# Authz Resource Permission Detail
+authz-add-resource-permission=Add Resource Permission
+authz-permission-resource-apply-to-resource-type=Apply to Resource Type
+authz-permission-resource-apply-to-resource-type.tooltip=Specifies if this permission would be applied to all resources with a given type. In this case, this permission will be evaluated for all instances of a given resource type.
+authz-permission-resource-resource.tooltip=Specifies that this permission must be applied to a specific resource instance.
+authz-permission-resource-type.tooltip=Specifies that this permission must be applied to all resources instances of a given type.
+
+# Authz Scope Permission Detail
+authz-add-scope-permission=Add Scope Permission
+authz-permission-scope-resource.tooltip=Restrict the scopes to those associated with the selected resource. If not selected all scopes would be available.
+authz-permission-scope-scope.tooltip=Specifies that this permission must be applied to one or more scopes.
+
+# Authz Evaluation
+authz-evaluation-identity-information=Identity Information
+authz-evaluation-identity-information.tooltip=The available options to configure the identity information that will be used when evaluating policies.
+authz-evaluation-client.tooltip=Select the client making this authorization request. If not provided, authorization requests would be done based on the client you are in.
+authz-evaluation-user.tooltip=Select an user whose identity is going to be used to query permissions from the server.
+authz-evaluation-role.tooltip=Select the roles you want to associate with the selected user.
+authz-evaluation-new=New Evaluation
+authz-evaluation-re-evaluate=Re-Evaluate
+authz-evaluation-previous=Previous Evaluation
+authz-evaluation-contextual-info=Contextual Information
+authz-evaluation-contextual-info.tooltip=The available options to configure any contextual information that will be used when evaluating policies.
+authz-evaluation-contextual-attributes=Contextual Attributes
+authz-evaluation-contextual-attributes.tooltip=Any attribute provided by a running environment or execution context.
+authz-evaluation-permissions.tooltip=The available options to configure the permissions to which policies will be applied.
+authz-evaluation-evaluate=Evaluate
+authz-evaluation-any-resource-with-scopes=Any resource with scope(s)
+authz-evaluation-no-result=Could not obtain any result for the given authorization request. Check if the provided resource(s) or scope(s) are associated with any policy.
+authz-evaluation-no-policies-resource=No policies were found for this resource.
+authz-evaluation-result.tooltip=The overall result for this permission request.
+authz-evaluation-scopes.tooltip=The list of allowed scopes.
+authz-evaluation-policies.tooltip=Details about which policies were evaluated and their decisions.
+authz-evaluation-authorization-data=Response
+authz-evaluation-authorization-data.tooltip=Represents a token carrying authorization data as a result of the processing of an authorization request. This representation is basically what Keycloak issues to clients asking for permissions. Check the 'authorization' claim for the permissions that were granted based on the current authorization request.
+authz-show-authorization-data=Show Authorization Data
diff --git a/themes/src/main/resources/theme/base/admin/messages/admin-messages_ru.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_ru.properties
new file mode 100644
index 0000000..c28da56
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_ru.properties
@@ -0,0 +1,915 @@
+consoleTitle=\u041A\u043E\u043D\u0441\u043E\u043B\u044C \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430 Keycloak
+
+# Common messages
+enabled=\u0412\u043A\u043B\u044E\u0447\u0435\u043D\u043E
+name=\u0418\u043C\u044F
+displayName=\u041E\u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0435\u043C\u043E\u0435 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u0435
+displayNameHtml=\u041E\u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0435\u043C\u043E\u0435 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u0432 HTML
+save=\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C
+cancel=\u041E\u0442\u043C\u0435\u043D\u0430
+onText=\u0412\u041A\u041B
+offText=\u0412\u042B\u041A
+client=\u041A\u043B\u0438\u0435\u043D\u0442
+clients=\u041A\u043B\u0438\u0435\u043D\u0442\u044B
+clear=\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C
+selectOne=\u0412\u044B\u0431\u0440\u0430\u0442\u044C...
+
+true=\u0414\u0430
+false=\u041D\u0435\u0442
+
+
+# Realm settings
+realm-detail.enabled.tooltip=\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0438 \u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u044B \u043C\u043E\u0433\u0443\u0442 \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u0434\u043E\u0441\u0442\u0443\u043F \u043A Realm \u0442\u043E\u043B\u044C\u043A\u043E \u0435\u0441\u043B\u0438 \u043E\u043D \u0432\u043A\u043B\u044E\u0447\u0435\u043D
+registrationAllowed=\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
+registrationAllowed.tooltip=\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C/\u0432\u044B\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0443 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438. \u0421\u0441\u044B\u043B\u043A\u0430 \u0434\u043B\u044F \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u0442\u0430\u043A\u0436\u0435 \u043F\u043E\u043A\u0430\u0437\u0430\u043D\u0430 \u043D\u0430 \u0444\u043E\u0440\u043C\u0435 \u0432\u0445\u043E\u0434\u0430.
+registrationEmailAsUsername=Email \u043A\u0430\u043A \u0438\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
+registrationEmailAsUsername.tooltip=\u0415\u0441\u043B\u0438 \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u043E, \u0442\u043E \u043D\u0430 \u0444\u043E\u0440\u043C\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043F\u043E\u043B\u0435 \u0438\u043C\u0435\u043D\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0431\u0443\u0434\u0435\u0442 \u0441\u043A\u0440\u044B\u0442\u043E \u0438 \u0432 \u043A\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0438\u043C\u0435\u043D\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0434\u043B\u044F \u043D\u043E\u0432\u044B\u0445 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C\u0441\u044F email.
+editUsernameAllowed=\u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u0443\u0435\u043C\u043E\u0435 \u0438\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
+editUsernameAllowed.tooltip=\u0415\u0441\u043B\u0438 \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u043E,\u0442\u043E \u0438\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u043C\u043E\u0436\u043D\u043E \u0431\u0443\u0434\u0435\u0442 \u043E\u0442\u0440\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C, \u0438\u043D\u0430\u0447\u0435 \u043E\u043D\u043E \u0431\u0443\u0434\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u043C \u0442\u043E\u043B\u044C\u043A\u043E \u0434\u043B\u044F \u0447\u0442\u0435\u043D\u0438\u044F.
+resetPasswordAllowed=\u0417\u0430\u0431\u044B\u043B\u0438 \u043F\u0430\u0440\u043E\u043B\u044C
+resetPasswordAllowed.tooltip=\u041F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442 \u0441\u0441\u044B\u043B\u043A\u0443 \u043D\u0430 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0435 \u0432\u0445\u043E\u0434\u0430 \u0434\u043B\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F, \u043F\u043E \u043F\u0435\u0440\u0435\u0445\u043E\u0434\u0443 \u043D\u0430 \u043A\u043E\u0442\u043E\u0440\u0443\u044E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u0441\u043C\u043E\u0436\u0435\u0442 \u0432\u043E\u0441\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0441\u0432\u043E\u0438 \u0434\u0430\u043D\u043D\u044B\u0435 \u0434\u043B\u044F \u0432\u0445\u043E\u0434\u0430.
+rememberMe=\u0417\u0430\u043F\u043E\u043C\u043D\u0438\u0442\u044C \u043C\u0435\u043D\u044F
+rememberMe.tooltip=\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0447\u0435\u043A\u0431\u043E\u043A\u0441 \u043D\u0430 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0435 \u0432\u0445\u043E\u0434\u0430, \u0447\u0442\u043E\u0431\u044B \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044C \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E \u0437\u0430\u043F\u043E\u043C\u043D\u0438\u0442\u044C \u0432\u0445\u043E\u0434 \u0432 \u0443\u0447\u0435\u0442\u043D\u0443\u044E \u0437\u0430\u043F\u0438\u0441\u044C \u0432 \u0441\u043B\u0443\u0447\u0430\u0435 \u0435\u0441\u043B\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043D\u0430\u044F \u0441\u0435\u0441\u0441\u0438\u044F \u0443\u0441\u0442\u0430\u0440\u0435\u0435\u0442.
+verifyEmail=\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 email
+verifyEmail.tooltip=\u0422\u0440\u0435\u0431\u0443\u0435\u0442 \u0443 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044C \u0441\u0432\u043E\u0439 email \u043F\u0440\u0438 \u043F\u0435\u0440\u0432\u043E\u043C \u0432\u0445\u043E\u0434\u0435 \u0432 \u0443\u0447\u0435\u0442\u043D\u0443\u044E \u0437\u0430\u043F\u0438\u0441\u044C.
+sslRequired=\u0422\u0440\u0435\u0431\u0443\u0435\u0442 SSL
+sslRequired.option.all=\u0432\u0441\u0435 \u0437\u0430\u043F\u0440\u043E\u0441\u044B
+sslRequired.option.external=\u0432\u043D\u0435\u0448\u043D\u0438\u0435 \u0437\u0430\u043F\u0440\u043E\u0441\u044B
+sslRequired.option.none=\u043D\u0435\u0442
+sslRequired.tooltip=\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044F \u043B\u0438 HTTPS? '\u043D\u0435\u0442' \u043E\u0437\u043D\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043E HTTPS \u043D\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044F \u0434\u043B\u044F \u043B\u044E\u0431\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430 \u0441 \u043B\u044E\u0431\u044B\u043C IP \u0430\u0434\u0440\u0435\u0441\u043E\u043C. '\u0412\u043D\u0435\u0448\u043D\u0438\u0435 \u0437\u0430\u043F\u0440\u043E\u0441\u044B' \u043E\u0437\u043D\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043E localhost \u0438 \u043F\u0440\u0438\u0432\u0430\u0442\u043D\u044B\u0435 IP \u0430\u0434\u0440\u0435\u0441\u0430 \u043C\u043E\u0433\u0443\u0442 \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u0434\u043E\u0441\u0442\u0443\u043F \u0431\u0435\u0437 HTTPS. '\u0412\u0441\u0435 \u0437\u0430\u043F\u0440\u043E\u0441\u044B' \u043E\u0437\u043D\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043E HTTPS \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044F \u0434\u043B\u044F \u0432\u0441\u0435\u0445 IP \u0430\u0434\u0440\u0435\u0441\u043E\u0432.
+publicKey=\u041F\u0443\u0431\u043B\u0438\u0447\u043D\u044B\u0439 \u043A\u043B\u044E\u0447
+privateKey=\u041F\u0440\u0438\u0432\u0430\u0442\u043D\u044B\u0439 \u043A\u043B\u044E\u0447
+gen-new-keys=\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043D\u043E\u0432\u044B\u0439 \u043A\u043B\u044E\u0447
+certificate=\u0421\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442
+host=\u0425\u043E\u0441\u0442
+smtp-host=SMTP \u0445\u043E\u0441\u0442
+port=\u041F\u043E\u0440\u0442
+smtp-port=SMTP \u043F\u043E\u0440\u0442 (\u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E 25)
+from=\u041E\u0442
+sender-email-addr=Email \u043E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u0435\u043B\u044F
+enable-ssl=\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C SSL
+enable-start-tls=\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C StartTLS
+enable-auth=\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044E
+username=\u0418\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
+login-username=\u0418\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0434\u043B\u044F \u0432\u0445\u043E\u0434\u0430
+password=\u041F\u0430\u0440\u043E\u043B\u044C
+login-password=\u041F\u0430\u0440\u043E\u043B\u044C \u0434\u043B\u044F \u0432\u0445\u043E\u0434\u0430
+login-theme=\u0422\u0435\u043C\u0430 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B \u0432\u0445\u043E\u0434\u0430
+login-theme.tooltip=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0442\u0435\u043C\u0443 \u0434\u043B\u044F \u0441\u0442\u0440\u0430\u043D\u0438\u0446 \u0432\u0445\u043E\u0434\u0430, \u0432\u0440\u0435\u043C\u0435\u043D\u043D\u043E\u0433\u043E \u043E\u0434\u043D\u043E\u0440\u0430\u0437\u043E\u0432\u043E\u0433\u043E \u043F\u0430\u0440\u043E\u043B\u044F (TOTP), \u0432\u044B\u0434\u0430\u0447\u0438 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u0438\u0439, \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0438 \u0432\u043E\u0441\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F \u043F\u0430\u0440\u043E\u043B\u044F.
+account-theme=\u0422\u0435\u043C\u0430 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u0438
+account-theme.tooltip=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0442\u0435\u043C\u0443 \u0434\u043B\u044F \u0443\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u044F \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u044C\u044E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F.
+admin-console-theme=\u0422\u0435\u043C\u0430 \u043A\u043E\u043D\u0441\u043E\u043B\u0438 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430
+select-theme-admin-console=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0442\u0435\u043C\u0443 \u0434\u043B\u044F \u043A\u043E\u043D\u0441\u043E\u043B\u0438 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430.
+email-theme=\u0422\u0435\u043C\u0430 \u0434\u043B\u044F email
+select-theme-email=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0442\u0435\u043C\u0443 \u0434\u043B\u044F email, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0431\u0443\u0434\u0443\u0442 \u043E\u0442\u0441\u044B\u043B\u0430\u0442\u044C\u0441\u044F \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430.
+i18n-enabled=\u0418\u043D\u0442\u0435\u0440\u043D\u0430\u0446\u0438\u043E\u043D\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u044F
+supported-locales=\u041F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043C\u044B\u0435 \u044F\u0437\u044B\u043A\u0438
+supported-locales.placeholder=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u044F\u0437\u044B\u043A \u0438 \u043D\u0430\u0436\u043C\u0438\u0442\u0435 Enter
+default-locale=\u042F\u0437\u044B\u043A \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E
+realm-cache-clear=\u041A\u044D\u0448 Realm
+realm-cache-clear.tooltip=\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0432\u0441\u0435 \u0437\u0430\u043F\u0438\u0441\u0438 \u0432 \u043A\u044D\u0448\u0435 realm (\u0443\u0434\u0430\u043B\u0438\u0442 \u0432\u0441\u0435 \u0437\u0430\u043F\u0438\u0441\u0438 \u0434\u043B\u044F \u0432\u0441\u0435\u0445 realm)
+user-cache-clear=\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C\u0441\u043A\u0438\u0439 \u043A\u044D\u0448
+user-cache-clear.tooltip=\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C \u0432\u0441\u0435 \u0437\u0430\u043F\u0438\u0441\u0438 \u0432 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C\u0441\u043A\u043E\u043C \u043A\u044D\u0448\u0435 (\u044D\u0442\u043E \u0443\u0434\u0430\u043B\u0438\u0442 \u0437\u0430\u043F\u0438\u0441\u0438 \u0434\u043B\u044F \u0432\u0441\u0435\u0445 realm)
+revoke-refresh-token=\u041E\u0442\u0437\u044B\u0432 \u0442\u043E\u043A\u0435\u043D\u0430 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F
+revoke-refresh-token.tooltip=\u0415\u0441\u043B\u0438 \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u043E, \u0442\u043E \u0442\u043E\u043A\u0435\u043D\u044B \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F \u043C\u043E\u0433\u0443\u0442 \u0431\u044B\u0442\u044C \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u044B \u0435\u0434\u0438\u043D\u043E\u0436\u0434\u044B. \u0412 \u043F\u0440\u043E\u0442\u0438\u0432\u043D\u043E\u043C \u0441\u043B\u0443\u0447\u0430\u0435, \u0442\u043E\u043A\u0435\u043D \u043E\u0442\u0437\u044B\u0432\u0430\u0442\u044C\u0441\u044F \u043D\u0435 \u0431\u0443\u0434\u0435\u0442 \u0438 \u043C\u043E\u0436\u0435\u0442 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C\u0441\u044F \u043C\u043D\u043E\u0433\u043E\u043A\u0440\u0430\u0442\u043D\u043E.
+sso-session-idle=\u0422\u0430\u0439\u043C\u0430\u0443\u0442 \u0441\u0435\u0441\u0441\u0438\u0438 SSO
+seconds=\u0441\u0435\u043A\u0443\u043D\u0434
+minutes=\u043C\u0438\u043D\u0443\u0442
+hours=\u0447\u0430\u0441\u043E\u0432
+days=\u0434\u043D\u0435\u0439
+sso-session-max=\u041E\u0433\u0440\u0430\u043D\u0438\u0447\u0435\u043D\u0438\u0435 \u0441\u0435\u0441\u0441\u0438\u0438 SSO
+sso-session-idle.tooltip=\u0414\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E\u0435 \u0432\u0440\u0435\u043C\u044F \u0431\u0435\u0437\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u0441\u0435\u0441\u0441\u0438\u0438. \u041F\u043E \u0438\u0441\u0442\u0435\u0447\u0435\u043D\u0438\u0438 \u044D\u0442\u043E\u0433\u043E \u0432\u0440\u0435\u043C\u0435\u043D\u0438 \u0442\u043E\u043A\u0435\u043D\u044B \u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043D\u044B\u0435 \u0441\u0435\u0441\u0441\u0438\u0438 \u0441\u0442\u0430\u043D\u043E\u0432\u044F\u0442\u0441\u044F \u043D\u0435\u0432\u0430\u043B\u0438\u0434\u043D\u044B\u043C\u0438.
+sso-session-max.tooltip=\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0432\u0440\u0435\u043C\u044F \u0434\u043E \u0442\u043E\u0433\u043E, \u043A\u0430\u043A \u0438\u0441\u0442\u0435\u0447\u0435\u0442 \u0441\u0435\u0441\u0441\u0438\u044F. \u041F\u043E \u0438\u0441\u0442\u0435\u0447\u0435\u043D\u0438\u0438 \u044D\u0442\u043E\u0433\u043E \u0432\u0440\u0435\u043C\u0435\u043D\u0438 \u0442\u043E\u043A\u0435\u043D\u044B \u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043D\u044B\u0435 \u0441\u0435\u0441\u0441\u0438\u0438 \u0441\u0442\u0430\u043D\u043E\u0432\u044F\u0442\u0441\u044F \u043D\u0435\u0432\u0430\u043B\u0438\u0434\u043D\u044B\u043C\u0438.
+offline-session-idle=\u0422\u0430\u0439\u043C\u0430\u0443\u0442 \u043E\u0444\u0444\u043B\u0430\u0439\u043D \u0441\u0435\u0441\u0441\u0438\u0438
+offline-session-idle.tooltip=\u0414\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E\u0435 \u0432\u0440\u0435\u043C\u044F \u0431\u0435\u0437\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u043E\u0444\u0444\u043B\u0430\u0439\u043D \u0441\u0435\u0441\u0441\u0438\u0438. \u0412\u0430\u043C \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C \u043E\u0444\u0444\u043B\u0430\u0439\u043D \u0442\u043E\u043A\u0435\u043D \u0434\u043B\u044F \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F \u0445\u043E\u0442\u044F \u0431\u044B \u0440\u0430\u0437 \u0437\u0430 \u044D\u0442\u043E\u0442 \u043F\u0435\u0440\u0438\u043E\u0434, \u0438\u043D\u0430\u0447\u0435 \u0441\u0435\u0441\u0441\u0438\u044F \u0438\u0441\u0442\u0435\u0447\u0435\u0442.
+access-token-lifespan=\u041F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u044C \u0436\u0438\u0437\u043D\u0438 \u0442\u043E\u043A\u0435\u043D\u0430 \u0434\u043E\u0441\u0442\u0443\u043F\u0430
+access-token-lifespan.tooltip=\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0432\u0440\u0435\u043C\u044F \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u0442\u043E\u043A\u0435\u043D\u0430 \u0434\u043E\u0441\u0442\u0443\u043F\u0430. \u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0443\u0435\u0442\u0441\u044F \u0443\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u0442\u044C \u043A\u0430\u043A \u043C\u043E\u0436\u043D\u043E \u0431\u043B\u0438\u0436\u0435 \u043A \u0442\u0430\u0439\u043C\u0430\u0443\u0442\u0443 SSO.
+access-token-lifespan-for-implicit-flow=\u041F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u044C \u0436\u0438\u0437\u043D\u0438 \u0442\u043E\u043A\u0435\u043D\u0430 \u0434\u043E\u0441\u0442\u0443\u043F\u0430 \u0434\u043B\u044F Implicit Flow
+access-token-lifespan-for-implicit-flow.tooltip=\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0432\u0440\u0435\u043C\u044F \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u0442\u043E\u043A\u0435\u043D\u0430 \u0434\u043E\u0441\u0442\u0443\u043F\u0430 \u043F\u043E\u0441\u043B\u0435 \u0442\u043E\u0433\u043E \u043A\u0430\u043A \u0441\u0435\u0441\u0441\u0438\u044F \u0442\u043E\u043A\u0435\u043D\u0430 OpenID Connect Implicit Flow \u0438\u0441\u0442\u0435\u043A\u043B\u0430. \u042D\u0442\u043E \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0443\u0435\u0442\u0441\u044F \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u043A\u0430\u043A \u043C\u043E\u0436\u043D\u043E \u0431\u043B\u0438\u0436\u0435 \u043A \u0442\u0430\u0439\u043C\u0430\u0443\u0442\u0443 SSO. \u041D\u0435\u0442 \u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E\u0441\u0442\u0438 \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u0442\u043E\u043A\u0435\u043D \u0432\u043E \u0432\u0440\u0435\u043C\u044F Implicit Flow, \u043F\u043E\u044D\u0442\u043E\u043C\u0443 \u044D\u0442\u043E\u0442 \u0442\u0430\u0439\u043C\u0430\u0443\u0442 \u043E\u0442\u043B\u0438\u0447\u0430\u0435\u0442\u0441\u044F \u043E\u0442 '\u041F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u0438 \u0436\u0438\u0437\u043D\u0438 \u0442\u043E\u043A\u0435\u043D\u0430 \u0434\u043E\u0441\u0442\u0443\u043F\u0430' 
+client-login-timeout=\u0422\u0430\u0439\u043C\u0430\u0443\u0442 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u0430
+client-login-timeout.tooltip=\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0432\u0440\u0435\u043C\u044F \u043A\u043B\u0438\u0435\u043D\u0442\u0430 \u0434\u043B\u044F \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0438\u044F \u043F\u0440\u043E\u0442\u043E\u043A\u043E\u043B\u0430 access token. \u041E\u0431\u044B\u0447\u043D\u043E \u0443\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u0435\u0442\u0441\u044F \u0440\u0430\u0432\u043D\u044B\u043C 1 \u043C\u0438\u043D\u0443\u0442\u0435.
+login-timeout=\u0422\u0430\u0439\u043C\u0430\u0443\u0442 \u0432\u0445\u043E\u0434\u0430
+login-timeout.tooltip=\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0432\u0440\u0435\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0434\u043B\u044F \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0438\u044F \u0432\u0445\u043E\u0434\u0430. \u0420\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0443\u0435\u0442\u0441\u044F \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0435\u043B\u044C\u043D\u043E \u0431\u043E\u043B\u044C\u0448\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 (30 \u043C\u0438\u043D\u0443\u0442 \u0438 \u0431\u043E\u043B\u0435\u0435).
+login-action-timeout=\u0422\u0430\u0439\u043C\u0430\u0443\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u043F\u043E \u0432\u0445\u043E\u0434\u0443
+login-action-timeout.tooltip=\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0432\u0440\u0435\u043C\u044F, \u0437\u0430 \u043A\u043E\u0442\u043E\u0440\u043E\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u0434\u043E\u043B\u0436\u0435\u043D \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043F\u043E\u0441\u043B\u0435 \u0432\u0445\u043E\u0434\u0430, \u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440, \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\u0430\u0440\u043E\u043B\u044F \u0438\u043B\u0438 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F \u043E\u0434\u043D\u043E\u0440\u0430\u0437\u043E\u0432\u043E\u0433\u043E \u0432\u0440\u0435\u043C\u0435\u043D\u043D\u043E\u0433\u043E \u043F\u0430\u0440\u043E\u043B\u044F. \u0420\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0443\u0435\u0442\u0441\u044F \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0435\u043B\u044C\u043D\u043E \u0431\u043E\u043B\u044C\u0448\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 (5 \u043C\u0438\u043D\u0443\u0442 \u0438 \u0431\u043E\u043B\u0435\u0435).
+headers=\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0438
+brute-force-detection=\u041E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0435 Brute Force
+x-frame-options=X-Frame-Options
+x-frame-options-tooltip=\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E \u043D\u0435 \u043F\u043E\u0437\u0432\u043E\u043B\u044F\u0435\u0442 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0430\u043C \u0431\u044B\u0442\u044C \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u043D\u044B\u043C\u0438 \u0432 iframe \u0441\u0442\u043E\u0440\u043E\u043D\u043D\u0438\u0445 \u0441\u0430\u0439\u0442\u043E\u0432 (\u043F\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043F\u043E \u0441\u0441\u044B\u043B\u043A\u0435 \u0434\u043B\u044F \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0439 \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u0438)
+content-sec-policy=Content-Security-Policy
+content-sec-policy-tooltip=\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E \u043D\u0435 \u043F\u043E\u0437\u0432\u043E\u043B\u044F\u0435\u0442 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0430\u043C \u0431\u044B\u0442\u044C \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u043D\u044B\u043C\u0438 \u0432 iframe \u0441\u0442\u043E\u0440\u043E\u043D\u043D\u0438\u0445 \u0441\u0430\u0439\u0442\u043E\u0432 (\u043F\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043F\u043E \u0441\u0441\u044B\u043B\u043A\u0435 \u0434\u043B\u044F \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0439 \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u0438)
+content-type-options=X-Content-Type-Options
+content-type-options-tooltip=\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E \u043D\u0435 \u043F\u043E\u0437\u0432\u043E\u043B\u044F\u0435\u0442 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u043C Internet Explorer \u0438 Google Chrome \u0432\u044B\u0447\u0438\u0441\u043B\u044F\u0442\u044C \u0442\u0438\u043F \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u043C\u043E\u0433\u043E \u0432 \u043E\u0442\u0432\u0435\u0442\u0435 \u043E\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0434\u0430\u043B\u044C\u0448\u0435 \u043E\u0442 \u043E\u0431\u044A\u044F\u0432\u043B\u0435\u043D\u043D\u043E\u0433\u043E \u0442\u0438\u043F\u0430 \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u043C\u043E\u0433\u043E (\u043F\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043F\u043E \u0441\u0441\u044B\u043B\u043A\u0435 \u0434\u043B\u044F \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0439 \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u0438)
+max-login-failures=\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u043A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u043D\u0435\u0443\u0434\u0430\u0447\u043D\u044B\u0445 \u043F\u043E\u043F\u044B\u0442\u043E\u043A \u0432\u0445\u043E\u0434\u0430
+max-login-failures.tooltip=\u0421\u043A\u043E\u043B\u044C\u043A\u043E \u043D\u0435\u0443\u0434\u0430\u0447\u043D\u044B\u0445 \u043F\u043E\u043F\u044B\u0442\u043E\u043A \u0432\u0445\u043E\u0434\u0430 \u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u044C, \u043F\u043E\u043A\u0430 \u044D\u0442\u043E \u043D\u0435 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043F\u0440\u0435\u0449\u0435\u043D\u043E.
+wait-increment=\u041F\u043E\u0440\u043E\u0433 \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u044F
+wait-increment.tooltip=\u0415\u0441\u043B\u0438 \u043F\u043E\u0440\u043E\u0433 \u043E\u0448\u0438\u0431\u043E\u043A \u043F\u0440\u0435\u0432\u044B\u0448\u0435\u043D, \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0432\u0440\u0435\u043C\u0435\u043D\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u0430\u043D?
+quick-login-check-millis=\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u043A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043C\u0438\u043B\u043B\u0438\u0441\u0435\u043A\u0443\u043D\u0434 \u043C\u0435\u0436\u0434\u0443 \u043F\u043E\u043F\u044B\u0442\u043A\u0430\u043C\u0438 \u0432\u0445\u043E\u0434\u0430
+quick-login-check-millis.tooltip=\u0415\u0441\u043B\u0438 \u043F\u043E\u043F\u044B\u0442\u043A\u0438 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u043F\u0440\u043E\u0438\u0441\u0445\u043E\u0434\u044F\u0442 \u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0447\u0430\u0441\u0442\u043E, \u0442\u043E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u0437\u0430\u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u0430\u0442\u044C.
+min-quick-login-wait=\u041C\u0438\u043D\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u0435 \u0431\u044B\u0441\u0442\u0440\u043E\u0433\u043E \u0432\u0445\u043E\u0434\u0430
+min-quick-login-wait.tooltip=\u041A\u0430\u043A \u0434\u043E\u043B\u0433\u043E \u0436\u0434\u0430\u0442\u044C \u043F\u043E\u0441\u043B\u0435 \u043D\u0435\u0443\u0434\u0430\u0447\u043D\u043E\u0439 \u043F\u043E\u043F\u044B\u0442\u043A\u0438 \u0431\u044B\u0441\u0442\u0440\u043E\u0433\u043E \u0432\u0445\u043E\u0434\u0430.
+max-wait=\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u0435
+max-wait.tooltip=\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0432\u0440\u0435\u043C\u044F, \u043D\u0430 \u043A\u043E\u0442\u043E\u0440\u043E\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u0430\u043D.
+failure-reset-time=\u0412\u0440\u0435\u043C\u044F \u0441\u0431\u0440\u043E\u0441\u0430 \u043D\u0435\u0443\u0434\u0430\u0447\u043D\u044B\u0445 \u043F\u043E\u043F\u044B\u0442\u043E\u043A
+failure-reset-time.tooltip=\u0427\u0435\u0440\u0435\u0437 \u043A\u0430\u043A\u043E\u0435 \u0432\u0440\u0435\u043C\u044F \u0441\u0447\u0435\u0442\u0447\u0438\u043A \u043D\u0435\u0443\u0434\u0430\u0447\u043D\u044B\u0445 \u043F\u043E\u043F\u044B\u0442\u043E\u043A \u0431\u0443\u0434\u0435\u0442 \u0441\u0431\u0440\u043E\u0448\u0435\u043D?
+realm-tab-login=\u0412\u0445\u043E\u0434
+realm-tab-keys=\u041A\u043B\u044E\u0447\u0438
+realm-tab-email=Email
+realm-tab-themes=\u0422\u0435\u043C\u044B
+realm-tab-cache=\u041A\u044D\u0448
+realm-tab-tokens=\u0422\u043E\u043A\u0435\u043D\u044B
+realm-tab-client-initial-access=\u041F\u0435\u0440\u0432\u043E\u043D\u0430\u0447\u0430\u043B\u044C\u043D\u044B\u0435 \u0442\u043E\u043A\u0435\u043D\u044B \u0434\u043E\u0441\u0442\u0443\u043F\u0430
+realm-tab-security-defenses=\u0417\u0430\u0449\u0438\u0442\u0430 \u0431\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u043E\u0441\u0442\u0438
+realm-tab-general=\u0413\u043B\u0430\u0432\u043D\u0430\u044F
+add-realm=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C realm
+
+#Session settings
+realm-sessions=\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 Realm
+revocation=\u041E\u0442\u0437\u044B\u0432
+logout-all=\u0420\u0430\u0437\u043B\u043E\u0433\u0438\u043D\u0438\u0442\u044C \u0432\u0441\u0435 \u0441\u0435\u0441\u0441\u0438\u0438
+active-sessions=\u0410\u043A\u0442\u0438\u0432\u043D\u044B\u0435 \u0441\u0435\u0441\u0441\u0438\u0438
+sessions=\u0421\u0435\u0441\u0441\u0438\u0438
+not-before=\u041D\u0435 \u0440\u0430\u043D\u0435\u0435 \u0447\u0435\u043C
+not-before.tooltip=\u041E\u0442\u043E\u0437\u0432\u0430\u0442\u044C \u043B\u044E\u0431\u044B\u0435 \u0442\u043E\u043A\u0435\u043D\u044B, \u0432\u044B\u0434\u0430\u043D\u043D\u044B\u0435 \u0440\u0430\u043D\u0435\u0435 \u044D\u0442\u043E\u0439 \u0434\u0430\u0442\u044B.
+set-to-now=\u0423\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u043D\u0430 \u0441\u0435\u0439\u0447\u0430\u0441
+push=\u0420\u0430\u0437\u043E\u0441\u043B\u0430\u0442\u044C
+push.tooltip=\u0423\u0432\u0435\u0434\u043E\u043C\u0438\u0442\u044C \u043A\u0430\u0436\u0434\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430, \u0438\u043C\u0435\u044E\u0449\u0435\u0433\u043E URL \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430, \u043E \u043D\u043E\u0432\u043E\u0439 \u043F\u043E\u043B\u0438\u0442\u0438\u043A\u0435 \u043E\u0442\u0437\u044B\u0432\u0430 \u0442\u043E\u043A\u0435\u043D\u0430.
+
+#Protocol Mapper
+usermodel.prop.label=\u0421\u0432\u043E\u0439\u0441\u0442\u0432\u043E
+usermodel.prop.tooltip=\u0418\u043C\u044F \u0441\u0432\u043E\u0439\u0441\u0442\u0432\u0430 \u043C\u0435\u0442\u043E\u0434\u0430 \u0432 \u0438\u043D\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435 UserModel. \u0414\u043B\u044F \u043F\u0440\u0438\u043C\u0435\u0440\u0430, \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 'email' \u0431\u0443\u0434\u0435\u0442 \u0441\u0441\u044B\u043B\u043A\u043E\u0439 \u043D\u0430 \u043C\u0435\u0442\u043E\u0434 UserModel.getEmail().
+usermodel.attr.label=\u0410\u0442\u0440\u0438\u0431\u0443\u0442 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
+usermodel.attr.tooltip=\u0418\u043C\u044F \u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u043D\u043E\u0433\u043E \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F, \u043A\u043E\u0442\u043E\u0440\u043E\u0435 \u044F\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0438\u043C\u0435\u043D\u0435\u043C \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430, \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u043D\u044B\u043C \u0441 UserModel.attribute.
+userSession.modelNote.label=\u0417\u0430\u043C\u0435\u0442\u043A\u0430 \u0441\u0435\u0441\u0441\u0438\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
+userSession.modelNote.tooltip=\u041D\u0430\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u0438\u0435 \u043F\u0440\u043E\u0446\u0435\u0434\u0443\u0440\u044B \u0437\u0430\u043C\u0435\u0442\u043A\u0438 \u0441\u0435\u0441\u0441\u0438\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u043D\u044B\u043C \u0441 UserSessionModel.note.
+multivalued.label=\u041D\u0435\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0439
+multivalued.tooltip=\u041E\u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044F, \u0435\u0441\u043B\u0438 \u0430\u0442\u0440\u0438\u0431\u0443\u0442 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043D\u0435\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0439. \u0415\u0441\u043B\u0438 \u0432\u043A\u043B\u044E\u0447\u0435\u043D, \u0442\u043E \u0441\u043F\u0438\u0441\u043E\u043A \u0432\u0441\u0435\u0445 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0439 \u0431\u0443\u0434\u0435\u0442 \u043F\u0440\u0435\u0442\u0435\u043D\u0434\u043E\u0432\u0430\u0442\u044C \u043D\u0430 \u044D\u0442\u043E\u0442 \u0430\u0442\u0440\u0438\u0431\u0443\u0442. \u0412 \u043F\u0440\u043E\u0442\u0438\u0432\u043D\u043E\u043C \u0441\u043B\u0443\u0447\u0430\u0435 \u0432\u044B\u0431\u0438\u0440\u0430\u0442\u044C\u0441\u044F \u0431\u0443\u0434\u0435\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u0435\u0440\u0432\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 
+selectRole.label=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0440\u043E\u043B\u044C
+selectRole.tooltip=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0440\u043E\u043B\u044C \u0432 \u0442\u0435\u043A\u0441\u0442\u043E\u0432\u043E\u0435 \u043F\u043E\u043B\u0435 \u0441\u043B\u0435\u0432\u0430, \u0438\u043B\u0438 \u043D\u0430\u0436\u043C\u0438\u0442\u0435 \u043D\u0430 \u043A\u043D\u043E\u043F\u043A\u0443, \u0447\u0442\u043E\u0431\u044B \u0432\u044B\u0431\u0440\u0430\u0442\u044C \u0436\u0435\u043B\u0430\u0435\u043C\u0443\u044E \u0440\u043E\u043B\u044C.
+tokenClaimName.label=\u0418\u043C\u044F \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u043E\u0439 \u0432 \u0442\u043E\u043A\u0435\u043D\u0435
+tokenClaimName.tooltip=\u0418\u043C\u044F \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u043E\u0439 \u043F\u0440\u0438 \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u0438 \u0435\u0435 \u0432 \u0442\u043E\u043A\u0435\u043D. \u041C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043F\u043E\u043B\u043D\u043E\u0435 \u0438\u043C\u044F, \u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440 'address.street'. \u0412 \u0442\u0430\u043A\u043E\u043C \u0441\u043B\u0443\u0447\u0430\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u043E\u0437\u0434\u0430\u043D \u0432\u043B\u043E\u0436\u0435\u043D\u043D\u044B\u0439 json \u043E\u0431\u044A\u0435\u043A\u0442.
+jsonType.label=\u0422\u0438\u043F \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u043E\u0439 JSON
+jsonType.tooltip=\u0422\u0438\u043F \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u043E\u0439 \u0432 JSON, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0434\u043E\u043B\u0436\u0435\u043D \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C\u0441\u044F \u043F\u0440\u0438 \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u0438 \u0435\u0435 \u0432 \u0442\u043E\u043A\u0435\u043D. \u0414\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u044B\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F long, int, boolean, \u0438 String.
+includeInIdToken.label=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0432 \u0442\u043E\u043A\u0435\u043D ID
+includeInIdToken.tooltip=\u0414\u043E\u043B\u0436\u043D\u043E \u043B\u0438 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0431\u044B\u0442\u044C \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u043E \u0432 \u0442\u043E\u043A\u0435\u043D ID?
+includeInAccessToken.label=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0432 \u0442\u043E\u043A\u0435\u043D \u0434\u043E\u0441\u0442\u0443\u043F\u0430
+includeInAccessToken.tooltip=\u0414\u043E\u043B\u0436\u043D\u043E \u043B\u0438 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0431\u044B\u0442\u044C \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u043E \u0432 \u0442\u043E\u043A\u0435\u043D \u0434\u043E\u0441\u0442\u0443\u043F\u0430?
+
+
+# client details
+clients.tooltip=\u041A\u043B\u0438\u0435\u043D\u0442\u044B \u0434\u043E\u0432\u0435\u0440\u0435\u043D\u043D\u044B\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u043D\u044B\u0445 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0439 \u0438 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0438\u0441\u043E\u0432 \u0432 realm. \u042D\u0442\u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u044B \u043C\u043E\u0433\u0443\u0442 \u0437\u0430\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044C \u0432\u0445\u043E\u0434. \u0412\u044B \u0442\u0430\u043A\u0436\u0435 \u043C\u043E\u0436\u0435\u0442\u0435 \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0438\u0442\u044C \u0441\u043F\u0435\u0446\u0438\u0444\u0438\u0447\u0435\u0441\u043A\u0438\u0435 \u0440\u043E\u043B\u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u0430.
+search.placeholder=\u041F\u043E\u0438\u0441\u043A...
+create=\u0421\u043E\u0437\u0434\u0430\u0442\u044C
+import=\u0418\u043C\u043F\u043E\u0440\u0442
+client-id=ID \u043A\u043B\u0438\u0435\u043D\u0442\u0430
+base-url=\u0411\u0430\u0437\u043E\u0432\u044B\u0439 URL
+actions=\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044F
+not-defined=\u041D\u0435 \u0437\u0430\u0434\u0430\u043D
+edit=\u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C
+delete=\u0423\u0434\u0430\u043B\u0438\u0442\u044C
+no-results=\u041D\u0435\u0442 \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\u043E\u0432
+no-clients-available=\u041D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0445 \u043A\u043B\u0438\u0435\u043D\u0442\u043E\u0432
+add-client=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043A\u043B\u0438\u0435\u043D\u0442\u0430
+select-file=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0444\u0430\u0439\u043B
+view-details=\u0421\u043C\u043E\u0442\u0440\u0435\u0442\u044C \u0434\u0435\u0442\u0430\u043B\u0438
+clear-import=\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C \u0438\u043C\u043F\u043E\u0440\u0442
+client-id.tooltip=\u0417\u0430\u0434\u0430\u0435\u0442 ID, \u0441\u0441\u044B\u043B\u0430\u044E\u0449\u0438\u0439\u0441\u044F \u0432 URI \u0438 \u0442\u043E\u043A\u0435\u043D\u0430\u0445. \u041D\u0430\u043F\u0440\u0438\u043C\u0435\u0440 'my-client'. \u0414\u043B\u044F SAML \u044D\u0442\u043E \u0442\u0430\u043A\u0436\u0435 \u043E\u0436\u0438\u0434\u0430\u0435\u043C\u043E\u0435 \u0438\u043C\u044F \u0438\u0437\u0434\u0430\u0442\u0435\u043B\u044F \u0434\u043B\u044F \u0437\u0430\u043F\u0440\u043E\u0441\u043E\u0432 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438
+client.name.tooltip=\u0417\u0430\u0434\u0430\u0435\u0442 \u043E\u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0435\u043C\u043E\u0435 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u043A\u043B\u0438\u0435\u043D\u0442\u0430. \u041D\u0430\u043F\u0440\u0438\u043C\u0435\u0440 'My Client'. \u041F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043A\u043B\u044E\u0447\u0438 \u0434\u043B\u044F \u043B\u043E\u043A\u0430\u043B\u0438\u0437\u043E\u0432\u0430\u043D\u043D\u044B\u0445 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0439. \u041D\u0430\u043F\u0440\u0438\u043C\u0435\u0440\\: ${my_client}
+client.enabled.tooltip=\u041E\u0442\u043A\u043B\u044E\u0447\u0435\u043D\u043D\u044B\u0435 \u043A\u043B\u0438\u0435\u043D\u0442\u044B \u043D\u0435 \u043C\u043E\u0433\u0443\u0442 \u0438\u043D\u0438\u0446\u0438\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0432\u0445\u043E\u0434 \u0438\u043B\u0438 \u0438\u043C\u0435\u0442\u044C \u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E\u0441\u0442\u044C \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u0442\u043E\u043A\u0435\u043D\u044B \u0434\u043E\u0441\u0442\u0443\u043F\u0430.
+consent-required=\u041D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435
+consent-required.tooltip=\u0415\u0441\u043B\u0438 \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u043E, \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0438 \u0434\u043E\u043B\u0436\u043D\u044B \u0434\u0430\u0442\u044C \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435 \u043D\u0430 \u0434\u043E\u0441\u0442\u0443\u043F \u043A\u043B\u0438\u0435\u043D\u0442\u0441\u043A\u043E\u043C\u0443 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044E.
+client-protocol=\u041F\u0440\u043E\u0442\u043E\u043A\u043E\u043B \u043A\u043B\u0438\u0435\u043D\u0442\u0430
+client-protocol.tooltip='OpenID connect' \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442 \u043A\u043B\u0438\u0435\u043D\u0442\u0430\u043C \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u043B\u0438\u0447\u043D\u043E\u0441\u0442\u044C \u043A\u043E\u043D\u0435\u0447\u043D\u043E\u0433\u043E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F, \u043E\u0441\u043D\u043E\u0432\u0430\u043D\u043D\u043E\u0433\u043E \u043D\u0430  \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0438 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u043D\u0430 \u0421\u0435\u0440\u0432\u0435\u0440\u0435 \u0410\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438.'SAML' \u0432\u043A\u043B\u044E\u0447\u0430\u0435\u0442 \u0432\u0435\u0431-\u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0438 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u0438 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u0432\u043A\u043B\u044E\u0447\u0430\u044F \u043A\u0440\u043E\u0441\u0441\u0434\u043E\u043C\u0435\u043D\u043D\u044B\u0435 \u0442\u043E\u0447\u043A\u0438 \u0442\u0435\u0445\u043D\u043E\u043B\u043E\u0433\u0438\u0438 \u0435\u0434\u0438\u043D\u043E\u0433\u043E \u0434\u043E\u0441\u0442\u0443\u043F\u0430 (SSO) \u0438 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u044E\u0449\u0438\u0435 \u0442\u043E\u043A\u0435\u043D\u044B \u0431\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u043E\u0441\u0442\u0438, \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0435  \u0437\u0430\u044F\u0432\u043B\u0435\u043D\u0438\u044F \u043D\u0430 \u043F\u0435\u0440\u0435\u0434\u0430\u0447\u0443 \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u0438.
+access-type=\u0422\u0438\u043F \u0434\u043E\u0441\u0442\u0443\u043F\u0430
+access-type.tooltip='Confidential' \u043A\u043B\u0438\u0435\u043D\u0442\u044B \u0442\u0440\u0435\u0431\u0443\u044E\u0442 \u0441\u0435\u043A\u0440\u0435\u0442 \u0434\u043B\u044F \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u0438 \u043F\u0440\u043E\u0442\u043E\u043A\u043E\u043B\u0430 \u0432\u0445\u043E\u0434\u0430. 'Public' \u043A\u043B\u0438\u0435\u043D\u0442\u0430\u043C \u0441\u0435\u043A\u0440\u0435\u0442 \u043D\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044F. 'Bearer-only' \u043A\u043B\u0438\u0435\u043D\u0442\u044B \u0438 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0438\u0441\u044B \u043D\u0438\u043A\u043E\u0433\u0434\u0430 \u043D\u0435 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0438\u0440\u0443\u044E\u0442 \u0432\u0445\u043E\u0434.
+standard-flow-enabled=Standard Flow \u0432\u043A\u043B\u044E\u0447\u0435\u043D
+standard-flow-enabled.tooltip=\u0412\u043A\u043B\u044E\u0447\u0430\u0435\u0442 \u0441\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u043E\u0435 OpenID Connect \u043F\u0435\u0440\u0435\u043D\u0430\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435, \u043E\u0441\u043D\u043E\u0432\u0430\u043D\u043D\u043E\u0435 \u043D\u0430 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u0441 \u043A\u043E\u0434\u043E\u043C \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438. \u0412 \u0442\u0435\u0440\u043C\u0438\u043D\u0430\u0445 OpenID Connect \u0438\u043B\u0438 OAuth2 \u0441\u043F\u0435\u0446\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0439 \u0432\u043A\u043B\u044E\u0447\u0430\u0435\u0442 'Authorization Code Flow' \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430.
+implicit-flow-enabled=Implicit Flow \u0432\u043A\u043B\u044E\u0447\u0435\u043D
+implicit-flow-enabled.tooltip=\u0412\u043A\u043B\u044E\u0447\u0430\u0435\u0442 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u043A\u0443 OpenID Connect \u043F\u0435\u0440\u0435\u043D\u0430\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u044F, \u043E\u0441\u043D\u043E\u0432\u0430\u043D\u043D\u043E\u0433\u043E \u043D\u0430 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u0431\u0435\u0437 \u043A\u043E\u0434\u0430 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438. \u0412 \u0442\u0435\u0440\u043C\u0438\u043D\u0430\u0445 OpenID Connect \u0438\u043B\u0438 OAuth2 \u0441\u043F\u0435\u0446\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0439 \u0432\u043A\u043B\u044E\u0447\u0430\u0435\u0442 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u043A\u0443 'Implicit Flow' \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430.
+direct-access-grants-enabled=Direct Access Grants \u0432\u043A\u043B\u044E\u0447\u0435\u043D
+direct-access-grants-enabled.tooltip=\u0412\u043A\u043B\u044E\u0447\u0430\u0435\u0442 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u043A\u0443 Direct Access Grants, \u043A\u043E\u0442\u043E\u0440\u0430\u044F \u043E\u0437\u043D\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043E \u043A\u043B\u0438\u0435\u043D\u0442 \u0438\u043C\u0435\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F \u043A \u0438\u043C\u0435\u043D\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0438 \u043F\u0430\u0440\u043E\u043B\u044F \u0438 \u043E\u0431\u043C\u0435\u043D\u0438\u0432\u0430\u0435\u0442 \u0438\u0445 \u043D\u0430\u043F\u0440\u044F\u043C\u0443\u044E \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043E\u043C Keycloak \u043D\u0430 \u0442\u043E\u043A\u0435\u043D \u0434\u043E\u0441\u0442\u0443\u043F\u0430. \u0412 \u0442\u0435\u0440\u043C\u0438\u043D\u0430\u0445 OAuth2 \u0441\u043F\u0435\u0446\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u043E\u0437\u043D\u0430\u0447\u0430\u0435\u0442 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u043A\u0443 'Resource Owner Password Credentials Grant' \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430.
+service-accounts-enabled=Service Accounts \u0432\u043A\u043B\u044E\u0447\u0435\u043D
+service-accounts-enabled.tooltip=\u0420\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442 \u0412\u0430\u043C \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430 \u0432 Keycloak \u0438 \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u0442\u043E\u043A\u0435\u043D \u0434\u043E\u0441\u0442\u0443\u043F\u0430 \u0441\u043F\u0435\u0446\u0438\u0430\u043B\u044C\u043D\u043E \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430. \u0412 \u0442\u0435\u0440\u043C\u0438\u043D\u0430\u0445 OAuth2 \u0441\u043F\u0435\u0446\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u0432\u043A\u043B\u044E\u0447\u0430\u0435\u0442 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u043A\u0443 'Client Credentials Grant' \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430.
+include-authnstatement=\u0412\u043A\u043B\u044E\u0447\u0430\u0442\u044C \u0410\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u043E\u043D\u043D\u044B\u0435 \u0417\u0430\u044F\u0432\u043A\u0438
+include-authnstatement.tooltip=\u0414\u043E\u043B\u0436\u043D\u044B \u043B\u0438 \u0437\u0430\u044F\u0432\u043A\u0438 \u043D\u0430 \u043C\u0435\u0442\u043E\u0434\u044B \u0438 \u0432\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0435 \u043C\u0435\u0442\u043A\u0438 \u0431\u044B\u0442\u044C \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u044B \u0432 \u043E\u0442\u0432\u0435\u0442\u0435 \u043D\u0430 \u0432\u0445\u043E\u0434?
+sign-documents=\u041F\u043E\u0434\u043F\u0438\u0441\u044C \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u0432
+sign-documents.tooltip=\u0414\u043E\u043B\u0436\u043D\u044B \u043B\u0438 SAML \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u044B \u0431\u044B\u0442\u044C \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u043D\u044B \u0432 realm?
+sign-assertions=Sign Assertions
+sign-assertions.tooltip=\u0414\u043E\u043B\u0436\u043D\u044B \u043B\u0438 \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F \u0432\u043D\u0443\u0442\u0440\u0438 SAML \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u0432 \u0431\u044B\u0442\u044C \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u043D\u044B? \u0423\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u0435\u0442 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E\u0441\u0442\u0438 \u043F\u043E\u0434\u043F\u0438\u0441\u044B\u0432\u0430\u0442\u044C \u0443\u0436\u0435 \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u043D\u043D\u044B\u0435 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u044B.
+signature-algorithm=\u0410\u043B\u0433\u043E\u0440\u0438\u0442\u043C \u043F\u043E\u0434\u043F\u0438\u0441\u0438
+signature-algorithm.tooltip=\u0410\u043B\u0433\u043E\u0440\u0438\u0442\u043C \u043F\u043E\u0434\u043F\u0438\u0441\u0438, \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u043C\u044B\u0439 \u0434\u043B\u044F \u043F\u043E\u0434\u043F\u0438\u0441\u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u0432.
+canonicalization-method=\u041C\u0435\u0442\u043E\u0434 \u043A\u0430\u043D\u043E\u043D\u0438\u0437\u0430\u0446\u0438\u0438
+canonicalization-method.tooltip=\u041C\u0435\u0442\u043E\u0434 \u043A\u0430\u043D\u043E\u043D\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u043B\u044F XML \u0441\u0438\u0433\u043D\u0430\u0442\u0443\u0440.
+encrypt-assertions=\u0417\u0430\u0448\u0438\u0444\u0440\u043E\u0432\u043A\u0430 \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0439
+encrypt-assertions.tooltip=\u0414\u043E\u043B\u0436\u043D\u044B \u043B\u0438 SAML \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F \u0431\u044B\u0442\u044C \u0437\u0430\u0448\u0438\u0444\u0440\u043E\u0432\u0430\u043D\u044B \u043F\u0443\u0431\u043B\u0438\u0447\u043D\u044B\u043C \u043A\u043B\u044E\u0447\u043E\u043C \u043A\u043B\u0438\u0435\u043D\u0442\u0430, \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u044F AES?
+client-signature-required=\u041E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u0430\u044F \u043F\u043E\u0434\u043F\u0438\u0441\u044C \u043A\u043B\u0438\u0435\u043D\u0442\u0430
+client-signature-required.tooltip=\u0411\u0443\u0434\u0435\u0442 \u043B\u0438 \u043A\u043B\u0438\u0435\u043D\u0442 \u043F\u043E\u0434\u043F\u0438\u0441\u044B\u0432\u0430\u0442\u044C \u0441\u0432\u043E\u0438 saml \u0437\u0430\u043F\u0440\u043E\u0441\u044B \u0438 \u043E\u0442\u0432\u0435\u0442\u044B? \u0418 \u0434\u043E\u043B\u0436\u043D\u044B \u043B\u0438 \u043E\u043D\u0438 \u0431\u044B\u0442\u044C \u043F\u0440\u043E\u0432\u0430\u043B\u0438\u0434\u0438\u0440\u043E\u0432\u0430\u043D\u044B?
+force-post-binding=\u0424\u043E\u0440\u0441\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0441\u0432\u044F\u0437\u044B\u0432\u0430\u043D\u0438\u0435 POST
+force-post-binding.tooltip=\u0412\u0441\u0435\u0433\u0434\u0430 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C POST \u0441\u0432\u044F\u0437\u044B\u0432\u0430\u043D\u0438\u0435 \u0434\u043B\u044F \u043E\u0442\u0432\u0435\u0442\u043E\u0432.
+front-channel-logout=\u0412\u044B\u0445\u043E\u0434 \u0441 \u043F\u0435\u0440\u0435\u0434\u043D\u0435\u0433\u043E \u043A\u0430\u043D\u0430\u043B\u0430
+front-channel-logout.tooltip=\u041A\u043E\u0433\u0434\u0430 \u043F\u0440\u0430\u0432\u0438\u043B\u0430, \u0432\u044B\u0445\u043E\u0434 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043F\u0435\u0440\u0435\u043D\u0430\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043D\u0430 \u043A\u043B\u0438\u0435\u043D\u0442\u0430. \u0415\u0441\u043B\u0438 \u043B\u043E\u0436\u044C, \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u044B\u043F\u043E\u043B\u043D\u044F\u0435\u0442 \u0444\u043E\u043D\u043E\u0432\u044B\u0439 \u0440\u0435\u0436\u0438\u043C \u0434\u043B\u044F \u0432\u044B\u0445\u043E\u0434\u0430 \u0438\u0437 \u0441\u0438\u0441\u0442\u0435\u043C\u044B.
+force-name-id-format=\u0424\u043E\u0440\u0441\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043D\u0430\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u0438\u0435 \u0444\u043E\u0440\u043C\u0430\u0442\u0430 ID
+force-name-id-format.tooltip=\u0418\u0433\u043D\u043E\u0440\u0438\u0440\u0443\u0435\u0442 \u0437\u0430\u043F\u0440\u043E\u0448\u0435\u043D\u043D\u044B\u0439 NameID \u0444\u043E\u0440\u043C\u0430\u0442 \u0442\u0435\u043C\u044B \u0438 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442 \u0441\u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u0443\u044E \u043A\u043E\u043D\u0441\u043E\u043B\u044C \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430.
+name-id-format=\u041D\u0430\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u0438\u0435 \u0444\u043E\u0440\u043C\u0430\u0442\u0430 ID
+name-id-format.tooltip=\u041D\u0430\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u0438\u0435 \u0444\u043E\u0440\u043C\u0430\u0442\u0430 ID \u0434\u043B\u044F \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u044F \u0432 \u0442\u0435\u043C\u0435.
+root-url=\u041A\u043E\u0440\u043D\u0435\u0432\u043E\u0439 URL
+root-url.tooltip=\u041A\u043E\u0440\u043D\u0435\u0432\u043E\u0439 URL \u0434\u043E\u0431\u0430\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u043A \u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C URL
+valid-redirect-uris=\u0412\u0430\u043B\u0438\u0434\u0430\u0446\u0438\u044F URI \u043F\u0435\u0440\u0435\u043D\u0430\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0439
+valid-redirect-uris.tooltip=\u0412\u0430\u043B\u0438\u0434\u0438\u0440\u0443\u0435\u0442 \u043F\u0430\u0442\u0442\u0435\u0440\u043D URI, \u043D\u0430 \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043F\u0435\u0440\u0435\u043D\u0430\u043F\u0440\u0430\u0432\u043B\u0435\u043D \u043F\u043E\u0441\u043B\u0435 \u0443\u0441\u043F\u0435\u0448\u043D\u043E\u0433\u043E \u0432\u0445\u043E\u0434\u0430 \u0438\u043B\u0438 \u0432\u044B\u0445\u043E\u0434\u0430. \u041F\u0440\u043E\u0441\u0442\u044B\u0435 \u0441\u0441\u044B\u043B\u043A\u0438 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u044B. \u041D\u0430\u043F\u0440. 'http://example.com/*'. \u041E\u0442\u043D\u043E\u0441\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0439 \u043F\u0443\u0442\u044C \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u0442\u0430\u043A\u0436\u0435 \u0441\u043F\u0435\u0446\u0438\u0444\u0438\u0446\u0438\u0440\u043E\u0432\u0430\u043D, \u043D\u0430\u043F\u0440. /my/relative/path/*. \u041E\u0442\u043D\u043E\u0441\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u043F\u0443\u0442\u0438 \u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0435\u043B\u044C\u043D\u044B \u043A\u043E\u0440\u043D\u0435\u0432\u043E\u0433\u043E URL \u043A\u043B\u0438\u0435\u043D\u0442\u0430, \u0438\u043B\u0438 \u0435\u0441\u043B\u0438 \u043E\u043D \u043D\u0435 \u0441\u043F\u0435\u0446\u0438\u0444\u0438\u0446\u0438\u0440\u043E\u0432\u0430\u043D, \u0442\u043E \u0440\u043E\u0434\u0438\u0442\u0435\u043B\u044C\u0441\u043A\u0438\u0439 URL \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D. \u0414\u043B\u044F SAML \u0432\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u0437\u0430\u0434\u0430\u0442\u044C \u0432\u0430\u043B\u0438\u0434\u043D\u044B\u0439 \u043F\u0430\u0442\u0442\u0435\u0440\u043D. \u0415\u0441\u043B\u0438 \u0412\u044B \u043F\u043E\u043B\u0430\u0433\u0430\u0435\u0442\u0435\u0441\u044C \u043D\u0430 \u0432\u043D\u0435\u0434\u0440\u0435\u043D\u043D\u044B\u0439 URL \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0437\u0430\u043A\u0430\u0437\u0447\u0438\u043A\u0430 \u0441 \u0437\u0430\u043F\u0440\u043E\u0441\u043E\u043C \u0432\u0445\u043E\u0434\u0430.
+base-url.tooltip=URL \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E \u0434\u043B\u044F \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u044F, \u0435\u0441\u043B\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044F \u043F\u0435\u0440\u0435\u043D\u0430\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0438\u043B\u0438 \u0441\u0441\u044B\u043B\u043A\u0430 \u043E\u0431\u0440\u0430\u0442\u043D\u043E \u043D\u0430 \u043A\u043B\u0438\u0435\u043D\u0442\u0430.
+admin-url=URL \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F
+admin-url.tooltip=URL \u0434\u043B\u044F \u0438\u043D\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430 \u0432 \u0434\u0430\u043D\u043D\u043E\u043C \u043A\u043B\u0438\u0435\u043D\u0442\u0435. \u0423\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0435 \u044D\u0442\u043E, \u0435\u0441\u043B\u0438 \u043A\u043B\u0438\u0435\u043D\u0442 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0430\u0434\u0430\u043F\u0442\u0435\u0440 REST API. \u042D\u0442\u043E REST API \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u043B\u0430\u0442\u044C \u043F\u043E\u043B\u0438\u0442\u0438\u043A\u0438 \u043E\u0442\u0437\u044B\u0432\u0430 \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u0438\u0432\u043D\u044B\u0435 \u0437\u0430\u0434\u0430\u0447\u0438. \u041E\u0431\u044B\u0447\u043D\u043E \u0443\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u0435\u0442\u0441\u044F \u0432 \u0431\u0430\u0437\u043E\u0432\u044B\u0439 URL \u043A\u043B\u0438\u0435\u043D\u0442\u0430.
+master-saml-processing-url=\u041E\u0441\u043D\u043E\u0432\u043D\u043E\u0439 URL \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u0447\u0438\u043A\u0430 SAML
+master-saml-processing-url.tooltip=\u0415\u0441\u043B\u0438 \u0441\u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C, \u0442\u043E \u044D\u0442\u043E\u0442 URL \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D \u0434\u043B\u044F \u043A\u0430\u0436\u0434\u043E\u0433\u043E \u0441\u0432\u044F\u0437\u044B\u0432\u0430\u043D\u0438\u044F \u0434\u043B\u044F \u043E\u0431\u043E\u0438\u0445 SP's Assertion Consumer \u0438 Single Logout Services. \u041C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u0438\u043D\u0434\u0438\u0432\u0438\u0434\u0443\u0430\u043B\u044C\u043D\u043E \u043F\u0435\u0440\u0435\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u043E \u0434\u043B\u044F \u043A\u0430\u0436\u0434\u043E\u0433\u043E \u0441\u0432\u044F\u0437\u044B\u0432\u0430\u043D\u0438\u044F \u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0432 \u0442\u043E\u043D\u043A\u043E\u0439 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0435 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043A\u043E\u043D\u0435\u0447\u043D\u044B\u0445 \u0442\u043E\u0447\u0435\u043A \u0434\u043E\u0441\u0442\u0443\u043F\u0430 SAML.
+idp-sso-url-ref=\u041D\u0430\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u0438\u0435 URL \u0434\u043B\u044F \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 IDP, \u0438\u043D\u0438\u0446\u0438\u0438\u0440\u0443\u044E\u0449\u0435\u0433\u043E SSO
+idp-sso-url-ref.tooltip=\u0418\u043C\u044F URL \u0444\u0440\u0430\u0433\u043C\u0435\u043D\u0442\u0430, \u043E\u0431\u043E\u0437\u043D\u0430\u0447\u0430\u044E\u0449\u0435\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430, \u0435\u0441\u043B\u0438 \u0432\u044B \u0445\u043E\u0442\u0438\u0442\u0435, \u0447\u0442\u043E\u0431\u044B SSO \u0431\u044B\u043B \u043F\u0440\u043E\u0438\u043D\u0438\u0446\u0438\u0438\u0440\u043E\u0432\u0430\u043D \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u043E\u043C \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438. \u041E\u0441\u0442\u0430\u0432\u044C\u0442\u0435 \u044D\u0442\u043E \u043F\u043E\u043B\u0435 \u043F\u0443\u0441\u0442\u044B\u043C, \u0447\u0442\u043E\u0431\u044B \u043E\u0442\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u0438\u043D\u0438\u0446\u0438\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435 SSO \u0441 \u043F\u043E\u043C\u043E\u0449\u044C\u044E \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438. URL \u0434\u043B\u044F \u0441\u0441\u044B\u043B\u043A\u0438 \u0432\u0430\u0448\u0435\u0433\u043E \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u0432 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0435\u043C \u0432\u0438\u0434\u0435: {server-root}/realms/{realm}/protocol/saml/clients/{client-url-name}
+idp-sso-relay-state=\u041F\u0435\u0440\u0435\u0434\u0430\u0447\u0430 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u044F SSO \u0438\u043D\u0438\u0446\u0438\u0438\u0440\u0443\u044E\u0449\u0438\u043C \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u043E\u043C \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438
+idp-sso-relay-state.tooltip=\u041F\u0435\u0440\u0435\u0434\u0430\u0442\u044C \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435, \u043A\u043E\u0442\u043E\u0440\u043E\u0435 \u0432\u044B \u0445\u043E\u0442\u0438\u0442\u0435 \u043F\u043E\u0441\u043B\u0430\u0442\u044C \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 SAML \u0437\u0430\u043F\u0440\u043E\u0441\u043E\u043C, \u043A\u043E\u0442\u043E\u0440\u044B\u043C \u0445\u043E\u0442\u0438\u0442\u0435 \u043F\u0440\u043E\u0438\u043D\u0438\u0446\u0438\u0440\u043E\u0432\u0430\u0442\u044C SSO \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u043E\u043C \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438.
+web-origins=Web \u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A\u0438
+web-origins.tooltip=\u0420\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442 CORS \u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A\u0430\u043C. \u0427\u0442\u043E\u0431\u044B \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044C \u0432\u0441\u0435\u043C \u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A\u0438 \u0441 \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u044B\u043C\u0438 URI-\u0430\u0434\u0440\u0435\u0441\u0430\u043C\u0438 \u043F\u0435\u0440\u0435\u0430\u0434\u0440\u0435\u0441\u0430\u0446\u0438\u0438, \u0434\u043E\u0431\u0430\u0432\u044C\u0442\u0435 '+'. \u0427\u0442\u043E\u0431\u044B \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044C \u0432\u0441\u0435 \u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A\u0438, \u0434\u043E\u0431\u0430\u0432\u044C\u0442\u0435 '*'.
+fine-saml-endpoint-conf=\u0422\u043E\u043D\u043A\u0430\u044F \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0430 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043A\u043E\u043D\u0435\u0447\u043D\u044B\u0445 \u0442\u043E\u0447\u0435\u043A \u0434\u043E\u0441\u0442\u0443\u043F\u0430 SAML
+fine-saml-endpoint-conf.tooltip=\u0420\u0430\u0437\u0432\u0435\u0440\u043D\u0438\u0442\u0435 \u044D\u0442\u0443 \u0441\u0435\u043A\u0446\u0438\u0438, \u0447\u0442\u043E\u0431\u044B \u0441\u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0442\u043E\u0447\u043D\u044B\u0435 URL-\u0430\u0434\u0440\u0435\u0441\u0430 \u0434\u043B\u044F \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u043D\u043E\u0433\u043E \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u044F \u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0435\u0434\u0438\u043D\u043E\u0433\u043E \u0432\u044B\u0445\u043E\u0434\u0430.
+assertion-consumer-post-binding-url=\u0421\u0432\u044F\u0437\u044B\u0432\u0430\u043D\u0438\u0435 URL \u0434\u043B\u044F POST \u0437\u0430\u043F\u0440\u043E\u0441\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u043D\u043E\u0433\u043E \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u044F
+assertion-consumer-post-binding-url.tooltip=SAML POST \u0441\u0432\u044F\u0437\u0430\u043D\u043D\u044B\u0439 URL \u0434\u043B\u044F \u043A\u043B\u0438\u0435\u043D\u0442\u0441\u043A\u0438\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043E\u0432 \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u043D\u043E\u0433\u043E \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u044F (\u0437\u0430\u043F\u0440\u043E\u0441\u044B \u0432\u0445\u043E\u0434\u0430). \u0412\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u044D\u0442\u043E \u043F\u043E\u043B\u0435 \u043F\u0443\u0441\u0442\u044B\u043C, \u0435\u0441\u043B\u0438 \u043D\u0435 \u0438\u043C\u0435\u0435\u0442\u0435 URL \u0434\u043B\u044F \u043E\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043B\u0435\u043D\u0438\u044F \u0442\u0430\u043A\u043E\u0439 \u0441\u0432\u044F\u0437\u043A\u0438.
+assertion-consumer-redirect-binding-url=\u0421\u0432\u044F\u0437\u044B\u0432\u0430\u043D\u0438\u0435 URL \u043F\u0435\u0440\u0435\u0430\u0434\u0440\u0435\u0441\u0430\u0446\u0438\u0438 \u0441 \u0441\u0435\u0440\u0432\u0438\u0441\u043E\u043C \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u043D\u043E\u0433\u043E \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u044F
+assertion-consumer-redirect-binding-url.tooltip=SAML \u043F\u0435\u0440\u0435\u0430\u0434\u0440\u0435\u0441\u0430\u0446\u0438\u044F \u043D\u0430 \u0441\u0432\u044F\u0437\u0430\u043D\u043D\u044B\u0439 URL \u0434\u043B\u044F \u043A\u043B\u0438\u0435\u043D\u0442\u0441\u043A\u043E\u0433\u043E \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0443\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u043D\u043E\u0433\u043E \u043F\u043E\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043B\u044F (\u0437\u0430\u043F\u0440\u043E\u0441\u044B \u0432\u0445\u043E\u0434\u0430). \u0412\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u044D\u0442\u043E \u043F\u043E\u043B\u0435 \u043F\u0443\u0441\u0442\u044B\u043C, \u0435\u0441\u043B\u0438 \u0432\u044B \u043D\u0435 \u0438\u043C\u0435\u0435\u0442\u0435 URL \u0434\u043B\u044F \u0442\u0430\u043A\u043E\u0433\u043E \u0441\u0432\u044F\u0437\u044B\u0432\u0430\u043D\u0438\u044F.
+logout-service-binding-post-url=\u0421\u0432\u044F\u0437\u044B\u0432\u0430\u043D\u0438\u0435 URL \u0434\u043B\u044F \u0432\u044B\u0445\u043E\u0434\u0430 \u0438\u0437 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0434\u043B\u044F POST-\u043C\u0435\u0442\u043E\u0434\u0430
+logout-service-binding-post-url.tooltip=SAML POST \u0441\u0432\u044F\u0437\u0430\u043D\u043D\u044B\u0439 URL \u0434\u043B\u044F \u043A\u043B\u0438\u0435\u043D\u0442\u0441\u043A\u043E\u0433\u043E \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0435\u0434\u0438\u043D\u043E\u0433\u043E \u0432\u044B\u0445\u043E\u0434\u0430. \u0412\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u044D\u0442\u043E \u043F\u043E\u043B\u0435 \u043F\u0443\u0441\u0442\u044B\u043C, \u0435\u0441\u043B\u0438 \u0432\u044B \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0435 \u0440\u0430\u0437\u043B\u0438\u0447\u043D\u044B\u0435 \u0441\u0432\u044F\u0437\u0438
+logout-service-redir-binding-url=\u0421\u0432\u044F\u0437\u044B\u0432\u0430\u043D\u0438\u0435 URL \u043F\u0435\u0440\u0435\u0430\u0434\u0440\u0435\u0441\u0430\u0446\u0438\u0438 \u0434\u043B\u044F \u0432\u044B\u0445\u043E\u0434\u0430 \u0438\u0437 \u0441\u0435\u0440\u0432\u0438\u0441\u0430
+logout-service-redir-binding-url.tooltip=SAML \u043F\u0435\u0440\u0435\u0430\u0434\u0440\u0435\u0441\u0443\u0435\u0442 \u043D\u0430 \u0441\u0432\u044F\u0437\u0430\u043D\u043D\u044B\u0439 URL \u0434\u043B\u044F \u0435\u0434\u0438\u043D\u043E\u0439 \u0442\u043E\u0447\u043A\u0438 \u0432\u044B\u0445\u043E\u0434\u0430 \u0438\u0437 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0434\u043B\u044F \u043A\u043B\u0438\u0435\u043D\u0442\u043E\u0432. \u0412\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u044D\u0442\u043E \u043F\u043E\u043B\u0435 \u043F\u0443\u0441\u0442\u044B\u043C, \u0435\u0441\u043B\u0438 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0435 \u0440\u0430\u0437\u043B\u0438\u0447\u043D\u044B\u0435 \u0441\u0432\u044F\u0437\u0438.
+
+# client import
+import-client=\u0418\u043C\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043A\u043B\u0438\u0435\u043D\u0442
+format-option=\u0424\u043E\u0440\u043C\u0430\u0442
+select-format=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0444\u043E\u0440\u043C\u0430\u0442
+import-file=\u0418\u043C\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0444\u0430\u0439\u043B
+
+# client tabs
+settings=\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438
+credentials=\u0423\u0447\u0435\u0442\u043D\u044B\u0435 \u0434\u0430\u043D\u043D\u044B\u0435
+saml-keys=\u041A\u043B\u044E\u0447\u0438 SAML
+roles=\u0420\u043E\u043B\u0438
+mappers=\u0421\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u044F
+mappers.tooltip=\u041F\u0440\u043E\u0442\u043E\u043A\u043E\u043B \u0441\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0439, \u043E\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043B\u044F\u044E\u0449\u0438\u0445 \u043F\u0440\u0435\u043E\u0431\u0440\u0430\u0437\u043E\u0432\u0430\u043D\u0438\u0435 \u0432 \u0442\u043E\u043A\u0435\u043D\u044B \u0438 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u044B. \u041C\u043E\u0433\u0443\u0442 \u0434\u0435\u043B\u0430\u0442\u044C \u0442\u0430\u043A\u0438\u0435 \u0432\u0435\u0449\u0438 \u043A\u0430\u043A \u0441\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C\u0441\u043A\u0438\u0445 \u0434\u0430\u043D\u043D\u044B\u0445 \u0432 \u0437\u0430\u044F\u0432\u043A\u0438 \u043F\u0440\u043E\u0442\u043E\u043A\u043E\u043B\u0430, \u0438\u043B\u0438 \u043F\u0440\u043E\u0441\u0442\u043E \u043F\u0440\u0435\u043E\u0431\u0440\u0430\u0437\u043E\u0432\u0430\u0442\u044C \u043B\u044E\u0431\u043E\u0439 \u0437\u0430\u043F\u0440\u043E\u0441, \u043F\u0440\u043E\u0438\u0441\u0445\u043E\u0434\u044F\u0449\u0438\u0439 \u043C\u0435\u0436\u0434\u0443 \u043A\u043B\u0438\u0435\u043D\u0442\u043E\u043C \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043E\u043C \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438.
+scope=\u041E\u0431\u043B\u0430\u0441\u0442\u044C
+scope.tooltip=\u0421\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043E\u0431\u043B\u0430\u0441\u0442\u0438 \u043F\u043E\u0437\u0432\u043E\u043B\u044F\u0435\u0442 \u0432\u0430\u043C \u043E\u0433\u0440\u0430\u043D\u0438\u0447\u0438\u0442\u044C \u0441\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u043D\u044B\u0435 \u0440\u043E\u043B\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F, \u0432\u043A\u043B\u044E\u0447\u0430\u0435\u043C\u044B\u0435 \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u0442\u043E\u043A\u0435\u043D\u043E\u043C \u0434\u043E\u0441\u0442\u0443\u043F\u0430, \u0437\u0430\u043F\u0440\u043E\u0448\u0435\u043D\u043D\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u043E\u043C.
+sessions.tooltip=\u041F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u0441\u0435\u0441\u0441\u0438\u0439 \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430. \u041F\u043E\u0437\u0432\u043E\u043B\u044F\u0435\u0442 \u0412\u0430\u043C \u0443\u0432\u0438\u0434\u0435\u0442\u044C, \u043A\u0430\u043A\u0438\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0438 \u0430\u043A\u0442\u0438\u0432\u043D\u044B \u0438 \u043A\u043E\u0433\u0434\u0430 \u043E\u043D\u0438 \u0432\u043E\u0448\u043B\u0438.
+offline-access=\u041E\u0444\u0444\u043B\u0430\u0439\u043D \u0434\u043E\u0441\u0442\u0443\u043F
+offline-access.tooltip=\u041F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u043E\u0444\u0444\u043B\u0430\u0439\u043D \u0441\u0435\u0441\u0441\u0438\u0439 \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430. \u041F\u043E\u0437\u0432\u043E\u043B\u044F\u0435\u0442 \u0412\u0430\u043C \u0443\u0432\u0438\u0434\u0435\u0442\u044C, \u043A\u0430\u043A\u0438\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0438 \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u0438 \u043E\u0444\u0444\u043B\u0430\u0439\u043D \u0442\u043E\u043A\u0435\u043D \u0438 \u043A\u043E\u0433\u0434\u0430 \u043E\u043D\u0438 \u0435\u0433\u043E \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u0438. \u0427\u0442\u043E\u0431\u044B \u043E\u0442\u043E\u0431\u0440\u0430\u0442\u044C \u0432\u0441\u0435 \u0442\u043E\u043A\u0435\u043D\u044B \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430, \u043F\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043D\u0430 \u0432\u043A\u043B\u0430\u0434\u043A\u0443 \u043E\u0442\u0437\u044B\u0432\u0430 \u0438 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043D\u0435 \u0440\u0430\u043D\u0435\u0435 \u0447\u0435\u043C \u0441\u0435\u0439\u0447\u0430\u0441.
+clustering=\u041A\u043B\u0430\u0441\u0442\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u044F
+installation=\u0423\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430
+installation.tooltip=\u0412\u0441\u043F\u043E\u043C\u043E\u0433\u0430\u0442\u0435\u043B\u044C\u043D\u0430\u044F \u0443\u0442\u0438\u043B\u0438\u0442\u0430 \u0434\u043B\u044F \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u0440\u0430\u0437\u043B\u0438\u0447\u043D\u044B\u0445 \u0444\u043E\u0440\u043C\u0430\u0442\u043E\u0432 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0430\u0434\u0430\u043F\u0442\u0435\u0440\u0430 \u043A\u043B\u0438\u0435\u043D\u0442\u0430, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0412\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u0441\u043A\u0430\u0447\u0430\u0442\u044C \u0438\u043B\u0438 \u0441\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0434\u043B\u044F \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0412\u0430\u0448\u0438\u0445 \u043A\u043B\u0438\u0435\u043D\u0442\u043E\u0432.
+service-account-roles=\u0420\u043E\u043B\u0438 Service Account
+service-account-roles.tooltip=\u0420\u0430\u0437\u0440\u0435\u0448\u0430\u044E\u0442 \u0412\u0430\u043C \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0441\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u043D\u044B\u0435 \u0440\u043E\u043B\u0438 \u0434\u043B\u044F \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439, \u0432\u044B\u0434\u0435\u043B\u0435\u043D\u043D\u043E\u0433\u043E \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430.
+
+# client credentials
+client-authenticator=\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u043F\u043E\u0434\u043B\u0438\u043D\u043D\u043E\u0441\u0442\u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u0430
+client-authenticator.tooltip=\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u043F\u043E\u0434\u043B\u0438\u043D\u043D\u043E\u0441\u0442\u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u0430 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0441\u044F \u0434\u043B\u044F \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430 \u0432\u043E\u043F\u0440\u0435\u043A\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0443 Keycloak
+certificate.tooltip=\u041A\u043B\u0438\u0435\u043D\u0442\u0441\u043A\u0438\u0439 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442 \u0434\u043B\u044F \u0432\u0430\u043B\u0438\u0434\u0430\u0446\u0438\u0438 JWT \u0432\u044B\u043F\u0443\u0449\u0435\u043D\u043D\u044B\u0439 \u043A\u043B\u0438\u0435\u043D\u0442\u043E\u043C \u0438 \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u043D\u043D\u044B\u0439 \u043A\u043B\u0438\u0435\u043D\u0442\u0441\u043A\u0438\u043C \u043F\u0440\u0438\u0432\u0430\u0442\u043D\u044B\u043C \u043A\u043B\u044E\u0447\u043E\u043C \u0438\u0437 \u0412\u0430\u0448\u0435\u0433\u043E \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0430 \u043A\u043B\u044E\u0447\u0435\u0439.
+no-client-certificate-configured=\u041A\u043B\u0438\u0435\u043D\u0442\u0441\u043A\u0438\u0439 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442 \u043D\u0435 \u0441\u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043E\u0432\u0430\u043D
+gen-new-keys-and-cert=\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043D\u043E\u0432\u044B\u0435 \u043A\u043B\u044E\u0447\u0438 \u0438 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442
+import-certificate=\u0418\u043C\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442
+gen-client-private-key=\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043F\u0440\u0438\u0432\u0430\u0442\u043D\u044B\u0439 \u043A\u043B\u044E\u0447 \u043A\u043B\u0438\u0435\u043D\u0442\u0430
+generate-private-key=\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043F\u0440\u0438\u0432\u0430\u0442\u043D\u044B\u0439 \u043A\u043B\u044E\u0447
+archive-format=\u0424\u043E\u0440\u043C\u0430\u0442 \u0430\u0440\u0445\u0438\u0432\u0430\u0446\u0438\u0438
+archive-format.tooltip=Java keystore \u0438\u043B\u0438 PKCS12 \u0444\u043E\u0440\u043C\u0430\u0442 \u0430\u0440\u0445\u0438\u0432\u0430\u0446\u0438\u0438.
+key-alias=\u0421\u0438\u043D\u043E\u043D\u0438\u043C \u043A\u043B\u044E\u0447\u0430
+key-alias.tooltip=\u0421\u0438\u043D\u043E\u043D\u0438\u043C \u0430\u0440\u0445\u0438\u0432\u0430 \u0434\u043B\u044F \u0412\u0430\u0448\u0435\u0433\u043E \u043F\u0440\u0438\u0432\u0430\u0442\u043D\u043E\u0433\u043E \u043A\u043B\u044E\u0447\u0430 \u0438 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u0430.
+key-password=\u041F\u0430\u0440\u043E\u043B\u044C \u0434\u043B\u044F \u043A\u043B\u044E\u0447\u0430
+key-password.tooltip=\u041F\u0430\u0440\u043E\u043B\u044C \u0434\u043B\u044F \u0434\u043E\u0441\u0442\u0443\u043F\u0430 \u043A \u043F\u0440\u0438\u0432\u0430\u0442\u043D\u043E\u0433\u043E \u043A\u043B\u044E\u0447\u0443 \u0432 \u0430\u0440\u0445\u0438\u0432\u0435
+store-password=\u041F\u0430\u0440\u043E\u043B\u044C \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0430
+store-password.tooltip=\u041F\u0430\u0440\u043E\u043B\u044C \u0434\u043B\u044F \u0434\u043E\u0441\u0442\u0443\u043F\u0430 \u0432 \u0441\u0430\u043C \u0430\u0440\u0445\u0438\u0432 
+generate-and-download=\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0438 \u0441\u043A\u0430\u0447\u0430\u0442\u044C
+client-certificate-import=\u0418\u043C\u043F\u043E\u0440\u0442 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u0430 \u043A\u043B\u0438\u0435\u043D\u0442\u0430
+import-client-certificate=\u0418\u043C\u043F\u043E\u0440\u0442 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u0430 \u043A\u043B\u0438\u0435\u043D\u0442\u0430
+jwt-import.key-alias.tooltip=\u0421\u0438\u043D\u043E\u043D\u0438\u043C \u0430\u0440\u0445\u0438\u0432\u0430 \u0434\u043B\u044F \u0432\u0430\u0448\u0435\u0433\u043E \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u0430.
+secret=\u0421\u0435\u043A\u0440\u0435\u0442
+regenerate-secret=\u041F\u0435\u0440\u0435\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0441\u0435\u043A\u0440\u0435\u0442
+registrationAccessToken=\u0422\u043E\u043A\u0435\u043D \u0434\u043E\u0441\u0442\u0443\u043F\u0430 \u043A \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438
+registrationAccessToken.regenerate=\u041F\u0435\u0440\u0435\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0442\u043E\u043A\u0435\u043D \u0434\u043E\u0441\u0442\u0443\u043F\u0430 \u043A \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438
+registrationAccessToken.tooltip=\u0422\u043E\u043A\u0435\u043D \u0434\u043E\u0441\u0442\u0443\u043F\u0430 \u043A \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043E\u0431\u0435\u0441\u043F\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F \u0434\u043B\u044F \u043A\u043B\u0438\u0435\u043D\u0442\u043E\u0432 \u043A \u0441\u0435\u0440\u0432\u0438\u0441\u0443 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u043E\u0432.
+add-role=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0440\u043E\u043B\u044C
+role-name=\u041D\u0430\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u0438\u0435 \u0440\u043E\u043B\u0438
+composite=\u0421\u043E\u0441\u0442\u0430\u0432\u043D\u0430\u044F
+description=\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435
+no-client-roles-available=\u041D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0445 \u0440\u043E\u043B\u0435\u0439 \u043A\u043B\u0438\u0435\u043D\u0442\u0430
+scope-param-required=\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044F \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 \u043E\u0431\u043B\u0430\u0441\u0442\u0438
+scope-param-required.tooltip=\u042D\u0442\u0430 \u0440\u043E\u043B\u044C \u0431\u0443\u0434\u0435\u0442 \u043F\u0440\u0435\u0434\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0430 \u0442\u043E\u043B\u044C\u043A\u043E \u0435\u0441\u043B\u0438 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 \u043E\u0431\u043B\u0430\u0441\u0442\u0438 \u0441 \u043D\u0430\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u0438\u0435\u043C \u0440\u043E\u043B\u0438 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0441\u044F \u0432 \u0437\u0430\u043F\u0440\u043E\u0441\u0430\u0445 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438/\u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0442\u043E\u043A\u0435\u043D\u0430.
+composite-roles=\u0421\u043E\u0441\u0442\u0430\u0432\u043D\u044B\u0435 \u0440\u043E\u043B\u0438
+composite-roles.tooltip=\u041A\u043E\u0433\u0434\u0430 \u044D\u0442\u0430 \u0440\u043E\u043B\u044C (\u043D\u0435)\u0430\u0441\u0441\u043E\u0446\u0438\u0438\u0440\u043E\u0432\u0430\u043D\u0430 \u0441 \u043B\u044E\u0431\u043E\u0439 \u0440\u043E\u043B\u044C\u044E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439, \u043E\u043D\u0430 (\u043D\u0435)\u0431\u0443\u0434\u0435\u0442 \u043D\u0435\u044F\u0432\u043D\u043E \u0430\u0441\u0441\u043E\u0446\u0438\u0438\u0440\u043E\u0432\u0430\u043D\u0430.
+realm-roles=\u0420\u043E\u043B\u0438 Realm
+available-roles=\u0414\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0435 \u0440\u043E\u043B\u0438
+add-selected=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u043E\u0435
+associated-roles=\u0410\u0441\u0441\u043E\u0446\u0438\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0435 \u0440\u043E\u043B\u0438
+composite.associated-realm-roles.tooltip=\u0420\u043E\u043B\u0438 \u0443\u0440\u043E\u0432\u043D\u044F Realm, \u0430\u0441\u0441\u043E\u0446\u0438\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0435 \u0441 \u0441\u043E\u0441\u0442\u0430\u0432\u043D\u044B\u043C\u0438 \u0440\u043E\u043B\u044F\u043C\u0438.
+composite.available-realm-roles.tooltip=\u0420\u043E\u043B\u0438 \u0443\u0440\u043E\u0432\u043D\u044F Realm, \u0430\u0441\u0441\u043E\u0446\u0438\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0435 \u0441 \u044D\u0442\u043E\u0439 \u0441\u043E\u0441\u0442\u0430\u0432\u043D\u043E\u0439 \u0440\u043E\u043B\u044C\u044E.
+remove-selected=\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u043E\u0435
+client-roles=\u0420\u043E\u043B\u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u043E\u0432
+select-client-to-view-roles=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u043A\u043B\u0438\u0435\u043D\u0442\u0430 \u0434\u043B\u044F \u043F\u0440\u043E\u0441\u043C\u043E\u0442\u0440\u0430 \u0435\u0433\u043E \u0440\u043E\u043B\u0435\u0439
+available-roles.tooltip=\u0420\u043E\u043B\u0438 \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0432\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u0430\u0441\u0441\u043E\u0446\u0438\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0441 \u0441\u043E\u0441\u0442\u0430\u0432\u043D\u043E\u0439 \u0440\u043E\u043B\u044C\u044E.
+client.associated-roles.tooltip=\u041A\u043B\u0438\u0435\u043D\u0442\u0441\u043A\u0438\u0435 \u0440\u043E\u043B\u0438, \u0430\u0441\u0441\u043E\u0446\u0438\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0435 \u0441 \u0441\u043E\u0441\u0442\u0430\u0432\u043D\u043E\u0439 \u0440\u043E\u043B\u044C\u044E.
+add-builtin=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0432\u0441\u0442\u0440\u043E\u0435\u043D\u043D\u044B\u0435
+category=\u041A\u0430\u0442\u0435\u0433\u043E\u0440\u0438\u044F
+type=\u0422\u0438\u043F
+no-mappers-available=\u0421\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u044F \u043D\u0435 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B
+add-builtin-protocol-mappers=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0432\u0441\u0442\u0440\u043E\u0435\u043D\u043D\u044B\u0435 \u0441\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u044F \u043F\u0440\u043E\u0442\u043E\u043A\u043E\u043B\u0430
+add-builtin-protocol-mapper=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0432\u0441\u0442\u0440\u043E\u0435\u043D\u043D\u043E\u0435 \u0441\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\u0440\u043E\u0442\u043E\u043A\u043E\u043B\u0430
+scope-mappings=\u0421\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043E\u0431\u043B\u0430\u0441\u0442\u0435\u0439
+full-scope-allowed=\u041F\u043E\u043B\u043D\u044B\u0439 \u0434\u043E\u0441\u0442\u0443\u043F \u043A \u043E\u0431\u043B\u0430\u0441\u0442\u044F\u043C
+full-scope-allowed.tooltip=\u041E\u0442\u043A\u043B\u044E\u0447\u0430\u0435\u0442 \u0432\u0441\u0435 \u043E\u0433\u0440\u0430\u043D\u0438\u0447\u0435\u043D\u0438\u044F.
+scope.available-roles.tooltip=\u0420\u043E\u043B\u0438 \u0443\u0440\u043E\u0432\u043D\u044F Realm, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043C\u043E\u0433\u0443\u0442 \u0431\u044B\u0442\u044C \u043F\u0440\u0438\u0441\u0432\u043E\u0435\u043D\u044B \u043E\u0431\u043B\u0430\u0441\u0442\u0438.
+assigned-roles=\u041F\u0440\u0438\u0441\u0432\u043E\u0435\u043D\u043D\u044B\u0435 \u0440\u043E\u043B\u0438
+assigned-roles.tooltip=\u0420\u043E\u043B\u0438 \u0443\u0440\u043E\u0432\u043D\u044F Realm, \u043F\u0440\u0438\u0441\u0432\u043E\u0435\u043D\u043D\u044B\u0435 \u043E\u0431\u043B\u0430\u0441\u0442\u0438.
+effective-roles=\u042D\u0444\u0444\u0435\u043A\u0442\u0438\u0432\u043D\u044B\u0435 \u0440\u043E\u043B\u0438
+realm.effective-roles.tooltip=\u041D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044B\u0435 \u0440\u043E\u043B\u0438 \u0443\u0440\u043E\u0432\u043D\u044F realm, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043C\u043E\u0433\u0443\u0442 \u0431\u044B\u0442\u044C \u0443\u043D\u0430\u0441\u043B\u0435\u0434\u043E\u0432\u0430\u043D\u044B \u0438\u0437 \u0441\u043E\u0441\u0442\u0430\u0432\u043D\u043E\u0439 \u0440\u043E\u043B\u0438.
+select-client-roles.tooltip=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u043A\u043B\u0438\u0435\u043D\u0442\u0430 \u0434\u043B\u044F \u043F\u0440\u043E\u0441\u043C\u043E\u0442\u0440\u0430 \u0435\u0433\u043E \u0440\u043E\u043B\u0435\u0439
+assign.available-roles.tooltip=\u0420\u043E\u043B\u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u043E\u0432, \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0435 \u0434\u043B\u044F \u043D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F.
+client.assigned-roles.tooltip=\u041D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044B\u0435 \u0440\u043E\u043B\u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u0430.
+client.effective-roles.tooltip=\u041D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044B\u0435 \u0440\u043E\u043B\u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u0430, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0432\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u0443\u043D\u0430\u0441\u043B\u0435\u0434\u043E\u0432\u0430\u0442\u044C \u0438\u0437 \u0441\u043E\u0441\u0442\u0430\u0432\u043D\u043E\u0439 \u0440\u043E\u043B\u0438.
+basic-configuration=\u041E\u0441\u043D\u043E\u0432\u043D\u0430\u044F \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F
+node-reregistration-timeout=\u0422\u0430\u0439\u043C\u0430\u0443\u0442 \u0443\u0437\u043B\u0430 \u043F\u0435\u0440\u0435\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438
+node-reregistration-timeout.tooltip=\u0418\u043D\u0442\u0435\u0440\u0432\u0430\u043B, \u043E\u0437\u043D\u0430\u0447\u0430\u044E\u0449\u0438\u0439 \u043C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0432\u0440\u0435\u043C\u044F \u0434\u043B\u044F \u0443\u0437\u043B\u043E\u0432 \u043A\u043B\u0430\u0441\u0442\u0435\u0440\u0430 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0445 \u043A\u043B\u0438\u0435\u043D\u0442\u043E\u0432 \u0434\u043B\u044F \u0438\u0445 \u043F\u0435\u0440\u0435\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438. \u0415\u0441\u043B\u0438 \u0443\u0437\u0435\u043B \u043A\u043B\u0430\u0441\u0442\u0435\u0440\u0430 \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u043F\u043E\u0441\u043B\u0430\u0442\u044C \u0437\u0430\u043F\u0440\u043E\u0441 \u043F\u0435\u0440\u0435\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0432 Keycloak \u0437\u0430 \u0443\u043A\u0430\u0437\u0430\u043D\u043D\u043E\u0435 \u0432\u0440\u0435\u043C\u044F, \u0442\u043E \u043E\u043D \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u043D \u0438\u0437 Keycloak
+registered-cluster-nodes=\u0417\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0435 \u0443\u0437\u043B\u044B \u043A\u043B\u0430\u0441\u0442\u0435\u0440\u0430
+register-node-manually=\u0417\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0443\u0437\u0435\u043B \u0432\u0440\u0443\u0447\u043D\u0443\u044E
+test-cluster-availability=\u041F\u0440\u043E\u0442\u0435\u0441\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u043E\u0441\u0442\u044C \u043A\u043B\u0430\u0441\u0442\u0435\u0440\u0430
+last-registration=\u041F\u043E\u0441\u043B\u0435\u0434\u043D\u044F\u044F \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044F
+node-host=\u0425\u043E\u0441\u0442 \u0443\u0437\u043B\u0430
+no-registered-cluster-nodes=\u041D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0445 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0445 \u0443\u0437\u043B\u043E\u0432 \u043A\u043B\u0430\u0441\u0442\u0435\u0440\u0430
+cluster-nodes=\u0423\u0437\u043B\u044B \u043A\u043B\u0430\u0441\u0442\u0435\u0440\u0430
+add-node=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0443\u0437\u0435\u043B
+active-sessions.tooltip=\u041E\u0431\u0449\u0435\u0435 \u043A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u0430\u043A\u0442\u0438\u0432\u043D\u044B\u0445 \u0441\u0435\u0441\u0441\u0438\u0439 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430.
+show-sessions=\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0441\u0435\u0441\u0441\u0438\u0438
+show-sessions.tooltip=\u041F\u0440\u0435\u0434\u0443\u043F\u0440\u0435\u0436\u0434\u0435\u043D\u0438\u0435, \u044D\u0442\u043E \u043F\u043E\u0442\u0435\u043D\u0446\u0438\u0430\u043B\u044C\u043D\u043E \u043D\u0430\u043A\u043B\u0430\u0434\u043D\u0430\u044F \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u044F \u0432 \u0441\u043B\u0443\u0447\u0430\u0435 \u0431\u043E\u043B\u044C\u0448\u043E\u0433\u043E \u0447\u0438\u0441\u043B\u0430 \u0430\u043A\u0442\u0438\u0432\u043D\u044B\u0445 \u0441\u0435\u0441\u0441\u0438\u0439.
+user=\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C
+from-ip=\u0421 IP
+session-start=\u0421\u0435\u0441\u0441\u0438\u044F \u043D\u0430\u0447\u0430\u0442\u0430
+first-page=\u041F\u0435\u0440\u0432\u0430\u044F \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0430
+previous-page=\u041F\u043E\u0441\u043B\u0435\u0434\u043D\u044F\u044F \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0430
+next-page=\u0421\u043B\u0435\u0434\u0443\u044E\u0449\u0430\u044F \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0430
+client-revoke.not-before.tooltip=\u041E\u0442\u043E\u0437\u0432\u0430\u0442\u044C \u043B\u044E\u0431\u044B\u0435 \u0442\u043E\u043A\u0435\u043D\u044B, \u0432\u044B\u0434\u0430\u043D\u043D\u044B\u0435 \u0434\u043E \u044D\u0442\u043E\u0439 \u0434\u0430\u0442\u044B \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430.
+client-revoke.push.tooltip=\u0415\u0441\u043B\u0438 URL \u0441\u0438\u0441\u0442\u0435\u043C\u044B \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0441\u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043E\u0432\u0430\u043D \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430, \u043F\u043E\u0441\u043B\u0430\u0442\u044C \u043F\u043E\u043B\u0438\u0442\u0438\u043A\u0438 \u044D\u0442\u043E\u043C\u0443 \u043A\u043B\u0438\u0435\u043D\u0442\u0443.
+select-a-format=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0444\u043E\u0440\u043C\u0430\u0442
+download=\u0421\u043A\u0430\u0447\u0430\u0442\u044C
+offline-tokens=\u041E\u0444\u0444\u043B\u0430\u0439\u043D \u0442\u043E\u043A\u0435\u043D\u044B
+offline-tokens.tooltip=\u041E\u0431\u0449\u0435\u0435 \u043A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u043E\u0444\u0444\u043B\u0430\u0439\u043D \u0442\u043E\u043A\u0435\u043D\u043E\u0432 \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430.
+show-offline-tokens=\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u043E\u0444\u0444\u043B\u0430\u0439\u043D \u0442\u043E\u043A\u0435\u043D\u044B
+show-offline-tokens.tooltip=\u041F\u0440\u0435\u0434\u0443\u043F\u0440\u0435\u0436\u0434\u0435\u043D\u0438\u0435, \u044D\u0442\u043E \u043F\u043E\u0442\u0435\u043D\u0446\u0438\u0430\u043B\u044C\u043D\u043E \u043D\u0430\u043A\u043B\u0430\u0434\u043D\u0430\u044F \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u044F \u0432 \u0441\u043B\u0443\u0447\u0430\u0435 \u0431\u043E\u043B\u044C\u0448\u043E\u0433\u043E \u043A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043E\u0444\u0444\u043B\u0430\u0439\u043D \u0442\u043E\u043A\u0435\u043D\u043E\u0432.
+token-issued=\u0422\u043E\u043A\u0435\u043D \u0432\u044B\u0434\u0430\u043D
+last-access=\u041F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u0439 \u0434\u043E\u0441\u0442\u0443\u043F
+last-refresh=\u041F\u043E\u0441\u043B\u0435\u0434\u043D\u0435\u0435 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435
+key-export=\u042D\u043A\u0441\u043F\u043E\u0440\u0442 \u043A\u043B\u044E\u0447\u0430
+key-import=\u0418\u043C\u043F\u043E\u0440\u0442 \u043A\u043B\u044E\u0447\u0430
+export-saml-key=\u042D\u043A\u0441\u043F\u043E\u0440\u0442 SAML \u043A\u043B\u044E\u0447\u0430
+import-saml-key=\u0418\u043C\u043F\u043E\u0440\u0442 SAML \u043A\u043B\u044E\u0447\u0430
+realm-certificate-alias=\u0421\u0438\u043D\u043E\u043D\u0438\u043C \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u0430 Realm
+realm-certificate-alias.tooltip=\u0421\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442 Realm \u0442\u0430\u043A\u0436\u0435 \u0441\u043E\u0445\u0440\u0430\u043D\u044F\u0435\u0442\u0441\u044F \u0432 \u0430\u0440\u0445\u0438\u0432\u0435. \u042D\u0442\u043E \u0441\u0438\u043D\u043E\u043D\u0438\u043C \u0434\u043B\u044F \u043D\u0435\u0433\u043E.
+signing-key=\u041A\u043B\u044E\u0447 \u043F\u043E\u0434\u043F\u0438\u0441\u0438
+saml-signing-key=SAML-\u043A\u043B\u044E\u0447 \u043F\u043E\u0434\u043F\u0438\u0441\u0438.
+private-key=\u041F\u0440\u0438\u0432\u0430\u0442\u043D\u044B\u0439 \u043A\u043B\u044E\u0447
+generate-new-keys=\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043D\u043E\u0432\u044B\u0435 \u043A\u043B\u044E\u0447\u0438
+export=\u042D\u043A\u0441\u043F\u043E\u0440\u0442
+encryption-key=\u041A\u043B\u044E\u0447 \u0448\u0438\u0444\u0440\u043E\u0432\u0430\u043D\u0438\u044F
+saml-encryption-key.tooltip=SAML \u043A\u043B\u044E\u0447 \u0448\u0438\u0444\u0440\u043E\u0432\u0430\u043D\u0438\u044F.
+service-accounts=\u0423\u0447\u0435\u0442\u043D\u044B\u0435 \u0437\u0430\u043F\u0438\u0441\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430
+service-account.available-roles.tooltip=\u0420\u043E\u043B\u0438 \u0443\u0440\u043E\u0432\u043D\u044F Realm, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043C\u043E\u0433\u0443\u0442 \u0431\u044B\u0442\u044C \u043F\u0440\u0438\u0441\u0432\u043E\u0435\u043D\u044B \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430.
+service-account.assigned-roles.tooltip=\u0420\u043E\u043B\u0438 \u0443\u0440\u043E\u0432\u043D\u044F Realm, \u043D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044B\u0435 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430.
+service-account-is-not-enabled-for=\u0423\u0447\u0435\u0442\u043D\u0430\u044F \u0437\u0430\u043F\u0438\u0441\u044C \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u043D\u0435 \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u0430 \u0434\u043B\u044F {{client}}
+create-protocol-mappers=\u0421\u043E\u0437\u0434\u0430\u0442\u044C \u0441\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\u0440\u043E\u0442\u043E\u043A\u043E\u043B\u0430
+create-protocol-mapper=\u0421\u043E\u0437\u0434\u0430\u0442\u044C \u0441\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\u0440\u043E\u0442\u043E\u043A\u043E\u043B\u0430
+protocol=\u041F\u0440\u043E\u0442\u043E\u043A\u043E\u043B
+protocol.tooltip=\u041F\u0440\u043E\u0442\u043E\u043A\u043E\u043B...
+id=ID
+mapper.name.tooltip=\u041D\u0430\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u0438\u0435 \u0441\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u044F.
+mapper.consent-required.tooltip=\u041D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u043B\u0438 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u043D\u0430 \u043F\u0440\u0435\u0434\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u044D\u0442\u043E\u0439 \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u0443?
+consent-text=\u0422\u0435\u043A\u0441\u0442 \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u0438\u044F
+consent-text.tooltip=\u0422\u0435\u043A\u0441\u0442, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0431\u0443\u0434\u0435\u0442 \u043F\u043E\u043A\u0430\u0437\u0430\u043D \u043D\u0430 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0435 \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u0438\u044F.
+mapper-type=\u0422\u0438\u043F \u0441\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u044F
+mapper-type.tooltip=\u0422\u0438\u043F \u0441\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u044F
+# realm identity providers
+identity-providers=\u041F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0438 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438
+table-of-identity-providers=\u0422\u0430\u0431\u043B\u0438\u0446\u0430 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u043E\u0432 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438
+add-provider.placeholder=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430...
+provider=\u041F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A
+gui-order=\u041E\u0447\u0435\u0440\u0435\u0434\u043D\u043E\u0441\u0442\u044C \u0432 GUI
+first-broker-login-flow=\u0421\u0446\u0435\u043D\u0430\u0440\u0438\u0439 \u043F\u0435\u0440\u0432\u043E\u0433\u043E \u0432\u0445\u043E\u0434\u0430
+post-broker-login-flow=\u0421\u0446\u0435\u043D\u0430\u0440\u0438\u0439 \u043F\u043E\u0441\u043B\u0435 \u0432\u0445\u043E\u0434\u0430
+redirect-uri=URI \u043F\u0435\u0440\u0435\u043D\u0430\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u044F
+redirect-uri.tooltip=\u042D\u0442\u043E\u0442 uri \u043F\u0435\u0440\u0435\u043D\u0430\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u044F \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0441\u044F \u0432 \u0441\u043B\u0443\u0447\u0430\u0435, \u0435\u0441\u043B\u0438 \u0441\u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043E\u0432\u0430\u043D \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438.
+alias=\u0421\u0438\u043D\u043E\u043D\u0438\u043C
+identity-provider.alias.tooltip=\u0421\u0438\u043D\u043E\u043D\u0438\u043C \u0443\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u043E \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u0442 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438, \u0430 \u0442\u0430\u043A\u0436\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0441\u044F \u0434\u043B\u044F \u043F\u043E\u0441\u0442\u0440\u043E\u0435\u043D\u0438\u044F \u0430\u0434\u0440\u0435\u0441\u0430 \u043F\u0435\u0440\u0435\u0430\u0434\u0440\u0435\u0441\u0430\u0446\u0438\u0438.
+identity-provider.enabled.tooltip=\u0412\u043A\u043B\u044E\u0447\u0430\u0435\u0442/\u0432\u044B\u043A\u043B\u044E\u0447\u0430\u0435\u0442 \u044D\u0442\u043E\u0433\u043E \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438.
+authenticate-by-default=\u0410\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044F \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E
+identity-provider.authenticate-by-default.tooltip=\u041E\u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044F, \u0435\u0441\u043B\u0438 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D \u0434\u043B\u044F \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u0430\u043A\u0430\u0446\u0438\u0438 \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E \u0434\u0430\u0436\u0435 \u043F\u0435\u0440\u0435\u0434 \u043E\u0442\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435\u043C \u044D\u043A\u0440\u0430\u043D\u0430 \u0432\u0445\u043E\u0434\u0430.
+store-tokens=\u0425\u0440\u0430\u043D\u0435\u043D\u0438\u0435 \u0442\u043E\u043A\u0435\u043D\u043E\u0432
+identity-provider.store-tokens.tooltip=\u0412\u043A\u043B\u044E\u0447\u0435\u043D\u043E/\u0432\u044B\u043A\u043B\u044E\u0447\u0435\u043D\u043E \u0445\u0440\u0430\u043D\u0435\u043D\u0438\u0435 \u0442\u043E\u043A\u0435\u043D\u043E\u0432 \u043F\u043E\u0441\u043B\u0435 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F.
+stored-tokens-readable=\u0421\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u043D\u044B\u0435 \u0442\u043E\u043A\u0435\u043D\u044B \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B \u043D\u0430 \u0447\u0442\u0435\u043D\u0438\u0435
+identity-provider.stored-tokens-readable.tooltip=\u0412\u043A\u043B\u044E\u0447\u0435\u043D\u043E/\u0432\u044B\u043A\u043B\u044E\u0447\u0435\u043D\u043E \u0447\u0442\u0435\u043D\u0438\u0435 \u043D\u043E\u0432\u044B\u043C\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F\u043C\u0438 \u043B\u044E\u0431\u044B\u0445 \u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u043D\u044B\u0445 \u0442\u043E\u043A\u0435\u043D\u043E\u0432. \u042D\u0442\u043E \u043D\u0430\u0437\u043D\u0430\u0447\u0430\u0435\u0442\u0441\u044F \u0440\u043E\u043B\u044C\u044E broker.read-token.
+update-profile-on-first-login=\u041E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u043F\u0440\u043E\u0444\u0438\u043B\u044C \u043F\u0440\u0438 \u043F\u0435\u0440\u0432\u043E\u043C \u0432\u0445\u043E\u0434\u0435
+on=\u0412\u043A\u043B
+on-missing-info=\u041F\u0440\u0438 \u043F\u0440\u043E\u043F\u0443\u0449\u0435\u043D\u043D\u043E\u0439 \u0438\u043D\u0444\u043E
+off=\u0412\u044B\u043A
+update-profile-on-first-login.tooltip=\u041E\u043F\u0440\u0435\u0434\u0435\u043B\u0438\u0442\u044C \u0443\u0441\u043B\u043E\u0432\u0438\u044F, \u043F\u0440\u0438 \u043A\u043E\u0442\u043E\u0440\u044B\u0445 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0438 \u0434\u043E\u043B\u0436\u043D\u044B \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0442\u044C \u0441\u0432\u043E\u0439 \u043F\u0440\u043E\u0444\u0438\u043B\u044C \u0432\u043E \u0432\u0440\u0435\u043C\u044F \u043F\u0435\u0440\u0432\u043E\u0433\u043E \u0432\u0445\u043E\u0434\u0430.
+trust-email=\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 Email
+trust-email.tooltip=\u0415\u0441\u043B\u0438 \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u043E, \u0442\u043E email, \u043F\u0440\u0435\u0434\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u043D\u044B\u0439 \u044D\u0442\u0438\u043C \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u043E\u043C \u043D\u0435 \u0431\u0443\u0434\u0435\u0442 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u043D\u044B\u043C \u0434\u0430\u0436\u0435 \u0435\u0441\u043B\u0438 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u043E \u0434\u043B\u044F realm.
+gui-order.tooltip=\u0427\u0438\u0441\u043B\u043E, \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u044F\u044E\u0449\u0435\u0435 \u043F\u043E\u0440\u044F\u0434\u043E\u043A \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u043E\u0432 \u0432 GUI (\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440, \u043D\u0430 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0435 \u0432\u0445\u043E\u0434\u0430).
+first-broker-login-flow.tooltip=\u0421\u0438\u043D\u043E\u043D\u0438\u043C \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u044F \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0441\u0440\u0430\u0431\u0430\u0442\u044B\u0432\u0430\u0435\u0442 \u043F\u043E\u0441\u043B\u0435 \u043F\u0435\u0440\u0432\u043E\u0433\u043E \u0432\u0445\u043E\u0434\u0430 \u0441 \u044D\u0442\u043E\u0433\u043E \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438. \u0422\u0435\u0440\u043C\u0438\u043D 'First Login' \u043E\u0437\u043D\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043E \u0435\u0449\u0435 \u043D\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u0438 Keycloak \u0441\u0432\u044F\u0437\u0430\u043D\u043D\u043E\u0439 \u0441 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u043E\u0439 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u044C\u044E \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438.
+post-broker-login-flow.tooltip=\u0421\u0438\u043D\u043E\u043D\u0438\u043C \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u044F \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0441\u0440\u0430\u0431\u0430\u0442\u044B\u0432\u0430\u0435\u0442 \u043F\u043E\u0441\u043B\u0435 \u043A\u0430\u0436\u0434\u043E\u0433\u043E \u0432\u0445\u043E\u0434\u0430 \u0438\u0437 \u044D\u0442\u043E\u0433\u043E \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438. \u041F\u043E\u043B\u0435\u0437\u043D\u043E, \u0435\u0441\u043B\u0438 \u0432\u044B \u0445\u043E\u0434\u0438\u0442\u0435 \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u0443\u044E \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443 \u043A\u0430\u0436\u0434\u043E\u0433\u043E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F, \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u043E\u0433\u043E \u0432 \u044D\u0442\u043E\u043C \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0435 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 (\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440 OTP). \u041E\u0441\u0442\u0430\u0432\u044C\u0442\u0435 \u044D\u0442\u043E \u043F\u043E\u043B\u0435 \u043F\u0443\u0441\u0442\u044B\u043C, \u0435\u0441\u043B\u0438 \u043D\u0435 \u0445\u043E\u0442\u0438\u0442\u0435, \u0447\u0442\u043E\u0431\u044B \u0441\u0440\u0430\u0431\u0430\u0442\u044B\u0432\u0430\u043B\u0438 \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u0430\u0443\u0442\u0435\u043D\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u043F\u043E\u0441\u043B\u0435 \u0432\u0445\u043E\u0434\u0430 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0441 \u044D\u0442\u0438\u043C \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u043E\u043C \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438. \u0422\u0430\u043A\u0436\u0435 \u043E\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043D\u0438\u043C\u0430\u043D\u0438\u0435, \u0447\u0442\u043E \u0440\u0435\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u0438 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u0430 \u0434\u043E\u043B\u0436\u043D\u044B \u043F\u0440\u0435\u0434\u043F\u043E\u043B\u0430\u0433\u0430\u0442\u044C \u0447\u0442\u043E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u0443\u0436\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u043B ClientSession \u0442\u0430\u043A\u0436\u0435 \u043A\u0430\u043A \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u043B \u0435\u0435 \u0432 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0435 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438.
+openid-connect-config=\u041A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F OpenID Connect
+openid-connect-config.tooltip=OIDC SP \u0438 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F \u0432\u043D\u0435\u0448\u043D\u0438\u0445 IDP.
+authorization-url=URL \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438
+authorization-url.tooltip=Url \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438.
+token-url=URL \u0442\u043E\u043A\u0435\u043D\u0430
+token-url.tooltip=URL \u0442\u043E\u043A\u0435\u043D\u0430.
+logout-url=URL \u0432\u044B\u0445\u043E\u0434\u0430
+identity-provider.logout-url.tooltip=\u041A\u043E\u043D\u0435\u0447\u043D\u0430\u044F \u0442\u043E\u0447\u043A\u0430 \u043E\u043A\u043E\u043D\u0447\u0430\u043D\u0438\u044F \u0441\u0435\u0441\u0441\u0438\u0438, \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u043C\u0430\u044F \u0434\u043B\u044F \u0432\u044B\u0445\u043E\u0434\u0430 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0438\u0437 \u0432\u043D\u0435\u0448\u043D\u0435\u0433\u043E IDP.
+backchannel-logout=Backchannel Logout
+backchannel-logout.tooltip=\u041F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043B\u0438 \u0432\u043D\u0435\u0448\u043D\u0438\u0439 IDP backchannel logout?
+user-info-url=URL \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u0438 \u043E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435
+user-info-url.tooltip=Url \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u0438 \u043E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435. \u042D\u0442\u043E \u043F\u043E\u043B\u0435 \u043E\u043F\u0446\u0438\u043E\u043D\u0430\u043B\u044C\u043D\u043E.
+identity-provider.client-id.tooltip=\u041A\u043B\u0438\u0435\u043D\u0442 \u0438\u043B\u0438 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u043A\u043B\u0438\u0435\u043D\u0442\u0430, \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u043E\u0433\u043E \u0441 \u043F\u043E\u043C\u043E\u0449\u044C\u044E \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438.
+client-secret=\u0421\u0435\u043A\u0440\u0435\u0442 \u043A\u043B\u0438\u0435\u043D\u0442\u0430
+show-secret=\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0441\u0435\u043A\u0440\u0435\u0442
+hide-secret=\u0421\u043A\u0440\u044B\u0442\u044C \u0441\u0435\u043A\u0440\u0435\u0442
+client-secret.tooltip=\u041A\u043B\u0438\u0435\u043D\u0442 \u0438\u043B\u0438 \u0441\u0435\u043A\u0440\u0435\u0442 \u043A\u043B\u0438\u0435\u043D\u0442\u0430, \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0441 \u043F\u043E\u043C\u043E\u0449\u044C\u044E \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438.
+issuer=\u042D\u043C\u0438\u0442\u0435\u043D\u0442
+issuer.tooltip=\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u044D\u043C\u0438\u0442\u0435\u043D\u0442\u0430 \u0434\u043B\u044F \u044D\u043C\u0438\u0442\u0435\u043D\u0442\u0430 \u043E\u0442\u0432\u0435\u0442\u0430. \u0415\u0441\u043B\u0438 \u043D\u0435 \u043F\u043E\u0441\u0442\u0430\u0432\u043B\u044F\u0435\u0442\u0441\u044F, \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u043D\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u044B\u043F\u043E\u043B\u043D\u044F\u0442\u044C\u0441\u044F.
+default-scopes=\u041E\u0431\u043B\u0430\u0441\u0442\u0438 \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E
+identity-provider.default-scopes.tooltip=\u041E\u0431\u043B\u0430\u0441\u0442\u0438, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0431\u0443\u0434\u0443\u0442 \u043F\u043E\u0441\u043B\u0430\u043D\u044B \u043F\u043E\u0441\u043B\u0435 \u0437\u0430\u043F\u0440\u043E\u0441\u0430 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438. \u042D\u0442\u043E \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u0441\u043F\u0438\u0441\u043E\u043A \u043E\u0431\u043B\u0430\u0441\u0442\u0435\u0439, \u0440\u0430\u0437\u0434\u0435\u043B\u0435\u043D\u043D\u044B\u0445 \u043F\u0440\u043E\u0431\u0435\u043B\u043E\u043C. \u041F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E 'openid'.
+prompt=\u041F\u043E\u0434\u0441\u043A\u0430\u0437\u043A\u0430
+unspecified.option=\u043D\u0435\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u043D\u044B\u0439
+none.option=\u043D\u0435\u0442
+consent.option=\u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435
+login.option=\u0432\u0445\u043E\u0434
+select-account.option=\u0432\u044B\u0431\u0435\u0440\u0438\u0442\u0435_\u0443\u0447\u0435\u0442\u043D\u0443\u044E_\u0437\u0430\u043F\u0438\u0441\u044C
+prompt.tooltip=\u0423\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442, \u0437\u0430\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442 \u043B\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u0443 \u043A\u043E\u043D\u0435\u0447\u043D\u043E\u0433\u043E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u043F\u0435\u0440\u0435\u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044E \u0438 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435.
+validate-signatures=\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u043F\u043E\u0434\u043F\u0438\u0441\u0435\u0439
+identity-provider.validate-signatures.tooltip=\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C/\u0432\u044B\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443 \u043F\u043E\u0434\u043F\u0438\u0441\u0435\u0439 \u0432\u043D\u0435\u0448\u043D\u0438\u0445 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u043E\u0432 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438.
+validating-public-key=\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u043F\u0443\u0431\u043B\u0438\u0447\u043D\u043E\u0433\u043E \u043A\u043B\u044E\u0447\u0430
+identity-provider.validating-public-key.tooltip=\u041F\u0443\u0431\u043B\u0438\u0447\u043D\u044B\u0439 \u043A\u043B\u044E\u0447 \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435 PEM, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0434\u043E\u043B\u0436\u0435\u043D \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C\u0441\u044F \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043F\u043E\u0434\u043F\u0438\u0441\u0435\u0439 \u0432\u043D\u0435\u0448\u043D\u0438\u0445 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u043E\u0432 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438.
+import-external-idp-config=\u0418\u043C\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044E \u0432\u043D\u0435\u0448\u043D\u0435\u0433\u043E IDP
+import-external-idp-config.tooltip=\u041F\u043E\u0437\u0432\u043E\u043B\u044F\u0435\u0442 \u0432\u0430\u043C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u043C\u0435\u0442\u0430\u0434\u0430\u043D\u043D\u044B\u0435 \u0432\u043D\u0435\u0448\u043D\u0435\u0433\u043E IDP \u0438\u0437 \u0444\u0430\u0439\u043B\u0430 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0438\u043B\u0438 \u0441\u043A\u0430\u0447\u0430\u0442\u044C \u0435\u0433\u043E \u0438\u0437 URL.
+import-from-url=\u0418\u043C\u043F\u043E\u0440\u0442 \u0438\u0437 URL
+identity-provider.import-from-url.tooltip=\u0418\u043C\u043F\u043E\u0440\u0442 \u043C\u0435\u0442\u0430\u0434\u0430\u043D\u043D\u044B\u0445 \u0438\u0437 \u0434\u0435\u0441\u043A\u0440\u0438\u043F\u0442\u043E\u0440\u0430 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044B\u0432\u0430\u043D\u0438\u044F \u0443\u0434\u0430\u043B\u0435\u043D\u043D\u043E\u0433\u043E \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438.
+import-from-file=\u0418\u043C\u043F\u043E\u0440\u0442 \u0438\u0437 \u0444\u0430\u0439\u043B\u0430
+identity-provider.import-from-file.tooltip=\u0418\u043C\u043F\u043E\u0440\u0442 \u043C\u0435\u0442\u0430\u0434\u0430\u043D\u043D\u044B\u0445 \u0441\u043E \u0441\u043A\u0430\u0447\u0430\u043D\u043D\u043E\u0433\u043E \u0434\u0435\u0441\u043A\u0440\u0438\u043F\u0442\u043E\u0440\u0430 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044B\u0432\u0430\u043D\u0438\u044F \u0443\u0434\u0430\u043B\u0435\u043D\u043D\u043E\u0433\u043E \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438.
+saml-config=\u041A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F SAML
+identity-provider.saml-config.tooltip=\u041A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F SAML SP  \u0438 \u0432\u043D\u0435\u0448\u043D\u0438\u0445 IDP.
+single-signon-service-url=\u0410\u0434\u0440\u0435\u0441 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0435\u0434\u0438\u043D\u043E\u0439 \u0442\u043E\u0447\u043A\u0438 \u0432\u0445\u043E\u0434\u0430
+saml.single-signon-service-url.tooltip=Url, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D \u0434\u043B\u044F \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u043D\u044B\u0445 \u0437\u0430\u043F\u0440\u043E\u0441\u043E\u0432 \u043D\u0430 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044E (SAML AuthnRequest).
+single-logout-service-url=\u0410\u0434\u0440\u0435\u0441\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 \u0435\u0434\u0438\u043D\u043E\u0433\u043E \u0432\u044B\u0445\u043E\u0434\u0430
+saml.single-logout-service-url.tooltip=Url, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D \u0434\u043B\u044F \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u043D\u044B\u0445 \u0437\u0430\u043F\u0440\u043E\u0441\u043E\u0432 \u043D\u0430 \u0432\u044B\u0445\u043E\u0434.
+nameid-policy-format=\u0424\u043E\u0440\u043C\u0430\u0442 \u043F\u043E\u043B\u0438\u0442\u0438\u043A\u0438 NameID
+nameid-policy-format.tooltip=\u041E\u043F\u0440\u0435\u0434\u0435\u043B\u044F\u0435\u0442 \u0441\u0441\u044B\u043B\u043A\u0443 URI, \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044E\u0449\u0443\u044E \u0444\u043E\u0440\u043C\u0430\u0442\u0443 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u0430 \u0438\u043C\u0435\u043D\u0438. \u041F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E urn:oasis:names:tc:SAML:2.0:nameid-format:persistent.
+http-post-binding-response=\u0421\u0432\u044F\u0437\u0430\u043D\u043D\u044B\u0439 \u043E\u0442\u0432\u0435\u0442 HTTP-POST
+http-post-binding-response.tooltip=\u0423\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442, \u0441\u043B\u0435\u0434\u0443\u0435\u0442 \u043B\u0438 \u043E\u0442\u0432\u0435\u0447\u0430\u0442\u044C \u043D\u0430 \u0437\u0430\u043F\u0440\u043E\u0441\u044B, \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u044F \u0441\u0432\u044F\u0437\u044B\u0432\u0430\u043D\u0438\u0435 HTTP-POST. \u0415\u0441\u043B\u0438 \u043D\u0435\u0442, \u0442\u043E \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D HTTP-REDIRECT.
+http-post-binding-for-authn-request=\u0421\u0432\u044F\u0437\u044B\u0432\u0430\u043D\u0438\u0435 HTTP-POST \u0434\u043B\u044F AuthnRequest
+http-post-binding-for-authn-request.tooltip=\u0423\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442, \u0434\u043E\u043B\u0436\u043D\u044B \u043B\u0438 AuthnRequest \u0431\u044B\u0442\u044C \u043F\u043E\u0441\u043B\u0430\u043D\u044B, \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u044F \u0441\u0432\u044F\u0437\u043A\u0443 HTTP-POST. \u0415\u0441\u043B\u0438 \u043D\u0435\u0442, \u0442\u043E \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D HTTP-REDIRECT.
+want-authn-requests-signed=\u0416\u0435\u043B\u0430\u043D\u0438\u0435 \u043F\u043E\u0434\u043F\u0438\u0441\u0438 AuthnRequests
+want-authn-requests-signed.tooltip=\u0423\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442, \u043E\u0436\u0438\u0434\u0430\u0435\u0442 \u043B\u0438 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u043F\u043E\u0434\u043F\u0438\u0441\u0430\u043D\u043D\u044B\u0445 AuthnRequest.
+force-authentication=\u041F\u0440\u0438\u043D\u0443\u0434\u0438\u0442\u0435\u043B\u044C\u043D\u0430\u044F \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044F
+identity-provider.force-authentication.tooltip=\u0423\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442, \u0434\u043E\u043B\u0436\u0435\u043D \u043B\u0438 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0432\u0435\u0434\u0443\u0449\u0435\u0433\u043E \u043D\u0430\u043F\u0440\u044F\u043C\u0443\u044E \u0430 \u043D\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C \u043F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0438\u0439 \u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442 \u0431\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u043E\u0441\u0442\u0438.
+validate-signature=\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u043F\u043E\u0434\u043F\u0438\u0441\u0438
+saml.validate-signature.tooltip=\u0412\u043A\u043B\u044E\u0447\u0430\u0435\u0442/\u0432\u044B\u043A\u043B\u044E\u0447\u0430\u0435\u0442 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443 \u043F\u043E\u0434\u043F\u0438\u0441\u0438 \u043E\u0442\u0432\u0435\u0442\u043E\u0432 \u043E\u0442 SAML.
+validating-x509-certificate=\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 X509 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0432
+validating-x509-certificate.tooltip=\u0421\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442 \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435 PEM, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043F\u043E\u0434\u043F\u0438\u0441\u0438.
+saml.import-from-url.tooltip=\u0418\u043C\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043C\u0435\u0442\u0430\u0434\u0430\u043D\u043D\u044B\u0435 \u0438\u0437 \u0443\u0434\u0430\u043B\u0435\u043D\u043D\u043E\u0433\u043E \u0434\u0435\u0441\u043A\u0440\u0438\u043F\u0442\u043E\u0440\u0430 \u0441\u0443\u0449\u043D\u043E\u0441\u0442\u0435\u0439 IDP SAML.
+social.client-id.tooltip=\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u043A\u043B\u0438\u0435\u043D\u0442\u0430, \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0441 \u043F\u043E\u043C\u043E\u0449\u044C\u044E \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438.
+social.client-secret.tooltip=\u0421\u0435\u043A\u0440\u0435\u0442 \u043A\u043B\u0438\u0435\u043D\u0442\u0430, \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0441 \u043F\u043E\u043C\u043E\u0449\u044C\u044E \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438.
+social.default-scopes.tooltip=\u041E\u0431\u043B\u0430\u0441\u0442\u0438, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0431\u0443\u0434\u0443\u0442 \u043F\u043E\u0441\u043B\u0430\u043D\u044B \u043F\u0440\u0438 \u0437\u0430\u043F\u0440\u043E\u0441\u0435 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438. \u0421\u043C\u043E\u0442\u0440\u0438\u0442\u0435 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\u0446\u0438\u044E \u0434\u043B\u044F \u0432\u043E\u0437\u043C\u043E\u0436\u043D\u044B\u0445 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0439, \u0440\u0430\u0437\u0434\u0435\u043B\u0438\u0442\u0435\u043B\u0435\u0439 \u0438 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0439 \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E.
+key=\u041A\u043B\u044E\u0447
+stackoverflow.key.tooltip=\u041A\u043B\u044E\u0447, \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u043D\u044B\u0439 \u043F\u0440\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u0430 \u0432 Stack Overflow.
+
+# User federation
+sync-ldap-roles-to-keycloak=\u0421\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0440\u043E\u043B\u0438 LDAP \u0441 Keycloak
+sync-keycloak-roles-to-ldap=\u0421\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0440\u043E\u043B\u0438 Keycloak \u0441 LDAP
+sync-ldap-groups-to-keycloak=\u0421\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0433\u0440\u0443\u043F\u043F\u044B LDAP \u0441 Keycloak
+sync-keycloak-groups-to-ldap=\u0421\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0433\u0440\u0443\u043F\u043F\u044B Keycloak \u0441 LDAP
+
+realms=Realms
+realm=Realm
+
+identity-provider-mappers=\u0421\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u043E\u0432 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438
+create-identity-provider-mapper=\u0421\u043E\u0437\u0434\u0430\u0442\u044C \u0441\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439
+add-identity-provider-mapper=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0441\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439
+client.description.tooltip=\u0417\u0430\u0434\u0430\u0435\u0442 \u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0435 \u043A\u043B\u0438\u0435\u043D\u0442\u0430. \u041D\u0430\u043F\u0440\u0438\u043C\u0435\u0440 '\u041C\u043E\u0439 \u043A\u043B\u0438\u0435\u043D\u0442 \u0434\u043B\u044F \u0442\u0430\u0431\u0435\u043B\u044F \u0443\u0447\u0435\u0442\u0430 \u0432\u0440\u0435\u043C\u0435\u043D\u0438'. \u041F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043A\u043B\u044E\u0447\u0438 \u0434\u043B\u044F \u043B\u043E\u043A\u0430\u043B\u0438\u0437\u043E\u0432\u0430\u043D\u043D\u044B\u0445 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0439. \u041D\u0430\u043F\u0440\u0438\u043C\u0435\u0440: ${my_client_description}
+
+expires=\u0418\u0441\u0442\u0435\u043A\u0430\u0435\u0442
+expiration=\u0418\u0441\u0442\u0435\u0447\u0435\u043D\u0438\u0435
+expiration.tooltip=\u041E\u043F\u0440\u0435\u0434\u0435\u043B\u044F\u0435\u0442, \u043A\u0430\u043A \u0434\u043E\u043B\u0433\u043E \u0442\u043E\u043A\u0435\u043D \u0431\u0443\u0434\u0435\u0442 \u043E\u0441\u0442\u0430\u0432\u0430\u0442\u044C\u0441\u044F \u0432\u0430\u043B\u0438\u0434\u043D\u044B\u043C
+count=\u0421\u0447\u0435\u0442\u0447\u0438\u043A
+count.tooltip=\u041E\u043F\u0440\u0435\u0434\u0435\u043B\u044F\u0435\u0442, \u043A\u0430\u043A \u043C\u043D\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u043E\u0432 \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u0441\u043E\u0437\u0434\u0430\u043D\u043E \u0441 \u043F\u043E\u043C\u043E\u0449\u044C\u044E \u044D\u0442\u043E\u0433\u043E \u0442\u043E\u043A\u0435\u043D\u0430
+remainingCount=\u0421\u0447\u0435\u0442\u0447\u0438\u043A \u043E\u0441\u0442\u0430\u0442\u043A\u0430
+created=\u0421\u043E\u0437\u0434\u0430\u043D\u043E
+back=\u041D\u0430\u0437\u0430\u0434
+initial-access-tokens=\u0422\u043E\u043A\u0435\u043D\u044B \u043F\u0435\u0440\u0432\u0438\u0447\u043D\u043E\u0433\u043E \u0434\u043E\u0441\u0442\u0443\u043F\u0430
+add-initial-access-tokens=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0442\u043E\u043A\u0435\u043D \u043F\u0435\u0440\u0432\u0438\u0447\u043D\u043E\u0433\u043E \u0434\u043E\u0441\u0442\u0443\u043F\u0430
+initial-access-token=\u0422\u043E\u043A\u0435\u043D \u043F\u0435\u0440\u0432\u0438\u0447\u043D\u043E\u0433\u043E \u0434\u043E\u0441\u0442\u0443\u043F\u0430
+initial-access.copyPaste.tooltip=\u0421\u043A\u043E\u043F\u0438\u0440\u0443\u0439\u0442\u0435/\u0432\u0441\u0442\u0430\u0432\u044C\u0442\u0435 \u0442\u043E\u043A\u0435\u043D \u043F\u0435\u0440\u0432\u0438\u0447\u043D\u043E\u0433\u043E \u0434\u043E\u0441\u0442\u0443\u043F\u0430 \u0434\u043E \u0442\u0435\u0445 \u043F\u043E\u0440, \u043A\u0430\u043A \u0443\u0439\u0434\u0435\u0442\u0435 \u0441 \u044D\u0442\u043E\u0439 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B, \u0442.\u043A. \u0432 \u0434\u0430\u043B\u044C\u043D\u0435\u0439\u0448\u0435\u043C \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u0435\u0433\u043E \u0431\u0443\u0434\u0435\u0442 \u043D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E
+continue=\u041F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u044C
+initial-access-token.confirm.title=\u0421\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0442\u043E\u043A\u0435\u043D \u043F\u0435\u0440\u0432\u0438\u0447\u043D\u043E\u0433\u043E \u0434\u043E\u0441\u0442\u0443\u043F\u0430
+initial-access-token.confirm.text=\u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0441\u043A\u043E\u043F\u0438\u0440\u0443\u0439\u0442\u0435 \u0438 \u0432\u0441\u0442\u0430\u0432\u044C\u0442\u0435 \u0442\u043E\u043A\u0435\u043D \u043F\u0435\u0440\u0432\u0438\u0447\u043D\u043E\u0433\u043E \u0434\u043E\u0441\u0442\u0443\u043F\u0430 \u0434\u043E \u0442\u043E\u0433\u043E, \u043A\u0430\u043A \u0441\u0434\u0435\u043B\u0430\u0435\u0442\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435, \u0442.\u043A. \u0432 \u0434\u0430\u043B\u044C\u043D\u0435\u0439\u0448\u0435\u043C \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u0435\u0433\u043E \u0431\u0443\u0434\u0435\u0442 \u043D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E
+
+client-templates=\u0428\u0430\u0431\u043B\u043E\u043D\u044B \u043A\u043B\u0438\u0435\u043D\u0442\u043E\u0432
+client-templates.tooltip=\u0428\u0430\u0431\u043B\u043E\u043D\u044B \u043A\u043B\u0438\u0435\u043D\u0442\u043E\u0432 \u043F\u043E\u0437\u0432\u043E\u043B\u044F\u044E\u0442 \u0432\u0430\u043C \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0438\u0442\u044C \u043E\u0441\u043D\u043E\u0432\u043D\u0443\u044E \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044E, \u043A\u043E\u0442\u043E\u0440\u0430\u044F \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043E\u0431\u0449\u0435\u0439 \u043C\u0435\u0436\u0434\u0443 \u043D\u0435\u0441\u043A\u043E\u043B\u044C\u043A\u0438\u043C\u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u0430\u043C\u0438
+
+groups=\u0413\u0440\u0443\u043F\u043F\u044B
+
+group.add-selected.tooltip=\u0420\u043E\u043B\u0438 Realm, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043C\u043E\u0433\u0443\u0442 \u0431\u044B\u0442\u044C \u043D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u044B \u043D\u0430 \u044D\u0442\u0443 \u0433\u0440\u0443\u043F\u043F\u0443.
+group.assigned-roles.tooltip=\u0420\u043E\u043B\u0438 Realm, \u0441\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u043D\u044B\u0435 \u043D\u0430 \u0433\u0440\u0443\u043F\u043F\u0443
+group.effective-roles.tooltip=\u0412\u0441\u0435 \u0441\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u044F realm \u0440\u043E\u043B\u0435\u0439. \u041D\u0435\u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0440\u043E\u043B\u0438 \u0437\u0434\u0435\u0441\u044C \u043C\u043E\u0433\u0443\u0442 \u0431\u044B\u0442\u044C \u0443\u043D\u0430\u0441\u043B\u0435\u0434\u043E\u0432\u0430\u043D\u044B \u0438\u0437 \u0441\u043E\u0441\u0442\u0430\u0432\u043D\u043E\u0439 \u0440\u043E\u043B\u0438.
+group.available-roles.tooltip=\u041D\u0430\u0437\u043D\u0430\u0447\u0430\u0435\u043C\u044B\u0435 \u0440\u043E\u043B\u0438 \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430.
+group.assigned-roles-client.tooltip=\u0421\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0440\u043E\u043B\u0435\u0439 \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430.
+group.effective-roles-client.tooltip=\u0421\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0440\u043E\u043B\u0435\u0439 \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430. \u041D\u0435\u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0440\u043E\u043B\u0438 \u0437\u0434\u0435\u0441\u044C \u043C\u043E\u0433\u0443\u0442 \u0431\u044B\u0442\u044C \u0443\u043D\u0430\u0441\u043B\u0435\u0434\u043E\u0432\u0430\u043D\u044B \u0438\u0437 \u0441\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u043D\u044B\u0445 \u0441\u043E\u0441\u0442\u0430\u0432\u043D\u044B\u0445 \u0440\u043E\u043B\u0435\u0439.
+
+default-roles=\u0420\u043E\u043B\u0438 \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E
+no-realm-roles-available=\u0420\u043E\u043B\u0438 realm \u043D\u0435 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B
+
+users=\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0438
+user.add-selected.tooltip=\u0420\u043E\u043B\u0438 Realm, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043C\u043E\u0433\u0443\u0442 \u0431\u044B\u0442\u044C \u043D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u044B \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E.
+user.assigned-roles.tooltip=\u0420\u043E\u043B\u0438 Realm, \u0441\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u043D\u044B\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E
+user.effective-roles.tooltip=\u0412\u0441\u0435 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u044F \u0440\u043E\u043B\u0435\u0439 realm. \u041D\u0435\u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0440\u043E\u043B\u0438 \u0437\u0434\u0435\u0441\u044C \u043C\u043E\u0433\u0443\u0442 \u0431\u044B\u0442\u044C \u0443\u043D\u0430\u0441\u043B\u0435\u0434\u043E\u0432\u0430\u043D\u044B \u0438\u0437 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0445 \u0441\u043E\u0441\u0442\u0430\u0432\u043D\u044B\u0445 \u0440\u043E\u043B\u0435\u0439.
+user.available-roles.tooltip=\u041D\u0430\u0437\u043D\u0430\u0447\u0430\u0435\u043C\u044B\u0435 \u0440\u043E\u043B\u0438 \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430.
+user.assigned-roles-client.tooltip=\u0421\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435 \u0440\u043E\u043B\u0435\u0439 \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430.
+user.effective-roles-client.tooltip=\u0421\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435 \u0440\u043E\u043B\u0435\u0439 \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430. \u041D\u0435\u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0440\u043E\u043B\u0438 \u0437\u0434\u0435\u0441\u044C \u043C\u043E\u0433\u0443\u0442 \u0431\u044B\u0442\u044C \u0443\u043D\u0430\u0441\u043B\u0435\u0434\u043E\u0432\u0430\u043D\u044B \u0438\u0437 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0445 \u0441\u043E\u0441\u0442\u0430\u0432\u043D\u044B\u0445 \u0440\u043E\u043B\u0435\u0439.
+default.available-roles.tooltip=\u0420\u043E\u043B\u0438 \u0443\u0440\u043E\u0432\u043D\u044F Realm, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043C\u043E\u0433\u0443\u0442 \u0431\u044B\u0442\u044C \u043D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u044B.
+realm-default-roles=\u0420\u043E\u043B\u0438 Realm \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E
+realm-default-roles.tooltip=\u0420\u043E\u043B\u0438 \u0443\u0440\u043E\u0432\u043D\u044F Realm, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043C\u043E\u0433\u0443\u0442 \u0431\u044B\u0442\u044C \u043D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u044B \u043D\u043E\u0432\u044B\u043C \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F\u043C.
+default.available-roles-client.tooltip=\u0420\u043E\u043B\u0438 \u0438\u0437 \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043C\u043E\u0433\u0443\u0442 \u0431\u044B\u0442\u044C \u043D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u044B \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E.
+client-default-roles=\u0420\u043E\u043B\u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u0430 \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E
+client-default-roles.tooltip=\u0420\u043E\u043B\u0438 \u0438\u0437 \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430, \u043D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u043D\u044B\u0435 \u043A\u0430\u043A \u0440\u043E\u043B\u0438 \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E.
+composite.available-roles.tooltip=\u0420\u043E\u043B\u0438 \u0443\u0440\u043E\u0432\u043D\u044F Realm \u0441\u0432\u044F\u0437\u0430\u043D\u043D\u044B\u0435 \u0441 \u044D\u0442\u043E\u0439 \u0441\u043E\u0441\u0442\u0430\u0432\u043D\u043E\u0439 \u0440\u043E\u043B\u044C\u044E.
+composite.associated-roles.tooltip=\u0420\u043E\u043B\u0438 \u0443\u0440\u043E\u0432\u043D\u044F Realm, \u0441\u0432\u044F\u0437\u0430\u043D\u043D\u044B\u0435 \u0441 \u044D\u0442\u043E\u0439 \u0441\u043E\u0441\u0442\u0430\u0432\u043D\u043E\u0439 \u0440\u043E\u043B\u044C\u044E.
+composite.available-roles-client.tooltip=\u0420\u043E\u043B\u0438 \u0438\u0437 \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043C\u043E\u0433\u0443\u0442 \u0431\u044B\u0442\u044C \u043D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u044B \u0441 \u044D\u0442\u043E\u0439 \u0441\u043E\u0441\u0442\u0430\u0432\u043D\u043E\u0439 \u0440\u043E\u043B\u044C\u044E.
+composite.associated-roles-client.tooltip=\u0420\u043E\u043B\u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u0430, \u0441\u0432\u044F\u0437\u0430\u043D\u043D\u044B\u0435 \u0441 \u044D\u0442\u043E\u0439 \u0441\u043E\u0441\u0442\u0430\u0432\u043D\u043E\u0439 \u0440\u043E\u043B\u044C\u044E.
+partial-import=\u0427\u0430\u0441\u0442\u0438\u0447\u043D\u044B\u0439 \u0438\u043C\u043F\u043E\u0440\u0442
+partial-import.tooltip=\u0427\u0430\u0441\u0442\u0438\u0447\u043D\u044B\u0439 \u0438\u043C\u043F\u043E\u0440\u0442 \u043F\u043E\u0437\u0432\u043E\u043B\u044F\u0435\u0442 \u0438\u043C\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439, \u043A\u043B\u0438\u0435\u043D\u0442\u043E\u0432, \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044B \u0438\u0437 \u0440\u0430\u043D\u0435\u0435 \u044D\u043A\u0441\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u043E\u0433\u043E json-\u0444\u0430\u0439\u043B\u0430.
+
+file=File
+exported-json-file=\u042D\u043A\u0441\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439 json \u0444\u0430\u0439\u043B
+import-from-realm=\u0418\u043C\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0438\u0437 realm
+import-users=\u0418\u043C\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439
+import-groups=\u0418\u043C\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0433\u0440\u0443\u043F\u043F\u044B
+import-clients=\u0418\u043C\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043A\u043B\u0438\u0435\u043D\u0442\u043E\u0432
+import-identity-providers=\u0418\u043C\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u043E\u0432 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438
+import-realm-roles=\u0418\u043C\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0440\u043E\u043B\u0438 realm
+import-client-roles=\u0418\u043C\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0440\u043E\u043B\u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u043E\u0432
+if-resource-exists=\u0415\u0441\u043B\u0438 \u0440\u0435\u0441\u0443\u0440\u0441 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442
+fail=\u041D\u0435\u0443\u0434\u0430\u0447\u0430
+skip=\u041F\u0440\u043E\u043F\u0443\u0441\u0442\u0438\u0442\u044C
+overwrite=\u041F\u0435\u0440\u0435\u0437\u0430\u043F\u0438\u0441\u0430\u0442\u044C
+if-resource-exists.tooltip=\u0423\u043A\u0430\u0437\u0430\u0442\u044C, \u0447\u0442\u043E \u0441\u043B\u0435\u0434\u0443\u0435\u0442 \u0434\u0435\u043B\u0430\u0442\u044C, \u0435\u0441\u043B\u0438 \u0432\u044B \u043F\u044B\u0442\u0430\u0435\u0442\u0435\u0441\u044C \u0438\u043C\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0440\u0435\u0441\u0443\u0440\u0441, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442.
+
+action=\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0435
+role-selector=\u0421\u0435\u043B\u0435\u043A\u0442\u043E\u0440 \u0440\u043E\u043B\u0435\u0439
+realm-roles.tooltip=\u0420\u043E\u043B\u0438 Realm, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043C\u043E\u0433\u0443\u0442 \u0431\u044B\u0442\u044C \u0432\u044B\u0431\u0440\u0430\u043D\u044B.
+
+select-a-role=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0440\u043E\u043B\u044C
+select-realm-role=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0440\u043E\u043B\u044C realm
+client-roles.tooltip=\u0420\u043E\u043B\u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u0430, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043C\u043E\u0433\u0443\u0442 \u0431\u044B\u0442\u044C \u0432\u044B\u0431\u0440\u0430\u043D\u044B.
+select-client-role=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0440\u043E\u043B\u044C \u043A\u043B\u0438\u0435\u043D\u0442\u0430
+
+client-template=\u0428\u0430\u0431\u043B\u043E\u043D \u043A\u043B\u0438\u0435\u043D\u0442\u0430
+client-template.tooltip=\u0428\u0430\u0431\u043B\u043E\u043D \u043A\u043B\u0438\u0435\u043D\u0442\u0430, \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u044F\u044E\u0449\u0438\u0439 \u043D\u0430\u0441\u043B\u0435\u0434\u043E\u0432\u0430\u043D\u0438\u0435 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430 \u0438\u0437
+client-saml-endpoint=\u041A\u043E\u043D\u0435\u0447\u043D\u0430\u044F \u0442\u043E\u0447\u043A\u0430 \u0434\u043E\u0441\u0442\u0443\u043F\u0430 SAML \u043A\u043B\u0438\u0435\u043D\u0442\u0430
+add-client-template=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0448\u0430\u0431\u043B\u043E\u043D \u043A\u043B\u0438\u0435\u043D\u0442\u0430
+
+manage=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435
+authentication=\u0410\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044F
+user-federation=\u0424\u0435\u0434\u0435\u0440\u0430\u0446\u0438\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439
+events=\u0421\u043E\u0431\u044B\u0442\u0438\u044F
+realm-settings=\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 Realm
+configure=\u041A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F
+select-realm=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 realm
+add=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C
+
+client-template.name.tooltip=\u041D\u0430\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u0438\u0435 \u0448\u0430\u0431\u043B\u043E\u043D\u0430 \u043A\u043B\u0438\u0435\u043D\u0442\u0430. \u0414\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0443\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u043E \u0434\u043B\u044F realm
+client-template.description.tooltip=\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435 \u0448\u0430\u0431\u043B\u043E\u043D\u0430 \u043A\u043B\u0438\u0435\u043D\u0442\u0430
+client-template.protocol.tooltip=\u041A\u0430\u043A\u0430\u044F \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F \u043F\u0440\u043E\u0442\u043E\u043A\u043E\u043B\u0430 SSO \u0431\u0443\u0434\u0435\u0442 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0430\u043D\u0430 \u0448\u0430\u0431\u043B\u043E\u043D\u043E\u043C \u043A\u043B\u0438\u0435\u043D\u0442\u0430
+
+add-user-federation-provider=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0441\u043B\u0443\u0436\u0431\u0443 \u0444\u0435\u0434\u0435\u0440\u0430\u0446\u0438\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439
+required-settings=\u0422\u0440\u0435\u0431\u0443\u0435\u043C\u044B\u0435 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438
+provider-id=ID \u0441\u043B\u0443\u0436\u0431\u044B
+console-display-name=\u041D\u0430\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u0438\u0435 \u0432 \u043A\u043E\u043D\u0441\u043E\u043B\u0438
+console-display-name.tooltip=\u041E\u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0435\u043C\u043E\u0435 \u0438\u043C\u044F \u0441\u043B\u0443\u0436\u0431\u044B, \u0441\u0432\u044F\u0437\u0430\u043D\u043D\u043E\u0435 \u0441 \u043A\u043E\u043D\u0441\u043E\u043B\u044C\u044E \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430.
+priority=\u041F\u0440\u0438\u043E\u0440\u0438\u0442\u0435\u0442
+priority.tooltip=\u041F\u0440\u0438\u043E\u0440\u0438\u0442\u0435\u0442 \u0441\u043B\u0443\u0436\u0431\u044B \u043F\u0440\u0438 \u043F\u043E\u0438\u0441\u043A\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F. \u0412\u043F\u0435\u0440\u0435\u0434 \u0438\u0434\u0443\u0442 \u0431\u043E\u043B\u0435\u0435 \u043D\u0438\u0437\u043A\u0438\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F.
+sync-settings=\u0421\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438
+periodic-full-sync=\u041F\u0435\u0440\u0438\u043E\u0434\u0438\u0447\u0435\u0441\u043A\u0430\u044F \u043F\u043E\u043B\u043D\u0430\u044F \u0441\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0430\u0446\u0438\u044F
+periodic-full-sync.tooltip=\u0414\u043E\u043B\u0436\u043D\u0430 \u043B\u0438 \u043F\u0435\u0440\u0438\u043E\u0434\u0438\u0447\u0435\u0441\u043A\u0430\u044F \u043F\u043E\u043B\u043D\u0430\u044F \u0441\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0430\u0446\u0438\u044F \u0441 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u043E\u043C \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u0432 Keycloak \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u0430 \u0438\u043B\u0438 \u043D\u0435\u0442
+full-sync-period=\u041F\u0435\u0440\u0438\u043E\u0434 \u043F\u043E\u043B\u043D\u043E\u0439 \u0441\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0430\u0446\u0438\u0438
+full-sync-period.tooltip=\u041F\u0435\u0440\u0438\u043E\u0434 \u0434\u043B\u044F \u043F\u043E\u043B\u043D\u043E\u0439 \u0441\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0430\u0446\u0438\u0438 \u0432 \u0441\u0435\u043A\u0443\u043D\u0434\u0430\u0445
+periodic-changed-users-sync=\u041F\u0435\u0440\u0438\u043E\u0434\u0438\u0447\u0435\u0441\u043A\u0430\u044F \u0441\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0430\u0446\u0438\u044F \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0439 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439
+periodic-changed-users-sync.tooltip=\u0414\u043E\u043B\u0436\u043D\u0430 \u043B\u0438 \u043F\u0440\u043E\u0438\u0441\u0445\u043E\u0434\u0438\u0442\u044C \u043F\u0435\u0440\u0438\u043E\u0434\u0438\u0447\u0435\u0441\u043A\u0430\u044F \u0441\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0430\u0446\u0438\u044F \u043D\u043E\u0432\u044B\u0445 \u0438 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u043D\u044B\u0445 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u0441 Keycloak
+changed-users-sync-period=\u041F\u0435\u0440\u0438\u043E\u0434 \u0441\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u043D\u044B\u0445 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439
+changed-users-sync-period.tooltip=\u041F\u0435\u0440\u0438\u043E\u0434 \u0434\u043B\u044F \u0441\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u043D\u044B\u0445 \u0438 \u043D\u043E\u0432\u044B\u0445 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 \u0432 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0435 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u0432 \u0441\u0435\u043A\u0443\u043D\u0434\u0430\u0445
+synchronize-changed-users=\u0421\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0430\u0446\u0438\u044F \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u043D\u044B\u0445 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439
+synchronize-all-users=\u0421\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0430\u0446\u0438\u044F \u0432\u0441\u0435\u0445 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439
+kerberos-realm=Kerberos Realm
+kerberos-realm.tooltip=\u041D\u0430\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u0438\u0435 kerberos realm. \u041D\u0430\u043F\u0440\u0438\u043C\u0435\u0440 FOO.ORG
+server-principal=\u041E\u0441\u043D\u043E\u0432\u043D\u043E\u0439 \u0441\u0435\u0440\u0432\u0435\u0440
+server-principal.tooltip=\u041F\u043E\u043B\u043D\u043E\u0435 \u0438\u043C\u044F \u043E\u0441\u043D\u043E\u0432\u043D\u043E\u0433\u043E \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0434\u043B\u044F HTTP \u0441\u0435\u0440\u0432\u0438\u0441\u0430, \u0432\u043A\u043B\u044E\u0447\u0430\u044F \u0441\u0435\u0440\u0432\u0435\u0440\u043D\u043E\u0435 \u0438 \u0434\u043E\u043C\u0435\u043D\u043D\u043E\u0435 \u0438\u043C\u044F. \u041D\u0430\u043F\u0440\u0438\u043C\u0435\u0440 HTTP/host.foo.org@FOO.ORG
+keytab=KeyTab
+keytab.tooltip=\u041C\u0435\u0441\u0442\u043E\u043F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u0444\u0430\u0439\u043B\u0430 KeyTab \u0432 Kerberos, \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0449\u0435\u0433\u043E \u0443\u0447\u0435\u0442\u043D\u044B\u0435 \u0434\u0430\u043D\u043D\u044B\u0435 \u043E\u0441\u043D\u043E\u0432\u043D\u043E\u0433\u043E \u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u041D\u0430\u043F\u0440\u0438\u043C\u0435\u0440 /etc/krb5.keytab
+debug=\u041E\u0442\u043B\u0430\u0434\u0447\u0438\u043A
+debug.tooltip=\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C/\u0432\u044B\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u043E\u0442\u043B\u0430\u0434\u043E\u0447\u043D\u044B\u0435 \u043B\u043E\u0433\u0438 \u0432 \u0441\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u044B\u0439 \u0432\u044B\u0432\u043E\u0434 \u0434\u043B\u044F Krb5LoginModule.
+allow-password-authentication=\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044C \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044E \u043F\u043E \u043F\u0430\u0440\u043E\u043B\u044E
+allow-password-authentication.tooltip=\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C/\u0432\u044B\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E\u0441\u0442\u044C \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u043F\u043E \u0438\u043C\u0435\u043D\u0438/\u043F\u0430\u0440\u043E\u043B\u044F \u0432\u043E\u043F\u0440\u0435\u043A\u0438 \u0431\u0430\u0437\u0435 \u0434\u0430\u043D\u043D\u044B\u0445 Kerberos
+edit-mode=\u0420\u0435\u0436\u0438\u043C \u0440\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F
+edit-mode.tooltip=READ_ONLY \u043E\u0437\u043D\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043E \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\u0430\u0440\u043E\u043B\u044F \u043D\u0435 \u0434\u043E\u043F\u0443\u0441\u043A\u0430\u0435\u0442\u0441\u044F \u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u0432\u0441\u0435\u0433\u0434\u0430 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0435\u0442\u0441\u044F \u0441 \u043F\u0430\u0440\u043E\u043B\u0435\u043C Kerberos. UNSYNCED \u043E\u0437\u043D\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u043C\u043E\u0436\u0435\u0442 \u0438\u0437\u043C\u0435\u043D\u0438\u0442\u044C \u0441\u0432\u043E\u0439 \u043F\u0430\u0440\u043E\u043B\u044C \u0432  \u0431\u0430\u0437\u0435 \u0434\u0430\u043D\u043D\u044B\u0445 Keycloak \u0438 \u0442\u043E\u0433\u0434\u0430 \u043E\u043D \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D \u0432\u043C\u0435\u0441\u0442\u043E \u043F\u0430\u0440\u043E\u043B\u044F Kerberos
+ldap.edit-mode.tooltip=READ_ONLY \u043E\u0437\u043D\u0430\u0447\u0430\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F \u0442\u043E\u043B\u044C\u043A\u043E \u043D\u0430 \u0447\u0442\u0435\u043D\u0438\u0435 \u0438\u0437 LDAP. WRITABLE \u043E\u0437\u043D\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043E \u0434\u0430\u043D\u043D\u044B\u0435 \u0431\u0443\u0434\u0443\u0442 \u043E\u0431\u0440\u0430\u0442\u043D\u043E \u0441\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u044B \u0432 LDAP \u043F\u043E \u0437\u0430\u044F\u0432\u043A\u0435. UNSYNCED \u043E\u0437\u043D\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043E \u0434\u0430\u043D\u043D\u044B\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0431\u0443\u0434\u0443\u0442 \u0438\u043C\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u044B, \u043D\u043E \u043D\u0435 \u0441\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u044B \u043E\u0431\u0440\u0430\u0442\u043D\u043E \u0432 LDAP.
+update-profile-first-login=\u041E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u043F\u0440\u043E\u0444\u0438\u043B\u044C \u043F\u0440\u0438 \u043F\u0435\u0440\u0432\u043E\u043C \u0432\u0445\u043E\u0434\u0435
+update-profile-first-login.tooltip=\u041E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u043F\u0440\u043E\u0444\u0438\u043B\u044C \u043F\u0440\u0438 \u043F\u0435\u0440\u0432\u043E\u043C \u0432\u0445\u043E\u0434\u0435
+sync-registrations=\u0421\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438
+ldap.sync-registrations.tooltip=\u0414\u043E\u043B\u0436\u043D\u044B \u043B\u0438 \u0432\u043D\u043E\u0432\u044C \u0441\u043E\u0437\u0434\u0430\u043D\u043D\u044B\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0438 \u0431\u044B\u0442\u044C \u0441\u043E\u0437\u0434\u0430\u043D\u044B \u0432 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 LDAP? \u041F\u0440\u0438\u043E\u0440\u0438\u0442\u0435\u0442 \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u044F\u0435\u0442 \u043A\u0430\u043A\u043E\u0439 \u0438\u0437 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u043E\u0432 \u0431\u0443\u0434\u0435\u0442 \u0432\u044B\u0431\u0440\u0430\u043D \u0434\u043B\u044F \u0441\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0430\u0446\u0438\u0438 \u043D\u043E\u0432\u043E\u0433\u043E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F.
+vendor=\u041F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A
+ldap.vendor.tooltip=LDAP \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A (\u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440)
+username-ldap-attribute=\u0410\u0442\u0440\u0438\u0431\u0443\u0442 Username \u0432 LDAP
+ldap-attribute-name-for-username=\u041D\u0430\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u0438\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430 LDAP \u0434\u043B\u044F \u0438\u043C\u0435\u043D\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
+username-ldap-attribute.tooltip=\u041D\u0430\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u0438\u0435 LDAP \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430, \u043A\u043E\u0442\u043E\u0440\u043E\u0435 \u043E\u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044F \u043A\u0430\u043A \u0438\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0432 Keycloak. \u0414\u043B\u044F \u043C\u043D\u043E\u0436\u0435\u0441\u0442\u0432\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u043E\u0432 LDAP \u044D\u0442\u043E \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C 'uid'. \u0414\u043B\u044F Active directory \u044D\u0442\u043E \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C 'sAMAccountName' \u0438\u043B\u0438 'cn'. \u0410\u0442\u0440\u0438\u0431\u0443\u0442 \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0437\u0430\u043F\u043E\u043B\u043D\u0435\u043D \u0434\u043B\u044F \u0432\u0441\u0435\u0445 LDAP \u0437\u0430\u043F\u0438\u0441\u0435\u0439 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0432\u044B \u0445\u043E\u0442\u0438\u0442\u0435 \u0438\u043C\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0438\u0437 LDAP \u0432 Keycloak.
+rdn-ldap-attribute=\u0410\u0442\u0440\u0438\u0431\u0443\u0442 RDN \u0432 LDAP
+ldap-attribute-name-for-user-rdn=\u041D\u0430\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u0438\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430 LDAP \u0434\u043B\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 RDN
+rdn-ldap-attribute.tooltip=\u041D\u0430\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u0438\u0435 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043E\u0432 LDAP, \u043A\u043E\u0442\u043E\u0440\u043E\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0441\u044F \u043A\u0430\u043A RDN (\u0432\u0435\u0440\u0445\u043D\u0438\u0439 \u0430\u0442\u0440\u0438\u0431\u0443\u0442) \u043E\u0431\u044B\u0447\u043D\u043E\u0433\u043E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F DN. \u041E\u0431\u044B\u0447\u043D\u043E \u043E\u043D\u043E \u0442\u0430\u043A\u043E\u0435 \u0436\u0435, \u043A\u0430\u043A \u0430\u0442\u0440\u0438\u0431\u0443\u0442 \u0438\u043C\u0435\u043D\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F LDAP, \u043E\u0434\u043D\u0430\u043A\u043E \u043E\u043D \u043D\u0435 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u0435\u043D. \u0414\u043B\u044F \u043F\u0440\u0438\u043C\u0435\u0440\u0430, \u0434\u043B\u044F Active directory \u043E\u0431\u044B\u0447\u043D\u043E \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0441\u044F 'cn' \u043A\u0430\u043A \u0430\u0442\u0440\u0438\u0431\u0443\u0442 RDN, \u0432 \u0442\u043E \u0432\u0440\u0435\u043C\u044F \u043A\u0430\u043A \u0430\u0442\u0440\u0438\u0431\u0443\u0442 \u0438\u043C\u0435\u043D\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C 'sAMAccountName'.
+uuid-ldap-attribute=\u0410\u0442\u0440\u0438\u0431\u0443\u0442 UUID \u0432 LDAP
+ldap-attribute-name-for-uuid=\u041D\u0430\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u0438\u0435 LDAP \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430 \u0434\u043B\u044F UUID
+uuid-ldap-attribute.tooltip=\u041D\u0430\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u0438\u0435 LDAP \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430,\u043A\u043E\u0442\u043E\u0440\u043E\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0441\u044F \u043A\u0430\u043A \u0443\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u043E\u0431\u044A\u0435\u043A\u0442\u043E\u0432 (UUID) \u0432 LDAP. \u0414\u043B\u044F \u043C\u043D\u043E\u0436\u0435\u0441\u0442\u0432\u0430 LDAP \u0441\u0435\u0440\u0432\u0435\u0440\u043E\u0432 \u044D\u0442\u043E 'entryUUID' \u043E\u0434\u043D\u0430\u043A\u043E \u043D\u0435\u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043C\u043E\u0433\u0443\u0442 \u043E\u0442\u043B\u0438\u0447\u0430\u0442\u044C\u0441\u044F. \u0414\u043B\u044F \u043F\u0440\u0438\u043C\u0435\u0440\u0430, \u0434\u043B\u044F Active directory \u043E\u043D \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C 'objectGUID'. \u0415\u0441\u043B\u0438 \u0432\u0430\u0448 LDAP \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u043E \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043F\u043E\u043D\u044F\u0442\u0438\u0435 UUID, \u0432\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C \u043B\u044E\u0431\u043E\u0439 \u0434\u0440\u0443\u0433\u043E\u0439 \u0430\u0442\u0440\u0438\u0431\u0443\u0442, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0443\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u043C \u0441\u0440\u0435\u0434\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 \u0432 \u0434\u0435\u0440\u0435\u0432\u0435 LDAP. \u041D\u0430\u043F\u0440\u0438\u043C\u0435\u0440 'uid' \u0438\u043B\u0438 'entryDN'.
+user-object-classes=\u041A\u043B\u0430\u0441\u0441\u044B \u043E\u0431\u044A\u0435\u043A\u0442\u043E\u0432 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
+ldap-user-object-classes.placeholder=\u041A\u043B\u0430\u0441\u0441\u044B \u043E\u0431\u044A\u0435\u043A\u0442\u043E\u0432 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F LDAP (\u0440\u0430\u0437\u0434\u0435\u043B\u0435\u043D\u043D\u044B\u0435 \u0437\u0430\u043F\u044F\u0442\u043E\u0439)
+
+ldap-connection-url=URL \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u044F \u0441 LDAP
+ldap-users-dn=\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0438 DN LDAP
+ldap-bind-dn=\u0421\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0435 DN LDAP
+ldap-bind-credentials=\u0421\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0434\u0430\u043D\u043D\u044B\u0445 LDAP
+ldap-filter=LDAP \u0444\u0438\u043B\u044C\u0442\u0440
+ldap.user-object-classes.tooltip=\u0412\u0441\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u0438\u0437 LDAP objectClass \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043E\u0432 \u0434\u043B\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 \u0432 LDAP, \u0440\u0430\u0437\u0434\u0435\u043B\u0435\u043D\u043D\u044B\u0435 \u0437\u0430\u043F\u044F\u0442\u043E\u0439. \u041D\u0430\u043F\u0440\u0438\u043C\u0435\u0440: 'inetOrgPerson, organizationalPerson' . \u0412\u043D\u043E\u0432\u044C \u0441\u043E\u0437\u0434\u0430\u043D\u043D\u044B\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0438 Keycloak \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u044B \u0432 LDAP \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u044D\u0442\u0438\u043C\u0438 \u043A\u043B\u0430\u0441\u0441\u0430\u043C\u0438 \u043E\u0431\u044A\u0435\u043A\u0442\u043E\u0432, \u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0435 \u0437\u0430\u043F\u0438\u0441\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 LDAP \u0431\u0443\u0434\u0443\u0442 \u043D\u0430\u0439\u0434\u0435\u043D\u044B \u0442\u043E\u043B\u044C\u043A\u043E \u0435\u0441\u043B\u0438 \u043E\u043D\u0438 \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442 \u0432\u0441\u0435 \u044D\u0442\u0438 \u043A\u043B\u0430\u0441\u0441\u044B \u043E\u0431\u044A\u0435\u043A\u0442\u043E\u0432.
+
+connection-url=URL \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u044F
+ldap.connection-url.tooltip=URL \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u044F \u0441 \u0432\u0430\u0448\u0438\u043C \u0441\u0435\u0440\u0432\u0435\u0440\u043E\u043C LDAP
+test-connection=\u0422\u0435\u0441\u0442 \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u044F
+users-dn=\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0438 DN
+ldap.users-dn.tooltip=\u041F\u043E\u043B\u043D\u044B\u0439 DN \u0438\u0437 \u0434\u0435\u0440\u0435\u0432\u0430 LDAP \u0433\u0434\u0435 \u043F\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044E\u0442 \u0432\u0430\u0448\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0438. \u042D\u0442\u043E\u0442 DN \u044F\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0440\u043E\u0434\u0438\u0442\u0435\u043B\u0435\u043C \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 LDAP. \u041E\u043D \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C, \u0434\u043B\u044F \u043F\u0440\u0438\u043C\u0435\u0440\u0430 'ou=users,dc=example,dc=com' \u043F\u0440\u0438 \u0443\u0441\u043B\u043E\u0432\u0438\u0438, \u0447\u0442\u043E \u0432\u0430\u0448 \u043E\u0431\u044B\u0447\u043D\u044B\u0439 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u0431\u0443\u0434\u0435\u0442 \u0438\u043C\u0435\u0442\u044C DN \u043F\u043E\u0445\u043E\u0436\u0438\u0439 \u043D\u0430'uid=john,ou=users,dc=example,dc=com'
+authentication-type=\u0422\u0438\u043F \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438
+ldap.authentication-type.tooltip=\u0422\u0438\u043F LDAP \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438. \u0421\u0435\u0439\u0447\u0430\u0441 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B \u0442\u043E\u043B\u044C\u043A\u043E \u043C\u0435\u0445\u0430\u043D\u0438\u0437\u043C\u044B 'none' (\u0430\u043D\u043E\u043D\u0438\u043C\u043D\u0430\u044F \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044F LDAP) \u0438\u043B\u0438 'simple' (\u0410\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044F \u043F\u043E \u0441\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u043D\u044B\u043C \u043B\u043E\u0433\u0438\u043D\u0443 \u0438 \u043F\u0430\u0440\u043E\u043B\u044E)
+bind-dn=\u0421\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0435 DN
+ldap.bind-dn.tooltip=DN \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430 LDAP, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u044B Keycloak \u0434\u043B\u044F \u0434\u043E\u0441\u0442\u0443\u043F\u0430 \u043D\u0430 \u0441\u0435\u0440\u0432\u0435\u0440 LDAP
+bind-credential=\u0421\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0434\u0430\u043D\u043D\u044B\u0445
+ldap.bind-credential.tooltip=\u041F\u0430\u0440\u043E\u043B\u044C \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430 LDAP
+test-authentication=\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438
+custom-user-ldap-filter=\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C\u0441\u043A\u0438\u0439 \u0424\u0438\u043B\u044C\u0442\u0440 LDAP \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439
+ldap.custom-user-ldap-filter.tooltip=\u0414\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0439 \u0444\u0438\u043B\u044C\u0442\u0440 LDAP \u0434\u043B\u044F \u0444\u0438\u043B\u044C\u0442\u0440\u0430\u0446\u0438\u0438 \u0438\u0441\u043A\u043E\u043C\u044B\u0445 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439. \u041E\u0441\u0442\u0430\u0432\u044C\u0442\u0435 \u043F\u043E\u043B\u0435 \u043F\u0443\u0441\u0442\u044B\u043C, \u0435\u0441\u043B\u0438 \u043D\u0435 \u043D\u0443\u0436\u0434\u0430\u0435\u0442\u0435\u0441\u044C \u0432 \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u043C \u0444\u0438\u043B\u044C\u0442\u0440\u0435. \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044C, \u0447\u0442\u043E \u043E\u043D \u043D\u0430\u0447\u0438\u043D\u0430\u0435\u0442\u0441\u044F \u0441 '(' \u0438 \u0437\u0430\u043A\u0430\u043D\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044F ')'
+search-scope=\u041F\u043E\u0438\u0441\u043A \u043E\u0431\u043B\u0430\u0441\u0442\u0438
+ldap.search-scope.tooltip=\u0414\u043B\u044F \u043E\u0434\u043D\u043E\u0433\u043E \u0443\u0440\u043E\u0432\u043D\u044F \u043C\u044B \u0438\u0449\u0435\u043C \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 \u0442\u043E\u043B\u044C\u043A\u043E \u0432 DN, \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u043D\u044B\u0445 \u043A\u0430\u043A \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C\u0441\u043A\u0438\u0435 DN. \u0414\u043B\u044F \u043F\u043E\u0434\u0434\u0435\u0440\u0435\u0432\u044C\u0435\u0432 \u043C\u044B \u0438\u0449\u0435\u043C \u043F\u043E\u043B\u043D\u043E\u0441\u0442\u044C\u044E \u0432 \u0438\u0445 \u043F\u043E\u0434\u0434\u0435\u0440\u0435\u0432\u044C\u044F\u0445. \u0421\u043C\u043E\u0442\u0440\u0438\u0442\u0435 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\u0446\u0438\u044E LDAP \u0434\u043B\u044F \u043F\u043E\u0434\u0440\u043E\u0431\u043D\u044B\u0445 \u0434\u0435\u0442\u0430\u043B\u0435\u0439
+use-truststore-spi=\u0418\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u0435 \u0434\u043E\u0432\u0435\u0440\u0435\u043D\u043D\u044B\u0445 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0432 SPI
+ldap.use-truststore-spi.tooltip=\u041E\u043F\u0440\u0435\u0434\u0435\u043B\u044F\u0435\u0442, \u0431\u0443\u0434\u0435\u0442 \u043B\u0438 \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u0441 LDAP \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 \u0434\u043E\u0432\u0435\u0440\u0435\u043D\u043D\u044B\u0445 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0432 SPI \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u0430\u043C\u0438, \u0441\u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u043C\u0438 \u0432 keycloak-server.json. '\u0412\u0441\u0435\u0433\u0434\u0430' \u043E\u0437\u043D\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043E \u043E\u043D\u0438 \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C\u0441\u044F \u0432\u0441\u0435\u0433\u0434\u0430. '\u041D\u0438\u043A\u043E\u0433\u0434\u0430' \u043E\u0437\u043D\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043E \u043E\u043D\u0438 \u043D\u0438\u043A\u043E\u0433\u0434\u0430 \u043D\u0435 \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u044B. '\u0422\u043E\u043B\u044C\u043A\u043E \u0434\u043B\u044F ldap`\u043E\u0432' \u043E\u0437\u043D\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043E \u043E\u043D\u0438 \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u044B \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u0432\u0430\u0448\u0438\u043C\u0438 \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u044F\u043C\u0438 \u043A ldap \u0441\u0435\u0440\u0432\u0435\u0440\u0430\u043C. \u041E\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043D\u0438\u043C\u0430\u043D\u0438\u0435, \u0447\u0442\u043E \u0435\u0441\u043B\u0438 keycloak-server.json \u043D\u0435 \u0441\u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043E\u0432\u0430\u043D, \u0442\u043E \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E Java \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C cacerts \u0438\u043B\u0438 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442, \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u043D\u044B\u0439 \u0432 'javax.net.ssl.trustStore'.
+connection-pooling=\u041F\u0443\u043B \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0439
+ldap.connection-pooling.tooltip=\u0414\u043E\u043B\u0436\u0435\u043D \u043B\u0438 Keycloak \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C \u043F\u0443\u043B \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0439 \u0434\u043B\u044F \u0434\u043E\u0441\u0442\u0443\u043F\u0430 \u043A LDAP \u0441\u0435\u0440\u0432\u0435\u0440\u0443
+ldap.pagination.tooltip=\u0414\u043E\u043B\u0436\u0435\u043D \u043B\u0438 LDAP \u0441\u0435\u0440\u0432\u0435\u0440 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044C \u043F\u043E\u0441\u0442\u0440\u0430\u043D\u0438\u0447\u043D\u044B\u0439 \u0432\u044B\u0432\u043E\u0434.
+kerberos-integration=\u0418\u043D\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044F \u0441 Kerberos
+allow-kerberos-authentication=\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044C \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044E Kerberos
+ldap.allow-kerberos-authentication.tooltip=\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C/\u0432\u044B\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044E HTTP \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 \u0441 \u0442\u043E\u043A\u0435\u043D\u0430\u043C\u0438 SPNEGO/Kerberos. \u0414\u0430\u043D\u043D\u044B\u0435 \u043E\u0431 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043E\u0432\u0430\u043D\u044B\u0445 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F\u0445 \u0431\u0443\u0434\u0443\u0442 \u043F\u0440\u0435\u0434\u0443\u0441\u043C\u043E\u0442\u0440\u0435\u043D\u044B \u0438\u0437 \u044D\u0442\u043E\u0433\u043E LDAP \u0441\u0435\u0440\u0432\u0435\u0440\u0430
+use-kerberos-for-password-authentication=\u0418\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C Kerberos \u0434\u043B\u044F \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u043F\u043E \u043F\u0430\u0440\u043E\u043B\u044E
+ldap.use-kerberos-for-password-authentication.tooltip=\u0418\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C \u043C\u043E\u0434\u0443\u043B\u044C \u0432\u0445\u043E\u0434\u0430 Kerberos \u0434\u043B\u044F \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u043F\u043E \u043B\u043E\u0433\u0438\u043D/\u043F\u0430\u0440\u043E\u043B\u044C \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 Kerberos \u0432\u043C\u0435\u0441\u0442\u043E \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u043D\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 LDAP \u0441 Directory Service API
+batch-size=\u0420\u0430\u0437\u043C\u0435\u0440 \u043F\u0430\u0447\u043A\u0438
+ldap.batch-size.tooltip=\u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 LDAP, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0431\u0443\u0434\u0443\u0442 \u0438\u043C\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u044B \u0432 Keycloak \u0437\u0430 \u043E\u0434\u043D\u0443 \u0442\u0440\u0430\u043D\u0437\u0430\u043A\u0446\u0438\u044E.
+ldap.periodic-full-sync.tooltip=\u0414\u043E\u043B\u0436\u043D\u0430 \u043B\u0438 \u0431\u044B\u0442\u044C \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u0430 \u043F\u043E\u043B\u043D\u0430\u044F \u043F\u0435\u0440\u0438\u043E\u0434\u0438\u0447\u0435\u0441\u043A\u0430\u044F \u0441\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0430\u0446\u0438\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 LDAP \u0432 Keycloak \u0438\u043B\u0438 \u043D\u0435\u0442
+ldap.periodic-changed-users-sync.tooltip=\u0414\u043E\u043B\u0436\u043D\u0430 \u043B\u0438 \u0431\u044B\u0442\u044C \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u0430 \u043F\u0435\u0440\u0438\u043E\u0434\u0438\u0447\u0435\u0441\u043A\u0430\u044F \u0441\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0430\u0446\u0438\u044F \u043D\u043E\u0432\u044B\u0445 \u0438 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u043D\u044B\u0445 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 LDAP \u0432 Keycloak \u0438\u043B\u0438 \u043D\u0435\u0442
+ldap.changed-users-sync-period.tooltip=\u041F\u0435\u0440\u0438\u043E\u0434 \u0434\u043B\u044F \u0441\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0430\u0446\u0438\u0438 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u043D\u044B\u0445 \u0438\u043B\u0438 \u0432\u043D\u043E\u0432\u044C \u0441\u043E\u0437\u0434\u0430\u043D\u043D\u044B\u0445 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 LDAP \u0432 \u0441\u0435\u043A\u0443\u043D\u0434\u0430\u0445
+user-federation-mappers=\u0421\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u044F \u0444\u0435\u0434\u0435\u0440\u0430\u0446\u0438\u0439 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439
+create-user-federation-mapper=\u0421\u043E\u0437\u0434\u0430\u0442\u044C \u043E\u0442\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435 \u0444\u0435\u0434\u0435\u0440\u0430\u0446\u0438\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439
+add-user-federation-mapper=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043E\u0442\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435 \u0444\u0435\u0434\u0435\u0440\u0430\u0446\u0438\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439
+provider-name=\u041D\u0430\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u0438\u0435 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430
+no-user-federation-providers-configured=\u041D\u0435 \u0441\u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043E\u0432\u0430\u043D \u0444\u0435\u0434\u0435\u0440\u0430\u0442\u0438\u0432\u043D\u044B\u0439 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438
+add-identity-provider=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438
+add-identity-provider-link=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0441\u0441\u044B\u043B\u043A\u0443 \u043D\u0430 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438
+identity-provider=\u041F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438
+identity-provider-user-id=ID \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438
+identity-provider-user-id.tooltip=\u0423\u043D\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439 ID \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u043D\u0430 \u0441\u0442\u043E\u0440\u043E\u043D\u0435 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438
+identity-provider-username=\u0418\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438
+identity-provider-username.tooltip=\u0418\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u043D\u0430 \u0441\u0442\u043E\u0440\u043E\u043D\u0435 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438
+pagination=\u041F\u043E\u0441\u0442\u0440\u0430\u043D\u0438\u0447\u043D\u044B\u0439 \u0432\u044B\u0432\u043E\u0434
+
+browser-flow=\u0421\u0446\u0435\u043D\u0430\u0440\u0438\u0439 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430
+browser-flow.tooltip=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0432\u044B \u0445\u043E\u0442\u0438\u0442\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C \u0434\u043B\u044F \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u0447\u0435\u0440\u0435\u0437 \u0431\u0440\u0430\u0443\u0437\u0435\u0440.
+registration-flow=\u0421\u0446\u0435\u043D\u0430\u0440\u0438\u0439 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438
+registration-flow.tooltip=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0432\u044B \u0445\u043E\u0442\u0438\u0442\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C \u0434\u043B\u044F \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F.
+direct-grant-flow=\u0421\u0446\u0435\u043D\u0430\u0440\u0438\u0439 Direct Grant Flow
+direct-grant-flow.tooltip=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0432\u044B \u0445\u043E\u0442\u0438\u0442\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C\u0441\u044F \u0434\u043B\u044F \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 direct grant.
+reset-credentials=\u0421\u0431\u0440\u043E\u0441\u0438\u0442\u044C \u0443\u0447\u0435\u0442\u043D\u044B\u0435 \u0434\u0430\u043D\u043D\u044B\u0435
+reset-credentials.tooltip=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0432\u044B \u0445\u043E\u0442\u0438\u0442\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C \u043A\u043E\u0433\u0434\u0430 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u0437\u0430\u0431\u044B\u043B \u0441\u0432\u043E\u0438 \u0443\u0447\u0435\u0442\u043D\u044B\u0435 \u0434\u0430\u043D\u043D\u044B\u0435.
+client-authentication=\u0410\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044F \u043A\u043B\u0438\u0435\u043D\u0442\u0430
+client-authentication.tooltip=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0432\u044B \u0445\u043E\u0442\u0438\u0442\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C \u0434\u043B\u044F \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u043E\u0432.
+new=\u0421\u043E\u0437\u0434\u0430\u0442\u044C
+copy=\u041A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C
+add-execution=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0438\u0441\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0435
+add-flow=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439
+auth-type=\u0422\u0438\u043F \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438
+requirement=\u0422\u0440\u0435\u0431\u043E\u0432\u0430\u043D\u0438\u044F
+config=\u041A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F
+no-executions-available=\u041D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0445 \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0439
+authentication-flows=\u0421\u0446\u0435\u043D\u0430\u0440\u0438\u0438 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438
+create-authenticator-config=\u0421\u043E\u0437\u0434\u0430\u0442\u044C \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044E \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u0430
+authenticator.alias.tooltip=\u041D\u0430\u0438\u043C\u0435\u043D\u043E\u0432\u0430\u043D\u0438\u0435 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438
+otp-type=\u0422\u0438\u043F \u043E\u0434\u043D\u043E\u0440\u0430\u0437\u043E\u0432\u043E\u0433\u043E \u043F\u0430\u0440\u043E\u043B\u044F OTP
+time-based=\u041E\u0441\u043D\u043E\u0432\u0430\u043D \u043D\u0430 \u0432\u0440\u0435\u043C\u0435\u043D\u0438
+counter-based=\u041E\u0441\u043D\u043E\u0432\u0430\u043D \u043D\u0430 \u0441\u0447\u0435\u0442\u0447\u0438\u043A\u0435
+otp-type.tooltip=totp \u044F\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0412\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u043C \u043E\u0434\u043D\u043E\u0440\u0430\u0437\u043E\u0432\u044B\u043C \u043F\u0430\u0440\u043E\u043B\u0435\u043C. 'hotp' \u043E\u0441\u043D\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u043D\u0430 \u0441\u0447\u0435\u0442\u0447\u0438\u043A\u0435 \u043E\u0434\u043D\u043E\u0440\u0430\u0437\u043E\u0432\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C \u0432 \u043A\u043E\u0442\u043E\u0440\u043E\u043C \u0441\u0435\u0440\u0432\u0435\u0440 \u0445\u0440\u0430\u043D\u0438\u0442 \u0441\u0447\u0435\u0442\u0447\u0438\u043A \u0445\u0435\u0448\u0430.
+otp-hash-algorithm=\u0410\u043B\u0433\u043E\u0440\u0438\u0442\u043C \u0445\u0435\u0448\u0430 OTP
+otp-hash-algorithm.tooltip=\u041A\u0430\u043A\u043E\u0439 \u0430\u043B\u0433\u043E\u0440\u0438\u0442\u043C \u0445\u0435\u0448\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D \u0434\u043B\u044F \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 OTP.
+number-of-digits=\u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u0446\u0438\u0444\u0440
+otp.number-of-digits.tooltip=\u0421\u043A\u043E\u043B\u044C\u043A\u043E \u0446\u0438\u0444\u0440 \u0434\u043E\u043B\u0436\u0435\u043D \u0438\u043C\u0435\u0442\u044C OTP?
+look-ahead-window=\u041E\u043A\u043D\u043E \u0432\u043F\u0435\u0440\u0435\u0434
+otp.look-ahead-window.tooltip=\u041A\u0430\u043A \u0434\u0430\u043B\u0435\u043A\u043E \u0432\u043F\u0435\u0440\u0435\u0434 \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u043E\u043B\u0436\u0435\u043D \u0432\u044B\u0433\u043B\u044F\u0434\u0435\u0442\u044C \u0432 \u0441\u043B\u0443\u0447\u0430\u0435 \u0435\u0441\u043B\u0438 \u0441\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0442\u043E\u043A\u0435\u043D \u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u043D\u0435 \u0441\u0438\u043D\u0445\u0440\u043E\u043D\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u044B \u0441 \u0432\u0440\u0435\u043C\u0435\u043D\u0435\u043C \u0438\u043B\u0438 \u0441\u0447\u0435\u0442\u0447\u0438\u043A\u043E\u043C
+initial-counter=\u041D\u0430\u0447\u0430\u043B\u044C\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0441\u0447\u0435\u0442\u0447\u0438\u043A\u0430
+otp.initial-counter.tooltip=\u041A\u0430\u043A\u0438\u043C \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u043D\u0430\u0447\u0430\u043B\u044C\u043D\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0441\u0447\u0435\u0442\u0447\u0438\u043A\u0430?
+otp-token-period=\u041F\u0435\u0440\u0438\u043E\u0434 \u0442\u043E\u043A\u0435\u043D\u0430 OTP
+otp-token-period.tooltip=\u0421\u043A\u043E\u043B\u044C\u043A\u043E \u0441\u0435\u043A\u0443\u043D\u0434 \u0442\u043E\u043A\u0435\u043D OTP \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u0435\u043D? \u041F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E 30 \u0441\u0435\u043A\u0443\u043D\u0434.
+table-of-password-policies=\u0422\u0430\u0431\u043B\u0438\u0446\u0430 \u043F\u043E\u043B\u0438\u0442\u0438\u043A \u043F\u0430\u0440\u043E\u043B\u044F
+add-policy.placeholder=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043F\u043E\u043B\u0438\u0442\u0438\u043A\u0443...
+policy-type=\u0422\u0438\u043F \u043F\u043E\u043B\u0438\u0442\u0438\u043A\u0438
+policy-value=\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043F\u043E\u043B\u0438\u0442\u0438\u043A\u0438
+admin-events=\u0421\u043E\u0431\u044B\u0442\u0438\u044F \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430
+admin-events.tooltip=\u041E\u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0435\u0442 \u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u043D\u044B\u0435 \u0441\u043E\u0431\u044B\u0442\u0438\u044F \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430 \u0432 \u044D\u0442\u043E\u043C realm. \u0421\u043E\u0431\u044B\u0442\u0438\u044F, \u0441\u0432\u044F\u0437\u0430\u043D\u043D\u044B\u0435 \u0441 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u044C\u044E \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430, \u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440 \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u0435 realm. \u0427\u0442\u043E\u0431\u044B \u0432\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u0438\u0435 \u0441\u043E\u0431\u044B\u0442\u0438\u0439, \u043F\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u0432 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044E.
+login-events=\u0421\u043E\u0431\u044B\u0442\u0438\u044F \u0432\u0445\u043E\u0434\u0430
+filter=\u0424\u0438\u043B\u044C\u0442\u0440
+update=\u041E\u0431\u043D\u043E\u0432\u0438\u0442\u044C
+reset=\u0421\u0431\u0440\u043E\u0441\u0438\u0442\u044C
+operation-types=\u0422\u0438\u043F\u044B \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0439
+select-operations.placeholder=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438...
+resource-path=\u041F\u0443\u0442\u044C \u043A \u0440\u0435\u0441\u0443\u0440\u0441\u0443
+resource-path.tooltip=\u0424\u0438\u043B\u044C\u0442\u0440 \u043F\u043E \u043F\u0443\u0442\u0438 \u043A \u0440\u0435\u0441\u0443\u0440\u0441\u0443. \u041F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043F\u043E\u0434\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0443 '*' \u0434\u043B\u044F \u0441\u043E\u0432\u043F\u0430\u0434\u0435\u043D\u0438\u044F \u043E\u0434\u043D\u043E\u0439 \u0447\u0430\u0441\u0442\u0438 \u043F\u0443\u0442\u0438 \u0438 '**' \u0441\u043E\u0432\u043F\u0430\u0434\u0435\u043D\u0438\u0435 \u043D\u0435\u0441\u043A\u043E\u043B\u044C\u043A\u0438\u0445 \u0447\u0430\u0441\u0442\u0435\u0439. \u041D\u0430\u043F\u0440\u0438\u043C\u0435\u0440 'realms/*/clients/asbc' \u0432\u044B\u0431\u0435\u0440\u0435\u0442 \u043A\u043B\u0438\u0435\u043D\u0442\u0430 \u0441 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u043E\u043C asbc \u0432 \u043B\u044E\u0431\u043E\u043C realm, \u0432 \u0442\u043E \u0432\u0440\u0435\u043C\u044F \u043A\u0430\u043A 'realms/master/**' \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u0442 \u043D\u0438\u0447\u0435\u0433\u043E \u0432 master realm.
+date-(from)=\u0414\u0430\u0442\u0430 (\u0421)
+date-(to)=\u0414\u0430\u0442\u0430 (\u041F\u043E)
+authentication-details=\u0414\u0435\u0442\u0430\u043B\u0438 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438
+ip-address=IP \u0430\u0434\u0440\u0435\u0441
+time=\u0412\u0440\u0435\u043C\u044F
+operation-type=\u0422\u0438\u043F \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438
+auth=\u0410\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044F
+representation=\u041F\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0435
+register=\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044F
+required-action=\u0422\u0440\u0435\u0431\u0443\u0435\u043C\u043E\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435
+default-action=\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E
+auth.default-action.tooltip=\u0415\u0441\u043B\u0438 \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u043E, \u0442\u043E \u043B\u044E\u0431\u043E\u043C\u0443 \u043D\u043E\u0432\u043E\u043C\u0443 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E \u0431\u0443\u0434\u0435\u0442 \u0431\u0443\u0434\u0435\u0442 \u043D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u043E \u0442\u0440\u0435\u0431\u0443\u0435\u043C\u043E\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435.
+no-required-actions-configured=\u0422\u0440\u0435\u0431\u0443\u0435\u043C\u044B\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u043D\u0435 \u0441\u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u044B
+defaults-to-id=\u041F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E id
+flows=\u0421\u0446\u0435\u043D\u0430\u0440\u0438\u0438
+bindings=\u0421\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u044F
+required-actions=\u0422\u0440\u0435\u0431\u0443\u0435\u043C\u044B\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044F
+password-policy=\u041F\u043E\u043B\u0438\u0442\u0438\u043A\u0438 \u043F\u0430\u0440\u043E\u043B\u044F
+otp-policy=\u041F\u043E\u043B\u0438\u0442\u0438\u043A\u0438 OTP
+user-groups=\u0413\u0440\u0443\u043F\u043F\u044B \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439
+default-groups=\u0413\u0440\u0443\u043F\u043F\u044B \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E
+groups.default-groups.tooltip=\u0423\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u0435\u0442 \u0433\u0440\u0443\u043F\u043F\u044B, \u0432 \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043D\u043E\u0432\u044B\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0438 \u0431\u0443\u0434\u0443\u0442 \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u044B \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438.
+cut=\u0412\u044B\u0440\u0435\u0437\u0430\u0442\u044C
+paste=\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C
+
+create-group=\u0421\u043E\u0437\u0434\u0430\u0442\u044C \u0433\u0440\u0443\u043F\u043F\u0443
+create-authenticator-execution=\u0421\u043E\u0437\u0434\u0430\u0442\u044C \u0438\u0441\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0435 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u0430
+create-form-action-execution=\u0421\u043E\u0437\u0434\u0430\u0442\u044C \u0444\u043E\u0440\u043C\u0443 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u0438\u0441\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u044F
+create-top-level-form=\u0421\u043E\u0437\u0434\u0430\u0442\u044C \u0432\u0435\u0440\u0445\u043D\u0435\u0443\u0440\u043E\u0432\u043D\u0435\u0432\u0443\u044E \u0444\u043E\u0440\u043C\u0443
+flow.alias.tooltip=\u0417\u0430\u0434\u0430\u0435\u0442 \u043E\u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0435\u043C\u043E\u0435 \u0438\u043C\u044F \u0434\u043B\u044F \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u044F.
+top-level-flow-type=Top Level Flow Type
+flow.generic=\u043E\u0431\u0449\u0438\u0439
+flow.client=\u043A\u043B\u0438\u0435\u043D\u0442
+top-level-flow-type.tooltip=\u041A\u0430\u043A\u043E\u0439 \u044D\u0442\u043E \u0442\u0438\u043F \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u044F \u0432\u0435\u0440\u0445\u043D\u0435\u0433\u043E \u0443\u0440\u043E\u0432\u043D\u044F? \u0422\u0438\u043F "\u043A\u043B\u0438\u0435\u043D\u0442" \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0441\u044F \u0434\u043B\u044F \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u043A\u043B\u0438\u0435\u043D\u0442\u043E\u0432 (\u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0439), \u043A\u043E\u0433\u0434\u0430 "\u043E\u0431\u0449\u0438\u0439" \u0434\u043B\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 \u0438 \u0432\u0441\u0435\u0433\u043E \u043E\u0441\u0442\u0430\u043B\u044C\u043D\u043E\u0433\u043E
+create-execution-flow=\u0421\u043E\u0437\u0434\u0430\u0442\u044C \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u0439 \u0438\u0441\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u044F
+flow-type=\u0422\u0438\u043F \u0441\u0446\u0435\u043D\u0430\u0440\u0438\u044F
+flow.form.type=\u0444\u043E\u0440\u043C\u0430
+flow-type.tooltip=\u041A\u0430\u043A\u043E\u0433\u043E \u0442\u0438\u043F\u0430 \u044D\u0442\u0430 \u0444\u043E\u0440\u043C\u0430
+form-provider=\u041F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A \u0444\u043E\u0440\u043C\u044B
+default-groups.tooltip=\u0412\u043D\u043E\u0432\u044C \u0441\u043E\u0437\u0434\u0430\u043D\u043D\u044B\u0435 \u0438\u043B\u0438 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0438 \u0431\u0443\u0434\u0443\u0442 \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438 \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u044B \u043A \u044D\u0442\u0438\u043C \u0433\u0440\u0443\u043F\u043F\u0430\u043C
+select-a-type.placeholder=\u0432\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0442\u0438\u043F
+available-groups=\u0414\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0435 \u0433\u0440\u0443\u043F\u043F\u044B
+available-groups.tooltip=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0433\u0440\u0443\u043F\u043F\u0443, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0432\u044B \u0445\u043E\u0442\u0438\u0442\u0435 \u0434\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E.
+value=\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435
+table-of-group-members=\u0422\u0430\u0431\u043B\u0438\u0446\u0430 \u0447\u043B\u0435\u043D\u043E\u0432 \u0433\u0440\u0443\u043F\u043F\u044B
+last-name=\u0424\u0430\u043C\u0438\u043B\u0438\u044F
+first-name=\u0418\u043C\u044F
+email=Email
+toggle-navigation=\u041F\u0435\u0440\u0435\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u043D\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u044E
+manage-account=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u044C\u044E
+sign-out=\u0412\u044B\u0445\u043E\u0434
+server-info=\u0418\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F \u043E \u0441\u0435\u0440\u0432\u0435\u0440\u0435
+resource-not-found=\u0420\u0435\u0441\u0443\u0440\u0441 <strong>\u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D</strong>...
+resource-not-found.instruction=\u041C\u044B \u043D\u0435 \u0441\u043C\u043E\u0433\u043B\u0438 \u043D\u0430\u0439\u0442\u0438 \u0440\u0435\u0441\u0443\u0440\u0441, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0432\u044B \u0438\u0449\u0435\u0442\u0435. \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0443\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044C, \u0447\u0442\u043E \u0432\u044B \u0432\u0432\u0435\u043B\u0438 \u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 URL.
+go-to-the-home-page=\u041F\u0435\u0440\u0435\u0439\u0442\u0438 \u043D\u0430 \u0434\u043E\u043C\u0430\u0448\u043D\u044E\u044E \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0443 &raquo;
+page-not-found=\u0421\u0442\u0440\u0430\u043D\u0438\u0446\u0430 <strong>\u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u0430</strong>...
+page-not-found.instruction=\u041C\u044B \u043D\u0435 \u0441\u043C\u043E\u0433\u043B\u0438 \u043D\u0430\u0439\u0442\u0438 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0443, \u043A\u043E\u0442\u043E\u0440\u0443\u044E \u0432\u044B \u0438\u0449\u0435\u0442\u0435. \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0443\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044C, \u0447\u0442\u043E URL-\u0430\u0434\u0440\u0435\u0441 \u0432\u0432\u0435\u0434\u0435\u043D \u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u043E.
+events.tooltip=\u041E\u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0435\u0442 \u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u043D\u044B\u0435 \u0441\u043E\u0431\u044B\u0442\u0438\u044F \u0434\u043B\u044F realm. \u0421\u043E\u0431\u044B\u0442\u0438\u044F, \u0441\u0432\u044F\u0437\u0430\u043D\u043D\u044B\u0435 \u0441 \u0443\u0447\u0435\u0442\u043D\u044B\u043C\u0438 \u0437\u0430\u043F\u0438\u0441\u044F\u043C\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439, \u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440, \u0432\u0445\u043E\u0434 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F. \u0414\u043B\u044F \u0442\u043E\u0433\u043E, \u0447\u0442\u043E\u0431\u044B \u0432\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u0438\u0435 \u0441\u043E\u0431\u044B\u0442\u0438\u0439, \u043F\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u0432 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044E.
+select-event-types.placeholder=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0442\u0438\u043F \u0441\u043E\u0431\u044B\u0442\u0438\u0439...
+events-config.tooltip=\u041E\u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0435\u0442 \u043E\u043F\u0446\u0438\u0438 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0434\u043B\u044F \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F \u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u0438\u044F \u0441\u043E\u0431\u044B\u0442\u0438\u0439 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 \u0438 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430.
+select-an-action.placeholder=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435...
+event-listeners.tooltip=\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0430 \u0441\u043B\u0443\u0448\u0430\u0442\u0435\u043B\u0435\u0439, \u043F\u043E\u043B\u0443\u0447\u0430\u044E\u0449\u0438\u0445 \u0441\u043E\u0431\u044B\u0442\u0438\u044F \u0434\u043B\u044F realm.
+login.save-events.tooltip=\u0415\u0441\u043B\u0438 \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u043E, \u0442\u043E \u0441\u043E\u0431\u044B\u0442\u0438\u044F \u0431\u0443\u0434\u0443\u0442 \u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u044B \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043D\u043D\u044B\u0445, \u0447\u0442\u043E \u0441\u0434\u0435\u043B\u0430\u0435\u0442 \u0438\u0445 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u043C\u0438 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0443 \u0438 \u043A\u043E\u043D\u0441\u043E\u043B\u0438 \u0443\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u044F \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u044C\u044E.
+clear-events.tooltip=\u0423\u0434\u0430\u043B\u044F\u0435\u0442 \u0432\u0441\u0435 \u0441\u043E\u0431\u044B\u0442\u0438\u044F \u0438\u0437 \u0431\u0430\u0437\u044B \u0434\u0430\u043D\u043D\u044B\u0445.
+events.expiration.tooltip=\u0423\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0441\u0440\u043E\u043A \u0438\u0441\u0442\u0435\u0447\u0435\u043D\u0438\u044F \u0434\u043B\u044F \u0441\u043E\u0431\u044B\u0442\u0438\u0439. \u0418\u0441\u0442\u0435\u043A\u0448\u0438\u0435 \u0441\u043E\u0431\u044B\u0442\u0438\u044F \u043F\u0435\u0440\u0438\u043E\u0434\u0438\u0447\u0435\u0441\u043A\u0438 \u0443\u0434\u0430\u043B\u044F\u044E\u0442\u0441\u044F \u0438\u0437 \u0431\u0430\u0437\u044B \u0434\u0430\u043D\u043D\u044B\u0445.
+admin-events-settings=\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 \u0441\u043E\u0431\u044B\u0442\u0438\u0439 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430
+save-events=\u0421\u043E\u0445\u0440\u0430\u043D\u044F\u0442\u044C \u0441\u043E\u0431\u044B\u0442\u0438\u044F
+admin.save-events.tooltip=\u0415\u0441\u043B\u0438 \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u043E, \u0442\u043E \u0441\u043E\u0431\u044B\u0442\u0438\u044F \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430 \u0431\u0443\u0434\u0435\u0442 \u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u044B \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043D\u043D\u044B\u0445, \u0447\u0442\u043E \u0441\u0434\u0435\u043B\u0430\u0435\u0442 \u0438\u0445 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u043C\u0438 \u0447\u0435\u0440\u0435\u0437 \u043A\u043E\u043D\u0441\u043E\u043B\u044C \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430.
+saved-types.tooltip=\u0421\u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C, \u043A\u0430\u043A\u0438\u0435 \u0442\u0438\u043F\u044B \u0441\u043E\u0431\u044B\u0442\u0438\u0439 \u0441\u043B\u0435\u0434\u0443\u0435\u0442 \u0441\u043E\u0445\u0440\u0430\u043D\u044F\u0442\u044C.
+include-representation=\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u043F\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0435
+include-representation.tooltip=\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C JSON \u043F\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0434\u043B\u044F \u0437\u0430\u043F\u0440\u043E\u0441\u043E\u0432 \u043D\u0430 \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u0435 \u0438 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435.
+clear-admin-events.tooltip=\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0432\u0441\u0435 \u0441\u043E\u0431\u044B\u0442\u0438\u044F \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430 \u0438\u0437 \u0431\u0430\u0437\u044B \u0434\u0430\u043D\u043D\u044B\u0445.
+server-version=\u0412\u0435\u0440\u0441\u0438\u044F \u0441\u0435\u0440\u0432\u0435\u0440\u0430
+info=\u0418\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F
+providers=\u041F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0438
+server-time=\u0412\u0440\u0435\u043C\u044F \u043D\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435
+server-uptime=\u0410\u043F\u0442\u0430\u0439\u043C \u0441\u0435\u0440\u0432\u0435\u0440\u0430
+memory=\u041F\u0430\u043C\u044F\u0442\u044C
+total-memory=\u0412\u0441\u0435\u0433\u043E \u043F\u0430\u043C\u044F\u0442\u0438
+free-memory=\u0421\u0432\u043E\u0431\u043E\u0434\u043D\u043E \u043F\u0430\u043C\u044F\u0442\u0438
+used-memory=\u0418\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u043E \u043F\u0430\u043C\u044F\u0442\u0438
+system=\u0421\u0438\u0441\u0442\u0435\u043C\u0430
+current-working-directory=\u0422\u0435\u043A\u0443\u0449\u0430\u044F \u0440\u0430\u0431\u043E\u0447\u0430\u044F \u0434\u0438\u0440\u0435\u043A\u0442\u043E\u0440\u0438\u044F
+java-version=\u0412\u0435\u0440\u0441\u0438\u044F Java
+java-vendor=\u041F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A Java
+java-runtime=Java Runtime
+java-vm=Java VM
+java-vm-version=\u0412\u0435\u0440\u0441\u0438\u044F Java VM
+java-home=Java Home
+user-name=\u0418\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
+user-timezone=\u0422\u0430\u0439\u043C\u0437\u043E\u043D\u0430 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
+user-locale=\u042F\u0437\u044B\u043A \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
+system-encoding=\u0421\u0438\u0441\u0442\u0435\u043C\u043D\u0430\u044F \u043A\u043E\u0434\u0438\u0440\u043E\u0432\u043A\u0430
+operating-system=\u041E\u043F\u0435\u0440\u0430\u0446\u0438\u043E\u043D\u043D\u0430\u044F \u0441\u0438\u0441\u0442\u0435\u043C\u0430
+os-architecture=\u0410\u0440\u0445\u0438\u0442\u0435\u043A\u0442\u0443\u0440\u0430 OS
+spi=SPI
+granted-roles=\u041F\u0440\u0435\u0434\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u043D\u044B\u0435 \u0440\u043E\u043B\u0438
+granted-protocol-mappers=\u0421\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u044F \u043F\u0440\u043E\u0442\u043E\u043A\u043E\u043B\u0430 \u043F\u0440\u0435\u0434\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u044F
+additional-grants=\u0414\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u043F\u043E\u043B\u043D\u043E\u043C\u043E\u0447\u0438\u044F
+revoke=\u041E\u0442\u043E\u0431\u0440\u0430\u0442\u044C
+new-password=\u041D\u043E\u0432\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C
+password-confirmation=\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u043F\u0430\u0440\u043E\u043B\u044F
+reset-password=\u0421\u0431\u0440\u043E\u0441 \u043F\u0430\u0440\u043E\u043B\u044F
+credentials.temporary.tooltip=\u0415\u0441\u043B\u0438 \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u043E, \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u0441\u043C\u0435\u043D\u0438\u0442\u044C \u043F\u0430\u0440\u043E\u043B\u044C \u043F\u0440\u0438 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0435\u043C \u0432\u0445\u043E\u0434\u0435
+remove-totp=\u0423\u0434\u0430\u043B\u0438\u0442\u044C TOTP
+credentials.remove-totp.tooltip=\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0433\u0435\u043D\u0435\u0440\u0430\u0442\u043E\u0440 \u043E\u0434\u043D\u043E\u0440\u0430\u0437\u043E\u0432\u044B\u0445 \u043F\u0430\u0440\u043E\u043B\u0435\u0439 \u0438\u0437 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F.
+reset-actions=\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u0441\u0431\u0440\u043E\u0441\u0430
+credentials.reset-actions.tooltip=\u041D\u0430\u0431\u043E\u0440 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u0434\u043B\u044F \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u044F \u043F\u0440\u0438 \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E \u043F\u0438\u0441\u044C\u043C\u0430 \u0441 \u0443\u043A\u0430\u0437\u0430\u043D\u0438\u044F\u043C\u0438 \u043F\u043E \u0441\u0431\u0440\u043E\u0441\u0443 \u043F\u0430\u0440\u043E\u043B\u044F. '\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044C email' \u0432\u044B\u0441\u044B\u043B\u0430\u0435\u0442 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E \u043F\u0438\u0441\u044C\u043C\u043E \u0434\u043B\u044F \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F \u0435\u0433\u043E email. '\u041E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u043F\u0440\u043E\u0444\u0438\u043B\u044C' \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043E\u0442 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0432\u0432\u0435\u0441\u0442\u0438 \u043D\u043E\u0432\u0443\u044E \u043F\u0435\u0440\u0441\u043E\u043D\u0430\u043B\u044C\u043D\u0443\u044E \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044E. '\u041E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u043F\u0430\u0440\u043E\u043B\u044C' \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043E\u0442 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0432\u0432\u0435\u0441\u0442\u0438 \u043D\u043E\u0432\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C. '\u041D\u0430\u0441\u0442\u0440\u043E\u0438\u0442\u044C TOTP' \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u043C\u043E\u0431\u0438\u043B\u044C\u043D\u043E\u0435 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u0441 \u0433\u0435\u043D\u0435\u0440\u0430\u0442\u043E\u0440\u043E\u043C \u043F\u0430\u0440\u043E\u043B\u0435\u0439.
+reset-actions-email=Email \u0441 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044F\u043C\u0438 \u0434\u043B\u044F \u0441\u0431\u0440\u043E\u0441\u0430 \u043F\u0430\u0440\u043E\u043B\u044F
+send-email=\u041F\u043E\u0441\u043B\u0430\u0442\u044C \u043F\u0438\u0441\u044C\u043C\u043E
+credentials.reset-actions-email.tooltip=\u041F\u043E\u0441\u044B\u043B\u0430\u0435\u0442 \u043F\u0438\u0441\u044C\u043C\u043E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E \u0441\u043E \u0432\u0441\u0442\u0440\u043E\u0435\u043D\u043D\u043E\u0439 \u0441\u0441\u044B\u043B\u043A\u043E\u0439. \u041A\u043B\u0438\u043A\u043D\u0443\u0432 \u043D\u0430 \u0441\u0441\u044B\u043B\u043A\u0443, \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u043E \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u0434\u043B\u044F \u0441\u0431\u0440\u043E\u0441\u0430. \u041E\u043D\u0438 \u043D\u0435 \u0434\u043E\u043B\u0436\u043D\u044B \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u0432\u0445\u043E\u0434\u0438\u0442\u044C \u0432 \u0441\u0438\u0441\u0442\u0435\u043C\u0443. \u041D\u0430\u043F\u0440\u0438\u043C\u0435\u0440, \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F \u043F\u0430\u0440\u043E\u043B\u044F, \u0449\u0435\u043B\u043A\u043D\u0438\u0442\u0435 \u043F\u043E \u044D\u0442\u043E\u0439 \u043A\u043D\u043E\u043F\u043A\u0435, \u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u043F\u043E\u043B\u0443\u0447\u0438\u0442 \u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E\u0441\u0442\u044C \u0441\u043C\u0435\u043D\u0438\u0442\u044C \u0441\u0432\u043E\u0439 \u043F\u0430\u0440\u043E\u043B\u044C \u0431\u0435\u0437 \u0432\u0445\u043E\u0434\u0430 \u0432 \u0441\u0438\u0441\u0442\u0435\u043C\u0443.
+add-user=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
+created-at=\u0421\u043E\u0437\u0434\u0430\u043D
+user-enabled=\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u0432\u043A\u043B\u044E\u0447\u0435\u043D
+user-enabled.tooltip=\u041E\u0442\u043A\u043B\u044E\u0447\u0435\u043D\u043D\u044B\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0438 \u043D\u0435 \u0441\u043C\u043E\u0433\u0443\u0442 \u0432\u043E\u0439\u0442\u0438.
+user-temporarily-locked=\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u0432\u0440\u0435\u043C\u0435\u043D\u043D\u043E \u0437\u0430\u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u0430\u043D
+user-temporarily-locked.tooltip=\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u0437\u0430\u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u0430\u043D \u0432 \u0441\u043B\u0443\u0447\u0430\u0435 \u043C\u043D\u043E\u0433\u043E\u043A\u0440\u0430\u0442\u043D\u044B\u0445 \u043D\u0435\u0443\u0434\u0430\u0447\u043D\u044B\u0445 \u043F\u043E\u043F\u044B\u0442\u043E\u043A \u0432\u0445\u043E\u0434\u0430.
+unlock-user=\u0420\u0430\u0437\u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
+federation-link=\u0421\u0441\u044B\u043B\u043A\u0430 \u0444\u0435\u0434\u0435\u0440\u0430\u0446\u0438\u0438
+email-verified=Email \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D
+email-verified.tooltip=\u0414\u043E\u043B\u0436\u0435\u043D \u043B\u0438 email \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0431\u044B\u0442\u044C \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D?
+required-user-actions=\u0422\u0440\u0435\u0431\u0443\u0435\u043C\u044B\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044F \u043E\u0442 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
+required-user-actions.tooltip=\u0422\u0440\u0435\u0431\u0443\u0435\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u043E\u0442 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u043A\u043E\u0433\u0434\u0430 \u043E\u043D \u0432\u0445\u043E\u0434\u0438\u0442. '\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044C email' \u0432\u044B\u0441\u044B\u043B\u0430\u0435\u0442 \u043F\u0438\u0441\u044C\u043C\u043E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E \u0434\u043B\u044F \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F \u0435\u0433\u043E email. '\u041E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u043F\u0440\u043E\u0444\u0438\u043B\u044C' \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043E\u0442 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0432\u0432\u0435\u0441\u0442\u0438 \u043D\u043E\u0432\u0443\u044E \u043F\u0435\u0440\u0441\u043E\u043D\u0430\u043B\u044C\u043D\u0443\u044E \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044E. '\u041E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u043F\u0430\u0440\u043E\u043B\u044C' \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043E\u0442 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0432\u0432\u0435\u0441\u0442\u0438 \u043D\u043E\u0432\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C. '\u041D\u0430\u0441\u0442\u0440\u043E\u0438\u0442\u044C TOTP' \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u043C\u043E\u0431\u0438\u043B\u044C\u043D\u043E\u0435 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u043F\u0430\u0440\u043E\u043B\u0435\u0439.
+locale=\u042F\u0437\u044B\u043A
+select-one.placeholder=\u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435...
+impersonate=\u0418\u043C\u043F\u0435\u0440\u0441\u043E\u043D\u0438\u0440\u043E\u0432\u0430\u0442\u044C
+impersonate-user=\u0418\u043C\u043F\u0435\u0440\u0441\u043E\u043D\u0438\u0440\u043E\u0432\u0430\u0442\u044C
+impersonate-user.tooltip=\u0412\u043E\u0439\u0442\u0438 \u043A\u0430\u043A \u044D\u0442\u043E\u0442 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C. \u0415\u0441\u043B\u0438 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u0432 \u0442\u043E\u043C \u0436\u0435 \u0441\u0430\u043C\u043E\u043C realm \u0447\u0442\u043E \u0438 \u0432\u044B, \u0442\u043E \u0432\u0430\u0448\u0430 \u0442\u0435\u043A\u0443\u0449\u0430\u044F \u0441\u0435\u0441\u0441\u0438\u044F \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u043B\u043E\u0433\u0438\u043D\u0435\u043D\u0430 \u043F\u0435\u0440\u0435\u0434 \u0442\u0435\u043C \u043A\u0430\u043A \u0432\u044B \u0432\u043E\u0439\u0434\u0435\u0442\u0435 \u043A\u0430\u043A \u044D\u0442\u043E\u0442 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C.
+identity-provider-alias=\u0421\u0438\u043D\u043E\u043D\u0438\u043C \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438
+provider-user-id=ID \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0443 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430
+provider-username=Username \u0443 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430
+no-identity-provider-links-available=\u0421\u0441\u044B\u043B\u043A\u0438 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u043D\u0435 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B
+group-membership=\u0427\u043B\u0435\u043D\u0441\u0442\u0432\u043E \u0432 \u0433\u0440\u0443\u043F\u043F\u0430\u0445
+leave=\u041F\u043E\u043A\u0438\u043D\u0443\u0442\u044C
+group-membership.tooltip=\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u044F\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0447\u043B\u0435\u043D\u043E\u043C \u0433\u0440\u0443\u043F\u043F\u044B. \u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0432 \u0441\u043F\u0438\u0441\u043A\u0435 \u0433\u0440\u0443\u043F\u043F\u0443 \u0438 \u043D\u0430\u0436\u043C\u0438\u0442\u0435 \u043A\u043D\u043E\u043F\u043A\u0443 \u041F\u043E\u043A\u0438\u043D\u0443\u0442\u044C, \u0447\u0442\u043E\u0431\u044B \u043F\u043E\u043A\u0438\u043D\u0443\u0442\u044C \u0433\u0440\u0443\u043F\u043F\u0443.
+membership.available-groups.tooltip=\u0413\u0440\u0443\u043F\u043F\u044B, \u043A \u043A\u043E\u0442\u043E\u0440\u044B\u043C \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u043C\u043E\u0436\u0435\u0442 \u043F\u0440\u0438\u0441\u043E\u0435\u0434\u0438\u043D\u0438\u0442\u044C\u0441\u044F. \u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0433\u0440\u0443\u043F\u043F\u0443 \u0438 \u043D\u0430\u0436\u043C\u0438\u0442\u0435 \u043A\u043D\u043E\u043F\u043A\u0443 \u043F\u0440\u0438\u0441\u043E\u0435\u0434\u0438\u043D\u0438\u0442\u044C\u0441\u044F.
+table-of-realm-users=\u0422\u0430\u0431\u043B\u0438\u0446\u0430 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439 Realm
+view-all-users=\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0432\u0441\u0435\u0445 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439
+unlock-users=\u0420\u0430\u0437\u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439
+no-users-available=\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0438 \u043D\u0435 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B
+users.instruction=\u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0437\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u0435 \u0441\u0442\u0440\u043E\u043A\u0443 \u043F\u043E\u0438\u0441\u043A\u0430, \u0438\u043B\u0438 \u043D\u0430\u0436\u043C\u0438\u0442\u0435 \u043F\u043E\u0441\u043C\u043E\u0442\u0440\u0435\u0442\u044C \u0432\u0441\u0435\u0445 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439
+consents=\u0421\u043E\u0433\u043B\u0430\u0441\u0438\u044F
+started=\u041D\u0430\u0447\u0430\u0442\u043E
+logout-all-sessions=\u0412\u044B\u0439\u0442\u0438 \u0438\u0437 \u0432\u0441\u0435\u0445 \u0441\u0435\u0441\u0441\u0438\u0439
+logout=\u0412\u044B\u0445\u043E\u0434
+new-name=\u041D\u043E\u0432\u043E\u0435 \u0438\u043C\u044F
+ok=\u041E\u043A
+attributes=\u0410\u0442\u0440\u0438\u0431\u0443\u0442\u044B
+role-mappings=\u0421\u043E\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0440\u043E\u043B\u0435\u0439
+members=\u0427\u043B\u0435\u043D\u044B
+details=\u0414\u0435\u0442\u0430\u043B\u0438
+identity-provider-links=\u0421\u0441\u044B\u043B\u043A\u0438 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438
+register-required-action=\u0417\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0442\u0440\u0435\u0431\u0443\u0435\u043C\u043E\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435
+gender=\u041F\u043E\u043B
+address=\u0410\u0434\u0440\u0435\u0441
+phone=\u0422\u0435\u043B\u0435\u0444\u043E\u043D
+profile-url=URL \u043F\u0440\u043E\u0444\u0438\u043B\u044F
+picture-url=URL \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F
+website=\u0412\u0435\u0431\u0441\u0430\u0439\u0442
+import-keys-and-cert=\u0418\u043C\u043F\u043E\u0440\u0442 \u043A\u043B\u044E\u0447\u0435\u0439 \u0438 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0432
+import-keys-and-cert.tooltip=\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u043F\u0430\u0440\u0443 \u043A\u043B\u044E\u0447\u0435\u0439 \u0438 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442 \u043A\u043B\u0438\u0435\u043D\u0442\u0430.
+upload-keys=\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u043A\u043B\u044E\u0447\u0438
+download-keys-and-cert=\u0421\u043A\u0430\u0447\u0430\u0442\u044C \u043A\u043B\u044E\u0447\u0438 \u0438 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442
+no-value-assigned.placeholder=\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043D\u0435 \u043D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u043E
+remove=\u0423\u0434\u0430\u043B\u0438\u0442\u044C
+no-group-members=\u0412 \u0433\u0440\u0443\u043F\u043F\u0435 \u043D\u0435\u0442 \u0447\u043B\u0435\u043D\u043E\u0432
+temporary=\u0412\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0439
+join=\u041F\u0440\u0438\u0441\u043E\u0435\u0434\u0438\u043D\u0438\u0442\u044C\u0441\u044F
+event-type=\u0422\u0438\u043F \u0441\u043E\u0431\u044B\u0442\u0438\u044F
+events-config=\u041A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F \u0441\u043E\u0431\u044B\u0442\u0438\u0439
+event-listeners=\u0421\u043B\u0443\u0448\u0430\u0442\u0435\u043B\u0438 \u0441\u043E\u0431\u044B\u0442\u0438\u0439
+login-events-settings=\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 \u0441\u043E\u0431\u044B\u0442\u0438\u0439 \u043F\u043E \u0432\u0445\u043E\u0434\u0443
+clear-events=\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C \u0441\u043E\u0431\u044B\u0442\u0438\u044F
+saved-types=\u0421\u043E\u0445\u0440\u0430\u043D\u044F\u0435\u043C\u044B\u0435 \u0442\u0438\u043F\u044B \u0441\u043E\u0431\u044B\u0442\u0438\u0439
+clear-admin-events=\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C \u0441\u043E\u0431\u044B\u0442\u0438\u044F \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430
+clear-changes=\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u044F
+error=\u041E\u0448\u0438\u0431\u043A\u0430
diff --git a/themes/src/main/resources/theme/base/admin/messages/messages_ru.properties b/themes/src/main/resources/theme/base/admin/messages/messages_ru.properties
new file mode 100644
index 0000000..556d574
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/messages/messages_ru.properties
@@ -0,0 +1,14 @@
+invalidPasswordMinLengthMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u043C\u0438\u043D\u0438\u043C\u0430\u043B\u044C\u043D\u0430\u044F \u0434\u043B\u0438\u043D\u0430 {0}.
+invalidPasswordMinDigitsMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u0446\u0438\u0444\u0440\u043E\u0432\u044B\u0445 \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432 \u043D\u0435 \u043C\u0435\u043D\u0435\u0435 {0}.
+invalidPasswordMinLowerCaseCharsMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432 \u0432 \u043D\u0438\u0436\u043D\u0435\u043C \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0435 \u043D\u0435 \u043C\u0435\u043D\u0435\u0435 {0}.
+invalidPasswordMinUpperCaseCharsMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432 \u0432 \u0432\u0435\u0440\u0445\u043D\u0435\u043C \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0435 \u043D\u0435 \u043C\u0435\u043D\u0435\u0435 {0}.
+invalidPasswordMinSpecialCharsMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u0441\u043F\u0435\u0446\u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432 \u043D\u0435 \u043C\u0435\u043D\u0435\u0435 {0}.
+invalidPasswordNotUsernameMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u043D\u0435 \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0432\u043F\u0430\u0434\u0430\u0442\u044C \u0441 \u0438\u043C\u0435\u043D\u0435\u043C \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F.
+invalidPasswordRegexPatternMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u043D\u0435 \u043F\u0440\u043E\u0448\u0435\u043B \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443 \u0440\u0435\u0433\u0443\u043B\u044F\u0440\u043D\u044B\u043C \u0432\u044B\u0440\u0430\u0436\u0435\u043D\u0438\u0435\u043C.
+invalidPasswordHistoryMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u043D\u0435 \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0432\u043F\u0430\u0434\u0430\u0442\u044C \u0441 \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u043C\u0438 {0} \u043F\u0430\u0440\u043E\u043B\u044F\u043C\u0438.
+
+ldapErrorInvalidCustomFilter=\u0421\u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u043C \u0444\u0438\u043B\u044C\u0442\u0440 LDAP \u043D\u0435 \u0434\u043E\u043B\u0436\u0435\u043D \u043D\u0430\u0447\u0438\u043D\u0430\u0442\u044C\u0441\u044F \u0441 "(" \u0438\u043B\u0438 \u0437\u0430\u043A\u0430\u043D\u0447\u0438\u0432\u0430\u0442\u044C\u0441\u044F \u043D\u0430 ")".
+ldapErrorMissingClientId=Client ID \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u043D\u0430\u0441\u0442\u0440\u043E\u0435\u043D \u0432 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438, \u0435\u0441\u043B\u0438 \u043D\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0441\u044F \u043C\u0430\u043F\u043F\u0438\u043D\u0433 \u0440\u043E\u043B\u0435\u0439 realm.
+ldapErrorCantPreserveGroupInheritanceWithUIDMembershipType=\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0443\u043D\u0430\u0441\u043B\u0435\u0434\u043E\u0432\u0430\u0442\u044C \u0433\u0440\u0443\u043F\u043F\u0443 \u0438 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C \u0447\u043B\u0435\u043D\u0441\u0442\u0432\u043E UID \u0442\u0438\u043F\u0430 \u0432\u043C\u0435\u0441\u0442\u0435.
+ldapErrorCantWriteOnlyForReadOnlyLdap=\u041D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0440\u0435\u0436\u0438\u043C \u0442\u043E\u043B\u044C\u043A\u043E-\u043D\u0430-\u0437\u0430\u043F\u0438\u0441\u044C, \u043A\u043E\u0433\u0434\u0430 LDAP \u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440 \u043D\u0435 \u0432 \u0440\u0435\u0436\u0438\u043C\u0435 WRITABLE
+ldapErrorCantWriteOnlyAndReadOnly=\u041D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0440\u0435\u0436\u0438\u043C\u044B \u0442\u043E\u043B\u044C\u043A\u043E-\u043D\u0430-\u0447\u0442\u0435\u043D\u0438\u0435 \u0438 \u0442\u043E\u043B\u044C\u043A\u043E-\u043D\u0430-\u0437\u0430\u043F\u0438\u0441\u044C \u0432\u043C\u0435\u0441\u0442\u0435
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/app.js b/themes/src/main/resources/theme/base/admin/resources/js/app.js
index ca78bac..c3b25ec 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/app.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/app.js
@@ -9,7 +9,7 @@ var auth = {};
 var resourceBundle;
 var locale = 'en';
 
-var module = angular.module('keycloak', [ 'keycloak.services', 'keycloak.loaders', 'ui.bootstrap', 'ui.select2', 'angularFileUpload', 'angularTreeview', 'pascalprecht.translate', 'ngCookies', 'ngSanitize']);
+var module = angular.module('keycloak', [ 'keycloak.services', 'keycloak.loaders', 'ui.bootstrap', 'ui.select2', 'angularFileUpload', 'angularTreeview', 'pascalprecht.translate', 'ngCookies', 'ngSanitize', 'ui.ace']);
 var resourceRequests = 0;
 var loadingTimer = -1;
 
@@ -208,6 +208,9 @@ module.config([ '$routeProvider', function($routeProvider) {
                 },
                 clientInitialAccess : function(ClientInitialAccessLoader) {
                     return ClientInitialAccessLoader();
+                },
+                clientRegTrustedHosts : function(ClientRegistrationTrustedHostListLoader) {
+                    return ClientRegistrationTrustedHostListLoader();
                 }
             },
             controller : 'ClientInitialAccessCtrl'
@@ -221,6 +224,30 @@ module.config([ '$routeProvider', function($routeProvider) {
             },
             controller : 'ClientInitialAccessCreateCtrl'
         })
+        .when('/realms/:realm/client-reg-trusted-hosts/create', {
+            templateUrl : resourceUrl + '/partials/client-reg-trusted-host-create.html',
+            resolve : {
+                realm : function(RealmLoader) {
+                    return RealmLoader();
+                },
+                clientRegTrustedHost : function() {
+                    return {};
+                }
+            },
+            controller : 'ClientRegistrationTrustedHostDetailCtrl'
+        })
+        .when('/realms/:realm/client-reg-trusted-hosts/:hostname', {
+            templateUrl : resourceUrl + '/partials/client-reg-trusted-host-detail.html',
+            resolve : {
+                realm : function(RealmLoader) {
+                    return RealmLoader();
+                },
+                clientRegTrustedHost : function(ClientRegistrationTrustedHostLoader) {
+                    return ClientRegistrationTrustedHostLoader();
+                }
+            },
+            controller : 'ClientRegistrationTrustedHostDetailCtrl'
+        })
         .when('/realms/:realm/keys-settings', {
             templateUrl : resourceUrl + '/partials/realm-keys.html',
             resolve : {
@@ -1338,11 +1365,52 @@ module.config([ '$routeProvider', function($routeProvider) {
             },
             controller : 'RealmSessionStatsCtrl'
         })
+        .when('/create/user-storage/:realm/providers/:provider', {
+            templateUrl : resourceUrl + '/partials/user-storage-generic.html',
+            resolve : {
+                realm : function(RealmLoader) {
+                    return RealmLoader();
+                },
+                instance : function() {
+                    return {
+
+                    };
+                },
+                providerId : function($route) {
+                    return $route.current.params.provider;
+                },
+                serverInfo : function(ServerInfoLoader) {
+                    return ServerInfoLoader();
+                }
+            },
+            controller : 'GenericUserStorageCtrl'
+        })
+        .when('/realms/:realm/user-storage/providers/:provider/:componentId', {
+            templateUrl : resourceUrl + '/partials/user-storage-generic.html',
+            resolve : {
+                realm : function(RealmLoader) {
+                    return RealmLoader();
+                },
+                instance : function(ComponentLoader) {
+                    return ComponentLoader();
+                },
+                providerId : function($route) {
+                    return $route.current.params.provider;
+                },
+                serverInfo : function(ServerInfoLoader) {
+                    return ServerInfoLoader();
+                }
+            },
+            controller : 'GenericUserStorageCtrl'
+        })
         .when('/realms/:realm/user-federation', {
             templateUrl : resourceUrl + '/partials/user-federation.html',
             resolve : {
                 realm : function(RealmLoader) {
                     return RealmLoader();
+                },
+                serverInfo : function(ServerInfoLoader) {
+                    return ServerInfoLoader();
                 }
             },
             controller : 'UserFederationCtrl'
@@ -1639,6 +1707,9 @@ module.config([ '$routeProvider', function($routeProvider) {
             resolve : {
                 realm : function(RealmLoader) {
                     return RealmLoader();
+                },
+                serverInfo : function(ServerInfoLoader) {
+                    return ServerInfoLoader();
                 }
             },
             controller : 'RealmPasswordPolicyCtrl'
@@ -2123,18 +2194,22 @@ module.directive('kcReadOnly', function() {
                 }
             }
 
+            var filterIgnored = function(i, e){
+                return !e.attributes['kc-read-only-ignore'];
+            }
+
             scope.$watch(attrs.kcReadOnly, function(readOnly) {
                 if (readOnly) {
-                    element.find('input').each(disable);
-                    element.find('button').each(disable);
-                    element.find('select').each(disable);
-                    element.find('textarea').each(disable);
+                    element.find('input').filter(filterIgnored).each(disable);
+                    element.find('button').filter(filterIgnored).each(disable);
+                    element.find('select').filter(filterIgnored).each(disable);
+                    element.find('textarea').filter(filterIgnored).each(disable);
                 } else {
-                    element.find('input').each(enable);
-                    element.find('input').each(enable);
-                    element.find('button').each(enable);
-                    element.find('select').each(enable);
-                    element.find('textarea').each(enable);
+                    element.find('input').filter(filterIgnored).each(enable);
+                    element.find('input').filter(filterIgnored).each(enable);
+                    element.find('button').filter(filterIgnored).each(enable);
+                    element.find('select').filter(filterIgnored).each(enable);
+                    element.find('textarea').filter(filterIgnored).each(enable);
                 }
             });
         }
@@ -2325,6 +2400,89 @@ module.directive('kcProviderConfig', function ($modal) {
     }
 });
 
+module.controller('ComponentRoleSelectorModalCtrl', function($scope, realm, config, configName, RealmRoles, Client, ClientRole, $modalInstance) {
+    $scope.selectedRealmRole = {
+        role: undefined
+    };
+    $scope.selectedClientRole = {
+        role: undefined
+    };
+    $scope.client = {
+        selected: undefined
+    };
+
+    $scope.selectRealmRole = function() {
+        config[configName][0] = $scope.selectedRealmRole.role.name;
+        $modalInstance.close();
+    }
+
+    $scope.selectClientRole = function() {
+        config[configName][0] = $scope.client.selected.clientId + "." + $scope.selectedClientRole.role.name;
+        $modalInstance.close();
+    }
+
+    $scope.cancel = function() {
+        $modalInstance.dismiss();
+    }
+
+    $scope.changeClient = function() {
+        if ($scope.client.selected) {
+            ClientRole.query({realm: realm.realm, client: $scope.client.selected.id}, function (data) {
+                $scope.clientRoles = data;
+            });
+        } else {
+            console.log('selected client was null');
+            $scope.clientRoles = null;
+        }
+
+    }
+    RealmRoles.query({realm: realm.realm}, function(data) {
+        $scope.realmRoles = data;
+    })
+    Client.query({realm: realm.realm}, function(data) {
+        $scope.clients = data;
+        if (data.length > 0) {
+            $scope.client.selected = data[0];
+            $scope.changeClient();
+        }
+    })
+});
+
+module.controller('ComponentConfigCtrl', function ($modal, $scope) {
+    $scope.openRoleSelector = function (configName, config) {
+        $modal.open({
+            templateUrl: resourceUrl + '/partials/modal/component-role-selector.html',
+            controller: 'ComponentRoleSelectorModalCtrl',
+            resolve: {
+                realm: function () {
+                    return $scope.realm;
+                },
+                config: function () {
+                    return config;
+                },
+                configName: function () {
+                    return configName;
+                }
+            }
+        })
+    }
+});
+module.directive('kcComponentConfig', function ($modal) {
+    return {
+        scope: {
+            config: '=',
+            properties: '=',
+            realm: '=',
+            clients: '=',
+            configName: '='
+        },
+        restrict: 'E',
+        replace: true,
+        controller: 'ComponentConfigCtrl',
+        templateUrl: resourceUrl + '/templates/kc-component-config.html'
+    }
+});
+
 /*
 *  Used to select the element (invoke $(elem).select()) on specified action list.
 *  Usages kc-select-action="click mouseover"
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-app.js b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-app.js
new file mode 100644
index 0000000..467038c
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-app.js
@@ -0,0 +1,412 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2016 Red Hat, Inc., and individual contributors
+ * as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+module.requires.push('ui.ace');
+
+module.config(['$routeProvider', function ($routeProvider) {
+    $routeProvider
+        .when('/realms/:realm/authz', {
+            templateUrl: resourceUrl + '/partials/authz/resource-server-list.html',
+            resolve: {
+                realm: function (RealmLoader) {
+                    return RealmLoader();
+                }
+            },
+            controller: 'ResourceServerCtrl'
+        }).when('/realms/:realm/clients/:client/authz/resource-server/create', {
+        templateUrl: resourceUrl + '/partials/authz/resource-server-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            },
+            clients: function (ClientListLoader) {
+                return ClientListLoader();
+            }
+        },
+        controller: 'ResourceServerDetailCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server', {
+        templateUrl: resourceUrl + '/partials/authz/resource-server-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            },
+            clients: function (ClientListLoader) {
+                return ClientListLoader();
+            },
+            serverInfo: function (ServerInfoLoader) {
+                return ServerInfoLoader();
+            }
+        },
+        controller: 'ResourceServerDetailCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/evaluate', {
+        templateUrl: resourceUrl + '/partials/authz/policy/resource-server-policy-evaluate.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            },
+            clients: function (ClientListLoader) {
+                return ClientListLoader();
+            },
+            roles: function (RoleListLoader) {
+                return new RoleListLoader();
+            }
+        },
+        controller: 'PolicyEvaluateCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/evaluate/result', {
+        templateUrl: resourceUrl + '/partials/authz/policy/resource-server-policy-evaluate-result.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            },
+        },
+        controller: 'PolicyEvaluateCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/resource', {
+        templateUrl: resourceUrl + '/partials/authz/resource-server-resource-list.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerResourceCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/resource/create', {
+        templateUrl: resourceUrl + '/partials/authz/resource-server-resource-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerResourceDetailCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/resource/:rsrid', {
+        templateUrl: resourceUrl + '/partials/authz/resource-server-resource-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerResourceDetailCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/scope', {
+        templateUrl: resourceUrl + '/partials/authz/resource-server-scope-list.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerScopeCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/scope/create', {
+        templateUrl: resourceUrl + '/partials/authz/resource-server-scope-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerScopeDetailCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/scope/:id', {
+        templateUrl: resourceUrl + '/partials/authz/resource-server-scope-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerScopeDetailCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/permission', {
+        templateUrl: resourceUrl + '/partials/authz/permission/resource-server-permission-list.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerPermissionCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/policy', {
+        templateUrl: resourceUrl + '/partials/authz/policy/resource-server-policy-list.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerPolicyCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/policy/drools/create', {
+        templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-drools-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerPolicyDroolsDetailCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/policy/drools/:id', {
+        templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-drools-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerPolicyDroolsDetailCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/permission/resource/create', {
+        templateUrl: resourceUrl + '/partials/authz/permission/provider/resource-server-policy-resource-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerPolicyResourceDetailCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/permission/resource/:id', {
+        templateUrl: resourceUrl + '/partials/authz/permission/provider/resource-server-policy-resource-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerPolicyResourceDetailCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/permission/scope/create', {
+        templateUrl: resourceUrl + '/partials/authz/permission/provider/resource-server-policy-scope-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerPolicyScopeDetailCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/permission/scope/:id', {
+        templateUrl: resourceUrl + '/partials/authz/permission/provider/resource-server-policy-scope-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerPolicyScopeDetailCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/policy/user/create', {
+        templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-user-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerPolicyUserDetailCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/policy/user/:id', {
+        templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-user-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerPolicyUserDetailCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/policy/role/create', {
+        templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-role-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerPolicyRoleDetailCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/policy/role/:id', {
+        templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-role-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerPolicyRoleDetailCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/policy/js/create', {
+        templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-js-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerPolicyJSDetailCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/policy/js/:id', {
+        templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-js-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerPolicyJSDetailCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/policy/time/create', {
+        templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-time-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerPolicyTimeDetailCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/policy/time/:id', {
+        templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-time-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerPolicyTimeDetailCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/policy/aggregate/create', {
+        templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-aggregate-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerPolicyAggregateDetailCtrl'
+    }).when('/realms/:realm/clients/:client/authz/resource-server/policy/aggregate/:id', {
+        templateUrl: resourceUrl + '/partials/authz/policy/provider/resource-server-policy-aggregate-detail.html',
+        resolve: {
+            realm: function (RealmLoader) {
+                return RealmLoader();
+            },
+            client : function(ClientLoader) {
+                return ClientLoader();
+            }
+        },
+        controller: 'ResourceServerPolicyAggregateDetailCtrl'
+    });
+}]);
+
+module.directive('kcTabsResourceServer', function () {
+    return {
+        scope: true,
+        restrict: 'E',
+        replace: true,
+        templateUrl: resourceUrl + '/templates/authz/kc-tabs-resource-server.html'
+    }
+});
+
+module.filter('unique', function () {
+
+    return function (items, filterOn) {
+
+        if (filterOn === false) {
+            return items;
+        }
+
+        if ((filterOn || angular.isUndefined(filterOn)) && angular.isArray(items)) {
+            var hashCheck = {}, newItems = [];
+
+            var extractValueToCompare = function (item) {
+                if (angular.isObject(item) && angular.isString(filterOn)) {
+                    return item[filterOn];
+                } else {
+                    return item;
+                }
+            };
+
+            angular.forEach(items, function (item) {
+                var valueToCheck, isDuplicate = false;
+
+                for (var i = 0; i < newItems.length; i++) {
+                    if (angular.equals(extractValueToCompare(newItems[i]), extractValueToCompare(item))) {
+                        isDuplicate = true;
+                        break;
+                    }
+                }
+                if (!isDuplicate) {
+                    newItems.push(item);
+                }
+
+            });
+            items = newItems;
+        }
+        return items;
+    };
+});
+
+module.filter('toCamelCase', function () {
+    return function (input) {
+        input = input || '';
+        return input.replace(/\w\S*/g, function (txt) {
+            return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
+        });
+    };
+})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js
new file mode 100644
index 0000000..ec37854
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-controller.js
@@ -0,0 +1,1454 @@
+module.controller('ResourceServerCtrl', function($scope, realm, ResourceServer) {
+    $scope.realm = realm;
+
+    ResourceServer.query({realm : realm.realm}, function (data) {
+        $scope.servers = data;
+    });
+});
+
+module.controller('ResourceServerDetailCtrl', function($scope, $http, $route, $location, $upload, $modal, realm, ResourceServer, client, AuthzDialog, Notifications) {
+    $scope.realm = realm;
+    $scope.client = client;
+
+    ResourceServer.get({
+        realm : $route.current.params.realm,
+        client : client.id
+    }, function(data) {
+        $scope.server = angular.copy(data);
+        $scope.changed = false;
+
+        $scope.$watch('server', function() {
+            if (!angular.equals($scope.server, data)) {
+                $scope.changed = true;
+            }
+        }, true);
+
+        $scope.save = function() {
+            ResourceServer.update({realm : realm.realm, client : $scope.server.clientId}, $scope.server, function() {
+                $route.reload();
+                Notifications.success("The resource server has been created.");
+            });
+        }
+
+        $scope.reset = function() {
+            $route.reload();
+        }
+
+        $scope.export = function() {
+            $scope.exportSettings = true;
+            ResourceServer.settings({
+                realm : $route.current.params.realm,
+                client : client.id
+            }, function(data) {
+                var tmp = angular.fromJson(data);
+                $scope.settings = angular.toJson(tmp, true);
+            })
+        }
+
+        $scope.downloadSettings = function() {
+            saveAs(new Blob([$scope.settings], { type: 'application/json' }), $scope.server.name + "-authz-config.json");
+        }
+
+        $scope.cancelExport = function() {
+            delete $scope.settings
+        }
+
+        $scope.onFileSelect = function($fileContent) {
+            $scope.server = angular.copy(JSON.parse($fileContent));
+            $scope.importing = true;
+        };
+
+        $scope.viewImportDetails = function() {
+            $modal.open({
+                templateUrl: resourceUrl + '/partials/modal/view-object.html',
+                controller: 'ObjectModalCtrl',
+                resolve: {
+                    object: function () {
+                        return $scope.server;
+                    }
+                }
+            })
+        };
+
+        $scope.import = function () {
+            ResourceServer.import({realm : realm.realm, client : client.id}, $scope.server, function() {
+                $route.reload();
+                Notifications.success("The resource server has been updated.");
+            });
+        }
+    });
+});
+
+module.controller('ResourceServerResourceCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerResource, client) {
+    $scope.realm = realm;
+    $scope.client = client;
+
+    ResourceServer.get({
+        realm : $route.current.params.realm,
+        client : client.id
+    }, function(data) {
+        $scope.server = data;
+
+        $scope.createPolicy = function(resource) {
+            $location.path('/realms/' + $route.current.params.realm + '/clients/' + client.id + '/authz/resource-server/permission/resource/create').search({rsrid: resource._id});
+        }
+
+        ResourceServerResource.query({realm : realm.realm, client : client.id}, function (data) {
+            $scope.resources = data;
+        });
+    });
+});
+
+module.controller('ResourceServerResourceDetailCtrl', function($scope, $http, $route, $location, realm, ResourceServer, client, ResourceServerResource, ResourceServerScope, AuthzDialog, Notifications) {
+    $scope.realm = realm;
+    $scope.client = client;
+
+    ResourceServerScope.query({realm : realm.realm, client : client.id}, function (data) {
+        $scope.scopes = data;
+    });
+
+    var $instance = this;
+
+    ResourceServer.get({
+        realm : $route.current.params.realm,
+        client : client.id
+    }, function(data) {
+        $scope.server = data;
+
+        var resourceId = $route.current.params.rsrid;
+
+        if (!resourceId) {
+            $scope.create = true;
+            $scope.changed = false;
+
+            var resource = {};
+            resource.scopes = [];
+
+            $scope.resource = angular.copy(resource);
+
+            $scope.$watch('resource', function() {
+                if (!angular.equals($scope.resource, resource)) {
+                    $scope.changed = true;
+                }
+            }, true);
+
+            $scope.save = function() {
+                $instance.checkNameAvailability(function () {
+                    ResourceServerResource.save({realm : realm.realm, client : $scope.client.id}, $scope.resource, function(data) {
+                        $location.url("/realms/" + realm.realm + "/clients/" + $scope.client.id + "/authz/resource-server/resource/" + data._id);
+                        Notifications.success("The resource has been created.");
+                    });
+                });
+            }
+
+            $scope.cancel = function() {
+                $location.url("/realms/" + realm.realm + "/clients/" + $scope.client.id + "/authz/resource-server/resource/");
+            }
+        } else {
+            ResourceServerResource.get({
+                realm : $route.current.params.realm,
+                client : client.id,
+                rsrid : $route.current.params.rsrid,
+            }, function(data) {
+                if (!data.scopes) {
+                    data.scopes = [];
+                }
+
+                if (!data.policies) {
+                    data.policies = [];
+                }
+
+                $scope.resource = angular.copy(data);
+                $scope.changed = false;
+
+                for (i = 0; i < $scope.resource.scopes.length; i++) {
+                    $scope.resource.scopes[i] = $scope.resource.scopes[i].name;
+                }
+
+                $scope.originalResource = angular.copy($scope.resource);
+
+                $scope.$watch('resource', function() {
+                    if (!angular.equals($scope.resource, data)) {
+                        $scope.changed = true;
+                    }
+                }, true);
+
+                $scope.save = function() {
+                    $instance.checkNameAvailability(function () {
+                        ResourceServerResource.update({realm : realm.realm, client : $scope.client.id, rsrid : $scope.resource._id}, $scope.resource, function() {
+                            $route.reload();
+                            Notifications.success("The resource has been updated.");
+                        });
+                    });
+                }
+
+                $scope.remove = function() {
+                    var msg = "";
+
+                    if ($scope.resource.policies.length > 0) {
+                        msg = "<p>This resource is referenced in some policies:</p>";
+                        msg += "<ul>";
+                        for (i = 0; i < $scope.resource.policies.length; i++) {
+                            msg+= "<li><strong>" + $scope.resource.policies[i].name + "</strong></li>";
+                        }
+                        msg += "</ul>";
+                        msg += "<p>If you remove this resource, the policies above will be affected and will not be associated with this resource anymore.</p>";
+                    }
+
+                    AuthzDialog.confirmDeleteWithMsg($scope.resource.name, "Resource", msg, function() {
+                        ResourceServerResource.delete({realm : realm.realm, client : $scope.client.id, rsrid : $scope.resource._id}, null, function() {
+                            $location.url("/realms/" + realm.realm + "/clients/" + $scope.client.id + "/authz/resource-server/resource");
+                            Notifications.success("The resource has been deleted.");
+                        });
+                    });
+                }
+
+                $scope.reset = function() {
+                    $route.reload();
+                }
+            });
+        }
+    });
+
+    $scope.checkNewNameAvailability = function () {
+        $instance.checkNameAvailability(function () {});
+    }
+
+    this.checkNameAvailability = function (onSuccess) {
+        ResourceServerResource.search({
+            realm : $route.current.params.realm,
+            client : client.id,
+            rsrid : $route.current.params.rsrid,
+            name: $scope.resource.name
+        }, function(data) {
+            if (data && data._id && data._id != $scope.resource._id) {
+                Notifications.error("Name already in use by another resource, please choose another one.");
+            } else {
+                onSuccess();
+            }
+        });
+    }
+});
+
+module.controller('ResourceServerScopeCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerScope, client) {
+    $scope.realm = realm;
+    $scope.client = client;
+
+    ResourceServer.get({
+        realm : $route.current.params.realm,
+        client : client.id
+    }, function(data) {
+        $scope.server = data;
+
+        ResourceServerScope.query({realm : realm.realm, client : client.id}, function (data) {
+            $scope.scopes = data;
+        });
+
+        $scope.createPolicy = function(scope) {
+            $location.path('/realms/' + $route.current.params.realm + '/clients/' + client.id + '/authz/resource-server/permission/scope/create').search({scpid: scope.id});
+        }
+    });
+});
+
+module.controller('ResourceServerScopeDetailCtrl', function($scope, $http, $route, $location, realm, ResourceServer, client, ResourceServerScope, AuthzDialog, Notifications) {
+    $scope.realm = realm;
+    $scope.client = client;
+
+    var $instance = this;
+
+    ResourceServer.get({
+        realm : $route.current.params.realm,
+        client : client.id
+    }, function(data) {
+        $scope.server = data;
+
+        var scopeId = $route.current.params.id;
+
+        if (!scopeId) {
+            $scope.create = true;
+            $scope.changed = false;
+
+            var scope = {};
+
+            $scope.scope = angular.copy(scope);
+
+            $scope.$watch('scope', function() {
+                if (!angular.equals($scope.scope, scope)) {
+                    $scope.changed = true;
+                }
+            }, true);
+
+            $scope.save = function() {
+                $instance.checkNameAvailability(function () {
+                    ResourceServerScope.save({realm : realm.realm, client : $scope.client.id}, $scope.scope, function(data) {
+                        $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/scope/" + data.id);
+                        Notifications.success("The scope has been created.");
+                    });
+                });
+            }
+        } else {
+            ResourceServerScope.get({
+                realm : $route.current.params.realm,
+                client : client.id,
+                id : $route.current.params.id,
+            }, function(data) {
+                $scope.scope = angular.copy(data);
+                $scope.changed = false;
+
+                $scope.$watch('scope', function() {
+                    if (!angular.equals($scope.scope, data)) {
+                        $scope.changed = true;
+                    }
+                }, true);
+
+                $scope.originalScope = angular.copy($scope.scope);
+
+                $scope.save = function() {
+                    $instance.checkNameAvailability(function () {
+                        ResourceServerScope.update({realm : realm.realm, client : $scope.client.id, id : $scope.scope.id}, $scope.scope, function() {
+                            $scope.changed = false;
+                            Notifications.success("The scope has been updated.");
+                        });
+                    });
+                }
+
+                $scope.remove = function() {
+                    var msg = "";
+
+                    if ($scope.scope.policies.length > 0) {
+                        msg = "<p>This resource is referenced in some policies:</p>";
+                        msg += "<ul>";
+                        for (i = 0; i < $scope.scope.policies.length; i++) {
+                            msg+= "<li><strong>" + $scope.scope.policies[i].name + "</strong></li>";
+                        }
+                        msg += "</ul>";
+                        msg += "<p>If you remove this resource, the policies above will be affected and will not be associated with this resource anymore.</p>";
+                    }
+
+                    AuthzDialog.confirmDeleteWithMsg($scope.scope.name, "Scope", msg, function() {
+                        ResourceServerScope.delete({realm : realm.realm, client : $scope.client.id, id : $scope.scope.id}, null, function() {
+                            $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/scope");
+                            Notifications.success("The scope has been deleted.");
+                        });
+                    });
+                }
+
+                $scope.reset = function() {
+                    $route.reload();
+                }
+            });
+        }
+    });
+
+    $scope.checkNewNameAvailability = function () {
+        $instance.checkNameAvailability(function () {});
+    }
+
+    this.checkNameAvailability = function (onSuccess) {
+        ResourceServerScope.search({
+            realm : $route.current.params.realm,
+            client : client.id,
+            name: $scope.scope.name
+        }, function(data) {
+            if (data && data.id && data.id != $scope.scope.id) {
+                Notifications.error("Name already in use by another scope, please choose another one.");
+            } else {
+                onSuccess();
+            }
+        });
+    }
+});
+
+module.controller('ResourceServerPolicyCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerPolicy, PolicyProvider, client) {
+    $scope.realm = realm;
+    $scope.client = client;
+    $scope.policyProviders = [];
+
+    PolicyProvider.query({
+        realm : $route.current.params.realm,
+        client : client.id
+    }, function (data) {
+        for (i = 0; i < data.length; i++) {
+            if (data[i].type != 'resource' && data[i].type != 'scope') {
+                $scope.policyProviders.push(data[i]);
+            }
+        }
+    });
+
+    ResourceServer.get({
+        realm : $route.current.params.realm,
+        client : client.id
+    }, function(data) {
+        $scope.server = data;
+
+        ResourceServerPolicy.query({realm : realm.realm, client : client.id}, function (data) {
+            $scope.policies = [];
+
+            for (i = 0; i < data.length; i++) {
+                if (data[i].type != 'resource' && data[i].type != 'scope') {
+                    $scope.policies.push(data[i]);
+                }
+            }
+        });
+    });
+
+    $scope.addPolicy = function(policyType) {
+        $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/policy/" + policyType.type + "/create");
+    }
+});
+
+module.controller('ResourceServerPermissionCtrl', function($scope, $http, $route, $location, realm, ResourceServer, ResourceServerPolicy, PolicyProvider, client) {
+    $scope.realm = realm;
+    $scope.client = client;
+    $scope.policyProviders = [];
+
+    PolicyProvider.query({
+        realm : $route.current.params.realm,
+        client : client.id
+    }, function (data) {
+        for (i = 0; i < data.length; i++) {
+            if (data[i].type == 'resource' || data[i].type == 'scope') {
+                $scope.policyProviders.push(data[i]);
+            }
+        }
+    });
+
+    ResourceServer.get({
+        realm : $route.current.params.realm,
+        client : client.id
+    }, function(data) {
+        $scope.server = data;
+
+        ResourceServerPolicy.query({realm : realm.realm, client : client.id}, function (data) {
+            $scope.policies = [];
+
+            for (i = 0; i < data.length; i++) {
+                if (data[i].type == 'resource' || data[i].type == 'scope') {
+                    $scope.policies.push(data[i]);
+                }
+            }
+        });
+    });
+
+    $scope.addPolicy = function(policyType) {
+        $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/permission/" + policyType.type + "/create");
+    }
+});
+
+module.controller('ResourceServerPolicyDroolsDetailCtrl', function($scope, $http, $route, realm, client, PolicyController) {
+    PolicyController.onInit({
+        getPolicyType : function() {
+            return "drools";
+        },
+
+        onInit : function() {
+            $scope.drools = {};
+
+            $scope.resolveModules = function(policy) {
+                if (!policy) {
+                    policy = $scope.policy;
+                }
+
+                $http.post(authUrl + '/admin/realms/'+ $route.current.params.realm + '/clients/' + client.id + '/authz/resource-server/policy/drools/resolveModules'
+                        , policy).success(function(data) {
+                            $scope.drools.moduleNames = data;
+                            $scope.resolveSessions();
+                        });
+            }
+
+            $scope.resolveSessions = function() {
+                $http.post(authUrl + '/admin/realms/'+ $route.current.params.realm + '/clients/' + client.id + '/authz/resource-server/policy/drools/resolveSessions'
+                        , $scope.policy).success(function(data) {
+                            $scope.drools.moduleSessions = data;
+                        });
+            }
+        },
+
+        onInitUpdate : function(policy) {
+            policy.config.scannerPeriod = parseInt(policy.config.scannerPeriod);
+            $scope.resolveModules(policy);
+        },
+
+        onUpdate : function() {
+            $scope.policy.config.resources = JSON.stringify($scope.policy.config.resources);
+        },
+
+        onInitCreate : function(newPolicy) {
+            newPolicy.config.scannerPeriod = 1;
+            newPolicy.config.scannerPeriodUnit = 'Hours';
+        }
+    }, realm, client, $scope);
+});
+
+module.controller('ResourceServerPolicyResourceDetailCtrl', function($scope, $route, $location, realm, client, PolicyController, ResourceServerPolicy, ResourceServerResource) {
+    PolicyController.onInit({
+        getPolicyType : function() {
+            return "resource";
+        },
+
+        isPermission : function() {
+            return true;
+        },
+
+        onInit : function() {
+            ResourceServerResource.query({realm : realm.realm, client : client.id}, function (data) {
+                $scope.resources = data;
+            });
+
+            ResourceServerPolicy.query({realm : realm.realm, client : client.id}, function (data) {
+                $scope.policies = [];
+
+                for (i = 0; i < data.length; i++) {
+                    if (data[i].type != 'resource' && data[i].type != 'scope') {
+                        $scope.policies.push(data[i]);
+                    }
+                }
+            });
+
+            $scope.applyToResourceType = function() {
+                if ($scope.policy.config.default) {
+                    $scope.policy.config.resources = [];
+                } else {
+                    $scope.policy.config.defaultResourceType = null;
+                }
+            }
+        },
+
+        onInitUpdate : function(policy) {
+            policy.config.default = eval(policy.config.default);
+            policy.config.resources = eval(policy.config.resources);
+            policy.config.applyPolicies = eval(policy.config.applyPolicies);
+        },
+
+        onUpdate : function() {
+            $scope.policy.config.resources = JSON.stringify($scope.policy.config.resources);
+            $scope.policy.config.applyPolicies = JSON.stringify($scope.policy.config.applyPolicies);
+        },
+
+        onInitCreate : function(newPolicy) {
+            newPolicy.decisionStrategy = 'UNANIMOUS';
+            newPolicy.config = {};
+            newPolicy.config.resources = '';
+
+            var resourceId = $location.search()['rsrid'];
+
+            if (resourceId) {
+                newPolicy.config.resources = [resourceId];
+            }
+        },
+
+        onCreate : function() {
+            $scope.policy.config.resources = JSON.stringify($scope.policy.config.resources);
+            $scope.policy.config.applyPolicies = JSON.stringify($scope.policy.config.applyPolicies);
+        }
+    }, realm, client, $scope);
+});
+
+module.controller('ResourceServerPolicyScopeDetailCtrl', function($scope, $route, $location, realm, client, PolicyController, ResourceServerPolicy, ResourceServerResource, ResourceServerScope) {
+    PolicyController.onInit({
+        getPolicyType : function() {
+            return "scope";
+        },
+
+        isPermission : function() {
+            return true;
+        },
+
+        onInit : function() {
+            ResourceServerScope.query({realm : realm.realm, client : client.id}, function (data) {
+                $scope.scopes = data;
+            });
+
+            ResourceServerResource.query({realm : realm.realm, client : client.id}, function (data) {
+                $scope.resources = data;
+            });
+
+            ResourceServerPolicy.query({realm : realm.realm, client : client.id}, function (data) {
+                $scope.policies = [];
+
+                for (i = 0; i < data.length; i++) {
+                    if (data[i].type != 'resource' && data[i].type != 'scope') {
+                        $scope.policies.push(data[i]);
+                    }
+                }
+            });
+
+            $scope.resolveScopes = function(policy, keepScopes) {
+                if (!keepScopes) {
+                    policy.config.scopes = [];
+                }
+
+                if (!policy) {
+                    policy = $scope.policy;
+                }
+
+                if (policy.config.resources != null) {
+                    ResourceServerResource.get({
+                        realm : $route.current.params.realm,
+                        client : client.id,
+                        rsrid : policy.config.resources
+                    }, function(data) {
+                        $scope.scopes = data.scopes;
+                    });
+                } else {
+                    ResourceServerScope.query({realm : realm.realm, client : client.id}, function (data) {
+                        $scope.scopes = data;
+                    });
+                }
+            }
+        },
+
+        onInitUpdate : function(policy) {
+            if (policy.config.resources) {
+                policy.config.resources = eval(policy.config.resources);
+
+                if (policy.config.resources.length > 0) {
+                    policy.config.resources = policy.config.resources[0];
+                } else {
+                    policy.config.resources = null;
+                }
+            }
+
+            $scope.resolveScopes(policy, true);
+
+            policy.config.applyPolicies = eval(policy.config.applyPolicies);
+            policy.config.scopes = eval(policy.config.scopes);
+        },
+
+        onUpdate : function() {
+            if ($scope.policy.config.resources != null) {
+                var resources = undefined;
+
+                if ($scope.policy.config.resources.length != 0) {
+                    resources = JSON.stringify([$scope.policy.config.resources])
+                }
+
+                $scope.policy.config.resources = resources;
+            }
+
+            $scope.policy.config.scopes = JSON.stringify($scope.policy.config.scopes);
+            $scope.policy.config.applyPolicies = JSON.stringify($scope.policy.config.applyPolicies);
+        },
+
+        onInitCreate : function(newPolicy) {
+            newPolicy.decisionStrategy = 'UNANIMOUS';
+            newPolicy.config = {};
+            newPolicy.config.resources = '';
+
+            var scopeId = $location.search()['scpid'];
+
+            if (scopeId) {
+                newPolicy.config.scopes = [scopeId];
+            }
+        },
+
+        onCreate : function() {
+            if ($scope.policy.config.resources != null) {
+                var resources = undefined;
+
+                if ($scope.policy.config.resources.length != 0) {
+                    resources = JSON.stringify([$scope.policy.config.resources])
+                }
+
+                $scope.policy.config.resources = resources;
+            }
+            $scope.policy.config.scopes = JSON.stringify($scope.policy.config.scopes);
+            $scope.policy.config.applyPolicies = JSON.stringify($scope.policy.config.applyPolicies);
+        }
+    }, realm, client, $scope);
+});
+
+module.controller('ResourceServerPolicyUserDetailCtrl', function($scope, $route, realm, client, PolicyController, User) {
+    PolicyController.onInit({
+        getPolicyType : function() {
+            return "user";
+        },
+
+        onInit : function() {
+            $scope.usersUiSelect = {
+                minimumInputLength: 1,
+                delay: 500,
+                allowClear: true,
+                query: function (query) {
+                    var data = {results: []};
+                    if ('' == query.term.trim()) {
+                        query.callback(data);
+                        return;
+                    }
+                    User.query({realm: $route.current.params.realm, search: query.term.trim(), max: 20}, function(response) {
+                        data.results = response;
+                        query.callback(data);
+                    });
+                },
+                formatResult: function(object, container, query) {
+                    return object.username;
+                }
+            };
+
+            $scope.selectedUsers = [];
+
+            $scope.selectUser = function(user) {
+                if (!user || !user.id) {
+                    return;
+                }
+
+                $scope.selectedUser = null;
+
+                for (i = 0; i < $scope.selectedUsers.length; i++) {
+                    if ($scope.selectedUsers[i].id == user.id) {
+                        return;
+                    }
+                }
+
+                $scope.selectedUsers.push(user);
+            }
+
+            $scope.removeFromList = function(list, index) {
+                list.splice(index, 1);
+            }
+        },
+
+        onInitUpdate : function(policy) {
+            var selectedUsers = [];
+
+            if (policy.config.users) {
+                var users = eval(policy.config.users);
+
+                for (i = 0; i < users.length; i++) {
+                    User.get({realm: $route.current.params.realm, userId: users[i]}, function(data) {
+                        selectedUsers.push(data);
+                        $scope.selectedUsers = angular.copy(selectedUsers);
+                    });
+                }
+            }
+
+            $scope.$watch('selectedUsers', function() {
+                if (!angular.equals($scope.selectedUsers, selectedUsers)) {
+                    $scope.changed = true;
+                }
+            }, true);
+        },
+
+        onUpdate : function() {
+            var users = [];
+
+            for (i = 0; i < $scope.selectedUsers.length; i++) {
+                users.push($scope.selectedUsers[i].id);
+            }
+
+            $scope.policy.config.users = JSON.stringify(users);
+        },
+
+        onCreate : function() {
+            var users = [];
+
+            for (i = 0; i < $scope.selectedUsers.length; i++) {
+                users.push($scope.selectedUsers[i].id);
+            }
+
+            $scope.policy.config.users = JSON.stringify(users);
+        }
+    }, realm, client, $scope);
+});
+
+module.controller('ResourceServerPolicyRoleDetailCtrl', function($scope, $route, realm, client, Client, ClientRole, PolicyController, Role, RoleById) {
+    PolicyController.onInit({
+        getPolicyType : function() {
+            return "role";
+        },
+
+        onInit : function() {
+            Role.query({realm: $route.current.params.realm}, function(data) {
+                $scope.roles = data;
+            });
+
+            Client.query({realm: $route.current.params.realm}, function (data) {
+                $scope.clients = data;
+            });
+
+            $scope.selectedRoles = [];
+
+            $scope.selectRole = function(role) {
+                if (!role || !role.id) {
+                    return;
+                }
+
+                $scope.selectedRole = null;
+
+                for (i = 0; i < $scope.selectedRoles.length; i++) {
+                    if ($scope.selectedRoles[i].id == role.id) {
+                        return;
+                    }
+                }
+
+                $scope.selectedRoles.push(role);
+
+                var clientRoles = [];
+
+                if ($scope.clientRoles) {
+                    for (i = 0; i < $scope.clientRoles.length; i++) {
+                        if ($scope.clientRoles[i].id != role.id) {
+                            clientRoles.push($scope.clientRoles[i]);
+                        }
+                    }
+                    $scope.clientRoles = clientRoles;
+                }
+            }
+
+            $scope.removeFromList = function(role) {
+                if ($scope.clientRoles && $scope.selectedClient && $scope.selectedClient.id == role.containerId) {
+                    $scope.clientRoles.push(role);
+                }
+                var index = $scope.selectedRoles.indexOf(role);
+                if (index != -1) {
+                    $scope.selectedRoles.splice(index, 1);
+                }
+            }
+
+            $scope.selectClient = function() {
+                if (!$scope.selectedClient) {
+                    $scope.clientRoles = [];
+                    return;
+                }
+                ClientRole.query({realm: $route.current.params.realm, client: $scope.selectedClient.id}, function(data) {
+                    var roles = [];
+
+                    for (j = 0; j < data.length; j++) {
+                        var defined = false;
+
+                        for (i = 0; i < $scope.selectedRoles.length; i++) {
+                            if ($scope.selectedRoles[i].id == data[j].id) {
+                                defined = true;
+                                break;
+                            }
+                        }
+
+                        if (!defined) {
+                            data[j].container = {};
+                            data[j].container.name = $scope.selectedClient.clientId;
+                            roles.push(data[j]);
+                        }
+                    }
+                    $scope.clientRoles = roles;
+                });
+            }
+        },
+
+        onInitUpdate : function(policy) {
+            var selectedRoles = [];
+
+            if (policy.config.roles) {
+                var roles = eval(policy.config.roles);
+
+                for (i = 0; i < roles.length; i++) {
+                    RoleById.get({realm: $route.current.params.realm, role: roles[i].id}, function(data) {
+                        for (i = 0; i < roles.length; i++) {
+                            if (roles[i].id == data.id) {
+                                data.required = roles[i].required ? true : false;
+                            }
+                        }
+                        for (i = 0; i < $scope.clients.length; i++) {
+                            if ($scope.clients[i].id == data.containerId) {
+                                data.container = {};
+                                data.container.name = $scope.clients[i].clientId;
+                            }
+                        }
+                        selectedRoles.push(data);
+                        $scope.selectedRoles = angular.copy(selectedRoles);
+                    });
+                }
+            }
+
+            $scope.$watch('selectedRoles', function() {
+                if (!angular.equals($scope.selectedRoles, selectedRoles)) {
+                    $scope.changed = true;
+                }
+            }, true);
+        },
+
+        onUpdate : function() {
+            var roles = [];
+
+            for (i = 0; i < $scope.selectedRoles.length; i++) {
+                var role = {};
+                role.id = $scope.selectedRoles[i].id;
+                if ($scope.selectedRoles[i].required) {
+                    role.required = $scope.selectedRoles[i].required;
+                }
+                roles.push(role);
+            }
+
+            $scope.policy.config.roles = JSON.stringify(roles);
+        },
+
+        onCreate : function() {
+            var roles = [];
+
+            for (i = 0; i < $scope.selectedRoles.length; i++) {
+                var role = {};
+                role.id = $scope.selectedRoles[i].id;
+                if ($scope.selectedRoles[i].required) {
+                    role.required = $scope.selectedRoles[i].required;
+                }
+                roles.push(role);
+            }
+
+            $scope.policy.config.roles = JSON.stringify(roles);
+        }
+    }, realm, client, $scope);
+    
+    $scope.hasRealmRole = function () {
+        for (i = 0; i < $scope.selectedRoles.length; i++) {
+            if (!$scope.selectedRoles[i].clientRole) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    $scope.hasClientRole = function () {
+        for (i = 0; i < $scope.selectedRoles.length; i++) {
+            if ($scope.selectedRoles[i].clientRole) {
+                return true;
+            }
+        }
+        return false;
+    }
+});
+
+module.controller('ResourceServerPolicyJSDetailCtrl', function($scope, $route, $location, realm, PolicyController, client) {
+    PolicyController.onInit({
+        getPolicyType : function() {
+            return "js";
+        },
+
+        onInit : function() {
+            $scope.initEditor = function(editor){
+                var session = editor.getSession();
+
+                session.setMode('ace/mode/javascript');
+            };
+        },
+
+        onInitUpdate : function(policy) {
+
+        },
+
+        onUpdate : function() {
+
+        },
+
+        onInitCreate : function(newPolicy) {
+            newPolicy.config = {};
+        },
+
+        onCreate : function() {
+
+        }
+    }, realm, client, $scope);
+});
+
+module.controller('ResourceServerPolicyTimeDetailCtrl', function($scope, $route, $location, realm, PolicyController, client) {
+    PolicyController.onInit({
+        getPolicyType : function() {
+            return "time";
+        },
+
+        onInit : function() {
+        },
+
+        onInitUpdate : function(policy) {
+
+        },
+
+        onUpdate : function() {
+
+        },
+
+        onInitCreate : function(newPolicy) {
+            newPolicy.config.expirationTime = 1;
+            newPolicy.config.expirationUnit = 'Minutes';
+        },
+
+        onCreate : function() {
+
+        }
+    }, realm, client, $scope);
+});
+
+module.controller('ResourceServerPolicyAggregateDetailCtrl', function($scope, $route, $location, realm, PolicyController, ResourceServerPolicy, client) {
+    PolicyController.onInit({
+        getPolicyType : function() {
+            return "aggregate";
+        },
+
+        onInit : function() {
+            ResourceServerPolicy.query({realm : realm.realm, client : client.id}, function (data) {
+                $scope.policies = [];
+
+                for (i = 0; i < data.length; i++) {
+                    if (data[i].type != 'resource' && data[i].type != 'scope') {
+                        $scope.policies.push(data[i]);
+                    }
+                }
+            });
+        },
+
+        onInitUpdate : function(policy) {
+            policy.config.applyPolicies = eval(policy.config.applyPolicies);
+        },
+
+        onUpdate : function() {
+            $scope.policy.config.applyPolicies = JSON.stringify($scope.policy.config.applyPolicies);
+        },
+
+        onInitCreate : function(newPolicy) {
+            newPolicy.config = {};
+            newPolicy.decisionStrategy = 'UNANIMOUS';
+        },
+
+        onCreate : function() {
+            $scope.policy.config.applyPolicies = JSON.stringify($scope.policy.config.applyPolicies);
+        }
+    }, realm, client, $scope);
+});
+
+module.service("PolicyController", function($http, $route, $location, ResourceServer, ResourceServerPolicy, AuthzDialog, Notifications) {
+
+    var PolicyController = {};
+
+    PolicyController.onInit = function(delegate, realm, client, $scope) {
+        if (!delegate.isPermission) {
+            delegate.isPermission = function () {
+                return false;
+            }
+        }
+
+        $scope.realm = realm;
+        $scope.client = client;
+
+        $scope.decisionStrategies = ['AFFIRMATIVE', 'UNANIMOUS', 'CONSENSUS'];
+        $scope.logics = ['POSITIVE', 'NEGATIVE'];
+
+        delegate.onInit();
+
+        var $instance = this;
+
+        ResourceServer.get({
+            realm : $route.current.params.realm,
+            client : client.id
+        }, function(data) {
+            $scope.server = data;
+
+            var policyId = $route.current.params.id;
+
+            if (!policyId) {
+                $scope.create = true;
+                $scope.changed = false;
+
+                var policy = {};
+
+                policy.type = delegate.getPolicyType();
+                policy.config = {};
+                policy.logic = 'POSITIVE';
+
+                if (delegate.onInitCreate) {
+                    delegate.onInitCreate(policy);
+                }
+
+                $scope.policy = angular.copy(policy);
+
+                $scope.$watch('policy', function() {
+                    if (!angular.equals($scope.policy, policy)) {
+                        $scope.changed = true;
+                    }
+                }, true);
+
+                $scope.save = function() {
+                    $instance.checkNameAvailability(function () {
+                        if (delegate.onCreate) {
+                            delegate.onCreate();
+                        }
+                        ResourceServerPolicy.save({realm : realm.realm, client : client.id}, $scope.policy, function(data) {
+                            if (delegate.isPermission()) {
+                                $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/permission/" + $scope.policy.type + "/" + data.id);
+                                Notifications.success("The permission has been created.");
+                            } else {
+                                $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/policy/" + $scope.policy.type + "/" + data.id);
+                                Notifications.success("The policy has been created.");
+                            }
+                        });
+                    });
+                }
+
+                $scope.cancel = function() {
+                    if (delegate.isPermission()) {
+                        $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/permission/");
+                    } else {
+                        $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/policy/");
+                    }
+                }
+            } else {
+                ResourceServerPolicy.get({
+                    realm : $route.current.params.realm,
+                    client : client.id,
+                    id : $route.current.params.id,
+                }, function(data) {
+                    $scope.originalPolicy = data;
+                    var policy = angular.copy(data);
+
+                    if (delegate.onInitUpdate) {
+                        delegate.onInitUpdate(policy);
+                    }
+
+                    $scope.policy = angular.copy(policy);
+                    $scope.changed = false;
+
+                    $scope.$watch('policy', function() {
+                        if (!angular.equals($scope.policy, policy)) {
+                            $scope.changed = true;
+                        }
+                    }, true);
+
+                    $scope.save = function() {
+                        $instance.checkNameAvailability(function () {
+                            if (delegate.onUpdate) {
+                                delegate.onUpdate();
+                            }
+                            ResourceServerPolicy.update({realm : realm.realm, client : client.id, id : $scope.policy.id}, $scope.policy, function() {
+                                $route.reload();
+                                if (delegate.isPermission()) {
+                                    Notifications.success("The permission has been updated.");
+                                } else {
+                                    Notifications.success("The policy has been updated.");
+                                }
+                            });
+                        });
+                    }
+
+                    $scope.reset = function() {
+                        var freshPolicy = angular.copy(data);
+
+                        if (delegate.onInitUpdate) {
+                            delegate.onInitUpdate(freshPolicy);
+                        }
+
+                        $scope.policy = angular.copy(freshPolicy);
+                        $scope.changed = false;
+                    }
+                });
+
+                $scope.remove = function() {
+                    var msg = "";
+
+                    if ($scope.policy.dependentPolicies.length > 0) {
+                        msg = "<p>This policy is being used by other policies:</p>";
+                        msg += "<ul>";
+                        for (i = 0; i < $scope.policy.dependentPolicies.length; i++) {
+                            msg+= "<li><strong>" + $scope.policy.dependentPolicies[i].name + "</strong></li>";
+                        }
+                        msg += "</ul>";
+                        msg += "<p>If you remove this policy, the policies above will be affected and will not be associated with this policy anymore.</p>";
+                    }
+
+                    AuthzDialog.confirmDeleteWithMsg($scope.policy.name, "Policy", msg, function() {
+                        ResourceServerPolicy.delete({realm : $scope.realm.realm, client : $scope.client.id, id : $scope.policy.id}, null, function() {
+                            if (delegate.isPermission()) {
+                                $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/permission");
+                                Notifications.success("The permission has been deleted.");
+                            } else {
+                                $location.url("/realms/" + realm.realm + "/clients/" + client.id + "/authz/resource-server/policy");
+                                Notifications.success("The policy has been deleted.");
+                            }
+                        });
+                    });
+                }
+            }
+        });
+
+        $scope.checkNewNameAvailability = function () {
+            $instance.checkNameAvailability(function () {});
+        }
+
+        this.checkNameAvailability = function (onSuccess) {
+            ResourceServerPolicy.search({
+                realm: $route.current.params.realm,
+                client: client.id,
+                name: $scope.policy.name
+            }, function(data) {
+                if (data && data.id && data.id != $scope.policy.id) {
+                    Notifications.error("Name already in use by another policy or permission, please choose another one.");
+                } else {
+                    onSuccess();
+                }
+            });
+        }
+    }
+
+    return PolicyController;
+});
+
+module.controller('PolicyEvaluateCtrl', function($scope, $http, $route, $location, realm, clients, roles, ResourceServer, client, ResourceServerResource, ResourceServerScope, User, Notifications) {
+    $scope.realm = realm;
+    $scope.client = client;
+    $scope.clients = clients;
+    $scope.roles = roles;
+    $scope.authzRequest = {};
+    $scope.authzRequest.resources = [];
+    $scope.authzRequest.context = {};
+    $scope.authzRequest.context.attributes = {};
+    $scope.authzRequest.roleIds = [];
+    $scope.newResource = {};
+    $scope.resultUrl = resourceUrl + '/partials/authz/policy/resource-server-policy-evaluate-result.html';
+
+    ResourceServerScope.query({realm : realm.realm, client : client.id}, function (data) {
+        $scope.scopes = data;
+    });
+
+    $scope.addContextAttribute = function() {
+        if (!$scope.newContextAttribute.value || $scope.newContextAttribute.value == '') {
+            Notifications.error("You must provide a value to a context attribute.");
+            return;
+        }
+
+        $scope.authzRequest.context.attributes[$scope.newContextAttribute.key] = $scope.newContextAttribute.value;
+        delete $scope.newContextAttribute;
+    }
+
+    $scope.removeContextAttribute = function(key) {
+        delete $scope.authzRequest.context.attributes[key];
+    }
+
+    $scope.getContextAttribute = function(key) {
+        for (i = 0; i < $scope.defaultContextAttributes.length; i++) {
+            if ($scope.defaultContextAttributes[i].key == key) {
+                return $scope.defaultContextAttributes[i];
+            }
+        }
+
+        return $scope.authzRequest.context.attributes[key];
+    }
+
+    $scope.getContextAttributeName = function(key) {
+        var attribute = $scope.getContextAttribute(key);
+
+        if (!attribute.name) {
+            return key;
+        }
+
+        return attribute.name;
+    }
+
+    $scope.defaultContextAttributes = [
+        {
+            key : "custom",
+            name : "Custom Attribute...",
+            custom: true
+        },
+        {
+            key : "kc.identity.authc.method",
+            name : "Authentication Method",
+            values: [
+                {
+                    key : "pwd",
+                    name : "Password"
+                },
+                {
+                    key : "otp",
+                    name : "One-Time Password"
+                },
+                {
+                    key : "kbr",
+                    name : "Kerberos"
+                }
+            ]
+        },
+        {
+            key : "kc.realm.name",
+            name : "Realm"
+        },
+        {
+            key : "kc.time.date_time",
+            name : "Date/Time (MM/dd/yyyy hh:mm:ss)"
+        },
+        {
+            key : "kc.client.network.ip_address",
+            name : "Client IPv4 Address"
+        },
+        {
+            key : "kc.client.network.host",
+            name : "Client Host"
+        },
+        {
+            key : "kc.client.user_agent",
+            name : "Client/User Agent"
+        }
+    ];
+
+    $scope.isDefaultContextAttribute = function() {
+        if (!$scope.newContextAttribute) {
+            return true;
+        }
+
+        if ($scope.newContextAttribute.custom) {
+            return false;
+        }
+
+        if (!$scope.getContextAttribute($scope.newContextAttribute.key).custom) {
+            return true;
+        }
+
+        return false;
+    }
+
+    $scope.selectDefaultContextAttribute = function() {
+        $scope.newContextAttribute = angular.copy($scope.newContextAttribute);
+    }
+
+    $scope.setApplyToResourceType = function() {
+        if ($scope.applyResourceType) {
+            ResourceServerScope.query({realm : realm.realm, client : client.id}, function (data) {
+                $scope.scopes = data;
+            });
+        }
+
+        delete $scope.newResource;
+        $scope.authzRequest.resources = [];
+    }
+
+    $scope.addResource = function() {
+        var resource = {};
+
+        resource.id = $scope.newResource._id;
+
+        for (i = 0; i < $scope.resources.length; i++) {
+            if ($scope.resources[i]._id == resource.id) {
+                resource.name = $scope.resources[i].name;
+                break;
+            }
+        }
+
+        resource.scopes = $scope.newResource.scopes;
+
+        $scope.authzRequest.resources.push(resource);
+
+        delete $scope.newResource;
+    }
+
+    $scope.removeResource = function(index) {
+        $scope.authzRequest.resources.splice(index, 1);
+    }
+
+    $scope.resolveScopes = function() {
+        if ($scope.newResource._id) {
+            $scope.newResource.scopes = [];
+            $scope.scopes = [];
+            ResourceServerResource.get({
+                realm: $route.current.params.realm,
+                client : client.id,
+                rsrid: $scope.newResource._id
+            }, function (data) {
+                $scope.scopes = data.scopes;
+                if (data.typedScopes) {
+                    for (i=0;i<data.typedScopes.length;i++) {
+                        $scope.scopes.push(data.typedScopes[i]);
+                    }
+                }
+            });
+        } else {
+            ResourceServerScope.query({realm : realm.realm, client : client.id}, function (data) {
+                $scope.scopes = data;
+            });
+        }
+    }
+
+    $scope.reevaluate = function() {
+        if ($scope.authzRequest.entitlements) {
+            $scope.entitlements();
+        } else {
+            $scope.save();
+        }
+    }
+
+    $scope.showAuthzData = function() {
+        $scope.showRpt = true;
+    }
+
+    $scope.save = function() {
+        $scope.authzRequest.entitlements = false;
+        if ($scope.applyResourceType) {
+            if (!$scope.newResource) {
+                $scope.newResource = {};
+            }
+            $scope.authzRequest.resources[0].scopes = $scope.newResource.scopes;
+        }
+
+        $http.post(authUrl + '/admin/realms/'+ $route.current.params.realm + '/clients/' + client.id + '/authz/resource-server/policy/evaluate'
+                , $scope.authzRequest).success(function(data) {
+                    $scope.evaluationResult = data;
+                    $scope.showResultTab();
+                });
+    }
+
+    $scope.entitlements = function() {
+        $scope.authzRequest.entitlements = true;
+        $http.post(authUrl + '/admin/realms/'+ $route.current.params.realm + '/clients/' + client.id + '/authz/resource-server/policy/evaluate'
+            , $scope.authzRequest).success(function(data) {
+            $scope.evaluationResult = data;
+            $scope.showResultTab();
+        });
+    }
+
+    $scope.showResultTab = function() {
+        $scope.showResult = true;
+        $scope.showRpt = false;
+    }
+
+    $scope.showRequestTab = function() {
+        $scope.showResult = false;
+        $scope.showRpt = false;
+    }
+
+    $scope.usersUiSelect = {
+        minimumInputLength: 1,
+        delay: 500,
+        allowClear: true,
+        query: function (query) {
+            var data = {results: []};
+            if ('' == query.term.trim()) {
+                query.callback(data);
+                return;
+            }
+            User.query({realm: $route.current.params.realm, search: query.term.trim(), max: 20}, function(response) {
+                data.results = response;
+                query.callback(data);
+            });
+        },
+        formatResult: function(object, container, query) {
+            object.text = object.username;
+            return object.username;
+        }
+    };
+
+    ResourceServerResource.query({realm : realm.realm, client : client.id}, function (data) {
+        $scope.resources = data;
+    });
+
+    ResourceServer.get({
+        realm : $route.current.params.realm,
+        client : client.id
+    }, function(data) {
+        $scope.server = data;
+    });
+
+    $scope.selectUser = function(user) {
+        if (!user || !user.id) {
+            $scope.selectedUser = null;
+            $scope.authzRequest.userId = '';
+            return;
+        }
+
+        $scope.authzRequest.userId = user.id;
+    }
+
+});
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-services.js b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-services.js
new file mode 100644
index 0000000..795cf1d
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/js/authz/authz-services.js
@@ -0,0 +1,121 @@
+module.factory('ResourceServer', function($resource) {
+    return $resource(authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server', {
+        realm : '@realm',
+        client: '@client'
+    }, {
+        'update' : {method : 'PUT'},
+        'import' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/import', method : 'POST'},
+        'settings' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/settings', method : 'GET'}
+    });
+});
+
+module.factory('ResourceServerResource', function($resource) {
+    return $resource(authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/resource/:rsrid', {
+        realm : '@realm',
+        client: '@client',
+        rsrid : '@rsrid'
+    }, {
+        'update' : {method : 'PUT'},
+        'search' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/resource/search', method : 'GET'}
+    });
+});
+
+module.factory('ResourceServerScope', function($resource) {
+    return $resource(authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/scope/:id', {
+        realm : '@realm',
+        client: '@client',
+        id : '@id'
+    }, {
+        'update' : {method : 'PUT'},
+        'search' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/scope/search', method : 'GET'}
+    });
+});
+
+module.factory('ResourceServerPolicy', function($resource) {
+    return $resource(authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/policy/:id', {
+        realm : '@realm',
+        client: '@client',
+        id : '@id'
+    }, {
+        'update' : {method : 'PUT'},
+        'search' : {url: authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/policy/search', method : 'GET'}
+    });
+});
+
+module.factory('PolicyProvider', function($resource) {
+    return $resource(authUrl + '/admin/realms/:realm/clients/:client/authz/resource-server/policy/providers', {
+        realm : '@realm',
+        client: '@client'
+    });
+});
+
+module.service('AuthzDialog', function($modal) {
+    var dialog = {};
+
+    var openDialog = function(title, message, btns, template) {
+        var controller = function($scope, $modalInstance, $sce, title, message, btns) {
+            $scope.title = title;
+            $scope.message = $sce.trustAsHtml(message);
+            $scope.btns = btns;
+
+            $scope.ok = function () {
+                $modalInstance.close();
+            };
+            $scope.cancel = function () {
+                $modalInstance.dismiss('cancel');
+            };
+        };
+
+        return $modal.open({
+            templateUrl: resourceUrl + template,
+            controller: controller,
+            resolve: {
+                title: function() {
+                    return title;
+                },
+                message: function() {
+                    return message;
+                },
+                btns: function() {
+                    return btns;
+                }
+            }
+        }).result;
+    }
+
+    dialog.confirmDeleteWithMsg = function(name, type, msg, success) {
+        var title = 'Delete ' + type;
+        msg += 'Are you sure you want to permanently delete the ' + type + ' <strong>' + name + '</strong> ?';
+        var btns = {
+            ok: {
+                label: 'Delete',
+                cssClass: 'btn btn-danger'
+            },
+            cancel: {
+                label: 'Cancel',
+                cssClass: 'btn btn-default'
+            }
+        }
+
+        openDialog(title, msg, btns, '/templates/authz/kc-authz-modal.html').then(success);
+    };
+
+    dialog.confirmDelete = function(name, type, success) {
+        var title = 'Delete ' + type;
+        var msg = 'Are you sure you want to permanently delete the ' + type + ' <strong>' + name + '</strong> ?';
+        var btns = {
+            ok: {
+                label: 'Delete',
+                cssClass: 'btn btn-danger'
+            },
+            cancel: {
+                label: 'Cancel',
+                cssClass: 'btn btn-default'
+            }
+        }
+
+        openDialog(title, msg, btns, '/templates/authz/kc-authz-modal.html').then(success);
+    }
+
+    return dialog;
+});
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/authz/lib/ace/ace.js b/themes/src/main/resources/theme/base/admin/resources/js/authz/lib/ace/ace.js
new file mode 100644
index 0000000..e099651
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/js/authz/lib/ace/ace.js
@@ -0,0 +1,11 @@
+(function(){function o(n){var i=e;n&&(e[n]||(e[n]={}),i=e[n]);if(!i.define||!i.define.packaged)t.original=i.define,i.define=t,i.define.packaged=!0;if(!i.require||!i.require.packaged)r.original=i.require,i.require=r,i.require.packaged=!0}var ACE_NAMESPACE="",e=function(){return this}();!e&&typeof window!="undefined"&&(e=window);if(!ACE_NAMESPACE&&typeof requirejs!="undefined")return;var t=function(e,n,r){if(typeof e!="string"){t.original?t.original.apply(this,arguments):(console.error("dropping module because define wasn't a string."),console.trace());return}arguments.length==2&&(r=n),t.modules[e]||(t.payloads[e]=r,t.modules[e]=null)};t.modules={},t.payloads={};var n=function(e,t,n){if(typeof t=="string"){var i=s(e,t);if(i!=undefined)return n&&n(),i}else if(Object.prototype.toString.call(t)==="[object Array]"){var o=[];for(var u=0,a=t.length;u<a;++u){var f=s(e,t[u]);if(f==undefined&&r.original)return;o.push(f)}return n&&n.apply(null,o)||!0}},r=function(e,t){var i=n("",e,t);return i==undefined&&r.original?r.original.apply(this,arguments):i},i=function(e,t){if(t.indexOf("!")!==-1){var n=t.split("!");return i(e,n[0])+"!"+i(e,n[1])}if(t.charAt(0)=="."){var r=e.split("/").slice(0,-1).join("/");t=r+"/"+t;while(t.indexOf(".")!==-1&&s!=t){var s=t;t=t.replace(/\/\.\//,"/").replace(/[^\/]+\/\.\.\//,"")}}return t},s=function(e,r){r=i(e,r);var s=t.modules[r];if(!s){s=t.payloads[r];if(typeof s=="function"){var o={},u={id:r,uri:"",exports:o,packaged:!0},a=function(e,t){return n(r,e,t)},f=s(a,o,u);o=f||u.exports,t.modules[r]=o,delete t.payloads[r]}s=t.modules[r]=o||s}return s};o(ACE_NAMESPACE)})(),define("ace/lib/regexp",["require","exports","module"],function(e,t,n){"use strict";function o(e){return(e.global?"g":"")+(e.ignoreCase?"i":"")+(e.multiline?"m":"")+(e.extended?"x":"")+(e.sticky?"y":"")}function u(e,t,n){if(Array.prototype.indexOf)return e.indexOf(t,n);for(var r=n||0;r<e.length;r++)if(e[r]===t)return r;return-1}var r={exec:RegExp.prototype.exec,test:RegExp.prototype.test,match:String.prototype.match,replace:String.prototype.replace,split:String.prototype.split},i=r.exec.call(/()??/,"")[1]===undefined,s=function(){var e=/^/g;return r.test.call(e,""),!e.lastIndex}();if(s&&i)return;RegExp.prototype.exec=function(e){var t=r.exec.apply(this,arguments),n,a;if(typeof e=="string"&&t){!i&&t.length>1&&u(t,"")>-1&&(a=RegExp(this.source,r.replace.call(o(this),"g","")),r.replace.call(e.slice(t.index),a,function(){for(var e=1;e<arguments.length-2;e++)arguments[e]===undefined&&(t[e]=undefined)}));if(this._xregexp&&this._xregexp.captureNames)for(var f=1;f<t.length;f++)n=this._xregexp.captureNames[f-1],n&&(t[n]=t[f]);!s&&this.global&&!t[0].length&&this.lastIndex>t.index&&this.lastIndex--}return t},s||(RegExp.prototype.test=function(e){var t=r.exec.call(this,e);return t&&this.global&&!t[0].length&&this.lastIndex>t.index&&this.lastIndex--,!!t})}),define("ace/lib/es5-shim",["require","exports","module"],function(e,t,n){function r(){}function w(e){try{return Object.defineProperty(e,"sentinel",{}),"sentinel"in e}catch(t){}}function H(e){return e=+e,e!==e?e=0:e!==0&&e!==1/0&&e!==-1/0&&(e=(e>0||-1)*Math.floor(Math.abs(e))),e}function B(e){var t=typeof e;return e===null||t==="undefined"||t==="boolean"||t==="number"||t==="string"}function j(e){var t,n,r;if(B(e))return e;n=e.valueOf;if(typeof n=="function"){t=n.call(e);if(B(t))return t}r=e.toString;if(typeof r=="function"){t=r.call(e);if(B(t))return t}throw new TypeError}Function.prototype.bind||(Function.prototype.bind=function(t){var n=this;if(typeof n!="function")throw new TypeError("Function.prototype.bind called on incompatible "+n);var i=u.call(arguments,1),s=function(){if(this instanceof s){var e=n.apply(this,i.concat(u.call(arguments)));return Object(e)===e?e:this}return n.apply(t,i.concat(u.call(arguments)))};return n.prototype&&(r.prototype=n.prototype,s.prototype=new r,r.prototype=null),s});var i=Function.prototype.call,s=Array.prototype,o=Object.prototype,u=s.slice,a=i.bind(o.toString),f=i.bind(o.hasOwnProperty),l,c,h,p,d;if(d=f(o,"__defineGetter__"))l=i.bind(o.__defineGetter__),c=i.bind(o.__defineSetter__),h=i.bind(o.__lookupGetter__),p=i.bind(o.__lookupSetter__);if([1,2].splice(0).length!=2)if(!function(){function e(e){var t=new Array(e+2);return t[0]=t[1]=0,t}var t=[],n;t.splice.apply(t,e(20)),t.splice.apply(t,e(26)),n=t.length,t.splice(5,0,"XXX"),n+1==t.length;if(n+1==t.length)return!0}())Array.prototype.splice=function(e,t){var n=this.length;e>0?e>n&&(e=n):e==void 0?e=0:e<0&&(e=Math.max(n+e,0)),e+t<n||(t=n-e);var r=this.slice(e,e+t),i=u.call(arguments,2),s=i.length;if(e===n)s&&this.push.apply(this,i);else{var o=Math.min(t,n-e),a=e+o,f=a+s-o,l=n-a,c=n-o;if(f<a)for(var h=0;h<l;++h)this[f+h]=this[a+h];else if(f>a)for(h=l;h--;)this[f+h]=this[a+h];if(s&&e===c)this.length=c,this.push.apply(this,i);else{this.length=c+s;for(h=0;h<s;++h)this[e+h]=i[h]}}return r};else{var v=Array.prototype.splice;Array.prototype.splice=function(e,t){return arguments.length?v.apply(this,[e===void 0?0:e,t===void 0?this.length-e:t].concat(u.call(arguments,2))):[]}}Array.isArray||(Array.isArray=function(t){return a(t)=="[object Array]"});var m=Object("a"),g=m[0]!="a"||!(0 in m);Array.prototype.forEach||(Array.prototype.forEach=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=arguments[1],s=-1,o=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError;while(++s<o)s in r&&t.call(i,r[s],s,n)}),Array.prototype.map||(Array.prototype.map=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=Array(i),o=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var u=0;u<i;u++)u in r&&(s[u]=t.call(o,r[u],u,n));return s}),Array.prototype.filter||(Array.prototype.filter=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=[],o,u=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var f=0;f<i;f++)f in r&&(o=r[f],t.call(u,o,f,n)&&s.push(o));return s}),Array.prototype.every||(Array.prototype.every=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&!t.call(s,r[o],o,n))return!1;return!0}),Array.prototype.some||(Array.prototype.some=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&t.call(s,r[o],o,n))return!0;return!1}),Array.prototype.reduce||(Array.prototype.reduce=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduce of empty array with no initial value");var s=0,o;if(arguments.length>=2)o=arguments[1];else do{if(s in r){o=r[s++];break}if(++s>=i)throw new TypeError("reduce of empty array with no initial value")}while(!0);for(;s<i;s++)s in r&&(o=t.call(void 0,o,r[s],s,n));return o}),Array.prototype.reduceRight||(Array.prototype.reduceRight=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduceRight of empty array with no initial value");var s,o=i-1;if(arguments.length>=2)s=arguments[1];else do{if(o in r){s=r[o--];break}if(--o<0)throw new TypeError("reduceRight of empty array with no initial value")}while(!0);do o in this&&(s=t.call(void 0,s,r[o],o,n));while(o--);return s});if(!Array.prototype.indexOf||[0,1].indexOf(1,2)!=-1)Array.prototype.indexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=0;arguments.length>1&&(i=H(arguments[1])),i=i>=0?i:Math.max(0,r+i);for(;i<r;i++)if(i in n&&n[i]===t)return i;return-1};if(!Array.prototype.lastIndexOf||[0,1].lastIndexOf(0,-3)!=-1)Array.prototype.lastIndexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=r-1;arguments.length>1&&(i=Math.min(i,H(arguments[1]))),i=i>=0?i:r-Math.abs(i);for(;i>=0;i--)if(i in n&&t===n[i])return i;return-1};Object.getPrototypeOf||(Object.getPrototypeOf=function(t){return t.__proto__||(t.constructor?t.constructor.prototype:o)});if(!Object.getOwnPropertyDescriptor){var y="Object.getOwnPropertyDescriptor called on a non-object: ";Object.getOwnPropertyDescriptor=function(t,n){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(y+t);if(!f(t,n))return;var r,i,s;r={enumerable:!0,configurable:!0};if(d){var u=t.__proto__;t.__proto__=o;var i=h(t,n),s=p(t,n);t.__proto__=u;if(i||s)return i&&(r.get=i),s&&(r.set=s),r}return r.value=t[n],r}}Object.getOwnPropertyNames||(Object.getOwnPropertyNames=function(t){return Object.keys(t)});if(!Object.create){var b;Object.prototype.__proto__===null?b=function(){return{__proto__:null}}:b=function(){var e={};for(var t in e)e[t]=null;return e.constructor=e.hasOwnProperty=e.propertyIsEnumerable=e.isPrototypeOf=e.toLocaleString=e.toString=e.valueOf=e.__proto__=null,e},Object.create=function(t,n){var r;if(t===null)r=b();else{if(typeof t!="object")throw new TypeError("typeof prototype["+typeof t+"] != 'object'");var i=function(){};i.prototype=t,r=new i,r.__proto__=t}return n!==void 0&&Object.defineProperties(r,n),r}}if(Object.defineProperty){var E=w({}),S=typeof document=="undefined"||w(document.createElement("div"));if(!E||!S)var x=Object.defineProperty}if(!Object.defineProperty||x){var T="Property description must be an object: ",N="Object.defineProperty called on non-object: ",C="getters & setters can not be defined on this javascript engine";Object.defineProperty=function(t,n,r){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(N+t);if(typeof r!="object"&&typeof r!="function"||r===null)throw new TypeError(T+r);if(x)try{return x.call(Object,t,n,r)}catch(i){}if(f(r,"value"))if(d&&(h(t,n)||p(t,n))){var s=t.__proto__;t.__proto__=o,delete t[n],t[n]=r.value,t.__proto__=s}else t[n]=r.value;else{if(!d)throw new TypeError(C);f(r,"get")&&l(t,n,r.get),f(r,"set")&&c(t,n,r.set)}return t}}Object.defineProperties||(Object.defineProperties=function(t,n){for(var r in n)f(n,r)&&Object.defineProperty(t,r,n[r]);return t}),Object.seal||(Object.seal=function(t){return t}),Object.freeze||(Object.freeze=function(t){return t});try{Object.freeze(function(){})}catch(k){Object.freeze=function(t){return function(n){return typeof n=="function"?n:t(n)}}(Object.freeze)}Object.preventExtensions||(Object.preventExtensions=function(t){return t}),Object.isSealed||(Object.isSealed=function(t){return!1}),Object.isFrozen||(Object.isFrozen=function(t){return!1}),Object.isExtensible||(Object.isExtensible=function(t){if(Object(t)===t)throw new TypeError;var n="";while(f(t,n))n+="?";t[n]=!0;var r=f(t,n);return delete t[n],r});if(!Object.keys){var L=!0,A=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],O=A.length;for(var M in{toString:null})L=!1;Object.keys=function I(e){if(typeof e!="object"&&typeof e!="function"||e===null)throw new TypeError("Object.keys called on a non-object");var I=[];for(var t in e)f(e,t)&&I.push(t);if(L)for(var n=0,r=O;n<r;n++){var i=A[n];f(e,i)&&I.push(i)}return I}}Date.now||(Date.now=function(){return(new Date).getTime()});var _="	\n\f\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\ufeff";if(!String.prototype.trim||_.trim()){_="["+_+"]";var D=new RegExp("^"+_+_+"*"),P=new RegExp(_+_+"*$");String.prototype.trim=function(){return String(this).replace(D,"").replace(P,"")}}var F=function(e){if(e==null)throw new TypeError("can't convert "+e+" to object");return Object(e)}}),define("ace/lib/fixoldbrowsers",["require","exports","module","ace/lib/regexp","ace/lib/es5-shim"],function(e,t,n){"use strict";e("./regexp"),e("./es5-shim")}),define("ace/lib/dom",["require","exports","module"],function(e,t,n){"use strict";var r="http://www.w3.org/1999/xhtml";t.getDocumentHead=function(e){return e||(e=document),e.head||e.getElementsByTagName("head")[0]||e.documentElement},t.createElement=function(e,t){return document.createElementNS?document.createElementNS(t||r,e):document.createElement(e)},t.hasCssClass=function(e,t){var n=(e.className||"").split(/\s+/g);return n.indexOf(t)!==-1},t.addCssClass=function(e,n){t.hasCssClass(e,n)||(e.className+=" "+n)},t.removeCssClass=function(e,t){var n=e.className.split(/\s+/g);for(;;){var r=n.indexOf(t);if(r==-1)break;n.splice(r,1)}e.className=n.join(" ")},t.toggleCssClass=function(e,t){var n=e.className.split(/\s+/g),r=!0;for(;;){var i=n.indexOf(t);if(i==-1)break;r=!1,n.splice(i,1)}return r&&n.push(t),e.className=n.join(" "),r},t.setCssClass=function(e,n,r){r?t.addCssClass(e,n):t.removeCssClass(e,n)},t.hasCssString=function(e,t){var n=0,r;t=t||document;if(t.createStyleSheet&&(r=t.styleSheets)){while(n<r.length)if(r[n++].owningElement.id===e)return!0}else if(r=t.getElementsByTagName("style"))while(n<r.length)if(r[n++].id===e)return!0;return!1},t.importCssString=function(n,r,i){i=i||document;if(r&&t.hasCssString(r,i))return null;var s;r&&(n+="\n/*# sourceURL=ace/css/"+r+" */"),i.createStyleSheet?(s=i.createStyleSheet(),s.cssText=n,r&&(s.owningElement.id=r)):(s=t.createElement("style"),s.appendChild(i.createTextNode(n)),r&&(s.id=r),t.getDocumentHead(i).appendChild(s))},t.importCssStylsheet=function(e,n){if(n.createStyleSheet)n.createStyleSheet(e);else{var r=t.createElement("link");r.rel="stylesheet",r.href=e,t.getDocumentHead(n).appendChild(r)}},t.getInnerWidth=function(e){return parseInt(t.computedStyle(e,"paddingLeft"),10)+parseInt(t.computedStyle(e,"paddingRight"),10)+e.clientWidth},t.getInnerHeight=function(e){return parseInt(t.computedStyle(e,"paddingTop"),10)+parseInt(t.computedStyle(e,"paddingBottom"),10)+e.clientHeight},t.scrollbarWidth=function(e){var n=t.createElement("ace_inner");n.style.width="100%",n.style.minWidth="0px",n.style.height="200px",n.style.display="block";var r=t.createElement("ace_outer"),i=r.style;i.position="absolute",i.left="-10000px",i.overflow="hidden",i.width="200px",i.minWidth="0px",i.height="150px",i.display="block",r.appendChild(n);var s=e.documentElement;s.appendChild(r);var o=n.offsetWidth;i.overflow="scroll";var u=n.offsetWidth;return o==u&&(u=r.clientWidth),s.removeChild(r),o-u};if(typeof document=="undefined"){t.importCssString=function(){};return}window.pageYOffset!==undefined?(t.getPageScrollTop=function(){return window.pageYOffset},t.getPageScrollLeft=function(){return window.pageXOffset}):(t.getPageScrollTop=function(){return document.body.scrollTop},t.getPageScrollLeft=function(){return document.body.scrollLeft}),window.getComputedStyle?t.computedStyle=function(e,t){return t?(window.getComputedStyle(e,"")||{})[t]||"":window.getComputedStyle(e,"")||{}}:t.computedStyle=function(e,t){return t?e.currentStyle[t]:e.currentStyle},t.setInnerHtml=function(e,t){var n=e.cloneNode(!1);return n.innerHTML=t,e.parentNode.replaceChild(n,e),n},"textContent"in document.documentElement?(t.setInnerText=function(e,t){e.textContent=t},t.getInnerText=function(e){return e.textContent}):(t.setInnerText=function(e,t){e.innerText=t},t.getInnerText=function(e){return e.innerText}),t.getParentWindow=function(e){return e.defaultView||e.parentWindow}}),define("ace/lib/oop",["require","exports","module"],function(e,t,n){"use strict";t.inherits=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})},t.mixin=function(e,t){for(var n in t)e[n]=t[n];return e},t.implement=function(e,n){t.mixin(e,n)}}),define("ace/lib/keys",["require","exports","module","ace/lib/fixoldbrowsers","ace/lib/oop"],function(e,t,n){"use strict";e("./fixoldbrowsers");var r=e("./oop"),i=function(){var e={MODIFIER_KEYS:{16:"Shift",17:"Ctrl",18:"Alt",224:"Meta"},KEY_MODS:{ctrl:1,alt:2,option:2,shift:4,"super":8,meta:8,command:8,cmd:8},FUNCTION_KEYS:{8:"Backspace",9:"Tab",13:"Return",19:"Pause",27:"Esc",32:"Space",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"Left",38:"Up",39:"Right",40:"Down",44:"Print",45:"Insert",46:"Delete",96:"Numpad0",97:"Numpad1",98:"Numpad2",99:"Numpad3",100:"Numpad4",101:"Numpad5",102:"Numpad6",103:"Numpad7",104:"Numpad8",105:"Numpad9","-13":"NumpadEnter",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"Numlock",145:"Scrolllock"},PRINTABLE_KEYS:{32:" ",48:"0",49:"1",50:"2",51:"3",52:"4",53:"5",54:"6",55:"7",56:"8",57:"9",59:";",61:"=",65:"a",66:"b",67:"c",68:"d",69:"e",70:"f",71:"g",72:"h",73:"i",74:"j",75:"k",76:"l",77:"m",78:"n",79:"o",80:"p",81:"q",82:"r",83:"s",84:"t",85:"u",86:"v",87:"w",88:"x",89:"y",90:"z",107:"+",109:"-",110:".",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'",111:"/",106:"*"}},t,n;for(n in e.FUNCTION_KEYS)t=e.FUNCTION_KEYS[n].toLowerCase(),e[t]=parseInt(n,10);for(n in e.PRINTABLE_KEYS)t=e.PRINTABLE_KEYS[n].toLowerCase(),e[t]=parseInt(n,10);return r.mixin(e,e.MODIFIER_KEYS),r.mixin(e,e.PRINTABLE_KEYS),r.mixin(e,e.FUNCTION_KEYS),e.enter=e["return"],e.escape=e.esc,e.del=e["delete"],e[173]="-",function(){var t=["cmd","ctrl","alt","shift"];for(var n=Math.pow(2,t.length);n--;)e.KEY_MODS[n]=t.filter(function(t){return n&e.KEY_MODS[t]}).join("-")+"-"}(),e.KEY_MODS[0]="",e.KEY_MODS[-1]="input-",e}();r.mixin(t,i),t.keyCodeToString=function(e){var t=i[e];return typeof t!="string"&&(t=String.fromCharCode(e)),t.toLowerCase()}}),define("ace/lib/useragent",["require","exports","module"],function(e,t,n){"use strict";t.OS={LINUX:"LINUX",MAC:"MAC",WINDOWS:"WINDOWS"},t.getOS=function(){return t.isMac?t.OS.MAC:t.isLinux?t.OS.LINUX:t.OS.WINDOWS};if(typeof navigator!="object")return;var r=(navigator.platform.match(/mac|win|linux/i)||["other"])[0].toLowerCase(),i=navigator.userAgent;t.isWin=r=="win",t.isMac=r=="mac",t.isLinux=r=="linux",t.isIE=navigator.appName=="Microsoft Internet Explorer"||navigator.appName.indexOf("MSAppHost")>=0?parseFloat((i.match(/(?:MSIE |Trident\/[0-9]+[\.0-9]+;.*rv:)([0-9]+[\.0-9]+)/)||[])[1]):parseFloat((i.match(/(?:Trident\/[0-9]+[\.0-9]+;.*rv:)([0-9]+[\.0-9]+)/)||[])[1]),t.isOldIE=t.isIE&&t.isIE<9,t.isGecko=t.isMozilla=(window.Controllers||window.controllers)&&window.navigator.product==="Gecko",t.isOldGecko=t.isGecko&&parseInt((i.match(/rv\:(\d+)/)||[])[1],10)<4,t.isOpera=window.opera&&Object.prototype.toString.call(window.opera)=="[object Opera]",t.isWebKit=parseFloat(i.split("WebKit/")[1])||undefined,t.isChrome=parseFloat(i.split(" Chrome/")[1])||undefined,t.isAIR=i.indexOf("AdobeAIR")>=0,t.isIPad=i.indexOf("iPad")>=0,t.isTouchPad=i.indexOf("TouchPad")>=0,t.isChromeOS=i.indexOf(" CrOS ")>=0}),define("ace/lib/event",["require","exports","module","ace/lib/keys","ace/lib/useragent"],function(e,t,n){"use strict";function a(e,t,n){var a=u(t);if(!i.isMac&&s){s.OSKey&&(a|=8);if(s.altGr){if((3&a)==3)return;s.altGr=0}if(n===18||n===17){var f="location"in t?t.location:t.keyLocation;if(n===17&&f===1)s[n]==1&&(o=t.timeStamp);else if(n===18&&a===3&&f===2){var l=t.timeStamp-o;l<50&&(s.altGr=!0)}}}n in r.MODIFIER_KEYS&&(n=-1),a&8&&n>=91&&n<=93&&(n=-1);if(!a&&n===13){var f="location"in t?t.location:t.keyLocation;if(f===3){e(t,a,-n);if(t.defaultPrevented)return}}if(i.isChromeOS&&a&8){e(t,a,n);if(t.defaultPrevented)return;a&=-9}return!!a||n in r.FUNCTION_KEYS||n in r.PRINTABLE_KEYS?e(t,a,n):!1}function f(){s=Object.create(null),s.count=0,s.lastT=0}var r=e("./keys"),i=e("./useragent"),s=null,o=0;t.addListener=function(e,t,n){if(e.addEventListener)return e.addEventListener(t,n,!1);if(e.attachEvent){var r=function(){n.call(e,window.event)};n._wrapper=r,e.attachEvent("on"+t,r)}},t.removeListener=function(e,t,n){if(e.removeEventListener)return e.removeEventListener(t,n,!1);e.detachEvent&&e.detachEvent("on"+t,n._wrapper||n)},t.stopEvent=function(e){return t.stopPropagation(e),t.preventDefault(e),!1},t.stopPropagation=function(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0},t.preventDefault=function(e){e.preventDefault?e.preventDefault():e.returnValue=!1},t.getButton=function(e){return e.type=="dblclick"?0:e.type=="contextmenu"||i.isMac&&e.ctrlKey&&!e.altKey&&!e.shiftKey?2:e.preventDefault?e.button:{1:0,2:2,4:1}[e.button]},t.capture=function(e,n,r){function i(e){n&&n(e),r&&r(e),t.removeListener(document,"mousemove",n,!0),t.removeListener(document,"mouseup",i,!0),t.removeListener(document,"dragstart",i,!0)}return t.addListener(document,"mousemove",n,!0),t.addListener(document,"mouseup",i,!0),t.addListener(document,"dragstart",i,!0),i},t.addTouchMoveListener=function(e,n){if("ontouchmove"in e){var r,i;t.addListener(e,"touchstart",function(e){var t=e.changedTouches[0];r=t.clientX,i=t.clientY}),t.addListener(e,"touchmove",function(e){var t=1,s=e.changedTouches[0];e.wheelX=-(s.clientX-r)/t,e.wheelY=-(s.clientY-i)/t,r=s.clientX,i=s.clientY,n(e)})}},t.addMouseWheelListener=function(e,n){"onmousewheel"in e?t.addListener(e,"mousewheel",function(e){var t=8;e.wheelDeltaX!==undefined?(e.wheelX=-e.wheelDeltaX/t,e.wheelY=-e.wheelDeltaY/t):(e.wheelX=0,e.wheelY=-e.wheelDelta/t),n(e)}):"onwheel"in e?t.addListener(e,"wheel",function(e){var t=.35;switch(e.deltaMode){case e.DOM_DELTA_PIXEL:e.wheelX=e.deltaX*t||0,e.wheelY=e.deltaY*t||0;break;case e.DOM_DELTA_LINE:case e.DOM_DELTA_PAGE:e.wheelX=(e.deltaX||0)*5,e.wheelY=(e.deltaY||0)*5}n(e)}):t.addListener(e,"DOMMouseScroll",function(e){e.axis&&e.axis==e.HORIZONTAL_AXIS?(e.wheelX=(e.detail||0)*5,e.wheelY=0):(e.wheelX=0,e.wheelY=(e.detail||0)*5),n(e)})},t.addMultiMouseDownListener=function(e,n,r,s){function c(e){t.getButton(e)!==0?o=0:e.detail>1?(o++,o>4&&(o=1)):o=1;if(i.isIE){var c=Math.abs(e.clientX-u)>5||Math.abs(e.clientY-a)>5;if(!f||c)o=1;f&&clearTimeout(f),f=setTimeout(function(){f=null},n[o-1]||600),o==1&&(u=e.clientX,a=e.clientY)}e._clicks=o,r[s]("mousedown",e);if(o>4)o=0;else if(o>1)return r[s](l[o],e)}function h(e){o=2,f&&clearTimeout(f),f=setTimeout(function(){f=null},n[o-1]||600),r[s]("mousedown",e),r[s](l[o],e)}var o=0,u,a,f,l={2:"dblclick",3:"tripleclick",4:"quadclick"};Array.isArray(e)||(e=[e]),e.forEach(function(e){t.addListener(e,"mousedown",c),i.isOldIE&&t.addListener(e,"dblclick",h)})};var u=!i.isMac||!i.isOpera||"KeyboardEvent"in window?function(e){return 0|(e.ctrlKey?1:0)|(e.altKey?2:0)|(e.shiftKey?4:0)|(e.metaKey?8:0)}:function(e){return 0|(e.metaKey?1:0)|(e.altKey?2:0)|(e.shiftKey?4:0)|(e.ctrlKey?8:0)};t.getModifierString=function(e){return r.KEY_MODS[u(e)]},t.addCommandKeyListener=function(e,n){var r=t.addListener;if(i.isOldGecko||i.isOpera&&!("KeyboardEvent"in window)){var o=null;r(e,"keydown",function(e){o=e.keyCode}),r(e,"keypress",function(e){return a(n,e,o)})}else{var u=null;r(e,"keydown",function(e){var t=e.keyCode;s[t]=(s[t]||0)+1,t==91||t==92?s.OSKey=!0:s.OSKey&&e.timeStamp-s.lastT>200&&s.count==1&&f(),s[t]==1&&s.count++,s.lastT=e.timeStamp;var r=a(n,e,t);return u=e.defaultPrevented,r}),r(e,"keypress",function(e){u&&(e.ctrlKey||e.altKey||e.shiftKey||e.metaKey)&&(t.stopEvent(e),u=null)}),r(e,"keyup",function(e){var t=e.keyCode;s[t]?s.count=Math.max(s.count-1,0):f();if(t==91||t==92)s.OSKey=!1;s[t]=null}),s||(f(),r(window,"focus",f))}};if(typeof window=="object"&&window.postMessage&&!i.isOldIE){var l=1;t.nextTick=function(e,n){n=n||window;var r="zero-timeout-message-"+l;t.addListener(n,"message",function i(s){s.data==r&&(t.stopPropagation(s),t.removeListener(n,"message",i),e())}),n.postMessage(r,"*")}}t.nextFrame=typeof window=="object"&&(window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame||window.oRequestAnimationFrame),t.nextFrame?t.nextFrame=t.nextFrame.bind(window):t.nextFrame=function(e){setTimeout(e,17)}}),define("ace/lib/lang",["require","exports","module"],function(e,t,n){"use strict";t.last=function(e){return e[e.length-1]},t.stringReverse=function(e){return e.split("").reverse().join("")},t.stringRepeat=function(e,t){var n="";while(t>0){t&1&&(n+=e);if(t>>=1)e+=e}return n};var r=/^\s\s*/,i=/\s\s*$/;t.stringTrimLeft=function(e){return e.replace(r,"")},t.stringTrimRight=function(e){return e.replace(i,"")},t.copyObject=function(e){var t={};for(var n in e)t[n]=e[n];return t},t.copyArray=function(e){var t=[];for(var n=0,r=e.length;n<r;n++)e[n]&&typeof e[n]=="object"?t[n]=this.copyObject(e[n]):t[n]=e[n];return t},t.deepCopy=function s(e){if(typeof e!="object"||!e)return e;var t;if(Array.isArray(e)){t=[];for(var n=0;n<e.length;n++)t[n]=s(e[n]);return t}var r=e.constructor;if(r===RegExp)return e;t=r();for(var n in e)t[n]=s(e[n]);return t},t.arrayToMap=function(e){var t={};for(var n=0;n<e.length;n++)t[e[n]]=1;return t},t.createMap=function(e){var t=Object.create(null);for(var n in e)t[n]=e[n];return t},t.arrayRemove=function(e,t){for(var n=0;n<=e.length;n++)t===e[n]&&e.splice(n,1)},t.escapeRegExp=function(e){return e.replace(/([.*+?^${}()|[\]\/\\])/g,"\\$1")},t.escapeHTML=function(e){return e.replace(/&/g,"&#38;").replace(/"/g,"&#34;").replace(/'/g,"&#39;").replace(/</g,"&#60;")},t.getMatchOffsets=function(e,t){var n=[];return e.replace(t,function(e){n.push({offset:arguments[arguments.length-2],length:e.length})}),n},t.deferredCall=function(e){var t=null,n=function(){t=null,e()},r=function(e){return r.cancel(),t=setTimeout(n,e||0),r};return r.schedule=r,r.call=function(){return this.cancel(),e(),r},r.cancel=function(){return clearTimeout(t),t=null,r},r.isPending=function(){return t},r},t.delayedCall=function(e,t){var n=null,r=function(){n=null,e()},i=function(e){n==null&&(n=setTimeout(r,e||t))};return i.delay=function(e){n&&clearTimeout(n),n=setTimeout(r,e||t)},i.schedule=i,i.call=function(){this.cancel(),e()},i.cancel=function(){n&&clearTimeout(n),n=null},i.isPending=function(){return n},i}}),define("ace/keyboard/textinput",["require","exports","module","ace/lib/event","ace/lib/useragent","ace/lib/dom","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../lib/event"),i=e("../lib/useragent"),s=e("../lib/dom"),o=e("../lib/lang"),u=i.isChrome<18,a=i.isIE,f=function(e,t){function b(e){if(h)return;h=!0;if(k)t=0,r=e?0:n.value.length-1;else var t=e?2:1,r=2;try{n.setSelectionRange(t,r)}catch(i){}h=!1}function w(){if(h)return;n.value=f,i.isWebKit&&y.schedule()}function R(){clearTimeout(q),q=setTimeout(function(){p&&(n.style.cssText=p,p=""),t.renderer.$keepTextAreaAtCursor==null&&(t.renderer.$keepTextAreaAtCursor=!0,t.renderer.$moveTextAreaToCursor())},i.isOldIE?200:0)}var n=s.createElement("textarea");n.className="ace_text-input",i.isTouchPad&&n.setAttribute("x-palm-disable-auto-cap",!0),n.setAttribute("wrap","off"),n.setAttribute("autocorrect","off"),n.setAttribute("autocapitalize","off"),n.setAttribute("spellcheck",!1),n.style.opacity="0",i.isOldIE&&(n.style.top="-1000px"),e.insertBefore(n,e.firstChild);var f="",l=!1,c=!1,h=!1,p="",d=!0;try{var v=document.activeElement===n}catch(m){}r.addListener(n,"blur",function(e){t.onBlur(e),v=!1}),r.addListener(n,"focus",function(e){v=!0,t.onFocus(e),b()}),this.focus=function(){if(p)return n.focus();var e=n.style.top;n.style.position="fixed",n.style.top="0px",n.focus(),setTimeout(function(){n.style.position="",n.style.top=="0px"&&(n.style.top=e)},0)},this.blur=function(){n.blur()},this.isFocused=function(){return v};var g=o.delayedCall(function(){v&&b(d)}),y=o.delayedCall(function(){h||(n.value=f,v&&b())});i.isWebKit||t.addEventListener("changeSelection",function(){t.selection.isEmpty()!=d&&(d=!d,g.schedule())}),w(),v&&t.onFocus();var E=function(e){return e.selectionStart===0&&e.selectionEnd===e.value.length};!n.setSelectionRange&&n.createTextRange&&(n.setSelectionRange=function(e,t){var n=this.createTextRange();n.collapse(!0),n.moveStart("character",e),n.moveEnd("character",t),n.select()},E=function(e){try{var t=e.ownerDocument.selection.createRange()}catch(n){}return!t||t.parentElement()!=e?!1:t.text==e.value});if(i.isOldIE){var S=!1,x=function(e){if(S)return;var t=n.value;if(h||!t||t==f)return;if(e&&t==f[0])return T.schedule();A(t),S=!0,w(),S=!1},T=o.delayedCall(x);r.addListener(n,"propertychange",x);var N={13:1,27:1};r.addListener(n,"keyup",function(e){h&&(!n.value||N[e.keyCode])&&setTimeout(F,0);if((n.value.charCodeAt(0)||0)<129)return T.call();h?j():B()}),r.addListener(n,"keydown",function(e){T.schedule(50)})}var C=function(e){l?l=!1:E(n)?(t.selectAll(),b()):k&&b(t.selection.isEmpty())},k=null;this.setInputHandler=function(e){k=e},this.getInputHandler=function(){return k};var L=!1,A=function(e){k&&(e=k(e),k=null),c?(b(),e&&t.onPaste(e),c=!1):e==f.charAt(0)?L?t.execCommand("del",{source:"ace"}):t.execCommand("backspace",{source:"ace"}):(e.substring(0,2)==f?e=e.substr(2):e.charAt(0)==f.charAt(0)?e=e.substr(1):e.charAt(e.length-1)==f.charAt(0)&&(e=e.slice(0,-1)),e.charAt(e.length-1)==f.charAt(0)&&(e=e.slice(0,-1)),e&&t.onTextInput(e)),L&&(L=!1)},O=function(e){if(h)return;var t=n.value;A(t),w()},M=function(e,t){var n=e.clipboardData||window.clipboardData;if(!n||u)return;var r=a?"Text":"text/plain";return t?n.setData(r,t)!==!1:n.getData(r)},_=function(e,i){var s=t.getCopyText();if(!s)return r.preventDefault(e);M(e,s)?(i?t.onCut():t.onCopy(),r.preventDefault(e)):(l=!0,n.value=s,n.select(),setTimeout(function(){l=!1,w(),b(),i?t.onCut():t.onCopy()}))},D=function(e){_(e,!0)},P=function(e){_(e,!1)},H=function(e){var s=M(e);typeof s=="string"?(s&&t.onPaste(s,e),i.isIE&&setTimeout(b),r.preventDefault(e)):(n.value="",c=!0)};r.addCommandKeyListener(n,t.onCommandKey.bind(t)),r.addListener(n,"select",C),r.addListener(n,"input",O),r.addListener(n,"cut",D),r.addListener(n,"copy",P),r.addListener(n,"paste",H),(!("oncut"in n)||!("oncopy"in n)||!("onpaste"in n))&&r.addListener(e,"keydown",function(e){if(i.isMac&&!e.metaKey||!e.ctrlKey)return;switch(e.keyCode){case 67:P(e);break;case 86:H(e);break;case 88:D(e)}});var B=function(e){if(h||!t.onCompositionStart||t.$readOnly)return;h={},t.onCompositionStart(),setTimeout(j,0),t.on("mousedown",F),t.selection.isEmpty()||(t.insert(""),t.session.markUndoGroup(),t.selection.clearSelection()),t.session.markUndoGroup()},j=function(){if(!h||!t.onCompositionUpdate||t.$readOnly)return;var e=n.value.replace(/\x01/g,"");if(h.lastValue===e)return;t.onCompositionUpdate(e),h.lastValue&&t.undo(),h.lastValue=e;if(h.lastValue){var r=t.selection.getRange();t.insert(h.lastValue),t.session.markUndoGroup(),h.range=t.selection.getRange(),t.selection.setRange(r),t.selection.clearSelection()}},F=function(e){if(!t.onCompositionEnd||t.$readOnly)return;var r=h;h=!1;var i=setTimeout(function(){i=null;var e=n.value.replace(/\x01/g,"");if(h)return;e==r.lastValue?w():!r.lastValue&&e&&(w(),A(e))});k=function(n){return i&&clearTimeout(i),n=n.replace(/\x01/g,""),n==r.lastValue?"":(r.lastValue&&i&&t.undo(),n)},t.onCompositionEnd(),t.removeListener("mousedown",F),e.type=="compositionend"&&r.range&&t.selection.setRange(r.range)},I=o.delayedCall(j,50);r.addListener(n,"compositionstart",B),i.isGecko?r.addListener(n,"text",function(){I.schedule()}):(r.addListener(n,"keyup",function(){I.schedule()}),r.addListener(n,"keydown",function(){I.schedule()})),r.addListener(n,"compositionend",F),this.getElement=function(){return n},this.setReadOnly=function(e){n.readOnly=e},this.onContextMenu=function(e){L=!0,b(t.selection.isEmpty()),t._emit("nativecontextmenu",{target:t,domEvent:e}),this.moveToMouse(e,!0)},this.moveToMouse=function(e,o){if(!o&&i.isOldIE)return;p||(p=n.style.cssText),n.style.cssText=(o?"z-index:100000;":"")+"height:"+n.style.height+";"+(i.isIE?"opacity:0.1;":"");var u=t.container.getBoundingClientRect(),a=s.computedStyle(t.container),f=u.top+(parseInt(a.borderTopWidth)||0),l=u.left+(parseInt(u.borderLeftWidth)||0),c=u.bottom-f-n.clientHeight-2,h=function(e){n.style.left=e.clientX-l-2+"px",n.style.top=Math.min(e.clientY-f-2,c)+"px"};h(e);if(e.type!="mousedown")return;t.renderer.$keepTextAreaAtCursor&&(t.renderer.$keepTextAreaAtCursor=null),clearTimeout(q),i.isWin&&!i.isOldIE&&r.capture(t.container,h,R)},this.onContextMenuClose=R;var q,U=function(e){t.textInput.onContextMenu(e),R()};r.addListener(n,"mouseup",U),r.addListener(n,"mousedown",function(e){e.preventDefault(),R()}),r.addListener(t.renderer.scroller,"contextmenu",U),r.addListener(n,"contextmenu",U)};t.TextInput=f}),define("ace/mouse/default_handlers",["require","exports","module","ace/lib/dom","ace/lib/event","ace/lib/useragent"],function(e,t,n){"use strict";function u(e){e.$clickSelection=null;var t=e.editor;t.setDefaultHandler("mousedown",this.onMouseDown.bind(e)),t.setDefaultHandler("dblclick",this.onDoubleClick.bind(e)),t.setDefaultHandler("tripleclick",this.onTripleClick.bind(e)),t.setDefaultHandler("quadclick",this.onQuadClick.bind(e)),t.setDefaultHandler("mousewheel",this.onMouseWheel.bind(e)),t.setDefaultHandler("touchmove",this.onTouchMove.bind(e));var n=["select","startSelect","selectEnd","selectAllEnd","selectByWordsEnd","selectByLinesEnd","dragWait","dragWaitEnd","focusWait"];n.forEach(function(t){e[t]=this[t]},this),e.selectByLines=this.extendSelectionBy.bind(e,"getLineRange"),e.selectByWords=this.extendSelectionBy.bind(e,"getWordRange")}function a(e,t,n,r){return Math.sqrt(Math.pow(n-e,2)+Math.pow(r-t,2))}function f(e,t){if(e.start.row==e.end.row)var n=2*t.column-e.start.column-e.end.column;else if(e.start.row==e.end.row-1&&!e.start.column&&!e.end.column)var n=t.column-4;else var n=2*t.row-e.start.row-e.end.row;return n<0?{cursor:e.start,anchor:e.end}:{cursor:e.end,anchor:e.start}}var r=e("../lib/dom"),i=e("../lib/event"),s=e("../lib/useragent"),o=0;(function(){this.onMouseDown=function(e){var t=e.inSelection(),n=e.getDocumentPosition();this.mousedownEvent=e;var r=this.editor,i=e.getButton();if(i!==0){var s=r.getSelectionRange(),o=s.isEmpty();r.$blockScrolling++,(o||i==1)&&r.selection.moveToPosition(n),r.$blockScrolling--,i==2&&r.textInput.onContextMenu(e.domEvent);return}this.mousedownEvent.time=Date.now();if(t&&!r.isFocused()){r.focus();if(this.$focusTimout&&!this.$clickSelection&&!r.inMultiSelectMode){this.setState("focusWait"),this.captureMouse(e);return}}return this.captureMouse(e),this.startSelect(n,e.domEvent._clicks>1),e.preventDefault()},this.startSelect=function(e,t){e=e||this.editor.renderer.screenToTextCoordinates(this.x,this.y);var n=this.editor;n.$blockScrolling++,this.mousedownEvent.getShiftKey()?n.selection.selectToPosition(e):t||n.selection.moveToPosition(e),t||this.select(),n.renderer.scroller.setCapture&&n.renderer.scroller.setCapture(),n.setStyle("ace_selecting"),this.setState("select"),n.$blockScrolling--},this.select=function(){var e,t=this.editor,n=t.renderer.screenToTextCoordinates(this.x,this.y);t.$blockScrolling++;if(this.$clickSelection){var r=this.$clickSelection.comparePoint(n);if(r==-1)e=this.$clickSelection.end;else if(r==1)e=this.$clickSelection.start;else{var i=f(this.$clickSelection,n);n=i.cursor,e=i.anchor}t.selection.setSelectionAnchor(e.row,e.column)}t.selection.selectToPosition(n),t.$blockScrolling--,t.renderer.scrollCursorIntoView()},this.extendSelectionBy=function(e){var t,n=this.editor,r=n.renderer.screenToTextCoordinates(this.x,this.y),i=n.selection[e](r.row,r.column);n.$blockScrolling++;if(this.$clickSelection){var s=this.$clickSelection.comparePoint(i.start),o=this.$clickSelection.comparePoint(i.end);if(s==-1&&o<=0){t=this.$clickSelection.end;if(i.end.row!=r.row||i.end.column!=r.column)r=i.start}else if(o==1&&s>=0){t=this.$clickSelection.start;if(i.start.row!=r.row||i.start.column!=r.column)r=i.end}else if(s==-1&&o==1)r=i.end,t=i.start;else{var u=f(this.$clickSelection,r);r=u.cursor,t=u.anchor}n.selection.setSelectionAnchor(t.row,t.column)}n.selection.selectToPosition(r),n.$blockScrolling--,n.renderer.scrollCursorIntoView()},this.selectEnd=this.selectAllEnd=this.selectByWordsEnd=this.selectByLinesEnd=function(){this.$clickSelection=null,this.editor.unsetStyle("ace_selecting"),this.editor.renderer.scroller.releaseCapture&&this.editor.renderer.scroller.releaseCapture()},this.focusWait=function(){var e=a(this.mousedownEvent.x,this.mousedownEvent.y,this.x,this.y),t=Date.now();(e>o||t-this.mousedownEvent.time>this.$focusTimout)&&this.startSelect(this.mousedownEvent.getDocumentPosition())},this.onDoubleClick=function(e){var t=e.getDocumentPosition(),n=this.editor,r=n.session,i=r.getBracketRange(t);i?(i.isEmpty()&&(i.start.column--,i.end.column++),this.setState("select")):(i=n.selection.getWordRange(t.row,t.column),this.setState("selectByWords")),this.$clickSelection=i,this.select()},this.onTripleClick=function(e){var t=e.getDocumentPosition(),n=this.editor;this.setState("selectByLines");var r=n.getSelectionRange();r.isMultiLine()&&r.contains(t.row,t.column)?(this.$clickSelection=n.selection.getLineRange(r.start.row),this.$clickSelection.end=n.selection.getLineRange(r.end.row).end):this.$clickSelection=n.selection.getLineRange(t.row),this.select()},this.onQuadClick=function(e){var t=this.editor;t.selectAll(),this.$clickSelection=t.getSelectionRange(),this.setState("selectAll")},this.onMouseWheel=function(e){if(e.getAccelKey())return;e.getShiftKey()&&e.wheelY&&!e.wheelX&&(e.wheelX=e.wheelY,e.wheelY=0);var t=e.domEvent.timeStamp,n=t-(this.$lastScrollTime||0),r=this.editor,i=r.renderer.isScrollableBy(e.wheelX*e.speed,e.wheelY*e.speed);if(i||n<200)return this.$lastScrollTime=t,r.renderer.scrollBy(e.wheelX*e.speed,e.wheelY*e.speed),e.stop()},this.onTouchMove=function(e){var t=e.domEvent.timeStamp,n=t-(this.$lastScrollTime||0),r=this.editor,i=r.renderer.isScrollableBy(e.wheelX*e.speed,e.wheelY*e.speed);if(i||n<200)return this.$lastScrollTime=t,r.renderer.scrollBy(e.wheelX*e.speed,e.wheelY*e.speed),e.stop()}}).call(u.prototype),t.DefaultHandlers=u}),define("ace/tooltip",["require","exports","module","ace/lib/oop","ace/lib/dom"],function(e,t,n){"use strict";function s(e){this.isOpen=!1,this.$element=null,this.$parentNode=e}var r=e("./lib/oop"),i=e("./lib/dom");(function(){this.$init=function(){return this.$element=i.createElement("div"),this.$element.className="ace_tooltip",this.$element.style.display="none",this.$parentNode.appendChild(this.$element),this.$element},this.getElement=function(){return this.$element||this.$init()},this.setText=function(e){i.setInnerText(this.getElement(),e)},this.setHtml=function(e){this.getElement().innerHTML=e},this.setPosition=function(e,t){this.getElement().style.left=e+"px",this.getElement().style.top=t+"px"},this.setClassName=function(e){i.addCssClass(this.getElement(),e)},this.show=function(e,t,n){e!=null&&this.setText(e),t!=null&&n!=null&&this.setPosition(t,n),this.isOpen||(this.getElement().style.display="block",this.isOpen=!0)},this.hide=function(){this.isOpen&&(this.getElement().style.display="none",this.isOpen=!1)},this.getHeight=function(){return this.getElement().offsetHeight},this.getWidth=function(){return this.getElement().offsetWidth}}).call(s.prototype),t.Tooltip=s}),define("ace/mouse/default_gutter_handler",["require","exports","module","ace/lib/dom","ace/lib/oop","ace/lib/event","ace/tooltip"],function(e,t,n){"use strict";function u(e){function l(){var r=u.getDocumentPosition().row,s=n.$annotations[r];if(!s)return c();var o=t.session.getLength();if(r==o){var a=t.renderer.pixelToScreenCoordinates(0,u.y).row,l=u.$pos;if(a>t.session.documentToScreenRow(l.row,l.column))return c()}if(f==s)return;f=s.text.join("<br/>"),i.setHtml(f),i.show(),t.on("mousewheel",c);if(e.$tooltipFollowsMouse)h(u);else{var p=u.domEvent.target,d=p.getBoundingClientRect(),v=i.getElement().style;v.left=d.right+"px",v.top=d.bottom+"px"}}function c(){o&&(o=clearTimeout(o)),f&&(i.hide(),f=null,t.removeEventListener("mousewheel",c))}function h(e){i.setPosition(e.x,e.y)}var t=e.editor,n=t.renderer.$gutterLayer,i=new a(t.container);e.editor.setDefaultHandler("guttermousedown",function(r){if(!t.isFocused()||r.getButton()!=0)return;var i=n.getRegion(r);if(i=="foldWidgets")return;var s=r.getDocumentPosition().row,o=t.session.selection;if(r.getShiftKey())o.selectTo(s,0);else{if(r.domEvent.detail==2)return t.selectAll(),r.preventDefault();e.$clickSelection=t.selection.getLineRange(s)}return e.setState("selectByLines"),e.captureMouse(r),r.preventDefault()});var o,u,f;e.editor.setDefaultHandler("guttermousemove",function(t){var n=t.domEvent.target||t.domEvent.srcElement;if(r.hasCssClass(n,"ace_fold-widget"))return c();f&&e.$tooltipFollowsMouse&&h(t),u=t;if(o)return;o=setTimeout(function(){o=null,u&&!e.isMousePressed?l():c()},50)}),s.addListener(t.renderer.$gutter,"mouseout",function(e){u=null;if(!f||o)return;o=setTimeout(function(){o=null,c()},50)}),t.on("changeSession",c)}function a(e){o.call(this,e)}var r=e("../lib/dom"),i=e("../lib/oop"),s=e("../lib/event"),o=e("../tooltip").Tooltip;i.inherits(a,o),function(){this.setPosition=function(e,t){var n=window.innerWidth||document.documentElement.clientWidth,r=window.innerHeight||document.documentElement.clientHeight,i=this.getWidth(),s=this.getHeight();e+=15,t+=15,e+i>n&&(e-=e+i-n),t+s>r&&(t-=20+s),o.prototype.setPosition.call(this,e,t)}}.call(a.prototype),t.GutterHandler=u}),define("ace/mouse/mouse_event",["require","exports","module","ace/lib/event","ace/lib/useragent"],function(e,t,n){"use strict";var r=e("../lib/event"),i=e("../lib/useragent"),s=t.MouseEvent=function(e,t){this.domEvent=e,this.editor=t,this.x=this.clientX=e.clientX,this.y=this.clientY=e.clientY,this.$pos=null,this.$inSelection=null,this.propagationStopped=!1,this.defaultPrevented=!1};(function(){this.stopPropagation=function(){r.stopPropagation(this.domEvent),this.propagationStopped=!0},this.preventDefault=function(){r.preventDefault(this.domEvent),this.defaultPrevented=!0},this.stop=function(){this.stopPropagation(),this.preventDefault()},this.getDocumentPosition=function(){return this.$pos?this.$pos:(this.$pos=this.editor.renderer.screenToTextCoordinates(this.clientX,this.clientY),this.$pos)},this.inSelection=function(){if(this.$inSelection!==null)return this.$inSelection;var e=this.editor,t=e.getSelectionRange();if(t.isEmpty())this.$inSelection=!1;else{var n=this.getDocumentPosition();this.$inSelection=t.contains(n.row,n.column)}return this.$inSelection},this.getButton=function(){return r.getButton(this.domEvent)},this.getShiftKey=function(){return this.domEvent.shiftKey},this.getAccelKey=i.isMac?function(){return this.domEvent.metaKey}:function(){return this.domEvent.ctrlKey}}).call(s.prototype)}),define("ace/mouse/dragdrop_handler",["require","exports","module","ace/lib/dom","ace/lib/event","ace/lib/useragent"],function(e,t,n){"use strict";function f(e){function T(e,n){var r=Date.now(),i=!n||e.row!=n.row,s=!n||e.column!=n.column;if(!S||i||s)t.$blockScrolling+=1,t.moveCursorToPosition(e),t.$blockScrolling-=1,S=r,x={x:p,y:d};else{var o=l(x.x,x.y,p,d);o>a?S=null:r-S>=u&&(t.renderer.scrollCursorIntoView(),S=null)}}function N(e,n){var r=Date.now(),i=t.renderer.layerConfig.lineHeight,s=t.renderer.layerConfig.characterWidth,u=t.renderer.scroller.getBoundingClientRect(),a={x:{left:p-u.left,right:u.right-p},y:{top:d-u.top,bottom:u.bottom-d}},f=Math.min(a.x.left,a.x.right),l=Math.min(a.y.top,a.y.bottom),c={row:e.row,column:e.column};f/s<=2&&(c.column+=a.x.left<a.x.right?-3:2),l/i<=1&&(c.row+=a.y.top<a.y.bottom?-1:1);var h=e.row!=c.row,v=e.column!=c.column,m=!n||e.row!=n.row;h||v&&!m?E?r-E>=o&&t.renderer.scrollCursorIntoView(c):E=r:E=null}function C(){var e=g;g=t.renderer.screenToTextCoordinates(p,d),T(g,e),N(g,e)}function k(){m=t.selection.toOrientedRange(),h=t.session.addMarker(m,"ace_selection",t.getSelectionStyle()),t.clearSelection(),t.isFocused()&&t.renderer.$cursorLayer.setBlinking(!1),clearInterval(v),C(),v=setInterval(C,20),y=0,i.addListener(document,"mousemove",O)}function L(){clearInterval(v),t.session.removeMarker(h),h=null,t.$blockScrolling+=1,t.selection.fromOrientedRange(m),t.$blockScrolling-=1,t.isFocused()&&!w&&t.renderer.$cursorLayer.setBlinking(!t.getReadOnly()),m=null,g=null,y=0,E=null,S=null,i.removeListener(document,"mousemove",O)}function O(){A==null&&(A=setTimeout(function(){A!=null&&h&&L()},20))}function M(e){var t=e.types;return!t||Array.prototype.some.call(t,function(e){return e=="text/plain"||e=="Text"})}function _(e){var t=["copy","copymove","all","uninitialized"],n=["move","copymove","linkmove","all","uninitialized"],r=s.isMac?e.altKey:e.ctrlKey,i="uninitialized";try{i=e.dataTransfer.effectAllowed.toLowerCase()}catch(e){}var o="none";return r&&t.indexOf(i)>=0?o="copy":n.indexOf(i)>=0?o="move":t.indexOf(i)>=0&&(o="copy"),o}var t=e.editor,n=r.createElement("img");n.src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",s.isOpera&&(n.style.cssText="width:1px;height:1px;position:fixed;top:0;left:0;z-index:2147483647;opacity:0;");var f=["dragWait","dragWaitEnd","startDrag","dragReadyEnd","onMouseDrag"];f.forEach(function(t){e[t]=this[t]},this),t.addEventListener("mousedown",this.onMouseDown.bind(e));var c=t.container,h,p,d,v,m,g,y=0,b,w,E,S,x;this.onDragStart=function(e){if(this.cancelDrag||!c.draggable){var r=this;return setTimeout(function(){r.startSelect(),r.captureMouse(e)},0),e.preventDefault()}m=t.getSelectionRange();var i=e.dataTransfer;i.effectAllowed=t.getReadOnly()?"copy":"copyMove",s.isOpera&&(t.container.appendChild(n),n.scrollTop=0),i.setDragImage&&i.setDragImage(n,0,0),s.isOpera&&t.container.removeChild(n),i.clearData(),i.setData("Text",t.session.getTextRange()),w=!0,this.setState("drag")},this.onDragEnd=function(e){c.draggable=!1,w=!1,this.setState(null);if(!t.getReadOnly()){var n=e.dataTransfer.dropEffect;!b&&n=="move"&&t.session.remove(t.getSelectionRange()),t.renderer.$cursorLayer.setBlinking(!0)}this.editor.unsetStyle("ace_dragging"),this.editor.renderer.setCursorStyle("")},this.onDragEnter=function(e){if(t.getReadOnly()||!M(e.dataTransfer))return;return p=e.clientX,d=e.clientY,h||k(),y++,e.dataTransfer.dropEffect=b=_(e),i.preventDefault(e)},this.onDragOver=function(e){if(t.getReadOnly()||!M(e.dataTransfer))return;return p=e.clientX,d=e.clientY,h||(k(),y++),A!==null&&(A=null),e.dataTransfer.dropEffect=b=_(e),i.preventDefault(e)},this.onDragLeave=function(e){y--;if(y<=0&&h)return L(),b=null,i.preventDefault(e)},this.onDrop=function(e){if(!g)return;var n=e.dataTransfer;if(w)switch(b){case"move":m.contains(g.row,g.column)?m={start:g,end:g}:m=t.moveText(m,g);break;case"copy":m=t.moveText(m,g,!0)}else{var r=n.getData("Text");m={start:g,end:t.session.insert(g,r)},t.focus(),b=null}return L(),i.preventDefault(e)},i.addListener(c,"dragstart",this.onDragStart.bind(e)),i.addListener(c,"dragend",this.onDragEnd.bind(e)),i.addListener(c,"dragenter",this.onDragEnter.bind(e)),i.addListener(c,"dragover",this.onDragOver.bind(e)),i.addListener(c,"dragleave",this.onDragLeave.bind(e)),i.addListener(c,"drop",this.onDrop.bind(e));var A=null}function l(e,t,n,r){return Math.sqrt(Math.pow(n-e,2)+Math.pow(r-t,2))}var r=e("../lib/dom"),i=e("../lib/event"),s=e("../lib/useragent"),o=200,u=200,a=5;(function(){this.dragWait=function(){var e=Date.now()-this.mousedownEvent.time;e>this.editor.getDragDelay()&&this.startDrag()},this.dragWaitEnd=function(){var e=this.editor.container;e.draggable=!1,this.startSelect(this.mousedownEvent.getDocumentPosition()),this.selectEnd()},this.dragReadyEnd=function(e){this.editor.renderer.$cursorLayer.setBlinking(!this.editor.getReadOnly()),this.editor.unsetStyle("ace_dragging"),this.editor.renderer.setCursorStyle(""),this.dragWaitEnd()},this.startDrag=function(){this.cancelDrag=!1;var e=this.editor,t=e.container;t.draggable=!0,e.renderer.$cursorLayer.setBlinking(!1),e.setStyle("ace_dragging");var n=s.isWin?"default":"move";e.renderer.setCursorStyle(n),this.setState("dragReady")},this.onMouseDrag=function(e){var t=this.editor.container;if(s.isIE&&this.state=="dragReady"){var n=l(this.mousedownEvent.x,this.mousedownEvent.y,this.x,this.y);n>3&&t.dragDrop()}if(this.state==="dragWait"){var n=l(this.mousedownEvent.x,this.mousedownEvent.y,this.x,this.y);n>0&&(t.draggable=!1,this.startSelect(this.mousedownEvent.getDocumentPosition()))}},this.onMouseDown=function(e){if(!this.$dragEnabled)return;this.mousedownEvent=e;var t=this.editor,n=e.inSelection(),r=e.getButton(),i=e.domEvent.detail||1;if(i===1&&r===0&&n){if(e.editor.inMultiSelectMode&&(e.getAccelKey()||e.getShiftKey()))return;this.mousedownEvent.time=Date.now();var o=e.domEvent.target||e.domEvent.srcElement;"unselectable"in o&&(o.unselectable="on");if(t.getDragDelay()){if(s.isWebKit){this.cancelDrag=!0;var u=t.container;u.draggable=!0}this.setState("dragWait")}else this.startDrag();this.captureMouse(e,this.onMouseDrag.bind(this)),e.defaultPrevented=!0}}}).call(f.prototype),t.DragdropHandler=f}),define("ace/lib/net",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";var r=e("./dom");t.get=function(e,t){var n=new XMLHttpRequest;n.open("GET",e,!0),n.onreadystatechange=function(){n.readyState===4&&t(n.responseText)},n.send(null)},t.loadScript=function(e,t){var n=r.getDocumentHead(),i=document.createElement("script");i.src=e,n.appendChild(i),i.onload=i.onreadystatechange=function(e,n){if(n||!i.readyState||i.readyState=="loaded"||i.readyState=="complete")i=i.onload=i.onreadystatechange=null,n||t()}},t.qualifyURL=function(e){var t=document.createElement("a");return t.href=e,t.href}}),define("ace/lib/event_emitter",["require","exports","module"],function(e,t,n){"use strict";var r={},i=function(){this.propagationStopped=!0},s=function(){this.defaultPrevented=!0};r._emit=r._dispatchEvent=function(e,t){this._eventRegistry||(this._eventRegistry={}),this._defaultHandlers||(this._defaultHandlers={});var n=this._eventRegistry[e]||[],r=this._defaultHandlers[e];if(!n.length&&!r)return;if(typeof t!="object"||!t)t={};t.type||(t.type=e),t.stopPropagation||(t.stopPropagation=i),t.preventDefault||(t.preventDefault=s),n=n.slice();for(var o=0;o<n.length;o++){n[o](t,this);if(t.propagationStopped)break}if(r&&!t.defaultPrevented)return r(t,this)},r._signal=function(e,t){var n=(this._eventRegistry||{})[e];if(!n)return;n=n.slice();for(var r=0;r<n.length;r++)n[r](t,this)},r.once=function(e,t){var n=this;t&&this.addEventListener(e,function r(){n.removeEventListener(e,r),t.apply(null,arguments)})},r.setDefaultHandler=function(e,t){var n=this._defaultHandlers;n||(n=this._defaultHandlers={_disabled_:{}});if(n[e]){var r=n[e],i=n._disabled_[e];i||(n._disabled_[e]=i=[]),i.push(r);var s=i.indexOf(t);s!=-1&&i.splice(s,1)}n[e]=t},r.removeDefaultHandler=function(e,t){var n=this._defaultHandlers;if(!n)return;var r=n._disabled_[e];if(n[e]==t){var i=n[e];r&&this.setDefaultHandler(e,r.pop())}else if(r){var s=r.indexOf(t);s!=-1&&r.splice(s,1)}},r.on=r.addEventListener=function(e,t,n){this._eventRegistry=this._eventRegistry||{};var r=this._eventRegistry[e];return r||(r=this._eventRegistry[e]=[]),r.indexOf(t)==-1&&r[n?"unshift":"push"](t),t},r.off=r.removeListener=r.removeEventListener=function(e,t){this._eventRegistry=this._eventRegistry||{};var n=this._eventRegistry[e];if(!n)return;var r=n.indexOf(t);r!==-1&&n.splice(r,1)},r.removeAllListeners=function(e){this._eventRegistry&&(this._eventRegistry[e]=[])},t.EventEmitter=r}),define("ace/lib/app_config",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"],function(e,t,n){"no use strict";function o(e){typeof console!="undefined"&&console.warn&&console.warn.apply(console,arguments)}function u(e,t){var n=new Error(e);n.data=t,typeof console=="object"&&console.error&&console.error(n),setTimeout(function(){throw n})}var r=e("./oop"),i=e("./event_emitter").EventEmitter,s={setOptions:function(e){Object.keys(e).forEach(function(t){this.setOption(t,e[t])},this)},getOptions:function(e){var t={};return e?Array.isArray(e)||(t=e,e=Object.keys(t)):e=Object.keys(this.$options),e.forEach(function(e){t[e]=this.getOption(e)},this),t},setOption:function(e,t){if(this["$"+e]===t)return;var n=this.$options[e];if(!n)return o('misspelled option "'+e+'"');if(n.forwardTo)return this[n.forwardTo]&&this[n.forwardTo].setOption(e,t);n.handlesSet||(this["$"+e]=t),n&&n.set&&n.set.call(this,t)},getOption:function(e){var t=this.$options[e];return t?t.forwardTo?this[t.forwardTo]&&this[t.forwardTo].getOption(e):t&&t.get?t.get.call(this):this["$"+e]:o('misspelled option "'+e+'"')}},a=function(){this.$defaultOptions={}};(function(){r.implement(this,i),this.defineOptions=function(e,t,n){return e.$options||(this.$defaultOptions[t]=e.$options={}),Object.keys(n).forEach(function(t){var r=n[t];typeof r=="string"&&(r={forwardTo:r}),r.name||(r.name=t),e.$options[r.name]=r,"initialValue"in r&&(e["$"+r.name]=r.initialValue)}),r.implement(e,s),this},this.resetOptions=function(e){Object.keys(e.$options).forEach(function(t){var n=e.$options[t];"value"in n&&e.setOption(t,n.value)})},this.setDefaultValue=function(e,t,n){var r=this.$defaultOptions[e]||(this.$defaultOptions[e]={});r[t]&&(r.forwardTo?this.setDefaultValue(r.forwardTo,t,n):r[t].value=n)},this.setDefaultValues=function(e,t){Object.keys(t).forEach(function(n){this.setDefaultValue(e,n,t[n])},this)},this.warn=o,this.reportError=u}).call(a.prototype),t.AppConfig=a}),define("ace/config",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/lib/net","ace/lib/app_config"],function(e,t,n){"no use strict";function f(r){if(!u||!u.document)return;a.packaged=r||e.packaged||n.packaged||u.define&&define.packaged;var i={},s="",o=document.currentScript||document._currentScript,f=o&&o.ownerDocument||document,c=f.getElementsByTagName("script");for(var h=0;h<c.length;h++){var p=c[h],d=p.src||p.getAttribute("src");if(!d)continue;var v=p.attributes;for(var m=0,g=v.length;m<g;m++){var y=v[m];y.name.indexOf("data-ace-")===0&&(i[l(y.name.replace(/^data-ace-/,""))]=y.value)}var b=d.match(/^(.*)\/ace(\-\w+)?\.js(\?|$)/);b&&(s=b[1])}s&&(i.base=i.base||s,i.packaged=!0),i.basePath=i.base,i.workerPath=i.workerPath||i.base,i.modePath=i.modePath||i.base,i.themePath=i.themePath||i.base,delete i.base;for(var w in i)typeof i[w]!="undefined"&&t.set(w,i[w])}function l(e){return e.replace(/-(.)/g,function(e,t){return t.toUpperCase()})}var r=e("./lib/lang"),i=e("./lib/oop"),s=e("./lib/net"),o=e("./lib/app_config").AppConfig;n.exports=t=new o;var u=function(){return this||typeof window!="undefined"&&window}(),a={packaged:!1,workerPath:null,modePath:null,themePath:null,basePath:"",suffix:".js",$moduleUrls:{}};t.get=function(e){if(!a.hasOwnProperty(e))throw new Error("Unknown config key: "+e);return a[e]},t.set=function(e,t){if(!a.hasOwnProperty(e))throw new Error("Unknown config key: "+e);a[e]=t},t.all=function(){return r.copyObject(a)},t.moduleUrl=function(e,t){if(a.$moduleUrls[e])return a.$moduleUrls[e];var n=e.split("/");t=t||n[n.length-2]||"";var r=t=="snippets"?"/":"-",i=n[n.length-1];if(t=="worker"&&r=="-"){var s=new RegExp("^"+t+"[\\-_]|[\\-_]"+t+"$","g");i=i.replace(s,"")}(!i||i==t)&&n.length>1&&(i=n[n.length-2]);var o=a[t+"Path"];return o==null?o=a.basePath:r=="/"&&(t=r=""),o&&o.slice(-1)!="/"&&(o+="/"),o+t+r+i+this.get("suffix")},t.setModuleUrl=function(e,t){return a.$moduleUrls[e]=t},t.$loading={},t.loadModule=function(n,r){var i,o;Array.isArray(n)&&(o=n[0],n=n[1]);try{i=e(n)}catch(u){}if(i&&!t.$loading[n])return r&&r(i);t.$loading[n]||(t.$loading[n]=[]),t.$loading[n].push(r);if(t.$loading[n].length>1)return;var a=function(){e([n],function(e){t._emit("load.module",{name:n,module:e});var r=t.$loading[n];t.$loading[n]=null,r.forEach(function(t){t&&t(e)})})};if(!t.get("packaged"))return a();s.loadScript(t.moduleUrl(n,o),a)},t.init=f}),define("ace/mouse/mouse_handler",["require","exports","module","ace/lib/event","ace/lib/useragent","ace/mouse/default_handlers","ace/mouse/default_gutter_handler","ace/mouse/mouse_event","ace/mouse/dragdrop_handler","ace/config"],function(e,t,n){"use strict";var r=e("../lib/event"),i=e("../lib/useragent"),s=e("./default_handlers").DefaultHandlers,o=e("./default_gutter_handler").GutterHandler,u=e("./mouse_event").MouseEvent,a=e("./dragdrop_handler").DragdropHandler,f=e("../config"),l=function(e){var t=this;this.editor=e,new s(this),new o(this),new a(this);var n=function(t){var n=!document.hasFocus||!document.hasFocus()||!e.isFocused()&&document.activeElement==(e.textInput&&e.textInput.getElement());n&&window.focus(),e.focus()},u=e.renderer.getMouseEventTarget();r.addListener(u,"click",this.onMouseEvent.bind(this,"click")),r.addListener(u,"mousemove",this.onMouseMove.bind(this,"mousemove")),r.addMultiMouseDownListener([u,e.renderer.scrollBarV&&e.renderer.scrollBarV.inner,e.renderer.scrollBarH&&e.renderer.scrollBarH.inner,e.textInput&&e.textInput.getElement()].filter(Boolean),[400,300,250],this,"onMouseEvent"),r.addMouseWheelListener(e.container,this.onMouseWheel.bind(this,"mousewheel")),r.addTouchMoveListener(e.container,this.onTouchMove.bind(this,"touchmove"));var f=e.renderer.$gutter;r.addListener(f,"mousedown",this.onMouseEvent.bind(this,"guttermousedown")),r.addListener(f,"click",this.onMouseEvent.bind(this,"gutterclick")),r.addListener(f,"dblclick",this.onMouseEvent.bind(this,"gutterdblclick")),r.addListener(f,"mousemove",this.onMouseEvent.bind(this,"guttermousemove")),r.addListener(u,"mousedown",n),r.addListener(f,"mousedown",n),i.isIE&&e.renderer.scrollBarV&&(r.addListener(e.renderer.scrollBarV.element,"mousedown",n),r.addListener(e.renderer.scrollBarH.element,"mousedown",n)),e.on("mousemove",function(n){if(t.state||t.$dragDelay||!t.$dragEnabled)return;var r=e.renderer.screenToTextCoordinates(n.x,n.y),i=e.session.selection.getRange(),s=e.renderer;!i.isEmpty()&&i.insideStart(r.row,r.column)?s.setCursorStyle("default"):s.setCursorStyle("")})};(function(){this.onMouseEvent=function(e,t){this.editor._emit(e,new u(t,this.editor))},this.onMouseMove=function(e,t){var n=this.editor._eventRegistry&&this.editor._eventRegistry.mousemove;if(!n||!n.length)return;this.editor._emit(e,new u(t,this.editor))},this.onMouseWheel=function(e,t){var n=new u(t,this.editor);n.speed=this.$scrollSpeed*2,n.wheelX=t.wheelX,n.wheelY=t.wheelY,this.editor._emit(e,n)},this.onTouchMove=function(e,t){var n=new u(t,this.editor);n.speed=1,n.wheelX=t.wheelX,n.wheelY=t.wheelY,this.editor._emit(e,n)},this.setState=function(e){this.state=e},this.captureMouse=function(e,t){this.x=e.x,this.y=e.y,this.isMousePressed=!0;var n=this.editor.renderer;n.$keepTextAreaAtCursor&&(n.$keepTextAreaAtCursor=null);var s=this,o=function(e){if(!e)return;if(i.isWebKit&&!e.which&&s.releaseMouse)return s.releaseMouse();s.x=e.clientX,s.y=e.clientY,t&&t(e),s.mouseEvent=new u(e,s.editor),s.$mouseMoved=!0},a=function(e){clearInterval(l),f(),s[s.state+"End"]&&s[s.state+"End"](e),s.state="",n.$keepTextAreaAtCursor==null&&(n.$keepTextAreaAtCursor=!0,n.$moveTextAreaToCursor()),s.isMousePressed=!1,s.$onCaptureMouseMove=s.releaseMouse=null,e&&s.onMouseEvent("mouseup",e)},f=function(){s[s.state]&&s[s.state](),s.$mouseMoved=!1};if(i.isOldIE&&e.domEvent.type=="dblclick")return setTimeout(function(){a(e)});s.$onCaptureMouseMove=o,s.releaseMouse=r.capture(this.editor.container,o,a);var l=setInterval(f,20)},this.releaseMouse=null,this.cancelContextMenu=function(){var e=function(t){if(t&&t.domEvent&&t.domEvent.type!="contextmenu")return;this.editor.off("nativecontextmenu",e),t&&t.domEvent&&r.stopEvent(t.domEvent)}.bind(this);setTimeout(e,10),this.editor.on("nativecontextmenu",e)}}).call(l.prototype),f.defineOptions(l.prototype,"mouseHandler",{scrollSpeed:{initialValue:2},dragDelay:{initialValue:i.isMac?150:0},dragEnabled:{initialValue:!0},focusTimout:{initialValue:0},tooltipFollowsMouse:{initialValue:!0}}),t.MouseHandler=l}),define("ace/mouse/fold_handler",["require","exports","module"],function(e,t,n){"use strict";function r(e){e.on("click",function(t){var n=t.getDocumentPosition(),r=e.session,i=r.getFoldAt(n.row,n.column,1);i&&(t.getAccelKey()?r.removeFold(i):r.expandFold(i),t.stop())}),e.on("gutterclick",function(t){var n=e.renderer.$gutterLayer.getRegion(t);if(n=="foldWidgets"){var r=t.getDocumentPosition().row,i=e.session;i.foldWidgets&&i.foldWidgets[r]&&e.session.onFoldWidgetClick(r,t),e.isFocused()||e.focus(),t.stop()}}),e.on("gutterdblclick",function(t){var n=e.renderer.$gutterLayer.getRegion(t);if(n=="foldWidgets"){var r=t.getDocumentPosition().row,i=e.session,s=i.getParentFoldRangeData(r,!0),o=s.range||s.firstRange;if(o){r=o.start.row;var u=i.getFoldAt(r,i.getLine(r).length,1);u?i.removeFold(u):(i.addFold("...",o),e.renderer.scrollCursorIntoView({row:o.start.row,column:0}))}t.stop()}})}t.FoldHandler=r}),define("ace/keyboard/keybinding",["require","exports","module","ace/lib/keys","ace/lib/event"],function(e,t,n){"use strict";var r=e("../lib/keys"),i=e("../lib/event"),s=function(e){this.$editor=e,this.$data={editor:e},this.$handlers=[],this.setDefaultHandler(e.commands)};(function(){this.setDefaultHandler=function(e){this.removeKeyboardHandler(this.$defaultHandler),this.$defaultHandler=e,this.addKeyboardHandler(e,0)},this.setKeyboardHandler=function(e){var t=this.$handlers;if(t[t.length-1]==e)return;while(t[t.length-1]&&t[t.length-1]!=this.$defaultHandler)this.removeKeyboardHandler(t[t.length-1]);this.addKeyboardHandler(e,1)},this.addKeyboardHandler=function(e,t){if(!e)return;typeof e=="function"&&!e.handleKeyboard&&(e.handleKeyboard=e);var n=this.$handlers.indexOf(e);n!=-1&&this.$handlers.splice(n,1),t==undefined?this.$handlers.push(e):this.$handlers.splice(t,0,e),n==-1&&e.attach&&e.attach(this.$editor)},this.removeKeyboardHandler=function(e){var t=this.$handlers.indexOf(e);return t==-1?!1:(this.$handlers.splice(t,1),e.detach&&e.detach(this.$editor),!0)},this.getKeyboardHandler=function(){return this.$handlers[this.$handlers.length-1]},this.getStatusText=function(){var e=this.$data,t=e.editor;return this.$handlers.map(function(n){return n.getStatusText&&n.getStatusText(t,e)||""}).filter(Boolean).join(" ")},this.$callKeyboardHandlers=function(e,t,n,r){var s,o=!1,u=this.$editor.commands;for(var a=this.$handlers.length;a--;){s=this.$handlers[a].handleKeyboard(this.$data,e,t,n,r);if(!s||!s.command)continue;s.command=="null"?o=!0:o=u.exec(s.command,this.$editor,s.args,r),o&&r&&e!=-1&&s.passEvent!=1&&s.command.passEvent!=1&&i.stopEvent(r);if(o)break}return!o&&e==-1&&(s={command:"insertstring"},o=u.exec("insertstring",this.$editor,t)),o&&this.$editor._signal("keyboardActivity",s),o},this.onCommandKey=function(e,t,n){var i=r.keyCodeToString(n);this.$callKeyboardHandlers(t,i,n,e)},this.onTextInput=function(e){this.$callKeyboardHandlers(-1,e)}}).call(s.prototype),t.KeyBinding=s}),define("ace/range",["require","exports","module"],function(e,t,n){"use strict";var r=function(e,t){return e.row-t.row||e.column-t.column},i=function(e,t,n,r){this.start={row:e,column:t},this.end={row:n,column:r}};(function(){this.isEqual=function(e){return this.start.row===e.start.row&&this.end.row===e.end.row&&this.start.column===e.start.column&&this.end.column===e.end.column},this.toString=function(){return"Range: ["+this.start.row+"/"+this.start.column+"] -> ["+this.end.row+"/"+this.end.column+"]"},this.contains=function(e,t){return this.compare(e,t)==0},this.compareRange=function(e){var t,n=e.end,r=e.start;return t=this.compare(n.row,n.column),t==1?(t=this.compare(r.row,r.column),t==1?2:t==0?1:0):t==-1?-2:(t=this.compare(r.row,r.column),t==-1?-1:t==1?42:0)},this.comparePoint=function(e){return this.compare(e.row,e.column)},this.containsRange=function(e){return this.comparePoint(e.start)==0&&this.comparePoint(e.end)==0},this.intersects=function(e){var t=this.compareRange(e);return t==-1||t==0||t==1},this.isEnd=function(e,t){return this.end.row==e&&this.end.column==t},this.isStart=function(e,t){return this.start.row==e&&this.start.column==t},this.setStart=function(e,t){typeof e=="object"?(this.start.column=e.column,this.start.row=e.row):(this.start.row=e,this.start.column=t)},this.setEnd=function(e,t){typeof e=="object"?(this.end.column=e.column,this.end.row=e.row):(this.end.row=e,this.end.column=t)},this.inside=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)||this.isStart(e,t)?!1:!0:!1},this.insideStart=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)?!1:!0:!1},this.insideEnd=function(e,t){return this.compare(e,t)==0?this.isStart(e,t)?!1:!0:!1},this.compare=function(e,t){return!this.isMultiLine()&&e===this.start.row?t<this.start.column?-1:t>this.end.column?1:0:e<this.start.row?-1:e>this.end.row?1:this.start.row===e?t>=this.start.column?0:-1:this.end.row===e?t<=this.end.column?0:1:0},this.compareStart=function(e,t){return this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.compareEnd=function(e,t){return this.end.row==e&&this.end.column==t?1:this.compare(e,t)},this.compareInside=function(e,t){return this.end.row==e&&this.end.column==t?1:this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.clipRows=function(e,t){if(this.end.row>t)var n={row:t+1,column:0};else if(this.end.row<e)var n={row:e,column:0};if(this.start.row>t)var r={row:t+1,column:0};else if(this.start.row<e)var r={row:e,column:0};return i.fromPoints(r||this.start,n||this.end)},this.extend=function(e,t){var n=this.compare(e,t);if(n==0)return this;if(n==-1)var r={row:e,column:t};else var s={row:e,column:t};return i.fromPoints(r||this.start,s||this.end)},this.isEmpty=function(){return this.start.row===this.end.row&&this.start.column===this.end.column},this.isMultiLine=function(){return this.start.row!==this.end.row},this.clone=function(){return i.fromPoints(this.start,this.end)},this.collapseRows=function(){return this.end.column==0?new i(this.start.row,0,Math.max(this.start.row,this.end.row-1),0):new i(this.start.row,0,this.end.row,0)},this.toScreenRange=function(e){var t=e.documentToScreenPosition(this.start),n=e.documentToScreenPosition(this.end);return new i(t.row,t.column,n.row,n.column)},this.moveBy=function(e,t){this.start.row+=e,this.start.column+=t,this.end.row+=e,this.end.column+=t}}).call(i.prototype),i.fromPoints=function(e,t){return new i(e.row,e.column,t.row,t.column)},i.comparePoints=r,i.comparePoints=function(e,t){return e.row-t.row||e.column-t.column},t.Range=i}),define("ace/selection",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter","ace/range"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/lang"),s=e("./lib/event_emitter").EventEmitter,o=e("./range").Range,u=function(e){this.session=e,this.doc=e.getDocument(),this.clearSelection(),this.lead=this.selectionLead=this.doc.createAnchor(0,0),this.anchor=this.selectionAnchor=this.doc.createAnchor(0,0);var t=this;this.lead.on("change",function(e){t._emit("changeCursor"),t.$isEmpty||t._emit("changeSelection"),!t.$keepDesiredColumnOnChange&&e.old.column!=e.value.column&&(t.$desiredColumn=null)}),this.selectionAnchor.on("change",function(){t.$isEmpty||t._emit("changeSelection")})};(function(){r.implement(this,s),this.isEmpty=function(){return this.$isEmpty||this.anchor.row==this.lead.row&&this.anchor.column==this.lead.column},this.isMultiLine=function(){return this.isEmpty()?!1:this.getRange().isMultiLine()},this.getCursor=function(){return this.lead.getPosition()},this.setSelectionAnchor=function(e,t){this.anchor.setPosition(e,t),this.$isEmpty&&(this.$isEmpty=!1,this._emit("changeSelection"))},this.getSelectionAnchor=function(){return this.$isEmpty?this.getSelectionLead():this.anchor.getPosition()},this.getSelectionLead=function(){return this.lead.getPosition()},this.shiftSelection=function(e){if(this.$isEmpty){this.moveCursorTo(this.lead.row,this.lead.column+e);return}var t=this.getSelectionAnchor(),n=this.getSelectionLead(),r=this.isBackwards();(!r||t.column!==0)&&this.setSelectionAnchor(t.row,t.column+e),(r||n.column!==0)&&this.$moveSelection(function(){this.moveCursorTo(n.row,n.column+e)})},this.isBackwards=function(){var e=this.anchor,t=this.lead;return e.row>t.row||e.row==t.row&&e.column>t.column},this.getRange=function(){var e=this.anchor,t=this.lead;return this.isEmpty()?o.fromPoints(t,t):this.isBackwards()?o.fromPoints(t,e):o.fromPoints(e,t)},this.clearSelection=function(){this.$isEmpty||(this.$isEmpty=!0,this._emit("changeSelection"))},this.selectAll=function(){var e=this.doc.getLength()-1;this.setSelectionAnchor(0,0),this.moveCursorTo(e,this.doc.getLine(e).length)},this.setRange=this.setSelectionRange=function(e,t){t?(this.setSelectionAnchor(e.end.row,e.end.column),this.selectTo(e.start.row,e.start.column)):(this.setSelectionAnchor(e.start.row,e.start.column),this.selectTo(e.end.row,e.end.column)),this.getRange().isEmpty()&&(this.$isEmpty=!0),this.$desiredColumn=null},this.$moveSelection=function(e){var t=this.lead;this.$isEmpty&&this.setSelectionAnchor(t.row,t.column),e.call(this)},this.selectTo=function(e,t){this.$moveSelection(function(){this.moveCursorTo(e,t)})},this.selectToPosition=function(e){this.$moveSelection(function(){this.moveCursorToPosition(e)})},this.moveTo=function(e,t){this.clearSelection(),this.moveCursorTo(e,t)},this.moveToPosition=function(e){this.clearSelection(),this.moveCursorToPosition(e)},this.selectUp=function(){this.$moveSelection(this.moveCursorUp)},this.selectDown=function(){this.$moveSelection(this.moveCursorDown)},this.selectRight=function(){this.$moveSelection(this.moveCursorRight)},this.selectLeft=function(){this.$moveSelection(this.moveCursorLeft)},this.selectLineStart=function(){this.$moveSelection(this.moveCursorLineStart)},this.selectLineEnd=function(){this.$moveSelection(this.moveCursorLineEnd)},this.selectFileEnd=function(){this.$moveSelection(this.moveCursorFileEnd)},this.selectFileStart=function(){this.$moveSelection(this.moveCursorFileStart)},this.selectWordRight=function(){this.$moveSelection(this.moveCursorWordRight)},this.selectWordLeft=function(){this.$moveSelection(this.moveCursorWordLeft)},this.getWordRange=function(e,t){if(typeof t=="undefined"){var n=e||this.lead;e=n.row,t=n.column}return this.session.getWordRange(e,t)},this.selectWord=function(){this.setSelectionRange(this.getWordRange())},this.selectAWord=function(){var e=this.getCursor(),t=this.session.getAWordRange(e.row,e.column);this.setSelectionRange(t)},this.getLineRange=function(e,t){var n=typeof e=="number"?e:this.lead.row,r,i=this.session.getFoldLine(n);return i?(n=i.start.row,r=i.end.row):r=n,t===!0?new o(n,0,r,this.session.getLine(r).length):new o(n,0,r+1,0)},this.selectLine=function(){this.setSelectionRange(this.getLineRange())},this.moveCursorUp=function(){this.moveCursorBy(-1,0)},this.moveCursorDown=function(){this.moveCursorBy(1,0)},this.moveCursorLeft=function(){var e=this.lead.getPosition(),t;if(t=this.session.getFoldAt(e.row,e.column,-1))this.moveCursorTo(t.start.row,t.start.column);else if(e.column===0)e.row>0&&this.moveCursorTo(e.row-1,this.doc.getLine(e.row-1).length);else{var n=this.session.getTabSize();this.session.isTabStop(e)&&this.doc.getLine(e.row).slice(e.column-n,e.column).split(" ").length-1==n?this.moveCursorBy(0,-n):this.moveCursorBy(0,-1)}},this.moveCursorRight=function(){var e=this.lead.getPosition(),t;if(t=this.session.getFoldAt(e.row,e.column,1))this.moveCursorTo(t.end.row,t.end.column);else if(this.lead.column==this.doc.getLine(this.lead.row).length)this.lead.row<this.doc.getLength()-1&&this.moveCursorTo(this.lead.row+1,0);else{var n=this.session.getTabSize(),e=this.lead;this.session.isTabStop(e)&&this.doc.getLine(e.row).slice(e.column,e.column+n).split(" ").length-1==n?this.moveCursorBy(0,n):this.moveCursorBy(0,1)}},this.moveCursorLineStart=function(){var e=this.lead.row,t=this.lead.column,n=this.session.documentToScreenRow(e,t),r=this.session.screenToDocumentPosition(n,0),i=this.session.getDisplayLine(e,null,r.row,r.column),s=i.match(/^\s*/);s[0].length!=t&&!this.session.$useEmacsStyleLineStart&&(r.column+=s[0].length),this.moveCursorToPosition(r)},this.moveCursorLineEnd=function(){var e=this.lead,t=this.session.getDocumentLastRowColumnPosition(e.row,e.column);if(this.lead.column==t.column){var n=this.session.getLine(t.row);if(t.column==n.length){var r=n.search(/\s+$/);r>0&&(t.column=r)}}this.moveCursorTo(t.row,t.column)},this.moveCursorFileEnd=function(){var e=this.doc.getLength()-1,t=this.doc.getLine(e).length;this.moveCursorTo(e,t)},this.moveCursorFileStart=function(){this.moveCursorTo(0,0)},this.moveCursorLongWordRight=function(){var e=this.lead.row,t=this.lead.column,n=this.doc.getLine(e),r=n.substring(t),i;this.session.nonTokenRe.lastIndex=0,this.session.tokenRe.lastIndex=0;var s=this.session.getFoldAt(e,t,1);if(s){this.moveCursorTo(s.end.row,s.end.column);return}if(i=this.session.nonTokenRe.exec(r))t+=this.session.nonTokenRe.lastIndex,this.session.nonTokenRe.lastIndex=0,r=n.substring(t);if(t>=n.length){this.moveCursorTo(e,n.length),this.moveCursorRight(),e<this.doc.getLength()-1&&this.moveCursorWordRight();return}if(i=this.session.tokenRe.exec(r))t+=this.session.tokenRe.lastIndex,this.session.tokenRe.lastIndex=0;this.moveCursorTo(e,t)},this.moveCursorLongWordLeft=function(){var e=this.lead.row,t=this.lead.column,n;if(n=this.session.getFoldAt(e,t,-1)){this.moveCursorTo(n.start.row,n.start.column);return}var r=this.session.getFoldStringAt(e,t,-1);r==null&&(r=this.doc.getLine(e).substring(0,t));var s=i.stringReverse(r),o;this.session.nonTokenRe.lastIndex=0,this.session.tokenRe.lastIndex=0;if(o=this.session.nonTokenRe.exec(s))t-=this.session.nonTokenRe.lastIndex,s=s.slice(this.session.nonTokenRe.lastIndex),this.session.nonTokenRe.lastIndex=0;if(t<=0){this.moveCursorTo(e,0),this.moveCursorLeft(),e>0&&this.moveCursorWordLeft();return}if(o=this.session.tokenRe.exec(s))t-=this.session.tokenRe.lastIndex,this.session.tokenRe.lastIndex=0;this.moveCursorTo(e,t)},this.$shortWordEndIndex=function(e){var t,n=0,r,i=/\s/,s=this.session.tokenRe;s.lastIndex=0;if(t=this.session.tokenRe.exec(e))n=this.session.tokenRe.lastIndex;else{while((r=e[n])&&i.test(r))n++;if(n<1){s.lastIndex=0;while((r=e[n])&&!s.test(r)){s.lastIndex=0,n++;if(i.test(r)){if(n>2){n--;break}while((r=e[n])&&i.test(r))n++;if(n>2)break}}}}return s.lastIndex=0,n},this.moveCursorShortWordRight=function(){var e=this.lead.row,t=this.lead.column,n=this.doc.getLine(e),r=n.substring(t),i=this.session.getFoldAt(e,t,1);if(i)return this.moveCursorTo(i.end.row,i.end.column);if(t==n.length){var s=this.doc.getLength();do e++,r=this.doc.getLine(e);while(e<s&&/^\s*$/.test(r));/^\s+/.test(r)||(r=""),t=0}var o=this.$shortWordEndIndex(r);this.moveCursorTo(e,t+o)},this.moveCursorShortWordLeft=function(){var e=this.lead.row,t=this.lead.column,n;if(n=this.session.getFoldAt(e,t,-1))return this.moveCursorTo(n.start.row,n.start.column);var r=this.session.getLine(e).substring(0,t);if(t===0){do e--,r=this.doc.getLine(e);while(e>0&&/^\s*$/.test(r));t=r.length,/\s+$/.test(r)||(r="")}var s=i.stringReverse(r),o=this.$shortWordEndIndex(s);return this.moveCursorTo(e,t-o)},this.moveCursorWordRight=function(){this.session.$selectLongWords?this.moveCursorLongWordRight():this.moveCursorShortWordRight()},this.moveCursorWordLeft=function(){this.session.$selectLongWords?this.moveCursorLongWordLeft():this.moveCursorShortWordLeft()},this.moveCursorBy=function(e,t){var n=this.session.documentToScreenPosition(this.lead.row,this.lead.column);t===0&&(this.$desiredColumn?n.column=this.$desiredColumn:this.$desiredColumn=n.column);var r=this.session.screenToDocumentPosition(n.row+e,n.column);e!==0&&t===0&&r.row===this.lead.row&&r.column===this.lead.column&&this.session.lineWidgets&&this.session.lineWidgets[r.row]&&(r.row>0||e>0)&&r.row++,this.moveCursorTo(r.row,r.column+t,t===0)},this.moveCursorToPosition=function(e){this.moveCursorTo(e.row,e.column)},this.moveCursorTo=function(e,t,n){var r=this.session.getFoldAt(e,t,1);r&&(e=r.start.row,t=r.start.column),this.$keepDesiredColumnOnChange=!0,this.lead.setPosition(e,t),this.$keepDesiredColumnOnChange=!1,n||(this.$desiredColumn=null)},this.moveCursorToScreen=function(e,t,n){var r=this.session.screenToDocumentPosition(e,t);this.moveCursorTo(r.row,r.column,n)},this.detach=function(){this.lead.detach(),this.anchor.detach(),this.session=this.doc=null},this.fromOrientedRange=function(e){this.setSelectionRange(e,e.cursor==e.start),this.$desiredColumn=e.desiredColumn||this.$desiredColumn},this.toOrientedRange=function(e){var t=this.getRange();return e?(e.start.column=t.start.column,e.start.row=t.start.row,e.end.column=t.end.column,e.end.row=t.end.row):e=t,e.cursor=this.isBackwards()?e.start:e.end,e.desiredColumn=this.$desiredColumn,e},this.getRangeOfMovements=function(e){var t=this.getCursor();try{e(this);var n=this.getCursor();return o.fromPoints(t,n)}catch(r){return o.fromPoints(t,t)}finally{this.moveCursorToPosition(t)}},this.toJSON=function(){if(this.rangeCount)var e=this.ranges.map(function(e){var t=e.clone();return t.isBackwards=e.cursor==e.start,t});else{var e=this.getRange();e.isBackwards=this.isBackwards()}return e},this.fromJSON=function(e){if(e.start==undefined){if(this.rangeList){this.toSingleRange(e[0]);for(var t=e.length;t--;){var n=o.fromPoints(e[t].start,e[t].end);e[t].isBackwards&&(n.cursor=n.start),this.addRange(n,!0)}return}e=e[0]}this.rangeList&&this.toSingleRange(e),this.setSelectionRange(e,e.isBackwards)},this.isEqual=function(e){if((e.length||this.rangeCount)&&e.length!=this.rangeCount)return!1;if(!e.length||!this.ranges)return this.getRange().isEqual(e);for(var t=this.ranges.length;t--;)if(!this.ranges[t].isEqual(e[t]))return!1;return!0}}).call(u.prototype),t.Selection=u}),define("ace/tokenizer",["require","exports","module","ace/config"],function(e,t,n){"use strict";var r=e("./config"),i=2e3,s=function(e){this.states=e,this.regExps={},this.matchMappings={};for(var t in this.states){var n=this.states[t],r=[],i=0,s=this.matchMappings[t]={defaultToken:"text"},o="g",u=[];for(var a=0;a<n.length;a++){var f=n[a];f.defaultToken&&(s.defaultToken=f.defaultToken),f.caseInsensitive&&(o="gi");if(f.regex==null)continue;f.regex instanceof RegExp&&(f.regex=f.regex.toString().slice(1,-1));var l=f.regex,c=(new RegExp("(?:("+l+")|(.))")).exec("a").length-2;Array.isArray(f.token)?f.token.length==1||c==1?f.token=f.token[0]:c-1!=f.token.length?(this.reportError("number of classes and regexp groups doesn't match",{rule:f,groupCount:c-1}),f.token=f.token[0]):(f.tokenArray=f.token,f.token=null,f.onMatch=this.$arrayTokens):typeof f.token=="function"&&!f.onMatch&&(c>1?f.onMatch=this.$applyToken:f.onMatch=f.token),c>1&&(/\\\d/.test(f.regex)?l=f.regex.replace(/\\([0-9]+)/g,function(e,t){return"\\"+(parseInt(t,10)+i+1)}):(c=1,l=this.removeCapturingGroups(f.regex)),!f.splitRegex&&typeof f.token!="string"&&u.push(f)),s[i]=a,i+=c,r.push(l),f.onMatch||(f.onMatch=null)}r.length||(s[0]=0,r.push("$")),u.forEach(function(e){e.splitRegex=this.createSplitterRegexp(e.regex,o)},this),this.regExps[t]=new RegExp("("+r.join(")|(")+")|($)",o)}};(function(){this.$setMaxTokenCount=function(e){i=e|0},this.$applyToken=function(e){var t=this.splitRegex.exec(e).slice(1),n=this.token.apply(this,t);if(typeof n=="string")return[{type:n,value:e}];var r=[];for(var i=0,s=n.length;i<s;i++)t[i]&&(r[r.length]={type:n[i],value:t[i]});return r},this.$arrayTokens=function(e){if(!e)return[];var t=this.splitRegex.exec(e);if(!t)return"text";var n=[],r=this.tokenArray;for(var i=0,s=r.length;i<s;i++)t[i+1]&&(n[n.length]={type:r[i],value:t[i+1]});return n},this.removeCapturingGroups=function(e){var t=e.replace(/\[(?:\\.|[^\]])*?\]|\\.|\(\?[:=!]|(\()/g,function(e,t){return t?"(?:":e});return t},this.createSplitterRegexp=function(e,t){if(e.indexOf("(?=")!=-1){var n=0,r=!1,i={};e.replace(/(\\.)|(\((?:\?[=!])?)|(\))|([\[\]])/g,function(e,t,s,o,u,a){return r?r=u!="]":u?r=!0:o?(n==i.stack&&(i.end=a+1,i.stack=-1),n--):s&&(n++,s.length!=1&&(i.stack=n,i.start=a)),e}),i.end!=null&&/^\)*$/.test(e.substr(i.end))&&(e=e.substring(0,i.start)+e.substr(i.end))}return e.charAt(0)!="^"&&(e="^"+e),e.charAt(e.length-1)!="$"&&(e+="$"),new RegExp(e,(t||"").replace("g",""))},this.getLineTokens=function(e,t){if(t&&typeof t!="string"){var n=t.slice(0);t=n[0],t==="#tmp"&&(n.shift(),t=n.shift())}else var n=[];var r=t||"start",s=this.states[r];s||(r="start",s=this.states[r]);var o=this.matchMappings[r],u=this.regExps[r];u.lastIndex=0;var a,f=[],l=0,c=0,h={type:null,value:""};while(a=u.exec(e)){var p=o.defaultToken,d=null,v=a[0],m=u.lastIndex;if(m-v.length>l){var g=e.substring(l,m-v.length);h.type==p?h.value+=g:(h.type&&f.push(h),h={type:p,value:g})}for(var y=0;y<a.length-2;y++){if(a[y+1]===undefined)continue;d=s[o[y]],d.onMatch?p=d.onMatch(v,r,n):p=d.token,d.next&&(typeof d.next=="string"?r=d.next:r=d.next(r,n),s=this.states[r],s||(this.reportError("state doesn't exist",r),r="start",s=this.states[r]),o=this.matchMappings[r],l=m,u=this.regExps[r],u.lastIndex=m);break}if(v)if(typeof p=="string")!!d&&d.merge===!1||h.type!==p?(h.type&&f.push(h),h={type:p,value:v}):h.value+=v;else if(p){h.type&&f.push(h),h={type:null,value:""};for(var y=0;y<p.length;y++)f.push(p[y])}if(l==e.length)break;l=m;if(c++>i){c>2*e.length&&this.reportError("infinite loop with in ace tokenizer",{startState:t,line:e});while(l<e.length)h.type&&f.push(h),h={value:e.substring(l,l+=2e3),type:"overflow"};r="start",n=[];break}}return h.type&&f.push(h),n.length>1&&n[0]!==r&&n.unshift("#tmp",r),{tokens:f,state:n.length?n:r}},this.reportError=r.reportError}).call(s.prototype),t.Tokenizer=s}),define("ace/mode/text_highlight_rules",["require","exports","module","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../lib/lang"),i=function(){this.$rules={start:[{token:"empty_line",regex:"^$"},{defaultToken:"text"}]}};(function(){this.addRules=function(e,t){if(!t){for(var n in e)this.$rules[n]=e[n];return}for(var n in e){var r=e[n];for(var i=0;i<r.length;i++){var s=r[i];if(s.next||s.onMatch)typeof s.next=="string"&&s.next.indexOf(t)!==0&&(s.next=t+s.next),s.nextState&&s.nextState.indexOf(t)!==0&&(s.nextState=t+s.nextState)}this.$rules[t+n]=r}},this.getRules=function(){return this.$rules},this.embedRules=function(e,t,n,i,s){var o=typeof e=="function"?(new e).getRules():e;if(i)for(var u=0;u<i.length;u++)i[u]=t+i[u];else{i=[];for(var a in o)i.push(t+a)}this.addRules(o,t);if(n){var f=Array.prototype[s?"push":"unshift"];for(var u=0;u<i.length;u++)f.apply(this.$rules[i[u]],r.deepCopy(n))}this.$embeds||(this.$embeds=[]),this.$embeds.push(t)},this.getEmbeds=function(){return this.$embeds};var e=function(e,t){return(e!="start"||t.length)&&t.unshift(this.nextState,e),this.nextState},t=function(e,t){return t.shift(),t.shift()||"start"};this.normalizeRules=function(){function i(s){var o=r[s];o.processed=!0;for(var u=0;u<o.length;u++){var a=o[u],f=null;Array.isArray(a)&&(f=a,a={}),!a.regex&&a.start&&(a.regex=a.start,a.next||(a.next=[]),a.next.push({defaultToken:a.token},{token:a.token+".end",regex:a.end||a.start,next:"pop"}),a.token=a.token+".start",a.push=!0);var l=a.next||a.push;if(l&&Array.isArray(l)){var c=a.stateName;c||(c=a.token,typeof c!="string"&&(c=c[0]||""),r[c]&&(c+=n++)),r[c]=l,a.next=c,i(c)}else l=="pop"&&(a.next=t);a.push&&(a.nextState=a.next||a.push,a.next=e,delete a.push);if(a.rules)for(var h in a.rules)r[h]?r[h].push&&r[h].push.apply(r[h],a.rules[h]):r[h]=a.rules[h];var p=typeof a=="string"?a:typeof a.include=="string"?a.include:"";p&&(f=r[p]);if(f){var d=[u,1].concat(f);a.noEscape&&(d=d.filter(function(e){return!e.next})),o.splice.apply(o,d),u--}a.keywordMap&&(a.token=this.createKeywordMapper(a.keywordMap,a.defaultToken||"text",a.caseInsensitive),delete a.defaultToken)}}var n=0,r=this.$rules;Object.keys(r).forEach(i,this)},this.createKeywordMapper=function(e,t,n,r){var i=Object.create(null);return Object.keys(e).forEach(function(t){var s=e[t];n&&(s=s.toLowerCase());var o=s.split(r||"|");for(var u=o.length;u--;)i[o[u]]=t}),Object.getPrototypeOf(i)&&(i.__proto__=null),this.$keywordList=Object.keys(i),e=null,n?function(e){return i[e.toLowerCase()]||t}:function(e){return i[e]||t}},this.getKeywords=function(){return this.$keywords}}).call(i.prototype),t.TextHighlightRules=i}),define("ace/mode/behaviour",["require","exports","module"],function(e,t,n){"use strict";var r=function(){this.$behaviours={}};(function(){this.add=function(e,t,n){switch(undefined){case this.$behaviours:this.$behaviours={};case this.$behaviours[e]:this.$behaviours[e]={}}this.$behaviours[e][t]=n},this.addBehaviours=function(e){for(var t in e)for(var n in e[t])this.add(t,n,e[t][n])},this.remove=function(e){this.$behaviours&&this.$behaviours[e]&&delete this.$behaviours[e]},this.inherit=function(e,t){if(typeof e=="function")var n=(new e).getBehaviours(t);else var n=e.getBehaviours(t);this.addBehaviours(n)},this.getBehaviours=function(e){if(!e)return this.$behaviours;var t={};for(var n=0;n<e.length;n++)this.$behaviours[e[n]]&&(t[e[n]]=this.$behaviours[e[n]]);return t}}).call(r.prototype),t.Behaviour=r}),define("ace/unicode",["require","exports","module"],function(e,t,n){"use strict";function r(e){var n=/\w{4}/g;for(var r in e)t.packages[r]=e[r].replace(n,"\\u$&")}t.packages={},r({L:"0041-005A0061-007A00AA00B500BA00C0-00D600D8-00F600F8-02C102C6-02D102E0-02E402EC02EE0370-037403760377037A-037D03860388-038A038C038E-03A103A3-03F503F7-0481048A-05250531-055605590561-058705D0-05EA05F0-05F20621-064A066E066F0671-06D306D506E506E606EE06EF06FA-06FC06FF07100712-072F074D-07A507B107CA-07EA07F407F507FA0800-0815081A082408280904-0939093D09500958-0961097109720979-097F0985-098C098F09900993-09A809AA-09B009B209B6-09B909BD09CE09DC09DD09DF-09E109F009F10A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A59-0A5C0A5E0A72-0A740A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD0AD00AE00AE10B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D0B5C0B5D0B5F-0B610B710B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BD00C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D0C580C590C600C610C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD0CDE0CE00CE10D05-0D0C0D0E-0D100D12-0D280D2A-0D390D3D0D600D610D7A-0D7F0D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60E01-0E300E320E330E40-0E460E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB00EB20EB30EBD0EC0-0EC40EC60EDC0EDD0F000F40-0F470F49-0F6C0F88-0F8B1000-102A103F1050-1055105A-105D106110651066106E-10701075-1081108E10A0-10C510D0-10FA10FC1100-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA1700-170C170E-17111720-17311740-17511760-176C176E-17701780-17B317D717DC1820-18771880-18A818AA18B0-18F51900-191C1950-196D1970-19741980-19AB19C1-19C71A00-1A161A20-1A541AA71B05-1B331B45-1B4B1B83-1BA01BAE1BAF1C00-1C231C4D-1C4F1C5A-1C7D1CE9-1CEC1CEE-1CF11D00-1DBF1E00-1F151F18-1F1D1F20-1F451F48-1F4D1F50-1F571F591F5B1F5D1F5F-1F7D1F80-1FB41FB6-1FBC1FBE1FC2-1FC41FC6-1FCC1FD0-1FD31FD6-1FDB1FE0-1FEC1FF2-1FF41FF6-1FFC2071207F2090-209421022107210A-211321152119-211D212421262128212A-212D212F-2139213C-213F2145-2149214E218321842C00-2C2E2C30-2C5E2C60-2CE42CEB-2CEE2D00-2D252D30-2D652D6F2D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE2E2F300530063031-3035303B303C3041-3096309D-309F30A1-30FA30FC-30FF3105-312D3131-318E31A0-31B731F0-31FF3400-4DB54E00-9FCBA000-A48CA4D0-A4FDA500-A60CA610-A61FA62AA62BA640-A65FA662-A66EA67F-A697A6A0-A6E5A717-A71FA722-A788A78BA78CA7FB-A801A803-A805A807-A80AA80C-A822A840-A873A882-A8B3A8F2-A8F7A8FBA90A-A925A930-A946A960-A97CA984-A9B2A9CFAA00-AA28AA40-AA42AA44-AA4BAA60-AA76AA7AAA80-AAAFAAB1AAB5AAB6AAB9-AABDAAC0AAC2AADB-AADDABC0-ABE2AC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA2DFA30-FA6DFA70-FAD9FB00-FB06FB13-FB17FB1DFB1F-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF21-FF3AFF41-FF5AFF66-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC",Ll:"0061-007A00AA00B500BA00DF-00F600F8-00FF01010103010501070109010B010D010F01110113011501170119011B011D011F01210123012501270129012B012D012F01310133013501370138013A013C013E014001420144014601480149014B014D014F01510153015501570159015B015D015F01610163016501670169016B016D016F0171017301750177017A017C017E-0180018301850188018C018D019201950199-019B019E01A101A301A501A801AA01AB01AD01B001B401B601B901BA01BD-01BF01C601C901CC01CE01D001D201D401D601D801DA01DC01DD01DF01E101E301E501E701E901EB01ED01EF01F001F301F501F901FB01FD01FF02010203020502070209020B020D020F02110213021502170219021B021D021F02210223022502270229022B022D022F02310233-0239023C023F0240024202470249024B024D024F-02930295-02AF037103730377037B-037D039003AC-03CE03D003D103D5-03D703D903DB03DD03DF03E103E303E503E703E903EB03ED03EF-03F303F503F803FB03FC0430-045F04610463046504670469046B046D046F04710473047504770479047B047D047F0481048B048D048F04910493049504970499049B049D049F04A104A304A504A704A904AB04AD04AF04B104B304B504B704B904BB04BD04BF04C204C404C604C804CA04CC04CE04CF04D104D304D504D704D904DB04DD04DF04E104E304E504E704E904EB04ED04EF04F104F304F504F704F904FB04FD04FF05010503050505070509050B050D050F05110513051505170519051B051D051F0521052305250561-05871D00-1D2B1D62-1D771D79-1D9A1E011E031E051E071E091E0B1E0D1E0F1E111E131E151E171E191E1B1E1D1E1F1E211E231E251E271E291E2B1E2D1E2F1E311E331E351E371E391E3B1E3D1E3F1E411E431E451E471E491E4B1E4D1E4F1E511E531E551E571E591E5B1E5D1E5F1E611E631E651E671E691E6B1E6D1E6F1E711E731E751E771E791E7B1E7D1E7F1E811E831E851E871E891E8B1E8D1E8F1E911E931E95-1E9D1E9F1EA11EA31EA51EA71EA91EAB1EAD1EAF1EB11EB31EB51EB71EB91EBB1EBD1EBF1EC11EC31EC51EC71EC91ECB1ECD1ECF1ED11ED31ED51ED71ED91EDB1EDD1EDF1EE11EE31EE51EE71EE91EEB1EED1EEF1EF11EF31EF51EF71EF91EFB1EFD1EFF-1F071F10-1F151F20-1F271F30-1F371F40-1F451F50-1F571F60-1F671F70-1F7D1F80-1F871F90-1F971FA0-1FA71FB0-1FB41FB61FB71FBE1FC2-1FC41FC61FC71FD0-1FD31FD61FD71FE0-1FE71FF2-1FF41FF61FF7210A210E210F2113212F21342139213C213D2146-2149214E21842C30-2C5E2C612C652C662C682C6A2C6C2C712C732C742C76-2C7C2C812C832C852C872C892C8B2C8D2C8F2C912C932C952C972C992C9B2C9D2C9F2CA12CA32CA52CA72CA92CAB2CAD2CAF2CB12CB32CB52CB72CB92CBB2CBD2CBF2CC12CC32CC52CC72CC92CCB2CCD2CCF2CD12CD32CD52CD72CD92CDB2CDD2CDF2CE12CE32CE42CEC2CEE2D00-2D25A641A643A645A647A649A64BA64DA64FA651A653A655A657A659A65BA65DA65FA663A665A667A669A66BA66DA681A683A685A687A689A68BA68DA68FA691A693A695A697A723A725A727A729A72BA72DA72F-A731A733A735A737A739A73BA73DA73FA741A743A745A747A749A74BA74DA74FA751A753A755A757A759A75BA75DA75FA761A763A765A767A769A76BA76DA76FA771-A778A77AA77CA77FA781A783A785A787A78CFB00-FB06FB13-FB17FF41-FF5A",Lu:"0041-005A00C0-00D600D8-00DE01000102010401060108010A010C010E01100112011401160118011A011C011E01200122012401260128012A012C012E01300132013401360139013B013D013F0141014301450147014A014C014E01500152015401560158015A015C015E01600162016401660168016A016C016E017001720174017601780179017B017D018101820184018601870189-018B018E-0191019301940196-0198019C019D019F01A001A201A401A601A701A901AC01AE01AF01B1-01B301B501B701B801BC01C401C701CA01CD01CF01D101D301D501D701D901DB01DE01E001E201E401E601E801EA01EC01EE01F101F401F6-01F801FA01FC01FE02000202020402060208020A020C020E02100212021402160218021A021C021E02200222022402260228022A022C022E02300232023A023B023D023E02410243-02460248024A024C024E03700372037603860388-038A038C038E038F0391-03A103A3-03AB03CF03D2-03D403D803DA03DC03DE03E003E203E403E603E803EA03EC03EE03F403F703F903FA03FD-042F04600462046404660468046A046C046E04700472047404760478047A047C047E0480048A048C048E04900492049404960498049A049C049E04A004A204A404A604A804AA04AC04AE04B004B204B404B604B804BA04BC04BE04C004C104C304C504C704C904CB04CD04D004D204D404D604D804DA04DC04DE04E004E204E404E604E804EA04EC04EE04F004F204F404F604F804FA04FC04FE05000502050405060508050A050C050E05100512051405160518051A051C051E0520052205240531-055610A0-10C51E001E021E041E061E081E0A1E0C1E0E1E101E121E141E161E181E1A1E1C1E1E1E201E221E241E261E281E2A1E2C1E2E1E301E321E341E361E381E3A1E3C1E3E1E401E421E441E461E481E4A1E4C1E4E1E501E521E541E561E581E5A1E5C1E5E1E601E621E641E661E681E6A1E6C1E6E1E701E721E741E761E781E7A1E7C1E7E1E801E821E841E861E881E8A1E8C1E8E1E901E921E941E9E1EA01EA21EA41EA61EA81EAA1EAC1EAE1EB01EB21EB41EB61EB81EBA1EBC1EBE1EC01EC21EC41EC61EC81ECA1ECC1ECE1ED01ED21ED41ED61ED81EDA1EDC1EDE1EE01EE21EE41EE61EE81EEA1EEC1EEE1EF01EF21EF41EF61EF81EFA1EFC1EFE1F08-1F0F1F18-1F1D1F28-1F2F1F38-1F3F1F48-1F4D1F591F5B1F5D1F5F1F68-1F6F1FB8-1FBB1FC8-1FCB1FD8-1FDB1FE8-1FEC1FF8-1FFB21022107210B-210D2110-211221152119-211D212421262128212A-212D2130-2133213E213F214521832C00-2C2E2C602C62-2C642C672C692C6B2C6D-2C702C722C752C7E-2C802C822C842C862C882C8A2C8C2C8E2C902C922C942C962C982C9A2C9C2C9E2CA02CA22CA42CA62CA82CAA2CAC2CAE2CB02CB22CB42CB62CB82CBA2CBC2CBE2CC02CC22CC42CC62CC82CCA2CCC2CCE2CD02CD22CD42CD62CD82CDA2CDC2CDE2CE02CE22CEB2CEDA640A642A644A646A648A64AA64CA64EA650A652A654A656A658A65AA65CA65EA662A664A666A668A66AA66CA680A682A684A686A688A68AA68CA68EA690A692A694A696A722A724A726A728A72AA72CA72EA732A734A736A738A73AA73CA73EA740A742A744A746A748A74AA74CA74EA750A752A754A756A758A75AA75CA75EA760A762A764A766A768A76AA76CA76EA779A77BA77DA77EA780A782A784A786A78BFF21-FF3A",Lt:"01C501C801CB01F21F88-1F8F1F98-1F9F1FA8-1FAF1FBC1FCC1FFC",Lm:"02B0-02C102C6-02D102E0-02E402EC02EE0374037A0559064006E506E607F407F507FA081A0824082809710E460EC610FC17D718431AA71C78-1C7D1D2C-1D611D781D9B-1DBF2071207F2090-20942C7D2D6F2E2F30053031-3035303B309D309E30FC-30FEA015A4F8-A4FDA60CA67FA717-A71FA770A788A9CFAA70AADDFF70FF9EFF9F",Lo:"01BB01C0-01C3029405D0-05EA05F0-05F20621-063F0641-064A066E066F0671-06D306D506EE06EF06FA-06FC06FF07100712-072F074D-07A507B107CA-07EA0800-08150904-0939093D09500958-096109720979-097F0985-098C098F09900993-09A809AA-09B009B209B6-09B909BD09CE09DC09DD09DF-09E109F009F10A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A59-0A5C0A5E0A72-0A740A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD0AD00AE00AE10B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D0B5C0B5D0B5F-0B610B710B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BD00C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D0C580C590C600C610C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD0CDE0CE00CE10D05-0D0C0D0E-0D100D12-0D280D2A-0D390D3D0D600D610D7A-0D7F0D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60E01-0E300E320E330E40-0E450E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB00EB20EB30EBD0EC0-0EC40EDC0EDD0F000F40-0F470F49-0F6C0F88-0F8B1000-102A103F1050-1055105A-105D106110651066106E-10701075-1081108E10D0-10FA1100-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA1700-170C170E-17111720-17311740-17511760-176C176E-17701780-17B317DC1820-18421844-18771880-18A818AA18B0-18F51900-191C1950-196D1970-19741980-19AB19C1-19C71A00-1A161A20-1A541B05-1B331B45-1B4B1B83-1BA01BAE1BAF1C00-1C231C4D-1C4F1C5A-1C771CE9-1CEC1CEE-1CF12135-21382D30-2D652D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE3006303C3041-3096309F30A1-30FA30FF3105-312D3131-318E31A0-31B731F0-31FF3400-4DB54E00-9FCBA000-A014A016-A48CA4D0-A4F7A500-A60BA610-A61FA62AA62BA66EA6A0-A6E5A7FB-A801A803-A805A807-A80AA80C-A822A840-A873A882-A8B3A8F2-A8F7A8FBA90A-A925A930-A946A960-A97CA984-A9B2AA00-AA28AA40-AA42AA44-AA4BAA60-AA6FAA71-AA76AA7AAA80-AAAFAAB1AAB5AAB6AAB9-AABDAAC0AAC2AADBAADCABC0-ABE2AC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA2DFA30-FA6DFA70-FAD9FB1DFB1F-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF66-FF6FFF71-FF9DFFA0-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC",M:"0300-036F0483-04890591-05BD05BF05C105C205C405C505C70610-061A064B-065E067006D6-06DC06DE-06E406E706E806EA-06ED07110730-074A07A6-07B007EB-07F30816-0819081B-08230825-08270829-082D0900-0903093C093E-094E0951-0955096209630981-098309BC09BE-09C409C709C809CB-09CD09D709E209E30A01-0A030A3C0A3E-0A420A470A480A4B-0A4D0A510A700A710A750A81-0A830ABC0ABE-0AC50AC7-0AC90ACB-0ACD0AE20AE30B01-0B030B3C0B3E-0B440B470B480B4B-0B4D0B560B570B620B630B820BBE-0BC20BC6-0BC80BCA-0BCD0BD70C01-0C030C3E-0C440C46-0C480C4A-0C4D0C550C560C620C630C820C830CBC0CBE-0CC40CC6-0CC80CCA-0CCD0CD50CD60CE20CE30D020D030D3E-0D440D46-0D480D4A-0D4D0D570D620D630D820D830DCA0DCF-0DD40DD60DD8-0DDF0DF20DF30E310E34-0E3A0E47-0E4E0EB10EB4-0EB90EBB0EBC0EC8-0ECD0F180F190F350F370F390F3E0F3F0F71-0F840F860F870F90-0F970F99-0FBC0FC6102B-103E1056-1059105E-10601062-10641067-106D1071-10741082-108D108F109A-109D135F1712-17141732-1734175217531772177317B6-17D317DD180B-180D18A91920-192B1930-193B19B0-19C019C819C91A17-1A1B1A55-1A5E1A60-1A7C1A7F1B00-1B041B34-1B441B6B-1B731B80-1B821BA1-1BAA1C24-1C371CD0-1CD21CD4-1CE81CED1CF21DC0-1DE61DFD-1DFF20D0-20F02CEF-2CF12DE0-2DFF302A-302F3099309AA66F-A672A67CA67DA6F0A6F1A802A806A80BA823-A827A880A881A8B4-A8C4A8E0-A8F1A926-A92DA947-A953A980-A983A9B3-A9C0AA29-AA36AA43AA4CAA4DAA7BAAB0AAB2-AAB4AAB7AAB8AABEAABFAAC1ABE3-ABEAABECABEDFB1EFE00-FE0FFE20-FE26",Mn:"0300-036F0483-04870591-05BD05BF05C105C205C405C505C70610-061A064B-065E067006D6-06DC06DF-06E406E706E806EA-06ED07110730-074A07A6-07B007EB-07F30816-0819081B-08230825-08270829-082D0900-0902093C0941-0948094D0951-095509620963098109BC09C1-09C409CD09E209E30A010A020A3C0A410A420A470A480A4B-0A4D0A510A700A710A750A810A820ABC0AC1-0AC50AC70AC80ACD0AE20AE30B010B3C0B3F0B41-0B440B4D0B560B620B630B820BC00BCD0C3E-0C400C46-0C480C4A-0C4D0C550C560C620C630CBC0CBF0CC60CCC0CCD0CE20CE30D41-0D440D4D0D620D630DCA0DD2-0DD40DD60E310E34-0E3A0E47-0E4E0EB10EB4-0EB90EBB0EBC0EC8-0ECD0F180F190F350F370F390F71-0F7E0F80-0F840F860F870F90-0F970F99-0FBC0FC6102D-10301032-10371039103A103D103E10581059105E-10601071-1074108210851086108D109D135F1712-17141732-1734175217531772177317B7-17BD17C617C9-17D317DD180B-180D18A91920-19221927192819321939-193B1A171A181A561A58-1A5E1A601A621A65-1A6C1A73-1A7C1A7F1B00-1B031B341B36-1B3A1B3C1B421B6B-1B731B801B811BA2-1BA51BA81BA91C2C-1C331C361C371CD0-1CD21CD4-1CE01CE2-1CE81CED1DC0-1DE61DFD-1DFF20D0-20DC20E120E5-20F02CEF-2CF12DE0-2DFF302A-302F3099309AA66FA67CA67DA6F0A6F1A802A806A80BA825A826A8C4A8E0-A8F1A926-A92DA947-A951A980-A982A9B3A9B6-A9B9A9BCAA29-AA2EAA31AA32AA35AA36AA43AA4CAAB0AAB2-AAB4AAB7AAB8AABEAABFAAC1ABE5ABE8ABEDFB1EFE00-FE0FFE20-FE26",Mc:"0903093E-09400949-094C094E0982098309BE-09C009C709C809CB09CC09D70A030A3E-0A400A830ABE-0AC00AC90ACB0ACC0B020B030B3E0B400B470B480B4B0B4C0B570BBE0BBF0BC10BC20BC6-0BC80BCA-0BCC0BD70C01-0C030C41-0C440C820C830CBE0CC0-0CC40CC70CC80CCA0CCB0CD50CD60D020D030D3E-0D400D46-0D480D4A-0D4C0D570D820D830DCF-0DD10DD8-0DDF0DF20DF30F3E0F3F0F7F102B102C10311038103B103C105610571062-10641067-106D108310841087-108C108F109A-109C17B617BE-17C517C717C81923-19261929-192B193019311933-193819B0-19C019C819C91A19-1A1B1A551A571A611A631A641A6D-1A721B041B351B3B1B3D-1B411B431B441B821BA11BA61BA71BAA1C24-1C2B1C341C351CE11CF2A823A824A827A880A881A8B4-A8C3A952A953A983A9B4A9B5A9BAA9BBA9BD-A9C0AA2FAA30AA33AA34AA4DAA7BABE3ABE4ABE6ABE7ABE9ABEAABEC",Me:"0488048906DE20DD-20E020E2-20E4A670-A672",N:"0030-003900B200B300B900BC-00BE0660-066906F0-06F907C0-07C90966-096F09E6-09EF09F4-09F90A66-0A6F0AE6-0AEF0B66-0B6F0BE6-0BF20C66-0C6F0C78-0C7E0CE6-0CEF0D66-0D750E50-0E590ED0-0ED90F20-0F331040-10491090-10991369-137C16EE-16F017E0-17E917F0-17F91810-18191946-194F19D0-19DA1A80-1A891A90-1A991B50-1B591BB0-1BB91C40-1C491C50-1C5920702074-20792080-20892150-21822185-21892460-249B24EA-24FF2776-27932CFD30073021-30293038-303A3192-31953220-32293251-325F3280-328932B1-32BFA620-A629A6E6-A6EFA830-A835A8D0-A8D9A900-A909A9D0-A9D9AA50-AA59ABF0-ABF9FF10-FF19",Nd:"0030-00390660-066906F0-06F907C0-07C90966-096F09E6-09EF0A66-0A6F0AE6-0AEF0B66-0B6F0BE6-0BEF0C66-0C6F0CE6-0CEF0D66-0D6F0E50-0E590ED0-0ED90F20-0F291040-10491090-109917E0-17E91810-18191946-194F19D0-19DA1A80-1A891A90-1A991B50-1B591BB0-1BB91C40-1C491C50-1C59A620-A629A8D0-A8D9A900-A909A9D0-A9D9AA50-AA59ABF0-ABF9FF10-FF19",Nl:"16EE-16F02160-21822185-218830073021-30293038-303AA6E6-A6EF",No:"00B200B300B900BC-00BE09F4-09F90BF0-0BF20C78-0C7E0D70-0D750F2A-0F331369-137C17F0-17F920702074-20792080-20892150-215F21892460-249B24EA-24FF2776-27932CFD3192-31953220-32293251-325F3280-328932B1-32BFA830-A835",P:"0021-00230025-002A002C-002F003A003B003F0040005B-005D005F007B007D00A100AB00B700BB00BF037E0387055A-055F0589058A05BE05C005C305C605F305F40609060A060C060D061B061E061F066A-066D06D40700-070D07F7-07F90830-083E0964096509700DF40E4F0E5A0E5B0F04-0F120F3A-0F3D0F850FD0-0FD4104A-104F10FB1361-13681400166D166E169B169C16EB-16ED1735173617D4-17D617D8-17DA1800-180A1944194519DE19DF1A1E1A1F1AA0-1AA61AA8-1AAD1B5A-1B601C3B-1C3F1C7E1C7F1CD32010-20272030-20432045-20512053-205E207D207E208D208E2329232A2768-277527C527C627E6-27EF2983-299829D8-29DB29FC29FD2CF9-2CFC2CFE2CFF2E00-2E2E2E302E313001-30033008-30113014-301F3030303D30A030FBA4FEA4FFA60D-A60FA673A67EA6F2-A6F7A874-A877A8CEA8CFA8F8-A8FAA92EA92FA95FA9C1-A9CDA9DEA9DFAA5C-AA5FAADEAADFABEBFD3EFD3FFE10-FE19FE30-FE52FE54-FE61FE63FE68FE6AFE6BFF01-FF03FF05-FF0AFF0C-FF0FFF1AFF1BFF1FFF20FF3B-FF3DFF3FFF5BFF5DFF5F-FF65",Pd:"002D058A05BE140018062010-20152E172E1A301C303030A0FE31FE32FE58FE63FF0D",Ps:"0028005B007B0F3A0F3C169B201A201E2045207D208D23292768276A276C276E27702772277427C527E627E827EA27EC27EE2983298529872989298B298D298F299129932995299729D829DA29FC2E222E242E262E283008300A300C300E3010301430163018301A301DFD3EFE17FE35FE37FE39FE3BFE3DFE3FFE41FE43FE47FE59FE5BFE5DFF08FF3BFF5BFF5FFF62",Pe:"0029005D007D0F3B0F3D169C2046207E208E232A2769276B276D276F27712773277527C627E727E927EB27ED27EF298429862988298A298C298E2990299229942996299829D929DB29FD2E232E252E272E293009300B300D300F3011301530173019301B301E301FFD3FFE18FE36FE38FE3AFE3CFE3EFE40FE42FE44FE48FE5AFE5CFE5EFF09FF3DFF5DFF60FF63",Pi:"00AB2018201B201C201F20392E022E042E092E0C2E1C2E20",Pf:"00BB2019201D203A2E032E052E0A2E0D2E1D2E21",Pc:"005F203F20402054FE33FE34FE4D-FE4FFF3F",Po:"0021-00230025-0027002A002C002E002F003A003B003F0040005C00A100B700BF037E0387055A-055F058905C005C305C605F305F40609060A060C060D061B061E061F066A-066D06D40700-070D07F7-07F90830-083E0964096509700DF40E4F0E5A0E5B0F04-0F120F850FD0-0FD4104A-104F10FB1361-1368166D166E16EB-16ED1735173617D4-17D617D8-17DA1800-18051807-180A1944194519DE19DF1A1E1A1F1AA0-1AA61AA8-1AAD1B5A-1B601C3B-1C3F1C7E1C7F1CD3201620172020-20272030-2038203B-203E2041-20432047-205120532055-205E2CF9-2CFC2CFE2CFF2E002E012E06-2E082E0B2E0E-2E162E182E192E1B2E1E2E1F2E2A-2E2E2E302E313001-3003303D30FBA4FEA4FFA60D-A60FA673A67EA6F2-A6F7A874-A877A8CEA8CFA8F8-A8FAA92EA92FA95FA9C1-A9CDA9DEA9DFAA5C-AA5FAADEAADFABEBFE10-FE16FE19FE30FE45FE46FE49-FE4CFE50-FE52FE54-FE57FE5F-FE61FE68FE6AFE6BFF01-FF03FF05-FF07FF0AFF0CFF0EFF0FFF1AFF1BFF1FFF20FF3CFF61FF64FF65",S:"0024002B003C-003E005E0060007C007E00A2-00A900AC00AE-00B100B400B600B800D700F702C2-02C502D2-02DF02E5-02EB02ED02EF-02FF03750384038503F604820606-0608060B060E060F06E906FD06FE07F609F209F309FA09FB0AF10B700BF3-0BFA0C7F0CF10CF20D790E3F0F01-0F030F13-0F170F1A-0F1F0F340F360F380FBE-0FC50FC7-0FCC0FCE0FCF0FD5-0FD8109E109F13601390-139917DB194019E0-19FF1B61-1B6A1B74-1B7C1FBD1FBF-1FC11FCD-1FCF1FDD-1FDF1FED-1FEF1FFD1FFE20442052207A-207C208A-208C20A0-20B8210021012103-21062108210921142116-2118211E-2123212521272129212E213A213B2140-2144214A-214D214F2190-2328232B-23E82400-24262440-244A249C-24E92500-26CD26CF-26E126E326E8-26FF2701-27042706-2709270C-27272729-274B274D274F-27522756-275E2761-276727942798-27AF27B1-27BE27C0-27C427C7-27CA27CC27D0-27E527F0-29822999-29D729DC-29FB29FE-2B4C2B50-2B592CE5-2CEA2E80-2E992E9B-2EF32F00-2FD52FF0-2FFB300430123013302030363037303E303F309B309C319031913196-319F31C0-31E33200-321E322A-32503260-327F328A-32B032C0-32FE3300-33FF4DC0-4DFFA490-A4C6A700-A716A720A721A789A78AA828-A82BA836-A839AA77-AA79FB29FDFCFDFDFE62FE64-FE66FE69FF04FF0BFF1C-FF1EFF3EFF40FF5CFF5EFFE0-FFE6FFE8-FFEEFFFCFFFD",Sm:"002B003C-003E007C007E00AC00B100D700F703F60606-060820442052207A-207C208A-208C2140-2144214B2190-2194219A219B21A021A321A621AE21CE21CF21D221D421F4-22FF2308-230B23202321237C239B-23B323DC-23E125B725C125F8-25FF266F27C0-27C427C7-27CA27CC27D0-27E527F0-27FF2900-29822999-29D729DC-29FB29FE-2AFF2B30-2B442B47-2B4CFB29FE62FE64-FE66FF0BFF1C-FF1EFF5CFF5EFFE2FFE9-FFEC",Sc:"002400A2-00A5060B09F209F309FB0AF10BF90E3F17DB20A0-20B8A838FDFCFE69FF04FFE0FFE1FFE5FFE6",Sk:"005E006000A800AF00B400B802C2-02C502D2-02DF02E5-02EB02ED02EF-02FF0375038403851FBD1FBF-1FC11FCD-1FCF1FDD-1FDF1FED-1FEF1FFD1FFE309B309CA700-A716A720A721A789A78AFF3EFF40FFE3",So:"00A600A700A900AE00B000B60482060E060F06E906FD06FE07F609FA0B700BF3-0BF80BFA0C7F0CF10CF20D790F01-0F030F13-0F170F1A-0F1F0F340F360F380FBE-0FC50FC7-0FCC0FCE0FCF0FD5-0FD8109E109F13601390-1399194019E0-19FF1B61-1B6A1B74-1B7C210021012103-21062108210921142116-2118211E-2123212521272129212E213A213B214A214C214D214F2195-2199219C-219F21A121A221A421A521A7-21AD21AF-21CD21D021D121D321D5-21F32300-2307230C-231F2322-2328232B-237B237D-239A23B4-23DB23E2-23E82400-24262440-244A249C-24E92500-25B625B8-25C025C2-25F72600-266E2670-26CD26CF-26E126E326E8-26FF2701-27042706-2709270C-27272729-274B274D274F-27522756-275E2761-276727942798-27AF27B1-27BE2800-28FF2B00-2B2F2B452B462B50-2B592CE5-2CEA2E80-2E992E9B-2EF32F00-2FD52FF0-2FFB300430123013302030363037303E303F319031913196-319F31C0-31E33200-321E322A-32503260-327F328A-32B032C0-32FE3300-33FF4DC0-4DFFA490-A4C6A828-A82BA836A837A839AA77-AA79FDFDFFE4FFE8FFEDFFEEFFFCFFFD",Z:"002000A01680180E2000-200A20282029202F205F3000",Zs:"002000A01680180E2000-200A202F205F3000",Zl:"2028",Zp:"2029",C:"0000-001F007F-009F00AD03780379037F-0383038B038D03A20526-05300557055805600588058B-059005C8-05CF05EB-05EF05F5-0605061C061D0620065F06DD070E070F074B074C07B2-07BF07FB-07FF082E082F083F-08FF093A093B094F095609570973-097809800984098D098E0991099209A909B109B3-09B509BA09BB09C509C609C909CA09CF-09D609D8-09DB09DE09E409E509FC-0A000A040A0B-0A0E0A110A120A290A310A340A370A3A0A3B0A3D0A43-0A460A490A4A0A4E-0A500A52-0A580A5D0A5F-0A650A76-0A800A840A8E0A920AA90AB10AB40ABA0ABB0AC60ACA0ACE0ACF0AD1-0ADF0AE40AE50AF00AF2-0B000B040B0D0B0E0B110B120B290B310B340B3A0B3B0B450B460B490B4A0B4E-0B550B58-0B5B0B5E0B640B650B72-0B810B840B8B-0B8D0B910B96-0B980B9B0B9D0BA0-0BA20BA5-0BA70BAB-0BAD0BBA-0BBD0BC3-0BC50BC90BCE0BCF0BD1-0BD60BD8-0BE50BFB-0C000C040C0D0C110C290C340C3A-0C3C0C450C490C4E-0C540C570C5A-0C5F0C640C650C70-0C770C800C810C840C8D0C910CA90CB40CBA0CBB0CC50CC90CCE-0CD40CD7-0CDD0CDF0CE40CE50CF00CF3-0D010D040D0D0D110D290D3A-0D3C0D450D490D4E-0D560D58-0D5F0D640D650D76-0D780D800D810D840D97-0D990DB20DBC0DBE0DBF0DC7-0DC90DCB-0DCE0DD50DD70DE0-0DF10DF5-0E000E3B-0E3E0E5C-0E800E830E850E860E890E8B0E8C0E8E-0E930E980EA00EA40EA60EA80EA90EAC0EBA0EBE0EBF0EC50EC70ECE0ECF0EDA0EDB0EDE-0EFF0F480F6D-0F700F8C-0F8F0F980FBD0FCD0FD9-0FFF10C6-10CF10FD-10FF1249124E124F12571259125E125F1289128E128F12B112B612B712BF12C112C612C712D7131113161317135B-135E137D-137F139A-139F13F5-13FF169D-169F16F1-16FF170D1715-171F1737-173F1754-175F176D17711774-177F17B417B517DE17DF17EA-17EF17FA-17FF180F181A-181F1878-187F18AB-18AF18F6-18FF191D-191F192C-192F193C-193F1941-1943196E196F1975-197F19AC-19AF19CA-19CF19DB-19DD1A1C1A1D1A5F1A7D1A7E1A8A-1A8F1A9A-1A9F1AAE-1AFF1B4C-1B4F1B7D-1B7F1BAB-1BAD1BBA-1BFF1C38-1C3A1C4A-1C4C1C80-1CCF1CF3-1CFF1DE7-1DFC1F161F171F1E1F1F1F461F471F4E1F4F1F581F5A1F5C1F5E1F7E1F7F1FB51FC51FD41FD51FDC1FF01FF11FF51FFF200B-200F202A-202E2060-206F20722073208F2095-209F20B9-20CF20F1-20FF218A-218F23E9-23FF2427-243F244B-245F26CE26E226E4-26E727002705270A270B2728274C274E2753-2755275F27602795-279727B027BF27CB27CD-27CF2B4D-2B4F2B5A-2BFF2C2F2C5F2CF2-2CF82D26-2D2F2D66-2D6E2D70-2D7F2D97-2D9F2DA72DAF2DB72DBF2DC72DCF2DD72DDF2E32-2E7F2E9A2EF4-2EFF2FD6-2FEF2FFC-2FFF3040309730983100-3104312E-3130318F31B8-31BF31E4-31EF321F32FF4DB6-4DBF9FCC-9FFFA48D-A48FA4C7-A4CFA62C-A63FA660A661A674-A67BA698-A69FA6F8-A6FFA78D-A7FAA82C-A82FA83A-A83FA878-A87FA8C5-A8CDA8DA-A8DFA8FC-A8FFA954-A95EA97D-A97FA9CEA9DA-A9DDA9E0-A9FFAA37-AA3FAA4EAA4FAA5AAA5BAA7C-AA7FAAC3-AADAAAE0-ABBFABEEABEFABFA-ABFFD7A4-D7AFD7C7-D7CAD7FC-F8FFFA2EFA2FFA6EFA6FFADA-FAFFFB07-FB12FB18-FB1CFB37FB3DFB3FFB42FB45FBB2-FBD2FD40-FD4FFD90FD91FDC8-FDEFFDFEFDFFFE1A-FE1FFE27-FE2FFE53FE67FE6C-FE6FFE75FEFD-FF00FFBF-FFC1FFC8FFC9FFD0FFD1FFD8FFD9FFDD-FFDFFFE7FFEF-FFFBFFFEFFFF",Cc:"0000-001F007F-009F",Cf:"00AD0600-060306DD070F17B417B5200B-200F202A-202E2060-2064206A-206FFEFFFFF9-FFFB",Co:"E000-F8FF",Cs:"D800-DFFF",Cn:"03780379037F-0383038B038D03A20526-05300557055805600588058B-059005C8-05CF05EB-05EF05F5-05FF06040605061C061D0620065F070E074B074C07B2-07BF07FB-07FF082E082F083F-08FF093A093B094F095609570973-097809800984098D098E0991099209A909B109B3-09B509BA09BB09C509C609C909CA09CF-09D609D8-09DB09DE09E409E509FC-0A000A040A0B-0A0E0A110A120A290A310A340A370A3A0A3B0A3D0A43-0A460A490A4A0A4E-0A500A52-0A580A5D0A5F-0A650A76-0A800A840A8E0A920AA90AB10AB40ABA0ABB0AC60ACA0ACE0ACF0AD1-0ADF0AE40AE50AF00AF2-0B000B040B0D0B0E0B110B120B290B310B340B3A0B3B0B450B460B490B4A0B4E-0B550B58-0B5B0B5E0B640B650B72-0B810B840B8B-0B8D0B910B96-0B980B9B0B9D0BA0-0BA20BA5-0BA70BAB-0BAD0BBA-0BBD0BC3-0BC50BC90BCE0BCF0BD1-0BD60BD8-0BE50BFB-0C000C040C0D0C110C290C340C3A-0C3C0C450C490C4E-0C540C570C5A-0C5F0C640C650C70-0C770C800C810C840C8D0C910CA90CB40CBA0CBB0CC50CC90CCE-0CD40CD7-0CDD0CDF0CE40CE50CF00CF3-0D010D040D0D0D110D290D3A-0D3C0D450D490D4E-0D560D58-0D5F0D640D650D76-0D780D800D810D840D97-0D990DB20DBC0DBE0DBF0DC7-0DC90DCB-0DCE0DD50DD70DE0-0DF10DF5-0E000E3B-0E3E0E5C-0E800E830E850E860E890E8B0E8C0E8E-0E930E980EA00EA40EA60EA80EA90EAC0EBA0EBE0EBF0EC50EC70ECE0ECF0EDA0EDB0EDE-0EFF0F480F6D-0F700F8C-0F8F0F980FBD0FCD0FD9-0FFF10C6-10CF10FD-10FF1249124E124F12571259125E125F1289128E128F12B112B612B712BF12C112C612C712D7131113161317135B-135E137D-137F139A-139F13F5-13FF169D-169F16F1-16FF170D1715-171F1737-173F1754-175F176D17711774-177F17DE17DF17EA-17EF17FA-17FF180F181A-181F1878-187F18AB-18AF18F6-18FF191D-191F192C-192F193C-193F1941-1943196E196F1975-197F19AC-19AF19CA-19CF19DB-19DD1A1C1A1D1A5F1A7D1A7E1A8A-1A8F1A9A-1A9F1AAE-1AFF1B4C-1B4F1B7D-1B7F1BAB-1BAD1BBA-1BFF1C38-1C3A1C4A-1C4C1C80-1CCF1CF3-1CFF1DE7-1DFC1F161F171F1E1F1F1F461F471F4E1F4F1F581F5A1F5C1F5E1F7E1F7F1FB51FC51FD41FD51FDC1FF01FF11FF51FFF2065-206920722073208F2095-209F20B9-20CF20F1-20FF218A-218F23E9-23FF2427-243F244B-245F26CE26E226E4-26E727002705270A270B2728274C274E2753-2755275F27602795-279727B027BF27CB27CD-27CF2B4D-2B4F2B5A-2BFF2C2F2C5F2CF2-2CF82D26-2D2F2D66-2D6E2D70-2D7F2D97-2D9F2DA72DAF2DB72DBF2DC72DCF2DD72DDF2E32-2E7F2E9A2EF4-2EFF2FD6-2FEF2FFC-2FFF3040309730983100-3104312E-3130318F31B8-31BF31E4-31EF321F32FF4DB6-4DBF9FCC-9FFFA48D-A48FA4C7-A4CFA62C-A63FA660A661A674-A67BA698-A69FA6F8-A6FFA78D-A7FAA82C-A82FA83A-A83FA878-A87FA8C5-A8CDA8DA-A8DFA8FC-A8FFA954-A95EA97D-A97FA9CEA9DA-A9DDA9E0-A9FFAA37-AA3FAA4EAA4FAA5AAA5BAA7C-AA7FAAC3-AADAAAE0-ABBFABEEABEFABFA-ABFFD7A4-D7AFD7C7-D7CAD7FC-D7FFFA2EFA2FFA6EFA6FFADA-FAFFFB07-FB12FB18-FB1CFB37FB3DFB3FFB42FB45FBB2-FBD2FD40-FD4FFD90FD91FDC8-FDEFFDFEFDFFFE1A-FE1FFE27-FE2FFE53FE67FE6C-FE6FFE75FEFDFEFEFF00FFBF-FFC1FFC8FFC9FFD0FFD1FFD8FFD9FFDD-FFDFFFE7FFEF-FFF8FFFEFFFF"})}),define("ace/token_iterator",["require","exports","module"],function(e,t,n){"use strict";var r=function(e,t,n){this.$session=e,this.$row=t,this.$rowTokens=e.getTokens(t);var r=e.getTokenAt(t,n);this.$tokenIndex=r?r.index:-1};(function(){this.stepBackward=function(){this.$tokenIndex-=1;while(this.$tokenIndex<0){this.$row-=1;if(this.$row<0)return this.$row=0,null;this.$rowTokens=this.$session.getTokens(this.$row),this.$tokenIndex=this.$rowTokens.length-1}return this.$rowTokens[this.$tokenIndex]},this.stepForward=function(){this.$tokenIndex+=1;var e;while(this.$tokenIndex>=this.$rowTokens.length){this.$row+=1,e||(e=this.$session.getLength());if(this.$row>=e)return this.$row=e-1,null;this.$rowTokens=this.$session.getTokens(this.$row),this.$tokenIndex=0}return this.$rowTokens[this.$tokenIndex]},this.getCurrentToken=function(){return this.$rowTokens[this.$tokenIndex]},this.getCurrentTokenRow=function(){return this.$row},this.getCurrentTokenColumn=function(){var e=this.$rowTokens,t=this.$tokenIndex,n=e[t].start;if(n!==undefined)return n;n=0;while(t>0)t-=1,n+=e[t].value.length;return n},this.getCurrentTokenPosition=function(){return{row:this.$row,column:this.getCurrentTokenColumn()}}}).call(r.prototype),t.TokenIterator=r}),define("ace/mode/text",["require","exports","module","ace/tokenizer","ace/mode/text_highlight_rules","ace/mode/behaviour","ace/unicode","ace/lib/lang","ace/token_iterator","ace/range"],function(e,t,n){"use strict";var r=e("../tokenizer").Tokenizer,i=e("./text_highlight_rules").TextHighlightRules,s=e("./behaviour").Behaviour,o=e("../unicode"),u=e("../lib/lang"),a=e("../token_iterator").TokenIterator,f=e("../range").Range,l=function(){this.HighlightRules=i,this.$behaviour=new s};(function(){this.tokenRe=new RegExp("^["+o.packages.L+o.packages.Mn+o.packages.Mc+o.packages.Nd+o.packages.Pc+"\\$_]+","g"),this.nonTokenRe=new RegExp("^(?:[^"+o.packages.L+o.packages.Mn+o.packages.Mc+o.packages.Nd+o.packages.Pc+"\\$_]|\\s])+","g"),this.getTokenizer=function(){return this.$tokenizer||(this.$highlightRules=this.$highlightRules||new this.HighlightRules,this.$tokenizer=new r(this.$highlightRules.getRules())),this.$tokenizer},this.lineCommentStart="",this.blockComment="",this.toggleCommentLines=function(e,t,n,r){function w(e){for(var t=n;t<=r;t++)e(i.getLine(t),t)}var i=t.doc,s=!0,o=!0,a=Infinity,f=t.getTabSize(),l=!1;if(!this.lineCommentStart){if(!this.blockComment)return!1;var c=this.blockComment.start,h=this.blockComment.end,p=new RegExp("^(\\s*)(?:"+u.escapeRegExp(c)+")"),d=new RegExp("(?:"+u.escapeRegExp(h)+")\\s*$"),v=function(e,t){if(g(e,t))return;if(!s||/\S/.test(e))i.insertInLine({row:t,column:e.length},h),i.insertInLine({row:t,column:a},c)},m=function(e,t){var n;(n=e.match(d))&&i.removeInLine(t,e.length-n[0].length,e.length),(n=e.match(p))&&i.removeInLine(t,n[1].length,n[0].length)},g=function(e,n){if(p.test(e))return!0;var r=t.getTokens(n);for(var i=0;i<r.length;i++)if(r[i].type==="comment")return!0}}else{if(Array.isArray(this.lineCommentStart))var p=this.lineCommentStart.map(u.escapeRegExp).join("|"),c=this.lineCommentStart[0];else var p=u.escapeRegExp(this.lineCommentStart),c=this.lineCommentStart;p=new RegExp("^(\\s*)(?:"+p+") ?"),l=t.getUseSoftTabs();var m=function(e,t){var n=e.match(p);if(!n)return;var r=n[1].length,s=n[0].length;!b(e,r,s)&&n[0][s-1]==" "&&s--,i.removeInLine(t,r,s)},y=c+" ",v=function(e,t){if(!s||/\S/.test(e))b(e,a,a)?i.insertInLine({row:t,column:a},y):i.insertInLine({row:t,column:a},c)},g=function(e,t){return p.test(e)},b=function(e,t,n){var r=0;while(t--&&e.charAt(t)==" ")r++;if(r%f!=0)return!1;var r=0;while(e.charAt(n++)==" ")r++;return f>2?r%f!=f-1:r%f==0}}var E=Infinity;w(function(e,t){var n=e.search(/\S/);n!==-1?(n<a&&(a=n),o&&!g(e,t)&&(o=!1)):E>e.length&&(E=e.length)}),a==Infinity&&(a=E,s=!1,o=!1),l&&a%f!=0&&(a=Math.floor(a/f)*f),w(o?m:v)},this.toggleBlockComment=function(e,t,n,r){var i=this.blockComment;if(!i)return;!i.start&&i[0]&&(i=i[0]);var s=new a(t,r.row,r.column),o=s.getCurrentToken(),u=t.selection,l=t.selection.toOrientedRange(),c,h;if(o&&/comment/.test(o.type)){var p,d;while(o&&/comment/.test(o.type)){var v=o.value.indexOf(i.start);if(v!=-1){var m=s.getCurrentTokenRow(),g=s.getCurrentTokenColumn()+v;p=new f(m,g,m,g+i.start.length);break}o=s.stepBackward()}var s=new a(t,r.row,r.column),o=s.getCurrentToken();while(o&&/comment/.test(o.type)){var v=o.value.indexOf(i.end);if(v!=-1){var m=s.getCurrentTokenRow(),g=s.getCurrentTokenColumn()+v;d=new f(m,g,m,g+i.end.length);break}o=s.stepForward()}d&&t.remove(d),p&&(t.remove(p),c=p.start.row,h=-i.start.length)}else h=i.start.length,c=n.start.row,t.insert(n.end,i.end),t.insert(n.start,i.start);l.start.row==c&&(l.start.column+=h),l.end.row==c&&(l.end.column+=h),t.selection.fromOrientedRange(l)},this.getNextLineIndent=function(e,t,n){return this.$getIndent(t)},this.checkOutdent=function(e,t,n){return!1},this.autoOutdent=function(e,t,n){},this.$getIndent=function(e){return e.match(/^\s*/)[0]},this.createWorker=function(e){return null},this.createModeDelegates=function(e){this.$embeds=[],this.$modes={};for(var t in e)e[t]&&(this.$embeds.push(t),this.$modes[t]=new e[t]);var n=["toggleBlockComment","toggleCommentLines","getNextLineIndent","checkOutdent","autoOutdent","transformAction","getCompletions"];for(var t=0;t<n.length;t++)(function(e){var r=n[t],i=e[r];e[n[t]]=function(){return this.$delegator(r,arguments,i)}})(this)},this.$delegator=function(e,t,n){var r=t[0];typeof r!="string"&&(r=r[0]);for(var i=0;i<this.$embeds.length;i++){if(!this.$modes[this.$embeds[i]])continue;var s=r.split(this.$embeds[i]);if(!s[0]&&s[1]){t[0]=s[1];var o=this.$modes[this.$embeds[i]];return o[e].apply(o,t)}}var u=n.apply(this,t);return n?u:undefined},this.transformAction=function(e,t,n,r,i){if(this.$behaviour){var s=this.$behaviour.getBehaviours();for(var o in s)if(s[o][t]){var u=s[o][t].apply(this,arguments);if(u)return u}}},this.getKeywords=function(e){if(!this.completionKeywords){var t=this.$tokenizer.rules,n=[];for(var r in t){var i=t[r];for(var s=0,o=i.length;s<o;s++)if(typeof i[s].token=="string")/keyword|support|storage/.test(i[s].token)&&n.push(i[s].regex);else if(typeof i[s].token=="object")for(var u=0,a=i[s].token.length;u<a;u++)if(/keyword|support|storage/.test(i[s].token[u])){var r=i[s].regex.match(/\(.+?\)/g)[u];n.push(r.substr(1,r.length-2))}}this.completionKeywords=n}return e?n.concat(this.$keywordList||[]):this.$keywordList},this.$createKeywordList=function(){return this.$highlightRules||this.getTokenizer(),this.$keywordList=this.$highlightRules.$keywordList||[]},this.getCompletions=function(e,t,n,r){var i=this.$keywordList||this.$createKeywordList();return i.map(function(e){return{name:e,value:e,score:0,meta:"keyword"}})},this.$id="ace/mode/text"}).call(l.prototype),t.Mode=l}),define("ace/apply_delta",["require","exports","module"],function(e,t,n){"use strict";function r(e,t){throw console.log("Invalid Delta:",e),"Invalid Delta: "+t}function i(e,t){return t.row>=0&&t.row<e.length&&t.column>=0&&t.column<=e[t.row].length}function s(e,t){t.action!="insert"&&t.action!="remove"&&r(t,"delta.action must be 'insert' or 'remove'"),t.lines instanceof Array||r(t,"delta.lines must be an Array"),(!t.start||!t.end)&&r(t,"delta.start/end must be an present");var n=t.start;i(e,t.start)||r(t,"delta.start must be contained in document");var s=t.end;t.action=="remove"&&!i(e,s)&&r(t,"delta.end must contained in document for 'remove' actions");var o=s.row-n.row,u=s.column-(o==0?n.column:0);(o!=t.lines.length-1||t.lines[o].length!=u)&&r(t,"delta.range must match delta lines")}t.applyDelta=function(e,t,n){var r=t.start.row,i=t.start.column,s=e[r]||"";switch(t.action){case"insert":var o=t.lines;if(o.length===1)e[r]=s.substring(0,i)+t.lines[0]+s.substring(i);else{var u=[r,1].concat(t.lines);e.splice.apply(e,u),e[r]=s.substring(0,i)+e[r],e[r+t.lines.length-1]+=s.substring(i)}break;case"remove":var a=t.end.column,f=t.end.row;r===f?e[r]=s.substring(0,i)+s.substring(a):e.splice(r,f-r+1,s.substring(0,i)+e[f].substring(a))}}}),define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=t.Anchor=function(e,t,n){this.$onChange=this.onChange.bind(this),this.attach(e),typeof n=="undefined"?this.setPosition(t.row,t.column):this.setPosition(t,n)};(function(){function e(e,t,n){var r=n?e.column<=t.column:e.column<t.column;return e.row<t.row||e.row==t.row&&r}function t(t,n,r){var i=t.action=="insert",s=(i?1:-1)*(t.end.row-t.start.row),o=(i?1:-1)*(t.end.column-t.start.column),u=t.start,a=i?u:t.end;return e(n,u,r)?{row:n.row,column:n.column}:e(a,n,!r)?{row:n.row+s,column:n.column+(n.row==a.row?o:0)}:{row:u.row,column:u.column}}r.implement(this,i),this.getPosition=function(){return this.$clipPositionToDocument(this.row,this.column)},this.getDocument=function(){return this.document},this.$insertRight=!1,this.onChange=function(e){if(e.start.row==e.end.row&&e.start.row!=this.row)return;if(e.start.row>this.row)return;var n=t(e,{row:this.row,column:this.column},this.$insertRight);this.setPosition(n.row,n.column,!0)},this.setPosition=function(e,t,n){var r;n?r={row:e,column:t}:r=this.$clipPositionToDocument(e,t);if(this.row==r.row&&this.column==r.column)return;var i={row:this.row,column:this.column};this.row=r.row,this.column=r.column,this._signal("change",{old:i,value:r})},this.detach=function(){this.document.removeEventListener("change",this.$onChange)},this.attach=function(e){this.document=e||this.document,this.document.on("change",this.$onChange)},this.$clipPositionToDocument=function(e,t){var n={};return e>=this.document.getLength()?(n.row=Math.max(0,this.document.getLength()-1),n.column=this.document.getLine(n.row).length):e<0?(n.row=0,n.column=0):(n.row=e,n.column=Math.min(this.document.getLine(n.row).length,Math.max(0,t))),t<0&&(n.column=0),n}}).call(s.prototype)}),define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./apply_delta").applyDelta,s=e("./lib/event_emitter").EventEmitter,o=e("./range").Range,u=e("./anchor").Anchor,a=function(e){this.$lines=[""],e.length===0?this.$lines=[""]:Array.isArray(e)?this.insertMergedLines({row:0,column:0},e):this.insert({row:0,column:0},e)};(function(){r.implement(this,s),this.setValue=function(e){var t=this.getLength()-1;this.remove(new o(0,0,t,this.getLine(t).length)),this.insert({row:0,column:0},e)},this.getValue=function(){return this.getAllLines().join(this.getNewLineCharacter())},this.createAnchor=function(e,t){return new u(this,e,t)},"aaa".split(/a/).length===0?this.$split=function(e){return e.replace(/\r\n|\r/g,"\n").split("\n")}:this.$split=function(e){return e.split(/\r\n|\r|\n/)},this.$detectNewLine=function(e){var t=e.match(/^.*?(\r\n|\r|\n)/m);this.$autoNewLine=t?t[1]:"\n",this._signal("changeNewLineMode")},this.getNewLineCharacter=function(){switch(this.$newLineMode){case"windows":return"\r\n";case"unix":return"\n";default:return this.$autoNewLine||"\n"}},this.$autoNewLine="",this.$newLineMode="auto",this.setNewLineMode=function(e){if(this.$newLineMode===e)return;this.$newLineMode=e,this._signal("changeNewLineMode")},this.getNewLineMode=function(){return this.$newLineMode},this.isNewLine=function(e){return e=="\r\n"||e=="\r"||e=="\n"},this.getLine=function(e){return this.$lines[e]||""},this.getLines=function(e,t){return this.$lines.slice(e,t+1)},this.getAllLines=function(){return this.getLines(0,this.getLength())},this.getLength=function(){return this.$lines.length},this.getTextRange=function(e){return this.getLinesForRange(e).join(this.getNewLineCharacter())},this.getLinesForRange=function(e){var t;if(e.start.row===e.end.row)t=[this.getLine(e.start.row).substring(e.start.column,e.end.column)];else{t=this.getLines(e.start.row,e.end.row),t[0]=(t[0]||"").substring(e.start.column);var n=t.length-1;e.end.row-e.start.row==n&&(t[n]=t[n].substring(0,e.end.column))}return t},this.insertLines=function(e,t){return console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."),this.insertFullLines(e,t)},this.removeLines=function(e,t){return console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."),this.removeFullLines(e,t)},this.insertNewLine=function(e){return console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead."),this.insertMergedLines(e,["",""])},this.insert=function(e,t){return this.getLength()<=1&&this.$detectNewLine(t),this.insertMergedLines(e,this.$split(t))},this.insertInLine=function(e,t){var n=this.clippedPos(e.row,e.column),r=this.pos(e.row,e.column+t.length);return this.applyDelta({start:n,end:r,action:"insert",lines:[t]},!0),this.clonePos(r)},this.clippedPos=function(e,t){var n=this.getLength();e===undefined?e=n:e<0?e=0:e>=n&&(e=n-1,t=undefined);var r=this.getLine(e);return t==undefined&&(t=r.length),t=Math.min(Math.max(t,0),r.length),{row:e,column:t}},this.clonePos=function(e){return{row:e.row,column:e.column}},this.pos=function(e,t){return{row:e,column:t}},this.$clipPosition=function(e){var t=this.getLength();return e.row>=t?(e.row=Math.max(0,t-1),e.column=this.getLine(t-1).length):(e.row=Math.max(0,e.row),e.column=Math.min(Math.max(e.column,0),this.getLine(e.row).length)),e},this.insertFullLines=function(e,t){e=Math.min(Math.max(e,0),this.getLength());var n=0;e<this.getLength()?(t=t.concat([""]),n=0):(t=[""].concat(t),e--,n=this.$lines[e].length),this.insertMergedLines({row:e,column:n},t)},this.insertMergedLines=function(e,t){var n=this.clippedPos(e.row,e.column),r={row:n.row+t.length-1,column:(t.length==1?n.column:0)+t[t.length-1].length};return this.applyDelta({start:n,end:r,action:"insert",lines:t}),this.clonePos(r)},this.remove=function(e){var t=this.clippedPos(e.start.row,e.start.column),n=this.clippedPos(e.end.row,e.end.column);return this.applyDelta({start:t,end:n,action:"remove",lines:this.getLinesForRange({start:t,end:n})}),this.clonePos(t)},this.removeInLine=function(e,t,n){var r=this.clippedPos(e,t),i=this.clippedPos(e,n);return this.applyDelta({start:r,end:i,action:"remove",lines:this.getLinesForRange({start:r,end:i})},!0),this.clonePos(r)},this.removeFullLines=function(e,t){e=Math.min(Math.max(0,e),this.getLength()-1),t=Math.min(Math.max(0,t),this.getLength()-1);var n=t==this.getLength()-1&&e>0,r=t<this.getLength()-1,i=n?e-1:e,s=n?this.getLine(i).length:0,u=r?t+1:t,a=r?0:this.getLine(u).length,f=new o(i,s,u,a),l=this.$lines.slice(e,t+1);return this.applyDelta({start:f.start,end:f.end,action:"remove",lines:this.getLinesForRange(f)}),l},this.removeNewLine=function(e){e<this.getLength()-1&&e>=0&&this.applyDelta({start:this.pos(e,this.getLine(e).length),end:this.pos(e+1,0),action:"remove",lines:["",""]})},this.replace=function(e,t){e instanceof o||(e=o.fromPoints(e.start,e.end));if(t.length===0&&e.isEmpty())return e.start;if(t==this.getTextRange(e))return e.end;this.remove(e);var n;return t?n=this.insert(e.start,t):n=e.start,n},this.applyDeltas=function(e){for(var t=0;t<e.length;t++)this.applyDelta(e[t])},this.revertDeltas=function(e){for(var t=e.length-1;t>=0;t--)this.revertDelta(e[t])},this.applyDelta=function(e,t){var n=e.action=="insert";if(n?e.lines.length<=1&&!e.lines[0]:!o.comparePoints(e.start,e.end))return;n&&e.lines.length>2e4&&this.$splitAndapplyLargeDelta(e,2e4),i(this.$lines,e,t),this._signal("change",e)},this.$splitAndapplyLargeDelta=function(e,t){var n=e.lines,r=n.length,i=e.start.row,s=e.start.column,o=0,u=0;do{o=u,u+=t-1;var a=n.slice(o,u);if(u>r){e.lines=a,e.start.row=i+o,e.start.column=s;break}a.push(""),this.applyDelta({start:this.pos(i+o,s),end:this.pos(i+u,s=0),action:e.action,lines:a},!0)}while(!0)},this.revertDelta=function(e){this.applyDelta({start:this.clonePos(e.start),end:this.clonePos(e.end),action:e.action=="insert"?"remove":"insert",lines:e.lines.slice()})},this.indexToPosition=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length;for(var i=t||0,s=n.length;i<s;i++){e-=n[i].length+r;if(e<0)return{row:i,column:e+n[i].length+r}}return{row:s-1,column:n[s-1].length}},this.positionToIndex=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length,i=0,s=Math.min(e.row,n.length);for(var o=t||0;o<s;++o)i+=n[o].length+r;return i+e.column}}).call(a.prototype),t.Document=a}),define("ace/background_tokenizer",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=function(e,t){this.running=!1,this.lines=[],this.states=[],this.currentLine=0,this.tokenizer=e;var n=this;this.$worker=function(){if(!n.running)return;var e=new Date,t=n.currentLine,r=-1,i=n.doc,s=t;while(n.lines[t])t++;var o=i.getLength(),u=0;n.running=!1;while(t<o){n.$tokenizeRow(t),r=t;do t++;while(n.lines[t]);u++;if(u%5===0&&new Date-e>20){n.running=setTimeout(n.$worker,20);break}}n.currentLine=t,s<=r&&n.fireUpdateEvent(s,r)}};(function(){r.implement(this,i),this.setTokenizer=function(e){this.tokenizer=e,this.lines=[],this.states=[],this.start(0)},this.setDocument=function(e){this.doc=e,this.lines=[],this.states=[],this.stop()},this.fireUpdateEvent=function(e,t){var n={first:e,last:t};this._signal("update",{data:n})},this.start=function(e){this.currentLine=Math.min(e||0,this.currentLine,this.doc.getLength()),this.lines.splice(this.currentLine,this.lines.length),this.states.splice(this.currentLine,this.states.length),this.stop(),this.running=setTimeout(this.$worker,700)},this.scheduleStart=function(){this.running||(this.running=setTimeout(this.$worker,700))},this.$updateOnChange=function(e){var t=e.start.row,n=e.end.row-t;if(n===0)this.lines[t]=null;else if(e.action=="remove")this.lines.splice(t,n+1,null),this.states.splice(t,n+1,null);else{var r=Array(n+1);r.unshift(t,1),this.lines.splice.apply(this.lines,r),this.states.splice.apply(this.states,r)}this.currentLine=Math.min(t,this.currentLine,this.doc.getLength()),this.stop()},this.stop=function(){this.running&&clearTimeout(this.running),this.running=!1},this.getTokens=function(e){return this.lines[e]||this.$tokenizeRow(e)},this.getState=function(e){return this.currentLine==e&&this.$tokenizeRow(e),this.states[e]||"start"},this.$tokenizeRow=function(e){var t=this.doc.getLine(e),n=this.states[e-1],r=this.tokenizer.getLineTokens(t,n,e);return this.states[e]+""!=r.state+""?(this.states[e]=r.state,this.lines[e+1]=null,this.currentLine>e+1&&(this.currentLine=e+1)):this.currentLine==e&&(this.currentLine=e+1),this.lines[e]=r.tokens}}).call(s.prototype),t.BackgroundTokenizer=s}),define("ace/search_highlight",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/range"],function(e,t,n){"use strict";var r=e("./lib/lang"),i=e("./lib/oop"),s=e("./range").Range,o=function(e,t,n){this.setRegexp(e),this.clazz=t,this.type=n||"text"};(function(){this.MAX_RANGES=500,this.setRegexp=function(e){if(this.regExp+""==e+"")return;this.regExp=e,this.cache=[]},this.update=function(e,t,n,i){if(!this.regExp)return;var o=i.firstRow,u=i.lastRow;for(var a=o;a<=u;a++){var f=this.cache[a];f==null&&(f=r.getMatchOffsets(n.getLine(a),this.regExp),f.length>this.MAX_RANGES&&(f=f.slice(0,this.MAX_RANGES)),f=f.map(function(e){return new s(a,e.offset,a,e.offset+e.length)}),this.cache[a]=f.length?f:"");for(var l=f.length;l--;)t.drawSingleLineMarker(e,f[l].toScreenRange(n),this.clazz,i)}}}).call(o.prototype),t.SearchHighlight=o}),define("ace/edit_session/fold_line",["require","exports","module","ace/range"],function(e,t,n){"use strict";function i(e,t){this.foldData=e,Array.isArray(t)?this.folds=t:t=this.folds=[t];var n=t[t.length-1];this.range=new r(t[0].start.row,t[0].start.column,n.end.row,n.end.column),this.start=this.range.start,this.end=this.range.end,this.folds.forEach(function(e){e.setFoldLine(this)},this)}var r=e("../range").Range;(function(){this.shiftRow=function(e){this.start.row+=e,this.end.row+=e,this.folds.forEach(function(t){t.start.row+=e,t.end.row+=e})},this.addFold=function(e){if(e.sameRow){if(e.start.row<this.startRow||e.endRow>this.endRow)throw new Error("Can't add a fold to this FoldLine as it has no connection");this.folds.push(e),this.folds.sort(function(e,t){return-e.range.compareEnd(t.start.row,t.start.column)}),this.range.compareEnd(e.start.row,e.start.column)>0?(this.end.row=e.end.row,this.end.column=e.end.column):this.range.compareStart(e.end.row,e.end.column)<0&&(this.start.row=e.start.row,this.start.column=e.start.column)}else if(e.start.row==this.end.row)this.folds.push(e),this.end.row=e.end.row,this.end.column=e.end.column;else{if(e.end.row!=this.start.row)throw new Error("Trying to add fold to FoldRow that doesn't have a matching row");this.folds.unshift(e),this.start.row=e.start.row,this.start.column=e.start.column}e.foldLine=this},this.containsRow=function(e){return e>=this.start.row&&e<=this.end.row},this.walk=function(e,t,n){var r=0,i=this.folds,s,o,u,a=!0;t==null&&(t=this.end.row,n=this.end.column);for(var f=0;f<i.length;f++){s=i[f],o=s.range.compareStart(t,n);if(o==-1){e(null,t,n,r,a);return}u=e(null,s.start.row,s.start.column,r,a),u=!u&&e(s.placeholder,s.start.row,s.start.column,r);if(u||o===0)return;a=!s.sameRow,r=s.end.column}e(null,t,n,r,a)},this.getNextFoldTo=function(e,t){var n,r;for(var i=0;i<this.folds.length;i++){n=this.folds[i],r=n.range.compareEnd(e,t);if(r==-1)return{fold:n,kind:"after"};if(r===0)return{fold:n,kind:"inside"}}return null},this.addRemoveChars=function(e,t,n){var r=this.getNextFoldTo(e,t),i,s;if(r){i=r.fold;if(r.kind=="inside"&&i.start.column!=t&&i.start.row!=e)window.console&&window.console.log(e,t,i);else if(i.start.row==e){s=this.folds;var o=s.indexOf(i);o===0&&(this.start.column+=n);for(o;o<s.length;o++){i=s[o],i.start.column+=n;if(!i.sameRow)return;i.end.column+=n}this.end.column+=n}}},this.split=function(e,t){var n=this.getNextFoldTo(e,t);if(!n||n.kind=="inside")return null;var r=n.fold,s=this.folds,o=this.foldData,u=s.indexOf(r),a=s[u-1];this.end.row=a.end.row,this.end.column=a.end.column,s=s.splice(u,s.length-u);var f=new i(o,s);return o.splice(o.indexOf(this)+1,0,f),f},this.merge=function(e){var t=e.folds;for(var n=0;n<t.length;n++)this.addFold(t[n]);var r=this.foldData;r.splice(r.indexOf(e),1)},this.toString=function(){var e=[this.range.toString()+": ["];return this.folds.forEach(function(t){e.push("  "+t.toString())}),e.push("]"),e.join("\n")},this.idxToPosition=function(e){var t=0;for(var n=0;n<this.folds.length;n++){var r=this.folds[n];e-=r.start.column-t;if(e<0)return{row:r.start.row,column:r.start.column+e};e-=r.placeholder.length;if(e<0)return r.start;t=r.end.column}return{row:this.end.row,column:this.end.column+e}}}).call(i.prototype),t.FoldLine=i}),define("ace/range_list",["require","exports","module","ace/range"],function(e,t,n){"use strict";var r=e("./range").Range,i=r.comparePoints,s=function(){this.ranges=[]};(function(){this.comparePoints=i,this.pointIndex=function(e,t,n){var r=this.ranges;for(var s=n||0;s<r.length;s++){var o=r[s],u=i(e,o.end);if(u>0)continue;var a=i(e,o.start);return u===0?t&&a!==0?-s-2:s:a>0||a===0&&!t?s:-s-1}return-s-1},this.add=function(e){var t=!e.isEmpty(),n=this.pointIndex(e.start,t);n<0&&(n=-n-1);var r=this.pointIndex(e.end,t,n);return r<0?r=-r-1:r++,this.ranges.splice(n,r-n,e)},this.addList=function(e){var t=[];for(var n=e.length;n--;)t.push.apply(t,this.add(e[n]));return t},this.substractPoint=function(e){var t=this.pointIndex(e);if(t>=0)return this.ranges.splice(t,1)},this.merge=function(){var e=[],t=this.ranges;t=t.sort(function(e,t){return i(e.start,t.start)});var n=t[0],r;for(var s=1;s<t.length;s++){r=n,n=t[s];var o=i(r.end,n.start);if(o<0)continue;if(o==0&&!r.isEmpty()&&!n.isEmpty())continue;i(r.end,n.end)<0&&(r.end.row=n.end.row,r.end.column=n.end.column),t.splice(s,1),e.push(n),n=r,s--}return this.ranges=t,e},this.contains=function(e,t){return this.pointIndex({row:e,column:t})>=0},this.containsPoint=function(e){return this.pointIndex(e)>=0},this.rangeAtPoint=function(e){var t=this.pointIndex(e);if(t>=0)return this.ranges[t]},this.clipRows=function(e,t){var n=this.ranges;if(n[0].start.row>t||n[n.length-1].start.row<e)return[];var r=this.pointIndex({row:e,column:0});r<0&&(r=-r-1);var i=this.pointIndex({row:t,column:0},r);i<0&&(i=-i-1);var s=[];for(var o=r;o<i;o++)s.push(n[o]);return s},this.removeAll=function(){return this.ranges.splice(0,this.ranges.length)},this.attach=function(e){this.session&&this.detach(),this.session=e,this.onChange=this.$onChange.bind(this),this.session.on("change",this.onChange)},this.detach=function(){if(!this.session)return;this.session.removeListener("change",this.onChange),this.session=null},this.$onChange=function(e){if(e.action=="insert")var t=e.start,n=e.end;else var n=e.start,t=e.end;var r=t.row,i=n.row,s=i-r,o=-t.column+n.column,u=this.ranges;for(var a=0,f=u.length;a<f;a++){var l=u[a];if(l.end.row<r)continue;if(l.start.row>r)break;l.start.row==r&&l.start.column>=t.column&&(l.start.column!=t.column||!this.$insertRight)&&(l.start.column+=o,l.start.row+=s);if(l.end.row==r&&l.end.column>=t.column){if(l.end.column==t.column&&this.$insertRight)continue;l.end.column==t.column&&o>0&&a<f-1&&l.end.column>l.start.column&&l.end.column==u[a+1].start.column&&(l.end.column-=o),l.end.column+=o,l.end.row+=s}}if(s!=0&&a<f)for(;a<f;a++){var l=u[a];l.start.row+=s,l.end.row+=s}}}).call(s.prototype),t.RangeList=s}),define("ace/edit_session/fold",["require","exports","module","ace/range","ace/range_list","ace/lib/oop"],function(e,t,n){"use strict";function u(e,t){e.row-=t.row,e.row==0&&(e.column-=t.column)}function a(e,t){u(e.start,t),u(e.end,t)}function f(e,t){e.row==0&&(e.column+=t.column),e.row+=t.row}function l(e,t){f(e.start,t),f(e.end,t)}var r=e("../range").Range,i=e("../range_list").RangeList,s=e("../lib/oop"),o=t.Fold=function(e,t){this.foldLine=null,this.placeholder=t,this.range=e,this.start=e.start,this.end=e.end,this.sameRow=e.start.row==e.end.row,this.subFolds=this.ranges=[]};s.inherits(o,i),function(){this.toString=function(){return'"'+this.placeholder+'" '+this.range.toString()},this.setFoldLine=function(e){this.foldLine=e,this.subFolds.forEach(function(t){t.setFoldLine(e)})},this.clone=function(){var e=this.range.clone(),t=new o(e,this.placeholder);return this.subFolds.forEach(function(e){t.subFolds.push(e.clone())}),t.collapseChildren=this.collapseChildren,t},this.addSubFold=function(e){if(this.range.isEqual(e))return;if(!this.range.containsRange(e))throw new Error("A fold can't intersect already existing fold"+e.range+this.range);a(e,this.start);var t=e.start.row,n=e.start.column;for(var r=0,i=-1;r<this.subFolds.length;r++){i=this.subFolds[r].range.compare(t,n);if(i!=1)break}var s=this.subFolds[r];if(i==0)return s.addSubFold(e);var t=e.range.end.row,n=e.range.end.column;for(var o=r,i=-1;o<this.subFolds.length;o++){i=this.subFolds[o].range.compare(t,n);if(i!=1)break}var u=this.subFolds[o];if(i==0)throw new Error("A fold can't intersect already existing fold"+e.range+this.range);var f=this.subFolds.splice(r,o-r,e);return e.setFoldLine(this.foldLine),e},this.restoreRange=function(e){return l(e,this.start)}}.call(o.prototype)}),define("ace/edit_session/folding",["require","exports","module","ace/range","ace/edit_session/fold_line","ace/edit_session/fold","ace/token_iterator"],function(e,t,n){"use strict";function u(){this.getFoldAt=function(e,t,n){var r=this.getFoldLine(e);if(!r)return null;var i=r.folds;for(var s=0;s<i.length;s++){var o=i[s];if(o.range.contains(e,t)){if(n==1&&o.range.isEnd(e,t))continue;if(n==-1&&o.range.isStart(e,t))continue;return o}}},this.getFoldsInRange=function(e){var t=e.start,n=e.end,r=this.$foldData,i=[];t.column+=1,n.column-=1;for(var s=0;s<r.length;s++){var o=r[s].range.compareRange(e);if(o==2)continue;if(o==-2)break;var u=r[s].folds;for(var a=0;a<u.length;a++){var f=u[a];o=f.range.compareRange(e);if(o==-2)break;if(o==2)continue;if(o==42)break;i.push(f)}}return t.column-=1,n.column+=1,i},this.getFoldsInRangeList=function(e){if(Array.isArray(e)){var t=[];e.forEach(function(e){t=t.concat(this.getFoldsInRange(e))},this)}else var t=this.getFoldsInRange(e);return t},this.getAllFolds=function(){var e=[],t=this.$foldData;for(var n=0;n<t.length;n++)for(var r=0;r<t[n].folds.length;r++)e.push(t[n].folds[r]);return e},this.getFoldStringAt=function(e,t,n,r){r=r||this.getFoldLine(e);if(!r)return null;var i={end:{column:0}},s,o;for(var u=0;u<r.folds.length;u++){o=r.folds[u];var a=o.range.compareEnd(e,t);if(a==-1){s=this.getLine(o.start.row).substring(i.end.column,o.start.column);break}if(a===0)return null;i=o}return s||(s=this.getLine(o.start.row).substring(i.end.column)),n==-1?s.substring(0,t-i.end.column):n==1?s.substring(t-i.end.column):s},this.getFoldLine=function(e,t){var n=this.$foldData,r=0;t&&(r=n.indexOf(t)),r==-1&&(r=0);for(r;r<n.length;r++){var i=n[r];if(i.start.row<=e&&i.end.row>=e)return i;if(i.end.row>e)return null}return null},this.getNextFoldLine=function(e,t){var n=this.$foldData,r=0;t&&(r=n.indexOf(t)),r==-1&&(r=0);for(r;r<n.length;r++){var i=n[r];if(i.end.row>=e)return i}return null},this.getFoldedRowCount=function(e,t){var n=this.$foldData,r=t-e+1;for(var i=0;i<n.length;i++){var s=n[i],o=s.end.row,u=s.start.row;if(o>=t){u<t&&(u>=e?r-=t-u:r=0);break}o>=e&&(u>=e?r-=o-u:r-=o-e+1)}return r},this.$addFoldLine=function(e){return this.$foldData.push(e),this.$foldData.sort(function(e,t){return e.start.row-t.start.row}),e},this.addFold=function(e,t){var n=this.$foldData,r=!1,o;e instanceof s?o=e:(o=new s(t,e),o.collapseChildren=t.collapseChildren),this.$clipRangeToDocument(o.range);var u=o.start.row,a=o.start.column,f=o.end.row,l=o.end.column;if(u<f||u==f&&a<=l-2){var c=this.getFoldAt(u,a,1),h=this.getFoldAt(f,l,-1);if(c&&h==c)return c.addSubFold(o);c&&!c.range.isStart(u,a)&&this.removeFold(c),h&&!h.range.isEnd(f,l)&&this.removeFold(h);var p=this.getFoldsInRange(o.range);p.length>0&&(this.removeFolds(p),p.forEach(function(e){o.addSubFold(e)}));for(var d=0;d<n.length;d++){var v=n[d];if(f==v.start.row){v.addFold(o),r=!0;break}if(u==v.end.row){v.addFold(o),r=!0;if(!o.sameRow){var m=n[d+1];if(m&&m.start.row==f){v.merge(m);break}}break}if(f<=v.start.row)break}return r||(v=this.$addFoldLine(new i(this.$foldData,o))),this.$useWrapMode?this.$updateWrapData(v.start.row,v.start.row):this.$updateRowLengthCache(v.start.row,v.start.row),this.$modified=!0,this._signal("changeFold",{data:o,action:"add"}),o}throw new Error("The range has to be at least 2 characters width")},this.addFolds=function(e){e.forEach(function(e){this.addFold(e)},this)},this.removeFold=function(e){var t=e.foldLine,n=t.start.row,r=t.end.row,i=this.$foldData,s=t.folds;if(s.length==1)i.splice(i.indexOf(t),1);else if(t.range.isEnd(e.end.row,e.end.column))s.pop(),t.end.row=s[s.length-1].end.row,t.end.column=s[s.length-1].end.column;else if(t.range.isStart(e.start.row,e.start.column))s.shift(),t.start.row=s[0].start.row,t.start.column=s[0].start.column;else if(e.sameRow)s.splice(s.indexOf(e),1);else{var o=t.split(e.start.row,e.start.column);s=o.folds,s.shift(),o.start.row=s[0].start.row,o.start.column=s[0].start.column}this.$updating||(this.$useWrapMode?this.$updateWrapData(n,r):this.$updateRowLengthCache(n,r)),this.$modified=!0,this._signal("changeFold",{data:e,action:"remove"})},this.removeFolds=function(e){var t=[];for(var n=0;n<e.length;n++)t.push(e[n]);t.forEach(function(e){this.removeFold(e)},this),this.$modified=!0},this.expandFold=function(e){this.removeFold(e),e.subFolds.forEach(function(t){e.restoreRange(t),this.addFold(t)},this),e.collapseChildren>0&&this.foldAll(e.start.row+1,e.end.row,e.collapseChildren-1),e.subFolds=[]},this.expandFolds=function(e){e.forEach(function(e){this.expandFold(e)},this)},this.unfold=function(e,t){var n,i;e==null?(n=new r(0,0,this.getLength(),0),t=!0):typeof e=="number"?n=new r(e,0,e,this.getLine(e).length):"row"in e?n=r.fromPoints(e,e):n=e,i=this.getFoldsInRangeList(n);if(t)this.removeFolds(i);else{var s=i;while(s.length)this.expandFolds(s),s=this.getFoldsInRangeList(n)}if(i.length)return i},this.isRowFolded=function(e,t){return!!this.getFoldLine(e,t)},this.getRowFoldEnd=function(e,t){var n=this.getFoldLine(e,t);return n?n.end.row:e},this.getRowFoldStart=function(e,t){var n=this.getFoldLine(e,t);return n?n.start.row:e},this.getFoldDisplayLine=function(e,t,n,r,i){r==null&&(r=e.start.row),i==null&&(i=0),t==null&&(t=e.end.row),n==null&&(n=this.getLine(t).length);var s=this.doc,o="";return e.walk(function(e,t,n,u){if(t<r)return;if(t==r){if(n<i)return;u=Math.max(i,u)}e!=null?o+=e:o+=s.getLine(t).substring(u,n)},t,n),o},this.getDisplayLine=function(e,t,n,r){var i=this.getFoldLine(e);if(!i){var s;return s=this.doc.getLine(e),s.substring(r||0,t||s.length)}return this.getFoldDisplayLine(i,e,t,n,r)},this.$cloneFoldData=function(){var e=[];return e=this.$foldData.map(function(t){var n=t.folds.map(function(e){return e.clone()});return new i(e,n)}),e},this.toggleFold=function(e){var t=this.selection,n=t.getRange(),r,i;if(n.isEmpty()){var s=n.start;r=this.getFoldAt(s.row,s.column);if(r){this.expandFold(r);return}(i=this.findMatchingBracket(s))?n.comparePoint(i)==1?n.end=i:(n.start=i,n.start.column++,n.end.column--):(i=this.findMatchingBracket({row:s.row,column:s.column+1}))?(n.comparePoint(i)==1?n.end=i:n.start=i,n.start.column++):n=this.getCommentFoldRange(s.row,s.column)||n}else{var o=this.getFoldsInRange(n);if(e&&o.length){this.expandFolds(o);return}o.length==1&&(r=o[0])}r||(r=this.getFoldAt(n.start.row,n.start.column));if(r&&r.range.toString()==n.toString()){this.expandFold(r);return}var u="...";if(!n.isMultiLine()){u=this.getTextRange(n);if(u.length<4)return;u=u.trim().substring(0,2)+".."}this.addFold(u,n)},this.getCommentFoldRange=function(e,t,n){var i=new o(this,e,t),s=i.getCurrentToken();if(s&&/^comment|string/.test(s.type)){var u=new r,a=new RegExp(s.type.replace(/\..*/,"\\."));if(n!=1){do s=i.stepBackward();while(s&&a.test(s.type));i.stepForward()}u.start.row=i.getCurrentTokenRow(),u.start.column=i.getCurrentTokenColumn()+2,i=new o(this,e,t);if(n!=-1){do s=i.stepForward();while(s&&a.test(s.type));s=i.stepBackward()}else s=i.getCurrentToken();return u.end.row=i.getCurrentTokenRow(),u.end.column=i.getCurrentTokenColumn()+s.value.length-2,u}},this.foldAll=function(e,t,n){n==undefined&&(n=1e5);var r=this.foldWidgets;if(!r)return;t=t||this.getLength(),e=e||0;for(var i=e;i<t;i++){r[i]==null&&(r[i]=this.getFoldWidget(i));if(r[i]!="start")continue;var s=this.getFoldWidgetRange(i);if(s&&s.isMultiLine()&&s.end.row<=t&&s.start.row>=e){i=s.end.row;try{var o=this.addFold("...",s);o&&(o.collapseChildren=n)}catch(u){}}}},this.$foldStyles={manual:1,markbegin:1,markbeginend:1},this.$foldStyle="markbegin",this.setFoldStyle=function(e){if(!this.$foldStyles[e])throw new Error("invalid fold style: "+e+"["+Object.keys(this.$foldStyles).join(", ")+"]");if(this.$foldStyle==e)return;this.$foldStyle=e,e=="manual"&&this.unfold();var t=this.$foldMode;this.$setFolding(null),this.$setFolding(t)},this.$setFolding=function(e){if(this.$foldMode==e)return;this.$foldMode=e,this.off("change",this.$updateFoldWidgets),this.off("tokenizerUpdate",this.$tokenizerUpdateFoldWidgets),this._signal("changeAnnotation");if(!e||this.$foldStyle=="manual"){this.foldWidgets=null;return}this.foldWidgets=[],this.getFoldWidget=e.getFoldWidget.bind(e,this,this.$foldStyle),this.getFoldWidgetRange=e.getFoldWidgetRange.bind(e,this,this.$foldStyle),this.$updateFoldWidgets=this.updateFoldWidgets.bind(this),this.$tokenizerUpdateFoldWidgets=this.tokenizerUpdateFoldWidgets.bind(this),this.on("change",this.$updateFoldWidgets),this.on("tokenizerUpdate",this.$tokenizerUpdateFoldWidgets)},this.getParentFoldRangeData=function(e,t){var n=this.foldWidgets;if(!n||t&&n[e])return{};var r=e-1,i;while(r>=0){var s=n[r];s==null&&(s=n[r]=this.getFoldWidget(r));if(s=="start"){var o=this.getFoldWidgetRange(r);i||(i=o);if(o&&o.end.row>=e)break}r--}return{range:r!==-1&&o,firstRange:i}},this.onFoldWidgetClick=function(e,t){t=t.domEvent;var n={children:t.shiftKey,all:t.ctrlKey||t.metaKey,siblings:t.altKey},r=this.$toggleFoldWidget(e,n);if(!r){var i=t.target||t.srcElement;i&&/ace_fold-widget/.test(i.className)&&(i.className+=" ace_invalid")}},this.$toggleFoldWidget=function(e,t){if(!this.getFoldWidget)return;var n=this.getFoldWidget(e),r=this.getLine(e),i=n==="end"?-1:1,s=this.getFoldAt(e,i===-1?0:r.length,i);if(s){t.children||t.all?this.removeFold(s):this.expandFold(s);return}var o=this.getFoldWidgetRange(e,!0);if(o&&!o.isMultiLine()){s=this.getFoldAt(o.start.row,o.start.column,1);if(s&&o.isEqual(s.range)){this.removeFold(s);return}}if(t.siblings){var u=this.getParentFoldRangeData(e);if(u.range)var a=u.range.start.row+1,f=u.range.end.row;this.foldAll(a,f,t.all?1e4:0)}else t.children?(f=o?o.end.row:this.getLength(),this.foldAll(e+1,f,t.all?1e4:0)):o&&(t.all&&(o.collapseChildren=1e4),this.addFold("...",o));return o},this.toggleFoldWidget=function(e){var t=this.selection.getCursor().row;t=this.getRowFoldStart(t);var n=this.$toggleFoldWidget(t,{});if(n)return;var r=this.getParentFoldRangeData(t,!0);n=r.range||r.firstRange;if(n){t=n.start.row;var i=this.getFoldAt(t,this.getLine(t).length,1);i?this.removeFold(i):this.addFold("...",n)}},this.updateFoldWidgets=function(e){var t=e.start.row,n=e.end.row-t;if(n===0)this.foldWidgets[t]=null;else if(e.action=="remove")this.foldWidgets.splice(t,n+1,null);else{var r=Array(n+1);r.unshift(t,1),this.foldWidgets.splice.apply(this.foldWidgets,r)}},this.tokenizerUpdateFoldWidgets=function(e){var t=e.data;t.first!=t.last&&this.foldWidgets.length>t.first&&this.foldWidgets.splice(t.first,this.foldWidgets.length)}}var r=e("../range").Range,i=e("./fold_line").FoldLine,s=e("./fold").Fold,o=e("../token_iterator").TokenIterator;t.Folding=u}),define("ace/edit_session/bracket_match",["require","exports","module","ace/token_iterator","ace/range"],function(e,t,n){"use strict";function s(){this.findMatchingBracket=function(e,t){if(e.column==0)return null;var n=t||this.getLine(e.row).charAt(e.column-1);if(n=="")return null;var r=n.match(/([\(\[\{])|([\)\]\}])/);return r?r[1]?this.$findClosingBracket(r[1],e):this.$findOpeningBracket(r[2],e):null},this.getBracketRange=function(e){var t=this.getLine(e.row),n=!0,r,s=t.charAt(e.column-1),o=s&&s.match(/([\(\[\{])|([\)\]\}])/);o||(s=t.charAt(e.column),e={row:e.row,column:e.column+1},o=s&&s.match(/([\(\[\{])|([\)\]\}])/),n=!1);if(!o)return null;if(o[1]){var u=this.$findClosingBracket(o[1],e);if(!u)return null;r=i.fromPoints(e,u),n||(r.end.column++,r.start.column--),r.cursor=r.end}else{var u=this.$findOpeningBracket(o[2],e);if(!u)return null;r=i.fromPoints(u,e),n||(r.start.column++,r.end.column--),r.cursor=r.start}return r},this.$brackets={")":"(","(":")","]":"[","[":"]","{":"}","}":"{"},this.$findOpeningBracket=function(e,t,n){var i=this.$brackets[e],s=1,o=new r(this,t.row,t.column),u=o.getCurrentToken();u||(u=o.stepForward());if(!u)return;n||(n=new RegExp("(\\.?"+u.type.replace(".","\\.").replace("rparen",".paren").replace(/\b(?:end)\b/,"(?:start|begin|end)")+")+"));var a=t.column-o.getCurrentTokenColumn()-2,f=u.value;for(;;){while(a>=0){var l=f.charAt(a);if(l==i){s-=1;if(s==0)return{row:o.getCurrentTokenRow(),column:a+o.getCurrentTokenColumn()}}else l==e&&(s+=1);a-=1}do u=o.stepBackward();while(u&&!n.test(u.type));if(u==null)break;f=u.value,a=f.length-1}return null},this.$findClosingBracket=function(e,t,n){var i=this.$brackets[e],s=1,o=new r(this,t.row,t.column),u=o.getCurrentToken();u||(u=o.stepForward());if(!u)return;n||(n=new RegExp("(\\.?"+u.type.replace(".","\\.").replace("lparen",".paren").replace(/\b(?:start|begin)\b/,"(?:start|begin|end)")+")+"));var a=t.column-o.getCurrentTokenColumn();for(;;){var f=u.value,l=f.length;while(a<l){var c=f.charAt(a);if(c==i){s-=1;if(s==0)return{row:o.getCurrentTokenRow(),column:a+o.getCurrentTokenColumn()}}else c==e&&(s+=1);a+=1}do u=o.stepForward();while(u&&!n.test(u.type));if(u==null)break;a=0}return null}}var r=e("../token_iterator").TokenIterator,i=e("../range").Range;t.BracketMatch=s}),define("ace/edit_session",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/config","ace/lib/event_emitter","ace/selection","ace/mode/text","ace/range","ace/document","ace/background_tokenizer","ace/search_highlight","ace/edit_session/folding","ace/edit_session/bracket_match"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/lang"),s=e("./config"),o=e("./lib/event_emitter").EventEmitter,u=e("./selection").Selection,a=e("./mode/text").Mode,f=e("./range").Range,l=e("./document").Document,c=e("./background_tokenizer").BackgroundTokenizer,h=e("./search_highlight").SearchHighlight,p=function(e,t){this.$breakpoints=[],this.$decorations=[],this.$frontMarkers={},this.$backMarkers={},this.$markerId=1,this.$undoSelect=!0,this.$foldData=[],this.$foldData.toString=function(){return this.join("\n")},this.on("changeFold",this.onChangeFold.bind(this)),this.$onChange=this.onChange.bind(this);if(typeof e!="object"||!e.getLine)e=new l(e);this.setDocument(e),this.selection=new u(this),s.resetOptions(this),this.setMode(t),s._signal("session",this)};(function(){function m(e){return e<4352?!1:e>=4352&&e<=4447||e>=4515&&e<=4519||e>=4602&&e<=4607||e>=9001&&e<=9002||e>=11904&&e<=11929||e>=11931&&e<=12019||e>=12032&&e<=12245||e>=12272&&e<=12283||e>=12288&&e<=12350||e>=12353&&e<=12438||e>=12441&&e<=12543||e>=12549&&e<=12589||e>=12593&&e<=12686||e>=12688&&e<=12730||e>=12736&&e<=12771||e>=12784&&e<=12830||e>=12832&&e<=12871||e>=12880&&e<=13054||e>=13056&&e<=19903||e>=19968&&e<=42124||e>=42128&&e<=42182||e>=43360&&e<=43388||e>=44032&&e<=55203||e>=55216&&e<=55238||e>=55243&&e<=55291||e>=63744&&e<=64255||e>=65040&&e<=65049||e>=65072&&e<=65106||e>=65108&&e<=65126||e>=65128&&e<=65131||e>=65281&&e<=65376||e>=65504&&e<=65510}r.implement(this,o),this.setDocument=function(e){this.doc&&this.doc.removeListener("change",this.$onChange),this.doc=e,e.on("change",this.$onChange),this.bgTokenizer&&this.bgTokenizer.setDocument(this.getDocument()),this.resetCaches()},this.getDocument=function(){return this.doc},this.$resetRowCache=function(e){if(!e){this.$docRowCache=[],this.$screenRowCache=[];return}var t=this.$docRowCache.length,n=this.$getRowCacheIndex(this.$docRowCache,e)+1;t>n&&(this.$docRowCache.splice(n,t),this.$screenRowCache.splice(n,t))},this.$getRowCacheIndex=function(e,t){var n=0,r=e.length-1;while(n<=r){var i=n+r>>1,s=e[i];if(t>s)n=i+1;else{if(!(t<s))return i;r=i-1}}return n-1},this.resetCaches=function(){this.$modified=!0,this.$wrapData=[],this.$rowLengthCache=[],this.$resetRowCache(0),this.bgTokenizer&&this.bgTokenizer.start(0)},this.onChangeFold=function(e){var t=e.data;this.$resetRowCache(t.start.row)},this.onChange=function(e){this.$modified=!0,this.$resetRowCache(e.start.row);var t=this.$updateInternalDataOnChange(e);!this.$fromUndo&&this.$undoManager&&!e.ignore&&(this.$deltasDoc.push(e),t&&t.length!=0&&this.$deltasFold.push({action:"removeFolds",folds:t}),this.$informUndoManager.schedule()),this.bgTokenizer&&this.bgTokenizer.$updateOnChange(e),this._signal("change",e)},this.setValue=function(e){this.doc.setValue(e),this.selection.moveTo(0,0),this.$resetRowCache(0),this.$deltas=[],this.$deltasDoc=[],this.$deltasFold=[],this.setUndoManager(this.$undoManager),this.getUndoManager().reset()},this.getValue=this.toString=function(){return this.doc.getValue()},this.getSelection=function(){return this.selection},this.getState=function(e){return this.bgTokenizer.getState(e)},this.getTokens=function(e){return this.bgTokenizer.getTokens(e)},this.getTokenAt=function(e,t){var n=this.bgTokenizer.getTokens(e),r,i=0;if(t==null)s=n.length-1,i=this.getLine(e).length;else for(var s=0;s<n.length;s++){i+=n[s].value.length;if(i>=t)break}return r=n[s],r?(r.index=s,r.start=i-r.value.length,r):null},this.setUndoManager=function(e){this.$undoManager=e,this.$deltas=[],this.$deltasDoc=[],this.$deltasFold=[],this.$informUndoManager&&this.$informUndoManager.cancel();if(e){var t=this;this.$syncInformUndoManager=function(){t.$informUndoManager.cancel(),t.$deltasFold.length&&(t.$deltas.push({group:"fold",deltas:t.$deltasFold}),t.$deltasFold=[]),t.$deltasDoc.length&&(t.$deltas.push({group:"doc",deltas:t.$deltasDoc}),t.$deltasDoc=[]),t.$deltas.length>0&&e.execute({action:"aceupdate",args:[t.$deltas,t],merge:t.mergeUndoDeltas}),t.mergeUndoDeltas=!1,t.$deltas=[]},this.$informUndoManager=i.delayedCall(this.$syncInformUndoManager)}},this.markUndoGroup=function(){this.$syncInformUndoManager&&this.$syncInformUndoManager()},this.$defaultUndoManager={undo:function(){},redo:function(){},reset:function(){}},this.getUndoManager=function(){return this.$undoManager||this.$defaultUndoManager},this.getTabString=function(){return this.getUseSoftTabs()?i.stringRepeat(" ",this.getTabSize()):"	"},this.setUseSoftTabs=function(e){this.setOption("useSoftTabs",e)},this.getUseSoftTabs=function(){return this.$useSoftTabs&&!this.$mode.$indentWithTabs},this.setTabSize=function(e){this.setOption("tabSize",e)},this.getTabSize=function(){return this.$tabSize},this.isTabStop=function(e){return this.$useSoftTabs&&e.column%this.$tabSize===0},this.$overwrite=!1,this.setOverwrite=function(e){this.setOption("overwrite",e)},this.getOverwrite=function(){return this.$overwrite},this.toggleOverwrite=function(){this.setOverwrite(!this.$overwrite)},this.addGutterDecoration=function(e,t){this.$decorations[e]||(this.$decorations[e]=""),this.$decorations[e]+=" "+t,this._signal("changeBreakpoint",{})},this.removeGutterDecoration=function(e,t){this.$decorations[e]=(this.$decorations[e]||"").replace(" "+t,""),this._signal("changeBreakpoint",{})},this.getBreakpoints=function(){return this.$breakpoints},this.setBreakpoints=function(e){this.$breakpoints=[];for(var t=0;t<e.length;t++)this.$breakpoints[e[t]]="ace_breakpoint";this._signal("changeBreakpoint",{})},this.clearBreakpoints=function(){this.$breakpoints=[],this._signal("changeBreakpoint",{})},this.setBreakpoint=function(e,t){t===undefined&&(t="ace_breakpoint"),t?this.$breakpoints[e]=t:delete this.$breakpoints[e],this._signal("changeBreakpoint",{})},this.clearBreakpoint=function(e){delete this.$breakpoints[e],this._signal("changeBreakpoint",{})},this.addMarker=function(e,t,n,r){var i=this.$markerId++,s={range:e,type:n||"line",renderer:typeof n=="function"?n:null,clazz:t,inFront:!!r,id:i};return r?(this.$frontMarkers[i]=s,this._signal("changeFrontMarker")):(this.$backMarkers[i]=s,this._signal("changeBackMarker")),i},this.addDynamicMarker=function(e,t){if(!e.update)return;var n=this.$markerId++;return e.id=n,e.inFront=!!t,t?(this.$frontMarkers[n]=e,this._signal("changeFrontMarker")):(this.$backMarkers[n]=e,this._signal("changeBackMarker")),e},this.removeMarker=function(e){var t=this.$frontMarkers[e]||this.$backMarkers[e];if(!t)return;var n=t.inFront?this.$frontMarkers:this.$backMarkers;t&&(delete n[e],this._signal(t.inFront?"changeFrontMarker":"changeBackMarker"))},this.getMarkers=function(e){return e?this.$frontMarkers:this.$backMarkers},this.highlight=function(e){if(!this.$searchHighlight){var t=new h(null,"ace_selected-word","text");this.$searchHighlight=this.addDynamicMarker(t)}this.$searchHighlight.setRegexp(e)},this.highlightLines=function(e,t,n,r){typeof t!="number"&&(n=t,t=e),n||(n="ace_step");var i=new f(e,0,t,Infinity);return i.id=this.addMarker(i,n,"fullLine",r),i},this.setAnnotations=function(e){this.$annotations=e,this._signal("changeAnnotation",{})},this.getAnnotations=function(){return this.$annotations||[]},this.clearAnnotations=function(){this.setAnnotations([])},this.$detectNewLine=function(e){var t=e.match(/^.*?(\r?\n)/m);t?this.$autoNewLine=t[1]:this.$autoNewLine="\n"},this.getWordRange=function(e,t){var n=this.getLine(e),r=!1;t>0&&(r=!!n.charAt(t-1).match(this.tokenRe)),r||(r=!!n.charAt(t).match(this.tokenRe));if(r)var i=this.tokenRe;else if(/^\s+$/.test(n.slice(t-1,t+1)))var i=/\s/;else var i=this.nonTokenRe;var s=t;if(s>0){do s--;while(s>=0&&n.charAt(s).match(i));s++}var o=t;while(o<n.length&&n.charAt(o).match(i))o++;return new f(e,s,e,o)},this.getAWordRange=function(e,t){var n=this.getWordRange(e,t),r=this.getLine(n.end.row);while(r.charAt(n.end.column).match(/[ \t]/))n.end.column+=1;return n},this.setNewLineMode=function(e){this.doc.setNewLineMode(e)},this.getNewLineMode=function(){return this.doc.getNewLineMode()},this.setUseWorker=function(e){this.setOption("useWorker",e)},this.getUseWorker=function(){return this.$useWorker},this.onReloadTokenizer=function(e){var t=e.data;this.bgTokenizer.start(t.first),this._signal("tokenizerUpdate",e)},this.$modes={},this.$mode=null,this.$modeId=null,this.setMode=function(e,t){if(e&&typeof e=="object"){if(e.getTokenizer)return this.$onChangeMode(e);var n=e,r=n.path}else r=e||"ace/mode/text";this.$modes["ace/mode/text"]||(this.$modes["ace/mode/text"]=new a);if(this.$modes[r]&&!n){this.$onChangeMode(this.$modes[r]),t&&t();return}this.$modeId=r,s.loadModule(["mode",r],function(e){if(this.$modeId!==r)return t&&t();this.$modes[r]&&!n?this.$onChangeMode(this.$modes[r]):e&&e.Mode&&(e=new e.Mode(n),n||(this.$modes[r]=e,e.$id=r),this.$onChangeMode(e)),t&&t()}.bind(this)),this.$mode||this.$onChangeMode(this.$modes["ace/mode/text"],!0)},this.$onChangeMode=function(e,t){t||(this.$modeId=e.$id);if(this.$mode===e)return;this.$mode=e,this.$stopWorker(),this.$useWorker&&this.$startWorker();var n=e.getTokenizer();if(n.addEventListener!==undefined){var r=this.onReloadTokenizer.bind(this);n.addEventListener("update",r)}if(!this.bgTokenizer){this.bgTokenizer=new c(n);var i=this;this.bgTokenizer.addEventListener("update",function(e){i._signal("tokenizerUpdate",e)})}else this.bgTokenizer.setTokenizer(n);this.bgTokenizer.setDocument(this.getDocument()),this.tokenRe=e.tokenRe,this.nonTokenRe=e.nonTokenRe,t||(e.attachToSession&&e.attachToSession(this),this.$options.wrapMethod.set.call(this,this.$wrapMethod),this.$setFolding(e.foldingRules),this.bgTokenizer.start(0),this._emit("changeMode"))},this.$stopWorker=function(){this.$worker&&(this.$worker.terminate(),this.$worker=null)},this.$startWorker=function(){try{this.$worker=this.$mode.createWorker(this)}catch(e){s.warn("Could not load worker",e),this.$worker=null}},this.getMode=function(){return this.$mode},this.$scrollTop=0,this.setScrollTop=function(e){if(this.$scrollTop===e||isNaN(e))return;this.$scrollTop=e,this._signal("changeScrollTop",e)},this.getScrollTop=function(){return this.$scrollTop},this.$scrollLeft=0,this.setScrollLeft=function(e){if(this.$scrollLeft===e||isNaN(e))return;this.$scrollLeft=e,this._signal("changeScrollLeft",e)},this.getScrollLeft=function(){return this.$scrollLeft},this.getScreenWidth=function(){return this.$computeWidth(),this.lineWidgets?Math.max(this.getLineWidgetMaxWidth(),this.screenWidth):this.screenWidth},this.getLineWidgetMaxWidth=function(){if(this.lineWidgetsWidth!=null)return this.lineWidgetsWidth;var e=0;return this.lineWidgets.forEach(function(t){t&&t.screenWidth>e&&(e=t.screenWidth)}),this.lineWidgetWidth=e},this.$computeWidth=function(e){if(this.$modified||e){this.$modified=!1;if(this.$useWrapMode)return this.screenWidth=this.$wrapLimit;var t=this.doc.getAllLines(),n=this.$rowLengthCache,r=0,i=0,s=this.$foldData[i],o=s?s.start.row:Infinity,u=t.length;for(var a=0;a<u;a++){if(a>o){a=s.end.row+1;if(a>=u)break;s=this.$foldData[i++],o=s?s.start.row:Infinity}n[a]==null&&(n[a]=this.$getStringScreenWidth(t[a])[0]),n[a]>r&&(r=n[a])}this.screenWidth=r}},this.getLine=function(e){return this.doc.getLine(e)},this.getLines=function(e,t){return this.doc.getLines(e,t)},this.getLength=function(){return this.doc.getLength()},this.getTextRange=function(e){return this.doc.getTextRange(e||this.selection.getRange())},this.insert=function(e,t){return this.doc.insert(e,t)},this.remove=function(e){return this.doc.remove(e)},this.removeFullLines=function(e,t){return this.doc.removeFullLines(e,t)},this.undoChanges=function(e,t){if(!e.length)return;this.$fromUndo=!0;var n=null;for(var r=e.length-1;r!=-1;r--){var i=e[r];i.group=="doc"?(this.doc.revertDeltas(i.deltas),n=this.$getUndoSelection(i.deltas,!0,n)):i.deltas.forEach(function(e){this.addFolds(e.folds)},this)}return this.$fromUndo=!1,n&&this.$undoSelect&&!t&&this.selection.setSelectionRange(n),n},this.redoChanges=function(e,t){if(!e.length)return;this.$fromUndo=!0;var n=null;for(var r=0;r<e.length;r++){var i=e[r];i.group=="doc"&&(this.doc.applyDeltas(i.deltas),n=this.$getUndoSelection(i.deltas,!1,n))}return this.$fromUndo=!1,n&&this.$undoSelect&&!t&&this.selection.setSelectionRange(n),n},this.setUndoSelect=function(e){this.$undoSelect=e},this.$getUndoSelection=function(e,t,n){function r(e){return t?e.action!=="insert":e.action==="insert"}var i=e[0],s,o,u=!1;r(i)?(s=f.fromPoints(i.start,i.end),u=!0):(s=f.fromPoints(i.start,i.start),u=!1);for(var a=1;a<e.length;a++)i=e[a],r(i)?(o=i.start,s.compare(o.row,o.column)==-1&&s.setStart(o),o=i.end,s.compare(o.row,o.column)==1&&s.setEnd(o),u=!0):(o=i.start,s.compare(o.row,o.column)==-1&&(s=f.fromPoints(i.start,i.start)),u=!1);if(n!=null){f.comparePoints(n.start,s.start)===0&&(n.start.column+=s.end.column-s.start.column,n.end.column+=s.end.column-s.start.column);var l=n.compareRange(s);l==1?s.setStart(n.start):l==-1&&s.setEnd(n.end)}return s},this.replace=function(e,t){return this.doc.replace(e,t)},this.moveText=function(e,t,n){var r=this.getTextRange(e),i=this.getFoldsInRange(e),s=f.fromPoints(t,t);if(!n){this.remove(e);var o=e.start.row-e.end.row,u=o?-e.end.column:e.start.column-e.end.column;u&&(s.start.row==e.end.row&&s.start.column>e.end.column&&(s.start.column+=u),s.end.row==e.end.row&&s.end.column>e.end.column&&(s.end.column+=u)),o&&s.start.row>=e.end.row&&(s.start.row+=o,s.end.row+=o)}s.end=this.insert(s.start,r);if(i.length){var a=e.start,l=s.start,o=l.row-a.row,u=l.column-a.column;this.addFolds(i.map(function(e){return e=e.clone(),e.start.row==a.row&&(e.start.column+=u),e.end.row==a.row&&(e.end.column+=u),e.start.row+=o,e.end.row+=o,e}))}return s},this.indentRows=function(e,t,n){n=n.replace(/\t/g,this.getTabString());for(var r=e;r<=t;r++)this.doc.insertInLine({row:r,column:0},n)},this.outdentRows=function(e){var t=e.collapseRows(),n=new f(0,0,0,0),r=this.getTabSize();for(var i=t.start.row;i<=t.end.row;++i){var s=this.getLine(i);n.start.row=i,n.end.row=i;for(var o=0;o<r;++o)if(s.charAt(o)!=" ")break;o<r&&s.charAt(o)=="	"?(n.start.column=o,n.end.column=o+1):(n.start.column=0,n.end.column=o),this.remove(n)}},this.$moveLines=function(e,t,n){e=this.getRowFoldStart(e),t=this.getRowFoldEnd(t);if(n<0){var r=this.getRowFoldStart(e+n);if(r<0)return 0;var i=r-e}else if(n>0){var r=this.getRowFoldEnd(t+n);if(r>this.doc.getLength()-1)return 0;var i=r-t}else{e=this.$clipRowToDocument(e),t=this.$clipRowToDocument(t);var i=t-e+1}var s=new f(e,0,t,Number.MAX_VALUE),o=this.getFoldsInRange(s).map(function(e){return e=e.clone(),e.start.row+=i,e.end.row+=i,e}),u=n==0?this.doc.getLines(e,t):this.doc.removeFullLines(e,t);return this.doc.insertFullLines(e+i,u),o.length&&this.addFolds(o),i},this.moveLinesUp=function(e,t){return this.$moveLines(e,t,-1)},this.moveLinesDown=function(e,t){return this.$moveLines(e,t,1)},this.duplicateLines=function(e,t){return this.$moveLines(e,t,0)},this.$clipRowToDocument=function(e){return Math.max(0,Math.min(e,this.doc.getLength()-1))},this.$clipColumnToRow=function(e,t){return t<0?0:Math.min(this.doc.getLine(e).length,t)},this.$clipPositionToDocument=function(e,t){t=Math.max(0,t);if(e<0)e=0,t=0;else{var n=this.doc.getLength();e>=n?(e=n-1,t=this.doc.getLine(n-1).length):t=Math.min(this.doc.getLine(e).length,t)}return{row:e,column:t}},this.$clipRangeToDocument=function(e){e.start.row<0?(e.start.row=0,e.start.column=0):e.start.column=this.$clipColumnToRow(e.start.row,e.start.column);var t=this.doc.getLength()-1;return e.end.row>t?(e.end.row=t,e.end.column=this.doc.getLine(t).length):e.end.column=this.$clipColumnToRow(e.end.row,e.end.column),e},this.$wrapLimit=80,this.$useWrapMode=!1,this.$wrapLimitRange={min:null,max:null},this.setUseWrapMode=function(e){if(e!=this.$useWrapMode){this.$useWrapMode=e,this.$modified=!0,this.$resetRowCache(0);if(e){var t=this.getLength();this.$wrapData=Array(t),this.$updateWrapData(0,t-1)}this._signal("changeWrapMode")}},this.getUseWrapMode=function(){return this.$useWrapMode},this.setWrapLimitRange=function(e,t){if(this.$wrapLimitRange.min!==e||this.$wrapLimitRange.max!==t)this.$wrapLimitRange={min:e,max:t},this.$modified=!0,this.$useWrapMode&&this._signal("changeWrapMode")},this.adjustWrapLimit=function(e,t){var n=this.$wrapLimitRange;n.max<0&&(n={min:t,max:t});var r=this.$constrainWrapLimit(e,n.min,n.max);return r!=this.$wrapLimit&&r>1?(this.$wrapLimit=r,this.$modified=!0,this.$useWrapMode&&(this.$updateWrapData(0,this.getLength()-1),this.$resetRowCache(0),this._signal("changeWrapLimit")),!0):!1},this.$constrainWrapLimit=function(e,t,n){return t&&(e=Math.max(t,e)),n&&(e=Math.min(n,e)),e},this.getWrapLimit=function(){return this.$wrapLimit},this.setWrapLimit=function(e){this.setWrapLimitRange(e,e)},this.getWrapLimitRange=function(){return{min:this.$wrapLimitRange.min,max:this.$wrapLimitRange.max}},this.$updateInternalDataOnChange=function(e){var t=this.$useWrapMode,n=e.action,r=e.start,i=e.end,s=r.row,o=i.row,u=o-s,a=null;this.$updating=!0;if(u!=0)if(n==="remove"){this[t?"$wrapData":"$rowLengthCache"].splice(s,u);var f=this.$foldData;a=this.getFoldsInRange(e),this.removeFolds(a);var l=this.getFoldLine(i.row),c=0;if(l){l.addRemoveChars(i.row,i.column,r.column-i.column),l.shiftRow(-u);var h=this.getFoldLine(s);h&&h!==l&&(h.merge(l),l=h),c=f.indexOf(l)+1}for(c;c<f.length;c++){var l=f[c];l.start.row>=i.row&&l.shiftRow(-u)}o=s}else{var p=Array(u);p.unshift(s,0);var d=t?this.$wrapData:this.$rowLengthCache;d.splice.apply(d,p);var f=this.$foldData,l=this.getFoldLine(s),c=0;if(l){var v=l.range.compareInside(r.row,r.column);v==0?(l=l.split(r.row,r.column),l&&(l.shiftRow(u),l.addRemoveChars(o,0,i.column-r.column))):v==-1&&(l.addRemoveChars(s,0,i.column-r.column),l.shiftRow(u)),c=f.indexOf(l)+1}for(c;c<f.length;c++){var l=f[c];l.start.row>=s&&l.shiftRow(u)}}else{u=Math.abs(e.start.column-e.end.column),n==="remove"&&(a=this.getFoldsInRange(e),this.removeFolds(a),u=-u);var l=this.getFoldLine(s);l&&l.addRemoveChars(s,r.column,u)}return t&&this.$wrapData.length!=this.doc.getLength()&&console.error("doc.getLength() and $wrapData.length have to be the same!"),this.$updating=!1,t?this.$updateWrapData(s,o):this.$updateRowLengthCache(s,o),a},this.$updateRowLengthCache=function(e,t,n){this.$rowLengthCache[e]=null,this.$rowLengthCache[t]=null},this.$updateWrapData=function(e,t){var r=this.doc.getAllLines(),i=this.getTabSize(),s=this.$wrapData,o=this.$wrapLimit,a,f,l=e;t=Math.min(t,r.length-1);while(l<=t)f=this.getFoldLine(l,f),f?(a=[],f.walk(function(e,t,i,s){var o;if(e!=null){o=this.$getDisplayTokens(e,a.length),o[0]=n;for(var f=1;f<o.length;f++)o[f]=u}else o=this.$getDisplayTokens(r[t].substring(s,i),a.length);a=a.concat(o)}.bind(this),f.end.row,r[f.end.row].length+1),s[f.start.row]=this.$computeWrapSplits(a,o,i),l=f.end.row+1):(a=this.$getDisplayTokens(r[l]),s[l]=this.$computeWrapSplits(a,o,i),l++)};var e=1,t=2,n=3,u=4,l=9,p=10,d=11,v=12;this.$computeWrapSplits=function(e,r,i){function g(){var t=0;if(m===0)return t;if(h)for(var n=0;n<e.length;n++){var r=e[n];if(r==p)t+=1;else{if(r!=d){if(r==v)continue;break}t+=i}}return c&&h!==!1&&(t+=i),Math.min(t,m)}function y(t){var n=e.slice(a,t),r=n.length;n.join("").replace(/12/g,function(){r-=1}).replace(/2/g,function(){r-=1}),s.length||(b=g(),s.indent=b),f+=r,s.push(f),a=t}if(e.length==0)return[];var s=[],o=e.length,a=0,f=0,c=this.$wrapAsCode,h=this.$indentedSoftWrap,m=r<=Math.max(2*i,8)||h===!1?0:Math.floor(r/2),b=0;while(o-a>r-b){var w=a+r-b;if(e[w-1]>=p&&e[w]>=p){y(w);continue}if(e[w]==n||e[w]==u){for(w;w!=a-1;w--)if(e[w]==n)break;if(w>a){y(w);continue}w=a+r;for(w;w<e.length;w++)if(e[w]!=u)break;if(w==e.length)break;y(w);continue}var E=Math.max(w-(r-(r>>2)),a-1);while(w>E&&e[w]<n)w--;if(c){while(w>E&&e[w]<n)w--;while(w>E&&e[w]==l)w--}else while(w>E&&e[w]<p)w--;if(w>E){y(++w);continue}w=a+r,e[w]==t&&w--,y(w-b)}return s},this.$getDisplayTokens=function(n,r){var i=[],s;r=r||0;for(var o=0;o<n.length;o++){var u=n.charCodeAt(o);if(u==9){s=this.getScreenTabSize(i.length+r),i.push(d);for(var a=1;a<s;a++)i.push(v)}else u==32?i.push(p):u>39&&u<48||u>57&&u<64?i.push(l):u>=4352&&m(u)?i.push(e,t):i.push(e)}return i},this.$getStringScreenWidth=function(e,t,n){if(t==0)return[0,0];t==null&&(t=Infinity),n=n||0;var r,i;for(i=0;i<e.length;i++){r=e.charCodeAt(i),r==9?n+=this.getScreenTabSize(n):r>=4352&&m(r)?n+=2:n+=1;if(n>t)break}return[n,i]},this.lineWidgets=null,this.getRowLength=function(e){if(this.lineWidgets)var t=this.lineWidgets[e]&&this.lineWidgets[e].rowCount||0;else t=0;return!this.$useWrapMode||!this.$wrapData[e]?1+t:this.$wrapData[e].length+1+t},this.getRowLineCount=function(e){return!this.$useWrapMode||!this.$wrapData[e]?1:this.$wrapData[e].length+1},this.getRowWrapIndent=function(e){if(this.$useWrapMode){var t=this.screenToDocumentPosition(e,Number.MAX_VALUE),n=this.$wrapData[t.row];return n.length&&n[0]<t.column?n.indent:0}return 0},this.getScreenLastRowColumn=function(e){var t=this.screenToDocumentPosition(e,Number.MAX_VALUE);return this.documentToScreenColumn(t.row,t.column)},this.getDocumentLastRowColumn=function(e,t){var n=this.documentToScreenRow(e,t);return this.getScreenLastRowColumn(n)},this.getDocumentLastRowColumnPosition=function(e,t){var n=this.documentToScreenRow(e,t);return this.screenToDocumentPosition(n,Number.MAX_VALUE/10)},this.getRowSplitData=function(e){return this.$useWrapMode?this.$wrapData[e]:undefined},this.getScreenTabSize=function(e){return this.$tabSize-e%this.$tabSize},this.screenToDocumentRow=function(e,t){return this.screenToDocumentPosition(e,t).row},this.screenToDocumentColumn=function(e,t){return this.screenToDocumentPosition(e,t).column},this.screenToDocumentPosition=function(e,t){if(e<0)return{row:0,column:0};var n,r=0,i=0,s,o=0,u=0,a=this.$screenRowCache,f=this.$getRowCacheIndex(a,e),l=a.length;if(l&&f>=0)var o=a[f],r=this.$docRowCache[f],c=e>a[l-1];else var c=!l;var h=this.getLength()-1,p=this.getNextFoldLine(r),d=p?p.start.row:Infinity;while(o<=e){u=this.getRowLength(r);if(o+u>e||r>=h)break;o+=u,r++,r>d&&(r=p.end.row+1,p=this.getNextFoldLine(r,p),d=p?p.start.row:Infinity),c&&(this.$docRowCache.push(r),this.$screenRowCache.push(o))}if(p&&p.start.row<=r)n=this.getFoldDisplayLine(p),r=p.start.row;else{if(o+u<=e||r>h)return{row:h,column:this.getLine(h).length};n=this.getLine(r),p=null}var v=0;if(this.$useWrapMode){var m=this.$wrapData[r];if(m){var g=Math.floor(e-o);s=m[g],g>0&&m.length&&(v=m.indent,i=m[g-1]||m[m.length-1],n=n.substring(i))}}return i+=this.$getStringScreenWidth(n,t-v)[1],this.$useWrapMode&&i>=s&&(i=s-1),p?p.idxToPosition(i):{row:r,column:i}},this.documentToScreenPosition=function(e,t){if(typeof t=="undefined")var n=this.$clipPositionToDocument(e.row,e.column);else n=this.$clipPositionToDocument(e,t);e=n.row,t=n.column;var r=0,i=null,s=null;s=this.getFoldAt(e,t,1),s&&(e=s.start.row,t=s.start.column);var o,u=0,a=this.$docRowCache,f=this.$getRowCacheIndex(a,e),l=a.length;if(l&&f>=0)var u=a[f],r=this.$screenRowCache[f],c=e>a[l-1];else var c=!l;var h=this.getNextFoldLine(u),p=h?h.start.row:Infinity;while(u<e){if(u>=p){o=h.end.row+1;if(o>e)break;h=this.getNextFoldLine(o,h),p=h?h.start.row:Infinity}else o=u+1;r+=this.getRowLength(u),u=o,c&&(this.$docRowCache.push(u),this.$screenRowCache.push(r))}var d="";h&&u>=p?(d=this.getFoldDisplayLine(h,e,t),i=h.start.row):(d=this.getLine(e).substring(0,t),i=e);var v=0;if(this.$useWrapMode){var m=this.$wrapData[i];if(m){var g=0;while(d.length>=m[g])r++,g++;d=d.substring(m[g-1]||0,d.length),v=g>0?m.indent:0}}return{row:r,column:v+this.$getStringScreenWidth(d)[0]}},this.documentToScreenColumn=function(e,t){return this.documentToScreenPosition(e,t).column},this.documentToScreenRow=function(e,t){return this.documentToScreenPosition(e,t).row},this.getScreenLength=function(){var e=0,t=null;if(!this.$useWrapMode){e=this.getLength();var n=this.$foldData;for(var r=0;r<n.length;r++)t=n[r],e-=t.end.row-t.start.row}else{var i=this.$wrapData.length,s=0,r=0,t=this.$foldData[r++],o=t?t.start.row:Infinity;while(s<i){var u=this.$wrapData[s];e+=u?u.length+1:1,s++,s>o&&(s=t.end.row+1,t=this.$foldData[r++],o=t?t.start.row:Infinity)}}return this.lineWidgets&&(e+=this.$getWidgetScreenLength()),e},this.$setFontMetrics=function(e){if(!this.$enableVarChar)return;this.$getStringScreenWidth=function(t,n,r){if(n===0)return[0,0];n||(n=Infinity),r=r||0;var i,s;for(s=0;s<t.length;s++){i=t.charAt(s),i==="	"?r+=this.getScreenTabSize(r):r+=e.getCharacterWidth(i);if(r>n)break}return[r,s]}},this.destroy=function(){this.bgTokenizer&&(this.bgTokenizer.setDocument(null),this.bgTokenizer=null),this.$stopWorker()}}).call(p.prototype),e("./edit_session/folding").Folding.call(p.prototype),e("./edit_session/bracket_match").BracketMatch.call(p.prototype),s.defineOptions(p.prototype,"session",{wrap:{set:function(e){!e||e=="off"?e=!1:e=="free"?e=!0:e=="printMargin"?e=-1:typeof e=="string"&&(e=parseInt(e,10)||!1);if(this.$wrap==e)return;this.$wrap=e;if(!e)this.setUseWrapMode(!1);else{var t=typeof e=="number"?e:null;this.setWrapLimitRange(t,t),this.setUseWrapMode(!0)}},get:function(){return this.getUseWrapMode()?this.$wrap==-1?"printMargin":this.getWrapLimitRange().min?this.$wrap:"free":"off"},handlesSet:!0},wrapMethod:{set:function(e){e=e=="auto"?this.$mode.type!="text":e!="text",e!=this.$wrapAsCode&&(this.$wrapAsCode=e,this.$useWrapMode&&(this.$modified=!0,this.$resetRowCache(0),this.$updateWrapData(0,this.getLength()-1)))},initialValue:"auto"},indentedSoftWrap:{initialValue:!0},firstLineNumber:{set:function(){this._signal("changeBreakpoint")},initialValue:1},useWorker:{set:function(e){this.$useWorker=e,this.$stopWorker(),e&&this.$startWorker()},initialValue:!0},useSoftTabs:{initialValue:!0},tabSize:{set:function(e){if(isNaN(e)||this.$tabSize===e)return;this.$modified=!0,this.$rowLengthCache=[],this.$tabSize=e,this._signal("changeTabSize")},initialValue:4,handlesSet:!0},overwrite:{set:function(e){this._signal("changeOverwrite")},initialValue:!1},newLineMode:{set:function(e){this.doc.setNewLineMode(e)},get:function(){return this.doc.getNewLineMode()},handlesSet:!0},mode:{set:function(e){this.setMode(e)},get:function(){return this.$modeId}}}),t.EditSession=p}),define("ace/search",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/range"],function(e,t,n){"use strict";var r=e("./lib/lang"),i=e("./lib/oop"),s=e("./range").Range,o=function(){this.$options={}};(function(){this.set=function(e){return i.mixin(this.$options,e),this},this.getOptions=function(){return r.copyObject(this.$options)},this.setOptions=function(e){this.$options=e},this.find=function(e){var t=this.$options,n=this.$matchIterator(e,t);if(!n)return!1;var r=null;return n.forEach(function(e,n,i){if(!e.start){var o=e.offset+(i||0);r=new s(n,o,n,o+e.length);if(!e.length&&t.start&&t.start.start&&t.skipCurrent!=0&&r.isEqual(t.start))return r=null,!1}else r=e;return!0}),r},this.findAll=function(e){var t=this.$options;if(!t.needle)return[];this.$assembleRegExp(t);var n=t.range,i=n?e.getLines(n.start.row,n.end.row):e.doc.getAllLines(),o=[],u=t.re;if(t.$isMultiLine){var a=u.length,f=i.length-a,l;e:for(var c=u.offset||0;c<=f;c++){for(var h=0;h<a;h++)if(i[c+h].search(u[h])==-1)continue e;var p=i[c],d=i[c+a-1],v=p.length-p.match(u[0])[0].length,m=d.match(u[a-1])[0].length;if(l&&l.end.row===c&&l.end.column>v)continue;o.push(l=new s(c,v,c+a-1,m)),a>2&&(c=c+a-2)}}else for(var g=0;g<i.length;g++){var y=r.getMatchOffsets(i[g],u);for(var h=0;h<y.length;h++){var b=y[h];o.push(new s(g,b.offset,g,b.offset+b.length))}}if(n){var w=n.start.column,E=n.start.column,g=0,h=o.length-1;while(g<h&&o[g].start.column<w&&o[g].start.row==n.start.row)g++;while(g<h&&o[h].end.column>E&&o[h].end.row==n.end.row)h--;o=o.slice(g,h+1);for(g=0,h=o.length;g<h;g++)o[g].start.row+=n.start.row,o[g].end.row+=n.start.row}return o},this.replace=function(e,t){var n=this.$options,r=this.$assembleRegExp(n);if(n.$isMultiLine)return t;if(!r)return;var i=r.exec(e);if(!i||i[0].length!=e.length)return null;t=e.replace(r,t);if(n.preserveCase){t=t.split("");for(var s=Math.min(e.length,e.length);s--;){var o=e[s];o&&o.toLowerCase()!=o?t[s]=t[s].toUpperCase():t[s]=t[s].toLowerCase()}t=t.join("")}return t},this.$matchIterator=function(e,t){var n=this.$assembleRegExp(t);if(!n)return!1;var i;if(t.$isMultiLine)var o=n.length,u=function(t,r,u){var a=t.search(n[0]);if(a==-1)return;for(var f=1;f<o;f++){t=e.getLine(r+f);if(t.search(n[f])==-1)return}var l=t.match(n[o-1])[0].length,c=new s(r,a,r+o-1,l);n.offset==1?(c.start.row--,c.start.column=Number.MAX_VALUE):u&&(c.start.column+=u);if(i(c))return!0};else if(t.backwards)var u=function(e,t,s){var o=r.getMatchOffsets(e,n);for(var u=o.length-1;u>=0;u--)if(i(o[u],t,s))return!0};else var u=function(e,t,s){var o=r.getMatchOffsets(e,n);for(var u=0;u<o.length;u++)if(i(o[u],t,s))return!0};var a=this.$lineIterator(e,t);return{forEach:function(e){i=e,a.forEach(u)}}},this.$assembleRegExp=function(e,t){if(e.needle instanceof RegExp)return e.re=e.needle;var n=e.needle;if(!e.needle)return e.re=!1;e.regExp||(n=r.escapeRegExp(n)),e.wholeWord&&(n="\\b"+n+"\\b");var i=e.caseSensitive?"gm":"gmi";e.$isMultiLine=!t&&/[\n\r]/.test(n);if(e.$isMultiLine)return e.re=this.$assembleMultilineRegExp(n,i);try{var s=new RegExp(n,i)}catch(o){s=!1}return e.re=s},this.$assembleMultilineRegExp=function(e,t){var n=e.replace(/\r\n|\r|\n/g,"$\n^").split("\n"),r=[];for(var i=0;i<n.length;i++)try{r.push(new RegExp(n[i],t))}catch(s){return!1}return n[0]==""?(r.shift(),r.offset=1):r.offset=0,r},this.$lineIterator=function(e,t){var n=t.backwards==1,r=t.skipCurrent!=0,i=t.range,s=t.start;s||(s=i?i[n?"end":"start"]:e.selection.getRange()),s.start&&(s=s[r!=n?"end":"start"]);var o=i?i.start.row:0,u=i?i.end.row:e.getLength()-1,a=n?function(n){var r=s.row,i=e.getLine(r).substring(0,s.column);if(n(i,r))return;for(r--;r>=o;r--)if(n(e.getLine(r),r))return;if(t.wrap==0)return;for(r=u,o=s.row;r>=o;r--)if(n(e.getLine(r),r))return}:function(n){var r=s.row,i=e.getLine(r).substr(s.column);if(n(i,r,s.column))return;for(r+=1;r<=u;r++)if(n(e.getLine(r),r))return;if(t.wrap==0)return;for(r=o,u=s.row;r<=u;r++)if(n(e.getLine(r),r))return};return{forEach:a}}}).call(o.prototype),t.Search=o}),define("ace/keyboard/hash_handler",["require","exports","module","ace/lib/keys","ace/lib/useragent"],function(e,t,n){"use strict";function o(e,t){this.platform=t||(i.isMac?"mac":"win"),this.commands={},this.commandKeyBinding={},this.addCommands(e),this.$singleCommand=!0}function u(e,t){o.call(this,e,t),this.$singleCommand=!1}var r=e("../lib/keys"),i=e("../lib/useragent"),s=r.KEY_MODS;u.prototype=o.prototype,function(){function e(e){return typeof e=="object"&&e.bindKey&&e.bindKey.position||0}this.addCommand=function(e){this.commands[e.name]&&this.removeCommand(e),this.commands[e.name]=e,e.bindKey&&this._buildKeyHash(e)},this.removeCommand=function(e,t){var n=e&&(typeof e=="string"?e:e.name);e=this.commands[n],t||delete this.commands[n];var r=this.commandKeyBinding;for(var i in r){var s=r[i];if(s==e)delete r[i];else if(Array.isArray(s)){var o=s.indexOf(e);o!=-1&&(s.splice(o,1),s.length==1&&(r[i]=s[0]))}}},this.bindKey=function(e,t,n){typeof e=="object"&&e&&(n==undefined&&(n=e.position),e=e[this.platform]);if(!e)return;if(typeof t=="function")return this.addCommand({exec:t,bindKey:e,name:t.name||e});e.split("|").forEach(function(e){var r="";if(e.indexOf(" ")!=-1){var i=e.split(/\s+/);e=i.pop(),i.forEach(function(e){var t=this.parseKeys(e),n=s[t.hashId]+t.key;r+=(r?" ":"")+n,this._addCommandToBinding(r,"chainKeys")},this),r+=" "}var o=this.parseKeys(e),u=s[o.hashId]+o.key;this._addCommandToBinding(r+u,t,n)},this)},this._addCommandToBinding=function(t,n,r){var i=this.commandKeyBinding,s;if(!n)delete i[t];else if(!i[t]||this.$singleCommand)i[t]=n;else{Array.isArray(i[t])?(s=i[t].indexOf(n))!=-1&&i[t].splice(s,1):i[t]=[i[t]],typeof r!="number"&&(r||n.isDefault?r=-100:r=e(n));var o=i[t];for(s=0;s<o.length;s++){var u=o[s],a=e(u);if(a>r)break}o.splice(s,0,n)}},this.addCommands=function(e){e&&Object.keys(e).forEach(function(t){var n=e[t];if(!n)return;if(typeof n=="string")return this.bindKey(n,t);typeof n=="function"&&(n={exec:n});if(typeof n!="object")return;n.name||(n.name=t),this.addCommand(n)},this)},this.removeCommands=function(e){Object.keys(e).forEach(function(t){this.removeCommand(e[t])},this)},this.bindKeys=function(e){Object.keys(e).forEach(function(t){this.bindKey(t,e[t])},this)},this._buildKeyHash=function(e){this.bindKey(e.bindKey,e)},this.parseKeys=function(e){var t=e.toLowerCase().split(/[\-\+]([\-\+])?/).filter(function(e){return e}),n=t.pop(),i=r[n];if(r.FUNCTION_KEYS[i])n=r.FUNCTION_KEYS[i].toLowerCase();else{if(!t.length)return{key:n,hashId:-1};if(t.length==1&&t[0]=="shift")return{key:n.toUpperCase(),hashId:-1}}var s=0;for(var o=t.length;o--;){var u=r.KEY_MODS[t[o]];if(u==null)return typeof console!="undefined"&&console.error("invalid modifier "+t[o]+" in "+e),!1;s|=u}return{key:n,hashId:s}},this.findKeyCommand=function(t,n){var r=s[t]+n;return this.commandKeyBinding[r]},this.handleKeyboard=function(e,t,n,r){if(r<0)return;var i=s[t]+n,o=this.commandKeyBinding[i];e.$keyChain&&(e.$keyChain+=" "+i,o=this.commandKeyBinding[e.$keyChain]||o);if(o)if(o=="chainKeys"||o[o.length-1]=="chainKeys")return e.$keyChain=e.$keyChain||i,{command:"null"};if(e.$keyChain)if(!!t&&t!=4||n.length!=1){if(t==-1||r>0)e.$keyChain=""}else e.$keyChain=e.$keyChain.slice(0,-i.length-1);return{command:o}},this.getStatusText=function(e,t){return t.$keyChain||""}}.call(o.prototype),t.HashHandler=o,t.MultiHashHandler=u}),define("ace/commands/command_manager",["require","exports","module","ace/lib/oop","ace/keyboard/hash_handler","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../keyboard/hash_handler").MultiHashHandler,s=e("../lib/event_emitter").EventEmitter,o=function(e,t){i.call(this,t,e),this.byName=this.commands,this.setDefaultHandler("exec",function(e){return e.command.exec(e.editor,e.args||{})})};r.inherits(o,i),function(){r.implement(this,s),this.exec=function(e,t,n){if(Array.isArray(e)){for(var r=e.length;r--;)if(this.exec(e[r],t,n))return!0;return!1}typeof e=="string"&&(e=this.commands[e]);if(!e)return!1;if(t&&t.$readOnly&&!e.readOnly)return!1;var i={editor:t,command:e,args:n};return i.returnValue=this._emit("exec",i),this._signal("afterExec",i),i.returnValue===!1?!1:!0},this.toggleRecording=function(e){if(this.$inReplay)return;return e&&e._emit("changeStatus"),this.recording?(this.macro.pop(),this.removeEventListener("exec",this.$addCommandToMacro),this.macro.length||(this.macro=this.oldMacro),this.recording=!1):(this.$addCommandToMacro||(this.$addCommandToMacro=function(e){this.macro.push([e.command,e.args])}.bind(this)),this.oldMacro=this.macro,this.macro=[],this.on("exec",this.$addCommandToMacro),this.recording=!0)},this.replay=function(e){if(this.$inReplay||!this.macro)return;if(this.recording)return this.toggleRecording(e);try{this.$inReplay=!0,this.macro.forEach(function(t){typeof t=="string"?this.exec(t,e):this.exec(t[0],e,t[1])},this)}finally{this.$inReplay=!1}},this.trimMacro=function(e){return e.map(function(e){return typeof e[0]!="string"&&(e[0]=e[0].name),e[1]||(e=e[0]),e})}}.call(o.prototype),t.CommandManager=o}),define("ace/commands/default_commands",["require","exports","module","ace/lib/lang","ace/config","ace/range"],function(e,t,n){"use strict";function o(e,t){return{win:e,mac:t}}var r=e("../lib/lang"),i=e("../config"),s=e("../range").Range;t.commands=[{name:"showSettingsMenu",bindKey:o("Ctrl-,","Command-,"),exec:function(e){i.loadModule("ace/ext/settings_menu",function(t){t.init(e),e.showSettingsMenu()})},readOnly:!0},{name:"goToNextError",bindKey:o("Alt-E","Ctrl-E"),exec:function(e){i.loadModule("ace/ext/error_marker",function(t){t.showErrorMarker(e,1)})},scrollIntoView:"animate",readOnly:!0},{name:"goToPreviousError",bindKey:o("Alt-Shift-E","Ctrl-Shift-E"),exec:function(e){i.loadModule("ace/ext/error_marker",function(t){t.showErrorMarker(e,-1)})},scrollIntoView:"animate",readOnly:!0},{name:"selectall",bindKey:o("Ctrl-A","Command-A"),exec:function(e){e.selectAll()},readOnly:!0},{name:"centerselection",bindKey:o(null,"Ctrl-L"),exec:function(e){e.centerSelection()},readOnly:!0},{name:"gotoline",bindKey:o("Ctrl-L","Command-L"),exec:function(e){var t=parseInt(prompt("Enter line number:"),10);isNaN(t)||e.gotoLine(t)},readOnly:!0},{name:"fold",bindKey:o("Alt-L|Ctrl-F1","Command-Alt-L|Command-F1"),exec:function(e){e.session.toggleFold(!1)},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"unfold",bindKey:o("Alt-Shift-L|Ctrl-Shift-F1","Command-Alt-Shift-L|Command-Shift-F1"),exec:function(e){e.session.toggleFold(!0)},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"toggleFoldWidget",bindKey:o("F2","F2"),exec:function(e){e.session.toggleFoldWidget()},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"toggleParentFoldWidget",bindKey:o("Alt-F2","Alt-F2"),exec:function(e){e.session.toggleFoldWidget(!0)},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"foldall",bindKey:o(null,"Ctrl-Command-Option-0"),exec:function(e){e.session.foldAll()},scrollIntoView:"center",readOnly:!0},{name:"foldOther",bindKey:o("Alt-0","Command-Option-0"),exec:function(e){e.session.foldAll(),e.session.unfold(e.selection.getAllRanges())},scrollIntoView:"center",readOnly:!0},{name:"unfoldall",bindKey:o("Alt-Shift-0","Command-Option-Shift-0"),exec:function(e){e.session.unfold()},scrollIntoView:"center",readOnly:!0},{name:"findnext",bindKey:o("Ctrl-K","Command-G"),exec:function(e){e.findNext()},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"findprevious",bindKey:o("Ctrl-Shift-K","Command-Shift-G"),exec:function(e){e.findPrevious()},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"selectOrFindNext",bindKey:o("Alt-K","Ctrl-G"),exec:function(e){e.selection.isEmpty()?e.selection.selectWord():e.findNext()},readOnly:!0},{name:"selectOrFindPrevious",bindKey:o("Alt-Shift-K","Ctrl-Shift-G"),exec:function(e){e.selection.isEmpty()?e.selection.selectWord():e.findPrevious()},readOnly:!0},{name:"find",bindKey:o("Ctrl-F","Command-F"),exec:function(e){i.loadModule("ace/ext/searchbox",function(t){t.Search(e)})},readOnly:!0},{name:"overwrite",bindKey:"Insert",exec:function(e){e.toggleOverwrite()},readOnly:!0},{name:"selecttostart",bindKey:o("Ctrl-Shift-Home","Command-Shift-Up"),exec:function(e){e.getSelection().selectFileStart()},multiSelectAction:"forEach",readOnly:!0,scrollIntoView:"animate",aceCommandGroup:"fileJump"},{name:"gotostart",bindKey:o("Ctrl-Home","Command-Home|Command-Up"),exec:function(e){e.navigateFileStart()},multiSelectAction:"forEach",readOnly:!0,scrollIntoView:"animate",aceCommandGroup:"fileJump"},{name:"selectup",bindKey:o("Shift-Up","Shift-Up"),exec:function(e){e.getSelection().selectUp()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"golineup",bindKey:o("Up","Up|Ctrl-P"),exec:function(e,t){e.navigateUp(t.times)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selecttoend",bindKey:o("Ctrl-Shift-End","Command-Shift-Down"),exec:function(e){e.getSelection().selectFileEnd()},multiSelectAction:"forEach",readOnly:!0,scrollIntoView:"animate",aceCommandGroup:"fileJump"},{name:"gotoend",bindKey:o("Ctrl-End","Command-End|Command-Down"),exec:function(e){e.navigateFileEnd()},multiSelectAction:"forEach",readOnly:!0,scrollIntoView:"animate",aceCommandGroup:"fileJump"},{name:"selectdown",bindKey:o("Shift-Down","Shift-Down"),exec:function(e){e.getSelection().selectDown()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"golinedown",bindKey:o("Down","Down|Ctrl-N"),exec:function(e,t){e.navigateDown(t.times)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectwordleft",bindKey:o("Ctrl-Shift-Left","Option-Shift-Left"),exec:function(e){e.getSelection().selectWordLeft()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotowordleft",bindKey:o("Ctrl-Left","Option-Left"),exec:function(e){e.navigateWordLeft()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selecttolinestart",bindKey:o("Alt-Shift-Left","Command-Shift-Left"),exec:function(e){e.getSelection().selectLineStart()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotolinestart",bindKey:o("Alt-Left|Home","Command-Left|Home|Ctrl-A"),exec:function(e){e.navigateLineStart()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectleft",bindKey:o("Shift-Left","Shift-Left"),exec:function(e){e.getSelection().selectLeft()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotoleft",bindKey:o("Left","Left|Ctrl-B"),exec:function(e,t){e.navigateLeft(t.times)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectwordright",bindKey:o("Ctrl-Shift-Right","Option-Shift-Right"),exec:function(e){e.getSelection().selectWordRight()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotowordright",bindKey:o("Ctrl-Right","Option-Right"),exec:function(e){e.navigateWordRight()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selecttolineend",bindKey:o("Alt-Shift-Right","Command-Shift-Right"),exec:function(e){e.getSelection().selectLineEnd()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotolineend",bindKey:o("Alt-Right|End","Command-Right|End|Ctrl-E"),exec:function(e){e.navigateLineEnd()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectright",bindKey:o("Shift-Right","Shift-Right"),exec:function(e){e.getSelection().selectRight()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotoright",bindKey:o("Right","Right|Ctrl-F"),exec:function(e,t){e.navigateRight(t.times)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectpagedown",bindKey:"Shift-PageDown",exec:function(e){e.selectPageDown()},readOnly:!0},{name:"pagedown",bindKey:o(null,"Option-PageDown"),exec:function(e){e.scrollPageDown()},readOnly:!0},{name:"gotopagedown",bindKey:o("PageDown","PageDown|Ctrl-V"),exec:function(e){e.gotoPageDown()},readOnly:!0},{name:"selectpageup",bindKey:"Shift-PageUp",exec:function(e){e.selectPageUp()},readOnly:!0},{name:"pageup",bindKey:o(null,"Option-PageUp"),exec:function(e){e.scrollPageUp()},readOnly:!0},{name:"gotopageup",bindKey:"PageUp",exec:function(e){e.gotoPageUp()},readOnly:!0},{name:"scrollup",bindKey:o("Ctrl-Up",null),exec:function(e){e.renderer.scrollBy(0,-2*e.renderer.layerConfig.lineHeight)},readOnly:!0},{name:"scrolldown",bindKey:o("Ctrl-Down",null),exec:function(e){e.renderer.scrollBy(0,2*e.renderer.layerConfig.lineHeight)},readOnly:!0},{name:"selectlinestart",bindKey:"Shift-Home",exec:function(e){e.getSelection().selectLineStart()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectlineend",bindKey:"Shift-End",exec:function(e){e.getSelection().selectLineEnd()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"togglerecording",bindKey:o("Ctrl-Alt-E","Command-Option-E"),exec:function(e){e.commands.toggleRecording(e)},readOnly:!0},{name:"replaymacro",bindKey:o("Ctrl-Shift-E","Command-Shift-E"),exec:function(e){e.commands.replay(e)},readOnly:!0},{name:"jumptomatching",bindKey:o("Ctrl-P","Ctrl-P"),exec:function(e){e.jumpToMatching()},multiSelectAction:"forEach",scrollIntoView:"animate",readOnly:!0},{name:"selecttomatching",bindKey:o("Ctrl-Shift-P","Ctrl-Shift-P"),exec:function(e){e.jumpToMatching(!0)},multiSelectAction:"forEach",scrollIntoView:"animate",readOnly:!0},{name:"expandToMatching",bindKey:o("Ctrl-Shift-M","Ctrl-Shift-M"),exec:function(e){e.jumpToMatching(!0,!0)},multiSelectAction:"forEach",scrollIntoView:"animate",readOnly:!0},{name:"passKeysToBrowser",bindKey:o(null,null),exec:function(){},passEvent:!0,readOnly:!0},{name:"copy",exec:function(e){},readOnly:!0},{name:"cut",exec:function(e){var t=e.getSelectionRange();e._emit("cut",t),e.selection.isEmpty()||(e.session.remove(t),e.clearSelection())},scrollIntoView:"cursor",multiSelectAction:"forEach"},{name:"paste",exec:function(e,t){e.$handlePaste(t)},scrollIntoView:"cursor"},{name:"removeline",bindKey:o("Ctrl-D","Command-D"),exec:function(e){e.removeLines()},scrollIntoView:"cursor",multiSelectAction:"forEachLine"},{name:"duplicateSelection",bindKey:o("Ctrl-Shift-D","Command-Shift-D"),exec:function(e){e.duplicateSelection()},scrollIntoView:"cursor",multiSelectAction:"forEach"},{name:"sortlines",bindKey:o("Ctrl-Alt-S","Command-Alt-S"),exec:function(e){e.sortLines()},scrollIntoView:"selection",multiSelectAction:"forEachLine"},{name:"togglecomment",bindKey:o("Ctrl-/","Command-/"),exec:function(e){e.toggleCommentLines()},multiSelectAction:"forEachLine",scrollIntoView:"selectionPart"},{name:"toggleBlockComment",bindKey:o("Ctrl-Shift-/","Command-Shift-/"),exec:function(e){e.toggleBlockComment()},multiSelectAction:"forEach",scrollIntoView:"selectionPart"},{name:"modifyNumberUp",bindKey:o("Ctrl-Shift-Up","Alt-Shift-Up"),exec:function(e){e.modifyNumber(1)},scrollIntoView:"cursor",multiSelectAction:"forEach"},{name:"modifyNumberDown",bindKey:o("Ctrl-Shift-Down","Alt-Shift-Down"),exec:function(e){e.modifyNumber(-1)},scrollIntoView:"cursor",multiSelectAction:"forEach"},{name:"replace",bindKey:o("Ctrl-H","Command-Option-F"),exec:function(e){i.loadModule("ace/ext/searchbox",function(t){t.Search(e,!0)})}},{name:"undo",bindKey:o("Ctrl-Z","Command-Z"),exec:function(e){e.undo()}},{name:"redo",bindKey:o("Ctrl-Shift-Z|Ctrl-Y","Command-Shift-Z|Command-Y"),exec:function(e){e.redo()}},{name:"copylinesup",bindKey:o("Alt-Shift-Up","Command-Option-Up"),exec:function(e){e.copyLinesUp()},scrollIntoView:"cursor"},{name:"movelinesup",bindKey:o("Alt-Up","Option-Up"),exec:function(e){e.moveLinesUp()},scrollIntoView:"cursor"},{name:"copylinesdown",bindKey:o("Alt-Shift-Down","Command-Option-Down"),exec:function(e){e.copyLinesDown()},scrollIntoView:"cursor"},{name:"movelinesdown",bindKey:o("Alt-Down","Option-Down"),exec:function(e){e.moveLinesDown()},scrollIntoView:"cursor"},{name:"del",bindKey:o("Delete","Delete|Ctrl-D|Shift-Delete"),exec:function(e){e.remove("right")},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"backspace",bindKey:o("Shift-Backspace|Backspace","Ctrl-Backspace|Shift-Backspace|Backspace|Ctrl-H"),exec:function(e){e.remove("left")},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"cut_or_delete",bindKey:o("Shift-Delete",null),exec:function(e){if(!e.selection.isEmpty())return!1;e.remove("left")},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removetolinestart",bindKey:o("Alt-Backspace","Command-Backspace"),exec:function(e){e.removeToLineStart()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removetolineend",bindKey:o("Alt-Delete","Ctrl-K"),exec:function(e){e.removeToLineEnd()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removewordleft",bindKey:o("Ctrl-Backspace","Alt-Backspace|Ctrl-Alt-Backspace"),exec:function(e){e.removeWordLeft()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removewordright",bindKey:o("Ctrl-Delete","Alt-Delete"),exec:function(e){e.removeWordRight()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"outdent",bindKey:o("Shift-Tab","Shift-Tab"),exec:function(e){e.blockOutdent()},multiSelectAction:"forEach",scrollIntoView:"selectionPart"},{name:"indent",bindKey:o("Tab","Tab"),exec:function(e){e.indent()},multiSelectAction:"forEach",scrollIntoView:"selectionPart"},{name:"blockoutdent",bindKey:o("Ctrl-[","Ctrl-["),exec:function(e){e.blockOutdent()},multiSelectAction:"forEachLine",scrollIntoView:"selectionPart"},{name:"blockindent",bindKey:o("Ctrl-]","Ctrl-]"),exec:function(e){e.blockIndent()},multiSelectAction:"forEachLine",scrollIntoView:"selectionPart"},{name:"insertstring",exec:function(e,t){e.insert(t)},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"inserttext",exec:function(e,t){e.insert(r.stringRepeat(t.text||"",t.times||1))},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"splitline",bindKey:o(null,"Ctrl-O"),exec:function(e){e.splitLine()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"transposeletters",bindKey:o("Ctrl-T","Ctrl-T"),exec:function(e){e.transposeLetters()},multiSelectAction:function(e){e.transposeSelections(1)},scrollIntoView:"cursor"},{name:"touppercase",bindKey:o("Ctrl-U","Ctrl-U"),exec:function(e){e.toUpperCase()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"tolowercase",bindKey:o("Ctrl-Shift-U","Ctrl-Shift-U"),exec:function(e){e.toLowerCase()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"expandtoline",bindKey:o("Ctrl-Shift-L","Command-Shift-L"),exec:function(e){var t=e.selection.getRange();t.start.column=t.end.column=0,t.end.row++,e.selection.setRange(t,!1)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"joinlines",bindKey:o(null,null),exec:function(e){var t=e.selection.isBackwards(),n=t?e.selection.getSelectionLead():e.selection.getSelectionAnchor(),i=t?e.selection.getSelectionAnchor():e.selection.getSelectionLead(),o=e.session.doc.getLine(n.row).length,u=e.session.doc.getTextRange(e.selection.getRange()),a=u.replace(/\n\s*/," ").length,f=e.session.doc.getLine(n.row);for(var l=n.row+1;l<=i.row+1;l++){var c=r.stringTrimLeft(r.stringTrimRight(e.session.doc.getLine(l)));c.length!==0&&(c=" "+c),f+=c}i.row+1<e.session.doc.getLength()-1&&(f+=e.session.doc.getNewLineCharacter()),e.clearSelection(),e.session.doc.replace(new s(n.row,0,i.row+2,0),f),a>0?(e.selection.moveCursorTo(n.row,n.column),e.selection.selectTo(n.row,n.column+a)):(o=e.session.doc.getLine(n.row).length>o?o+1:o,e.selection.moveCursorTo(n.row,o))},multiSelectAction:"forEach",readOnly:!0},{name:"invertSelection",bindKey:o(null,null),exec:function(e){var t=e.session.doc.getLength()-1,n=e.session.doc.getLine(t).length,r=e.selection.rangeList.ranges,i=[];r.length<1&&(r=[e.selection.getRange()]);for(var o=0;o<r.length;o++)o==r.length-1&&(r[o].end.row!==t||r[o].end.column!==n)&&i.push(new s(r[o].end.row,r[o].end.column,t,n)),o===0?(r[o].start.row!==0||r[o].start.column!==0)&&i.push(new s(0,0,r[o].start.row,r[o].start.column)):i.push(new s(r[o-1].end.row,r[o-1].end.column,r[o].start.row,r[o].start.column));e.exitMultiSelectMode(),e.clearSelection();for(var o=0;o<i.length;o++)e.selection.addRange(i[o],!1)},readOnly:!0,scrollIntoView:"none"}]}),define("ace/editor",["require","exports","module","ace/lib/fixoldbrowsers","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/lib/useragent","ace/keyboard/textinput","ace/mouse/mouse_handler","ace/mouse/fold_handler","ace/keyboard/keybinding","ace/edit_session","ace/search","ace/range","ace/lib/event_emitter","ace/commands/command_manager","ace/commands/default_commands","ace/config","ace/token_iterator"],function(e,t,n){"use strict";e("./lib/fixoldbrowsers");var r=e("./lib/oop"),i=e("./lib/dom"),s=e("./lib/lang"),o=e("./lib/useragent"),u=e("./keyboard/textinput").TextInput,a=e("./mouse/mouse_handler").MouseHandler,f=e("./mouse/fold_handler").FoldHandler,l=e("./keyboard/keybinding").KeyBinding,c=e("./edit_session").EditSession,h=e("./search").Search,p=e("./range").Range,d=e("./lib/event_emitter").EventEmitter,v=e("./commands/command_manager").CommandManager,m=e("./commands/default_commands").commands,g=e("./config"),y=e("./token_iterator").TokenIterator,b=function(e,t){var n=e.getContainerElement();this.container=n,this.renderer=e,this.commands=new v(o.isMac?"mac":"win",m),this.textInput=new u(e.getTextAreaContainer(),this),this.renderer.textarea=this.textInput.getElement(),this.keyBinding=new l(this),this.$mouseHandler=new a(this),new f(this),this.$blockScrolling=0,this.$search=(new h).set({wrap:!0}),this.$historyTracker=this.$historyTracker.bind(this),this.commands.on("exec",this.$historyTracker),this.$initOperationListeners(),this._$emitInputEvent=s.delayedCall(function(){this._signal("input",{}),this.session&&this.session.bgTokenizer&&this.session.bgTokenizer.scheduleStart()}.bind(this)),this.on("change",function(e,t){t._$emitInputEvent.schedule(31)}),this.setSession(t||new c("")),g.resetOptions(this),g._signal("editor",this)};(function(){r.implement(this,d),this.$initOperationListeners=function(){function e(e){return e[e.length-1]}this.selections=[],this.commands.on("exec",this.startOperation.bind(this),!0),this.commands.on("afterExec",this.endOperation.bind(this),!0),this.$opResetTimer=s.delayedCall(this.endOperation.bind(this)),this.on("change",function(){this.curOp||this.startOperation(),this.curOp.docChanged=!0}.bind(this),!0),this.on("changeSelection",function(){this.curOp||this.startOperation(),this.curOp.selectionChanged=!0}.bind(this),!0)},this.curOp=null,this.prevOp={},this.startOperation=function(e){if(this.curOp){if(!e||this.curOp.command)return;this.prevOp=this.curOp}e||(this.previousCommand=null,e={}),this.$opResetTimer.schedule(),this.curOp={command:e.command||{},args:e.args,scrollTop:this.renderer.scrollTop},this.curOp.command.name&&this.curOp.command.scrollIntoView!==undefined&&this.$blockScrolling++},this.endOperation=function(e){if(this.curOp){if(e&&e.returnValue===!1)return this.curOp=null;this._signal("beforeEndOperation");var t=this.curOp.command;t.name&&this.$blockScrolling>0&&this.$blockScrolling--;var n=t&&t.scrollIntoView;if(n){switch(n){case"center-animate":n="animate";case"center":this.renderer.scrollCursorIntoView(null,.5);break;case"animate":case"cursor":this.renderer.scrollCursorIntoView();break;case"selectionPart":var r=this.selection.getRange(),i=this.renderer.layerConfig;(r.start.row>=i.lastRow||r.end.row<=i.firstRow)&&this.renderer.scrollSelectionIntoView(this.selection.anchor,this.selection.lead);break;default:}n=="animate"&&this.renderer.animateScrolling(this.curOp.scrollTop)}this.prevOp=this.curOp,this.curOp=null}},this.$mergeableCommands=["backspace","del","insertstring"],this.$historyTracker=function(e){if(!this.$mergeUndoDeltas)return;var t=this.prevOp,n=this.$mergeableCommands,r=t.command&&e.command.name==t.command.name;if(e.command.name=="insertstring"){var i=e.args;this.mergeNextCommand===undefined&&(this.mergeNextCommand=!0),r=r&&this.mergeNextCommand&&(!/\s/.test(i)||/\s/.test(t.args)),this.mergeNextCommand=!0}else r=r&&n.indexOf(e.command.name)!==-1;this.$mergeUndoDeltas!="always"&&Date.now()-this.sequenceStartTime>2e3&&(r=!1),r?this.session.mergeUndoDeltas=!0:n.indexOf(e.command.name)!==-1&&(this.sequenceStartTime=Date.now())},this.setKeyboardHandler=function(e,t){if(e&&typeof e=="string"){this.$keybindingId=e;var n=this;g.loadModule(["keybinding",e],function(r){n.$keybindingId==e&&n.keyBinding.setKeyboardHandler(r&&r.handler),t&&t()})}else this.$keybindingId=null,this.keyBinding.setKeyboardHandler(e),t&&t()},this.getKeyboardHandler=function(){return this.keyBinding.getKeyboardHandler()},this.setSession=function(e){if(this.session==e)return;this.curOp&&this.endOperation(),this.curOp={};var t=this.session;if(t){this.session.off("change",this.$onDocumentChange),this.session.off("changeMode",this.$onChangeMode),this.session.off("tokenizerUpdate",this.$onTokenizerUpdate),this.session.off("changeTabSize",this.$onChangeTabSize),this.session.off("changeWrapLimit",this.$onChangeWrapLimit),this.session.off("changeWrapMode",this.$onChangeWrapMode),this.session.off("changeFold",this.$onChangeFold),this.session.off("changeFrontMarker",this.$onChangeFrontMarker),this.session.off("changeBackMarker",this.$onChangeBackMarker),this.session.off("changeBreakpoint",this.$onChangeBreakpoint),this.session.off("changeAnnotation",this.$onChangeAnnotation),this.session.off("changeOverwrite",this.$onCursorChange),this.session.off("changeScrollTop",this.$onScrollTopChange),this.session.off("changeScrollLeft",this.$onScrollLeftChange);var n=this.session.getSelection();n.off("changeCursor",this.$onCursorChange),n.off("changeSelection",this.$onSelectionChange)}this.session=e,e?(this.$onDocumentChange=this.onDocumentChange.bind(this),e.on("change",this.$onDocumentChange),this.renderer.setSession(e),this.$onChangeMode=this.onChangeMode.bind(this),e.on("changeMode",this.$onChangeMode),this.$onTokenizerUpdate=this.onTokenizerUpdate.bind(this),e.on("tokenizerUpdate",this.$onTokenizerUpdate),this.$onChangeTabSize=this.renderer.onChangeTabSize.bind(this.renderer),e.on("changeTabSize",this.$onChangeTabSize),this.$onChangeWrapLimit=this.onChangeWrapLimit.bind(this),e.on("changeWrapLimit",this.$onChangeWrapLimit),this.$onChangeWrapMode=this.onChangeWrapMode.bind(this),e.on("changeWrapMode",this.$onChangeWrapMode),this.$onChangeFold=this.onChangeFold.bind(this),e.on("changeFold",this.$onChangeFold),this.$onChangeFrontMarker=this.onChangeFrontMarker.bind(this),this.session.on("changeFrontMarker",this.$onChangeFrontMarker),this.$onChangeBackMarker=this.onChangeBackMarker.bind(this),this.session.on("changeBackMarker",this.$onChangeBackMarker),this.$onChangeBreakpoint=this.onChangeBreakpoint.bind(this),this.session.on("changeBreakpoint",this.$onChangeBreakpoint),this.$onChangeAnnotation=this.onChangeAnnotation.bind(this),this.session.on("changeAnnotation",this.$onChangeAnnotation),this.$onCursorChange=this.onCursorChange.bind(this),this.session.on("changeOverwrite",this.$onCursorChange),this.$onScrollTopChange=this.onScrollTopChange.bind(this),this.session.on("changeScrollTop",this.$onScrollTopChange),this.$onScrollLeftChange=this.onScrollLeftChange.bind(this),this.session.on("changeScrollLeft",this.$onScrollLeftChange),this.selection=e.getSelection(),this.selection.on("changeCursor",this.$onCursorChange),this.$onSelectionChange=this.onSelectionChange.bind(this),this.selection.on("changeSelection",this.$onSelectionChange),this.onChangeMode(),this.$blockScrolling+=1,this.onCursorChange(),this.$blockScrolling-=1,this.onScrollTopChange(),this.onScrollLeftChange(),this.onSelectionChange(),this.onChangeFrontMarker(),this.onChangeBackMarker(),this.onChangeBreakpoint(),this.onChangeAnnotation(),this.session.getUseWrapMode()&&this.renderer.adjustWrapLimit(),this.renderer.updateFull()):(this.selection=null,this.renderer.setSession(e)),this._signal("changeSession",{session:e,oldSession:t}),this.curOp=null,t&&t._signal("changeEditor",{oldEditor:this}),e&&e._signal("changeEditor",{editor:this})},this.getSession=function(){return this.session},this.setValue=function(e,t){return this.session.doc.setValue(e),t?t==1?this.navigateFileEnd():t==-1&&this.navigateFileStart():this.selectAll(),e},this.getValue=function(){return this.session.getValue()},this.getSelection=function(){return this.selection},this.resize=function(e){this.renderer.onResize(e)},this.setTheme=function(e,t){this.renderer.setTheme(e,t)},this.getTheme=function(){return this.renderer.getTheme()},this.setStyle=function(e){this.renderer.setStyle(e)},this.unsetStyle=function(e){this.renderer.unsetStyle(e)},this.getFontSize=function(){return this.getOption("fontSize")||i.computedStyle(this.container,"fontSize")},this.setFontSize=function(e){this.setOption("fontSize",e)},this.$highlightBrackets=function(){this.session.$bracketHighlight&&(this.session.removeMarker(this.session.$bracketHighlight),this.session.$bracketHighlight=null);if(this.$highlightPending)return;var e=this;this.$highlightPending=!0,setTimeout(function(){e.$highlightPending=!1;var t=e.session;if(!t||!t.bgTokenizer)return;var n=t.findMatchingBracket(e.getCursorPosition());if(n)var r=new p(n.row,n.column,n.row,n.column+1);else if(t.$mode.getMatching)var r=t.$mode.getMatching(e.session);r&&(t.$bracketHighlight=t.addMarker(r,"ace_bracket","text"))},50)},this.$highlightTags=function(){if(this.$highlightTagPending)return;var e=this;this.$highlightTagPending=!0,setTimeout(function(){e.$highlightTagPending=!1;var t=e.session;if(!t||!t.bgTokenizer)return;var n=e.getCursorPosition(),r=new y(e.session,n.row,n.column),i=r.getCurrentToken();if(!i||!/\b(?:tag-open|tag-name)/.test(i.type)){t.removeMarker(t.$tagHighlight),t.$tagHighlight=null;return}if(i.type.indexOf("tag-open")!=-1){i=r.stepForward();if(!i)return}var s=i.value,o=0,u=r.stepBackward();if(u.value=="<"){do u=i,i=r.stepForward(),i&&i.value===s&&i.type.indexOf("tag-name")!==-1&&(u.value==="<"?o++:u.value==="</"&&o--);while(i&&o>=0)}else{do i=u,u=r.stepBackward(),i&&i.value===s&&i.type.indexOf("tag-name")!==-1&&(u.value==="<"?o++:u.value==="</"&&o--);while(u&&o<=0);r.stepForward()}if(!i){t.removeMarker(t.$tagHighlight),t.$tagHighlight=null;return}var a=r.getCurrentTokenRow(),f=r.getCurrentTokenColumn(),l=new p(a,f,a,f+i.value.length);t.$tagHighlight&&l.compareRange(t.$backMarkers[t.$tagHighlight].range)!==0&&(t.removeMarker(t.$tagHighlight),t.$tagHighlight=null),l&&!t.$tagHighlight&&(t.$tagHighlight=t.addMarker(l,"ace_bracket","text"))},50)},this.focus=function(){var e=this;setTimeout(function(){e.textInput.focus()}),this.textInput.focus()},this.isFocused=function(){return this.textInput.isFocused()},this.blur=function(){this.textInput.blur()},this.onFocus=function(e){if(this.$isFocused)return;this.$isFocused=!0,this.renderer.showCursor(),this.renderer.visualizeFocus(),this._emit("focus",e)},this.onBlur=function(e){if(!this.$isFocused)return;this.$isFocused=!1,this.renderer.hideCursor(),this.renderer.visualizeBlur(),this._emit("blur",e)},this.$cursorChange=function(){this.renderer.updateCursor()},this.onDocumentChange=function(e){var t=this.session.$useWrapMode,n=e.start.row==e.end.row?e.end.row:Infinity;this.renderer.updateLines(e.start.row,n,t),this._signal("change",e),this.$cursorChange(),this.$updateHighlightActiveLine()},this.onTokenizerUpdate=function(e){var t=e.data;this.renderer.updateLines(t.first,t.last)},this.onScrollTopChange=function(){this.renderer.scrollToY(this.session.getScrollTop())},this.onScrollLeftChange=function(){this.renderer.scrollToX(this.session.getScrollLeft())},this.onCursorChange=function(){this.$cursorChange(),this.$blockScrolling||(g.warn("Automatically scrolling cursor into view after selection change","this will be disabled in the next version","set editor.$blockScrolling = Infinity to disable this message"),this.renderer.scrollCursorIntoView()),this.$highlightBrackets(),this.$highlightTags(),this.$updateHighlightActiveLine(),this._signal("changeSelection")},this.$updateHighlightActiveLine=function(){var e=this.getSession(),t;if(this.$highlightActiveLine){if(this.$selectionStyle!="line"||!this.selection.isMultiLine())t=this.getCursorPosition();this.renderer.$maxLines&&this.session.getLength()===1&&!(this.renderer.$minLines>1)&&(t=!1)}if(e.$highlightLineMarker&&!t)e.removeMarker(e.$highlightLineMarker.id),e.$highlightLineMarker=null;else if(!e.$highlightLineMarker&&t){var n=new p(t.row,t.column,t.row,Infinity);n.id=e.addMarker(n,"ace_active-line","screenLine"),e.$highlightLineMarker=n}else t&&(e.$highlightLineMarker.start.row=t.row,e.$highlightLineMarker.end.row=t.row,e.$highlightLineMarker.start.column=t.column,e._signal("changeBackMarker"))},this.onSelectionChange=function(e){var t=this.session;t.$selectionMarker&&t.removeMarker(t.$selectionMarker),t.$selectionMarker=null;if(!this.selection.isEmpty()){var n=this.selection.getRange(),r=this.getSelectionStyle();t.$selectionMarker=t.addMarker(n,"ace_selection",r)}else this.$updateHighlightActiveLine();var i=this.$highlightSelectedWord&&this.$getSelectionHighLightRegexp();this.session.highlight(i),this._signal("changeSelection")},this.$getSelectionHighLightRegexp=function(){var e=this.session,t=this.getSelectionRange();if(t.isEmpty()||t.isMultiLine())return;var n=t.start.column-1,r=t.end.column+1,i=e.getLine(t.start.row),s=i.length,o=i.substring(Math.max(n,0),Math.min(r,s));if(n>=0&&/^[\w\d]/.test(o)||r<=s&&/[\w\d]$/.test(o))return;o=i.substring(t.start.column,t.end.column);if(!/^[\w\d]+$/.test(o))return;var u=this.$search.$assembleRegExp({wholeWord:!0,caseSensitive:!0,needle:o});return u},this.onChangeFrontMarker=function(){this.renderer.updateFrontMarkers()},this.onChangeBackMarker=function(){this.renderer.updateBackMarkers()},this.onChangeBreakpoint=function(){this.renderer.updateBreakpoints()},this.onChangeAnnotation=function(){this.renderer.setAnnotations(this.session.getAnnotations())},this.onChangeMode=function(e){this.renderer.updateText(),this._emit("changeMode",e)},this.onChangeWrapLimit=function(){this.renderer.updateFull()},this.onChangeWrapMode=function(){this.renderer.onResize(!0)},this.onChangeFold=function(){this.$updateHighlightActiveLine(),this.renderer.updateFull()},this.getSelectedText=function(){return this.session.getTextRange(this.getSelectionRange())},this.getCopyText=function(){var e=this.getSelectedText();return this._signal("copy",e),e},this.onCopy=function(){this.commands.exec("copy",this)},this.onCut=function(){this.commands.exec("cut",this)},this.onPaste=function(e,t){var n={text:e,event:t};this.commands.exec("paste",this,n)},this.$handlePaste=function(e){typeof e=="string"&&(e={text:e}),this._signal("paste",e);var t=e.text;if(!this.inMultiSelectMode||this.inVirtualSelectionMode)this.insert(t);else{var n=t.split(/\r\n|\r|\n/),r=this.selection.rangeList.ranges;if(n.length>r.length||n.length<2||!n[1])return this.commands.exec("insertstring",this,t);for(var i=r.length;i--;){var s=r[i];s.isEmpty()||this.session.remove(s),this.session.insert(s.start,n[i])}}},this.execCommand=function(e,t){return this.commands.exec(e,this,t)},this.insert=function(e,t){var n=this.session,r=n.getMode(),i=this.getCursorPosition();if(this.getBehavioursEnabled()&&!t){var s=r.transformAction(n.getState(i.row),"insertion",this,n,e);s&&(e!==s.text&&(this.session.mergeUndoDeltas=!1,this.$mergeNextCommand=!1),e=s.text)}e=="	"&&(e=this.session.getTabString());if(!this.selection.isEmpty()){var o=this.getSelectionRange();i=this.session.remove(o),this.clearSelection()}else if(this.session.getOverwrite()){var o=new p.fromPoints(i,i);o.end.column+=e.length,this.session.remove(o)}if(e=="\n"||e=="\r\n"){var u=n.getLine(i.row);if(i.column>u.search(/\S|$/)){var a=u.substr(i.column).search(/\S|$/);n.doc.removeInLine(i.row,i.column,i.column+a)}}this.clearSelection();var f=i.column,l=n.getState(i.row),u=n.getLine(i.row),c=r.checkOutdent(l,u,e),h=n.insert(i,e);s&&s.selection&&(s.selection.length==2?this.selection.setSelectionRange(new p(i.row,f+s.selection[0],i.row,f+s.selection[1])):this.selection.setSelectionRange(new p(i.row+s.selection[0],s.selection[1],i.row+s.selection[2],s.selection[3])));if(n.getDocument().isNewLine(e)){var d=r.getNextLineIndent(l,u.slice(0,i.column),n.getTabString());n.insert({row:i.row+1,column:0},d)}c&&r.autoOutdent(l,n,i.row)},this.onTextInput=function(e){this.keyBinding.onTextInput(e)},this.onCommandKey=function(e,t,n){this.keyBinding.onCommandKey(e,t,n)},this.setOverwrite=function(e){this.session.setOverwrite(e)},this.getOverwrite=function(){return this.session.getOverwrite()},this.toggleOverwrite=function(){this.session.toggleOverwrite()},this.setScrollSpeed=function(e){this.setOption("scrollSpeed",e)},this.getScrollSpeed=function(){return this.getOption("scrollSpeed")},this.setDragDelay=function(e){this.setOption("dragDelay",e)},this.getDragDelay=function(){return this.getOption("dragDelay")},this.setSelectionStyle=function(e){this.setOption("selectionStyle",e)},this.getSelectionStyle=function(){return this.getOption("selectionStyle")},this.setHighlightActiveLine=function(e){this.setOption("highlightActiveLine",e)},this.getHighlightActiveLine=function(){return this.getOption("highlightActiveLine")},this.setHighlightGutterLine=function(e){this.setOption("highlightGutterLine",e)},this.getHighlightGutterLine=function(){return this.getOption("highlightGutterLine")},this.setHighlightSelectedWord=function(e){this.setOption("highlightSelectedWord",e)},this.getHighlightSelectedWord=function(){return this.$highlightSelectedWord},this.setAnimatedScroll=function(e){this.renderer.setAnimatedScroll(e)},this.getAnimatedScroll=function(){return this.renderer.getAnimatedScroll()},this.setShowInvisibles=function(e){this.renderer.setShowInvisibles(e)},this.getShowInvisibles=function(){return this.renderer.getShowInvisibles()},this.setDisplayIndentGuides=function(e){this.renderer.setDisplayIndentGuides(e)},this.getDisplayIndentGuides=function(){return this.renderer.getDisplayIndentGuides()},this.setShowPrintMargin=function(e){this.renderer.setShowPrintMargin(e)},this.getShowPrintMargin=function(){return this.renderer.getShowPrintMargin()},this.setPrintMarginColumn=function(e){this.renderer.setPrintMarginColumn(e)},this.getPrintMarginColumn=function(){return this.renderer.getPrintMarginColumn()},this.setReadOnly=function(e){this.setOption("readOnly",e)},this.getReadOnly=function(){return this.getOption("readOnly")},this.setBehavioursEnabled=function(e){this.setOption("behavioursEnabled",e)},this.getBehavioursEnabled=function(){return this.getOption("behavioursEnabled")},this.setWrapBehavioursEnabled=function(e){this.setOption("wrapBehavioursEnabled",e)},this.getWrapBehavioursEnabled=function(){return this.getOption("wrapBehavioursEnabled")},this.setShowFoldWidgets=function(e){this.setOption("showFoldWidgets",e)},this.getShowFoldWidgets=function(){return this.getOption("showFoldWidgets")},this.setFadeFoldWidgets=function(e){this.setOption("fadeFoldWidgets",e)},this.getFadeFoldWidgets=function(){return this.getOption("fadeFoldWidgets")},this.remove=function(e){this.selection.isEmpty()&&(e=="left"?this.selection.selectLeft():this.selection.selectRight());var t=this.getSelectionRange();if(this.getBehavioursEnabled()){var n=this.session,r=n.getState(t.start.row),i=n.getMode().transformAction(r,"deletion",this,n,t);if(t.end.column===0){var s=n.getTextRange(t);if(s[s.length-1]=="\n"){var o=n.getLine(t.end.row);/^\s+$/.test(o)&&(t.end.column=o.length)}}i&&(t=i)}this.session.remove(t),this.clearSelection()},this.removeWordRight=function(){this.selection.isEmpty()&&this.selection.selectWordRight(),this.session.remove(this.getSelectionRange()),this.clearSelection()},this.removeWordLeft=function(){this.selection.isEmpty()&&this.selection.selectWordLeft(),this.session.remove(this.getSelectionRange()),this.clearSelection()},this.removeToLineStart=function(){this.selection.isEmpty()&&this.selection.selectLineStart(),this.session.remove(this.getSelectionRange()),this.clearSelection()},this.removeToLineEnd=function(){this.selection.isEmpty()&&this.selection.selectLineEnd();var e=this.getSelectionRange();e.start.column==e.end.column&&e.start.row==e.end.row&&(e.end.column=0,e.end.row++),this.session.remove(e),this.clearSelection()},this.splitLine=function(){this.selection.isEmpty()||(this.session.remove(this.getSelectionRange()),this.clearSelection());var e=this.getCursorPosition();this.insert("\n"),this.moveCursorToPosition(e)},this.transposeLetters=function(){if(!this.selection.isEmpty())return;var e=this.getCursorPosition(),t=e.column;if(t===0)return;var n=this.session.getLine(e.row),r,i;t<n.length?(r=n.charAt(t)+n.charAt(t-1),i=new p(e.row,t-1,e.row,t+1)):(r=n.charAt(t-1)+n.charAt(t-2),i=new p(e.row,t-2,e.row,t)),this.session.replace(i,r)},this.toLowerCase=function(){var e=this.getSelectionRange();this.selection.isEmpty()&&this.selection.selectWord();var t=this.getSelectionRange(),n=this.session.getTextRange(t);this.session.replace(t,n.toLowerCase()),this.selection.setSelectionRange(e)},this.toUpperCase=function(){var e=this.getSelectionRange();this.selection.isEmpty()&&this.selection.selectWord();var t=this.getSelectionRange(),n=this.session.getTextRange(t);this.session.replace(t,n.toUpperCase()),this.selection.setSelectionRange(e)},this.indent=function(){var e=this.session,t=this.getSelectionRange();if(t.start.row<t.end.row){var n=this.$getSelectedRows();e.indentRows(n.first,n.last,"	");return}if(t.start.column<t.end.column){var r=e.getTextRange(t);if(!/^\s+$/.test(r)){var n=this.$getSelectedRows();e.indentRows(n.first,n.last,"	");return}}var i=e.getLine(t.start.row),o=t.start,u=e.getTabSize(),a=e.documentToScreenColumn(o.row,o.column);if(this.session.getUseSoftTabs())var f=u-a%u,l=s.stringRepeat(" ",f);else{var f=a%u;while(i[t.start.column]==" "&&f)t.start.column--,f--;this.selection.setSelectionRange(t),l="	"}return this.insert(l)},this.blockIndent=function(){var e=this.$getSelectedRows();this.session.indentRows(e.first,e.last,"	")},this.blockOutdent=function(){var e=this.session.getSelection();this.session.outdentRows(e.getRange())},this.sortLines=function(){var e=this.$getSelectedRows(),t=this.session,n=[];for(i=e.first;i<=e.last;i++)n.push(t.getLine(i));n.sort(function(e,t){return e.toLowerCase()<t.toLowerCase()?-1:e.toLowerCase()>t.toLowerCase()?1:0});var r=new p(0,0,0,0);for(var i=e.first;i<=e.last;i++){var s=t.getLine(i);r.start.row=i,r.end.row=i,r.end.column=s.length,t.replace(r,n[i-e.first])}},this.toggleCommentLines=function(){var e=this.session.getState(this.getCursorPosition().row),t=this.$getSelectedRows();this.session.getMode().toggleCommentLines(e,this.session,t.first,t.last)},this.toggleBlockComment=function(){var e=this.getCursorPosition(),t=this.session.getState(e.row),n=this.getSelectionRange();this.session.getMode().toggleBlockComment(t,this.session,n,e)},this.getNumberAt=function(e,t){var n=/[\-]?[0-9]+(?:\.[0-9]+)?/g;n.lastIndex=0;var r=this.session.getLine(e);while(n.lastIndex<t){var i=n.exec(r);if(i.index<=t&&i.index+i[0].length>=t){var s={value:i[0],start:i.index,end:i.index+i[0].length};return s}}return null},this.modifyNumber=function(e){var t=this.selection.getCursor().row,n=this.selection.getCursor().column,r=new p(t,n-1,t,n),i=this.session.getTextRange(r);if(!isNaN(parseFloat(i))&&isFinite(i)){var s=this.getNumberAt(t,n);if(s){var o=s.value.indexOf(".")>=0?s.start+s.value.indexOf(".")+1:s.end,u=s.start+s.value.length-o,a=parseFloat(s.value);a*=Math.pow(10,u),o!==s.end&&n<o?e*=Math.pow(10,s.end-n-1):e*=Math.pow(10,s.end-n),a+=e,a/=Math.pow(10,u);var f=a.toFixed(u),l=new p(t,s.start,t,s.end);this.session.replace(l,f),this.moveCursorTo(t,Math.max(s.start+1,n+f.length-s.value.length))}}},this.removeLines=function(){var e=this.$getSelectedRows();this.session.removeFullLines(e.first,e.last),this.clearSelection()},this.duplicateSelection=function(){var e=this.selection,t=this.session,n=e.getRange(),r=e.isBackwards();if(n.isEmpty()){var i=n.start.row;t.duplicateLines(i,i)}else{var s=r?n.start:n.end,o=t.insert(s,t.getTextRange(n),!1);n.start=s,n.end=o,e.setSelectionRange(n,r)}},this.moveLinesDown=function(){this.$moveLines(1,!1)},this.moveLinesUp=function(){this.$moveLines(-1,!1)},this.moveText=function(e,t,n){return this.session.moveText(e,t,n)},this.copyLinesUp=function(){this.$moveLines(-1,!0)},this.copyLinesDown=function(){this.$moveLines(1,!0)},this.$moveLines=function(e,t){var n,r,i=this.selection;if(!i.inMultiSelectMode||this.inVirtualSelectionMode){var s=i.toOrientedRange();n=this.$getSelectedRows(s),r=this.session.$moveLines(n.first,n.last,t?0:e),t&&e==-1&&(r=0),s.moveBy(r,0),i.fromOrientedRange(s)}else{var o=i.rangeList.ranges;i.rangeList.detach(this.session),this.inVirtualSelectionMode=!0;var u=0,a=0,f=o.length;for(var l=0;l<f;l++){var c=l;o[l].moveBy(u,0),n=this.$getSelectedRows(o[l]);var h=n.first,p=n.last;while(++l<f){a&&o[l].moveBy(a,0);var d=this.$getSelectedRows(o[l]);if(t&&d.first!=p)break;if(!t&&d.first>p+1)break;p=d.last}l--,u=this.session.$moveLines(h,p,t?0:e),t&&e==-1&&(c=l+1);while(c<=l)o[c].moveBy(u,0),c++;t||(u=0),a+=u}i.fromOrientedRange(i.ranges[0]),i.rangeList.attach(this.session),this.inVirtualSelectionMode=!1}},this.$getSelectedRows=function(e){return e=(e||this.getSelectionRange()).collapseRows(),{first:this.session.getRowFoldStart(e.start.row),last:this.session.getRowFoldEnd(e.end.row)}},this.onCompositionStart=function(e){this.renderer.showComposition(this.getCursorPosition())},this.onCompositionUpdate=function(e){this.renderer.setCompositionText(e)},this.onCompositionEnd=function(){this.renderer.hideComposition()},this.getFirstVisibleRow=function(){return this.renderer.getFirstVisibleRow()},this.getLastVisibleRow=function(){return this.renderer.getLastVisibleRow()},this.isRowVisible=function(e){return e>=this.getFirstVisibleRow()&&e<=this.getLastVisibleRow()},this.isRowFullyVisible=function(e){return e>=this.renderer.getFirstFullyVisibleRow()&&e<=this.renderer.getLastFullyVisibleRow()},this.$getVisibleRowCount=function(){return this.renderer.getScrollBottomRow()-this.renderer.getScrollTopRow()+1},this.$moveByPage=function(e,t){var n=this.renderer,r=this.renderer.layerConfig,i=e*Math.floor(r.height/r.lineHeight);this.$blockScrolling++,t===!0?this.selection.$moveSelection(function(){this.moveCursorBy(i,0)}):t===!1&&(this.selection.moveCursorBy(i,0),this.selection.clearSelection()),this.$blockScrolling--;var s=n.scrollTop;n.scrollBy(0,i*r.lineHeight),t!=null&&n.scrollCursorIntoView(null,.5),n.animateScrolling(s)},this.selectPageDown=function(){this.$moveByPage(1,!0)},this.selectPageUp=function(){this.$moveByPage(-1,!0)},this.gotoPageDown=function(){this.$moveByPage(1,!1)},this.gotoPageUp=function(){this.$moveByPage(-1,!1)},this.scrollPageDown=function(){this.$moveByPage(1)},this.scrollPageUp=function(){this.$moveByPage(-1)},this.scrollToRow=function(e){this.renderer.scrollToRow(e)},this.scrollToLine=function(e,t,n,r){this.renderer.scrollToLine(e,t,n,r)},this.centerSelection=function(){var e=this.getSelectionRange(),t={row:Math.floor(e.start.row+(e.end.row-e.start.row)/2),column:Math.floor(e.start.column+(e.end.column-e.start.column)/2)};this.renderer.alignCursor(t,.5)},this.getCursorPosition=function(){return this.selection.getCursor()},this.getCursorPositionScreen=function(){return this.session.documentToScreenPosition(this.getCursorPosition())},this.getSelectionRange=function(){return this.selection.getRange()},this.selectAll=function(){this.$blockScrolling+=1,this.selection.selectAll(),this.$blockScrolling-=1},this.clearSelection=function(){this.selection.clearSelection()},this.moveCursorTo=function(e,t){this.selection.moveCursorTo(e,t)},this.moveCursorToPosition=function(e){this.selection.moveCursorToPosition(e)},this.jumpToMatching=function(e,t){var n=this.getCursorPosition(),r=new y(this.session,n.row,n.column),i=r.getCurrentToken(),s=i||r.stepForward();if(!s)return;var o,u=!1,a={},f=n.column-s.start,l,c={")":"(","(":"(","]":"[","[":"[","{":"{","}":"{"};do{if(s.value.match(/[{}()\[\]]/g))for(;f<s.value.length&&!u;f++){if(!c[s.value[f]])continue;l=c[s.value[f]]+"."+s.type.replace("rparen","lparen"),isNaN(a[l])&&(a[l]=0);switch(s.value[f]){case"(":case"[":case"{":a[l]++;break;case")":case"]":case"}":a[l]--,a[l]===-1&&(o="bracket",u=!0)}}else s&&s.type.indexOf("tag-name")!==-1&&(isNaN(a[s.value])&&(a[s.value]=0),i.value==="<"?a[s.value]++:i.value==="</"&&a[s.value]--,a[s.value]===-1&&(o="tag",u=!0));u||(i=s,s=r.stepForward(),f=0)}while(s&&!u);if(!o)return;var h,d;if(o==="bracket"){h=this.session.getBracketRange(n);if(!h){h=new p(r.getCurrentTokenRow(),r.getCurrentTokenColumn()+f-1,r.getCurrentTokenRow(),r.getCurrentTokenColumn()+f-1),d=h.start;if(t||d.row===n.row&&Math.abs(d.column-n.column)<2)h=this.session.getBracketRange(d)}}else if(o==="tag"){if(!s||s.type.indexOf("tag-name")===-1)return;var v=s.value;h=new p(r.getCurrentTokenRow(),r.getCurrentTokenColumn()-2,r.getCurrentTokenRow(),r.getCurrentTokenColumn()-2);if(h.compare(n.row,n.column)===0){u=!1;do s=i,i=r.stepBackward(),i&&(i.type.indexOf("tag-close")!==-1&&h.setEnd(r.getCurrentTokenRow(),r.getCurrentTokenColumn()+1),s.value===v&&s.type.indexOf("tag-name")!==-1&&(i.value==="<"?a[v]++:i.value==="</"&&a[v]--,a[v]===0&&(u=!0)));while(i&&!u)}s&&s.type.indexOf("tag-name")&&(d=h.start,d.row==n.row&&Math.abs(d.column-n.column)<2&&(d=h.end))}d=h&&h.cursor||d,d&&(e?h&&t?this.selection.setRange(h):h&&h.isEqual(this.getSelectionRange())?this.clearSelection():this.selection.selectTo(d.row,d.column):this.selection.moveTo(d.row,d.column))},this.gotoLine=function(e,t,n){this.selection.clearSelection(),this.session.unfold({row:e-1,column:t||0}),this.$blockScrolling+=1,this.exitMultiSelectMode&&this.exitMultiSelectMode(),this.moveCursorTo(e-1,t||0),this.$blockScrolling-=1,this.isRowFullyVisible(e-1)||this.scrollToLine(e-1,!0,n)},this.navigateTo=function(e,t){this.selection.moveTo(e,t)},this.navigateUp=function(e){if(this.selection.isMultiLine()&&!this.selection.isBackwards()){var t=this.selection.anchor.getPosition();return this.moveCursorToPosition(t)}this.selection.clearSelection(),this.selection.moveCursorBy(-e||-1,0)},this.navigateDown=function(e){if(this.selection.isMultiLine()&&this.selection.isBackwards()){var t=this.selection.anchor.getPosition();return this.moveCursorToPosition(t)}this.selection.clearSelection(),this.selection.moveCursorBy(e||1,0)},this.navigateLeft=function(e){if(!this.selection.isEmpty()){var t=this.getSelectionRange().start;this.moveCursorToPosition(t)}else{e=e||1;while(e--)this.selection.moveCursorLeft()}this.clearSelection()},this.navigateRight=function(e){if(!this.selection.isEmpty()){var t=this.getSelectionRange().end;this.moveCursorToPosition(t)}else{e=e||1;while(e--)this.selection.moveCursorRight()}this.clearSelection()},this.navigateLineStart=function(){this.selection.moveCursorLineStart(),this.clearSelection()},this.navigateLineEnd=function(){this.selection.moveCursorLineEnd(),this.clearSelection()},this.navigateFileEnd=function(){this.selection.moveCursorFileEnd(),this.clearSelection()},this.navigateFileStart=function(){this.selection.moveCursorFileStart(),this.clearSelection()},this.navigateWordRight=function(){this.selection.moveCursorWordRight(),this.clearSelection()},this.navigateWordLeft=function(){this.selection.moveCursorWordLeft(),this.clearSelection()},this.replace=function(e,t){t&&this.$search.set(t);var n=this.$search.find(this.session),r=0;return n?(this.$tryReplace(n,e)&&(r=1),n!==null&&(this.selection.setSelectionRange(n),this.renderer.scrollSelectionIntoView(n.start,n.end)),r):r},this.replaceAll=function(e,t){t&&this.$search.set(t);var n=this.$search.findAll(this.session),r=0;if(!n.length)return r;this.$blockScrolling+=1;var i=this.getSelectionRange();this.selection.moveTo(0,0);for(var s=n.length-1;s>=0;--s)this.$tryReplace(n[s],e)&&r++;return this.selection.setSelectionRange(i),this.$blockScrolling-=1,r},this.$tryReplace=function(e,t){var n=this.session.getTextRange(e);return t=this.$search.replace(n,t),t!==null?(e.end=this.session.replace(e,t),e):null},this.getLastSearchOptions=function(){return this.$search.getOptions()},this.find=function(e,t,n){t||(t={}),typeof e=="string"||e instanceof RegExp?t.needle=e:typeof e=="object"&&r.mixin(t,e);var i=this.selection.getRange();t.needle==null&&(e=this.session.getTextRange(i)||this.$search.$options.needle,e||(i=this.session.getWordRange(i.start.row,i.start.column),e=this.session.getTextRange(i)),this.$search.set({needle:e})),this.$search.set(t),t.start||this.$search.set({start:i});var s=this.$search.find(this.session);if(t.preventScroll)return s;if(s)return this.revealRange(s,n),s;t.backwards?i.start=i.end:i.end=i.start,this.selection.setRange(i)},this.findNext=function(e,t){this.find({skipCurrent:!0,backwards:!1},e,t)},this.findPrevious=function(e,t){this.find(e,{skipCurrent:!0,backwards:!0},t)},this.revealRange=function(e,t){this.$blockScrolling+=1,this.session.unfold(e),this.selection.setSelectionRange(e),this.$blockScrolling-=1;var n=this.renderer.scrollTop;this.renderer.scrollSelectionIntoView(e.start,e.end,.5),t!==!1&&this.renderer.animateScrolling(n)},this.undo=function(){this.$blockScrolling++,this.session.getUndoManager().undo(),this.$blockScrolling--,this.renderer.scrollCursorIntoView(null,.5)},this.redo=function(){this.$blockScrolling++,this.session.getUndoManager().redo(),this.$blockScrolling--,this.renderer.scrollCursorIntoView(null,.5)},this.destroy=function(){this.renderer.destroy(),this._signal("destroy",this),this.session&&this.session.destroy()},this.setAutoScrollEditorIntoView=function(e){if(!e)return;var t,n=this,r=!1;this.$scrollAnchor||(this.$scrollAnchor=document.createElement("div"));var i=this.$scrollAnchor;i.style.cssText="position:absolute",this.container.insertBefore(i,this.container.firstChild);var s=this.on("changeSelection",function(){r=!0}),o=this.renderer.on("beforeRender",function(){r&&(t=n.renderer.container.getBoundingClientRect())}),u=this.renderer.on("afterRender",function(){if(r&&t&&(n.isFocused()||n.searchBox&&n.searchBox.isFocused())){var e=n.renderer,s=e.$cursorLayer.$pixelPos,o=e.layerConfig,u=s.top-o.offset;s.top>=0&&u+t.top<0?r=!0:s.top<o.height&&s.top+t.top+o.lineHeight>window.innerHeight?r=!1:r=null,r!=null&&(i.style.top=u+"px",i.style.left=s.left+"px",i.style.height=o.lineHeight+"px",i.scrollIntoView(r)),r=t=null}});this.setAutoScrollEditorIntoView=function(e){if(e)return;delete this.setAutoScrollEditorIntoView,this.off("changeSelection",s),this.renderer.off("afterRender",u),this.renderer.off("beforeRender",o)}},this.$resetCursorStyle=function(){var e=this.$cursorStyle||"ace",t=this.renderer.$cursorLayer;if(!t)return;t.setSmoothBlinking(/smooth/.test(e)),t.isBlinking=!this.$readOnly&&e!="wide",i.setCssClass(t.element,"ace_slim-cursors",/slim/.test(e))}}).call(b.prototype),g.defineOptions(b.prototype,"editor",{selectionStyle:{set:function(e){this.onSelectionChange(),this._signal("changeSelectionStyle",{data:e})},initialValue:"line"},highlightActiveLine:{set:function(){this.$updateHighlightActiveLine()},initialValue:!0},highlightSelectedWord:{set:function(e){this.$onSelectionChange()},initialValue:!0},readOnly:{set:function(e){this.$resetCursorStyle()},initialValue:!1},cursorStyle:{set:function(e){this.$resetCursorStyle()},values:["ace","slim","smooth","wide"],initialValue:"ace"},mergeUndoDeltas:{values:[!1,!0,"always"],initialValue:!0},behavioursEnabled:{initialValue:!0},wrapBehavioursEnabled:{initialValue:!0},autoScrollEditorIntoView:{set:function(e){this.setAutoScrollEditorIntoView(e)}},keyboardHandler:{set:function(e){this.setKeyboardHandler(e)},get:function(){return this.keybindingId},handlesSet:!0},hScrollBarAlwaysVisible:"renderer",vScrollBarAlwaysVisible:"renderer",highlightGutterLine:"renderer",animatedScroll:"renderer",showInvisibles:"renderer",showPrintMargin:"renderer",printMarginColumn:"renderer",printMargin:"renderer",fadeFoldWidgets:"renderer",showFoldWidgets:"renderer",showLineNumbers:"renderer",showGutter:"renderer",displayIndentGuides:"renderer",fontSize:"renderer",fontFamily:"renderer",maxLines:"renderer",minLines:"renderer",scrollPastEnd:"renderer",fixedWidthGutter:"renderer",theme:"renderer",scrollSpeed:"$mouseHandler",dragDelay:"$mouseHandler",dragEnabled:"$mouseHandler",focusTimout:"$mouseHandler",tooltipFollowsMouse:"$mouseHandler",firstLineNumber:"session",overwrite:"session",newLineMode:"session",useWorker:"session",useSoftTabs:"session",tabSize:"session",wrap:"session",indentedSoftWrap:"session",foldStyle:"session",mode:"session"}),t.Editor=b}),define("ace/undomanager",["require","exports","module"],function(e,t,n){"use strict";var r=function(){this.reset()};(function(){function e(e){return{action:e.action,start:e.start,end:e.end,lines:e.lines.length==1?null:e.lines,text:e.lines.length==1?e.lines[0]:null}}function t(e){return{action:e.action,start:e.start,end:e.end,lines:e.lines||[e.text]}}function n(e,t){var n=new Array(e.length);for(var r=0;r<e.length;r++){var i=e[r],s={group:i.group,deltas:new Array(i.length)};for(var o=0;o<i.deltas.length;o++){var u=i.deltas[o];s.deltas[o]=t(u)}n[r]=s}return n}this.execute=function(e){var t=e.args[0];this.$doc=e.args[1],e.merge&&this.hasUndo()&&(this.dirtyCounter--,t=this.$undoStack.pop().concat(t)),this.$undoStack.push(t),this.$redoStack=[],this.dirtyCounter<0&&(this.dirtyCounter=NaN),this.dirtyCounter++},this.undo=function(e){var t=this.$undoStack.pop(),n=null;return t&&(n=this.$doc.undoChanges(t,e),this.$redoStack.push(t),this.dirtyCounter--),n},this.redo=function(e){var t=this.$redoStack.pop(),n=null;return t&&(n=this.$doc.redoChanges(this.$deserializeDeltas(t),e),this.$undoStack.push(t),this.dirtyCounter++),n},this.reset=function(){this.$undoStack=[],this.$redoStack=[],this.dirtyCounter=0},this.hasUndo=function(){return this.$undoStack.length>0},this.hasRedo=function(){return this.$redoStack.length>0},this.markClean=function(){this.dirtyCounter=0},this.isClean=function(){return this.dirtyCounter===0},this.$serializeDeltas=function(t){return n(t,e)},this.$deserializeDeltas=function(e){return n(e,t)}}).call(r.prototype),t.UndoManager=r}),define("ace/layer/gutter",["require","exports","module","ace/lib/dom","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("../lib/dom"),i=e("../lib/oop"),s=e("../lib/lang"),o=e("../lib/event_emitter").EventEmitter,u=function(e){this.element=r.createElement("div"),this.element.className="ace_layer ace_gutter-layer",e.appendChild(this.element),this.setShowFoldWidgets(this.$showFoldWidgets),this.gutterWidth=0,this.$annotations=[],this.$updateAnnotations=this.$updateAnnotations.bind(this),this.$cells=[]};(function(){i.implement(this,o),this.setSession=function(e){this.session&&this.session.removeEventListener("change",this.$updateAnnotations),this.session=e,e&&e.on("change",this.$updateAnnotations)},this.addGutterDecoration=function(e,t){window.console&&console.warn&&console.warn("deprecated use session.addGutterDecoration"),this.session.addGutterDecoration(e,t)},this.removeGutterDecoration=function(e,t){window.console&&console.warn&&console.warn("deprecated use session.removeGutterDecoration"),this.session.removeGutterDecoration(e,t)},this.setAnnotations=function(e){this.$annotations=[];for(var t=0;t<e.length;t++){var n=e[t],r=n.row,i=this.$annotations[r];i||(i=this.$annotations[r]={text:[]});var o=n.text;o=o?s.escapeHTML(o):n.html||"",i.text.indexOf(o)===-1&&i.text.push(o);var u=n.type;u=="error"?i.className=" ace_error":u=="warning"&&i.className!=" ace_error"?i.className=" ace_warning":u=="info"&&!i.className&&(i.className=" ace_info")}},this.$updateAnnotations=function(e){if(!this.$annotations.length)return;var t=e.start.row,n=e.end.row-t;if(n!==0)if(e.action=="remove")this.$annotations.splice(t,n+1,null);else{var r=new Array(n+1);r.unshift(t,1),this.$annotations.splice.apply(this.$annotations,r)}},this.update=function(e){var t=this.session,n=e.firstRow,i=Math.min(e.lastRow+e.gutterOffset,t.getLength()-1),s=t.getNextFoldLine(n),o=s?s.start.row:Infinity,u=this.$showFoldWidgets&&t.foldWidgets,a=t.$breakpoints,f=t.$decorations,l=t.$firstLineNumber,c=0,h=t.gutterRenderer||this.$renderer,p=null,d=-1,v=n;for(;;){v>o&&(v=s.end.row+1,s=t.getNextFoldLine(v,s),o=s?s.start.row:Infinity);if(v>i){while(this.$cells.length>d+1)p=this.$cells.pop(),this.element.removeChild(p.element);break}p=this.$cells[++d],p||(p={element:null,textNode:null,foldWidget:null},p.element=r.createElement("div"),p.textNode=document.createTextNode(""),p.element.appendChild(p.textNode),this.element.appendChild(p.element),this.$cells[d]=p);var m="ace_gutter-cell ";a[v]&&(m+=a[v]),f[v]&&(m+=f[v]),this.$annotations[v]&&(m+=this.$annotations[v].className),p.element.className!=m&&(p.element.className=m);var g=t.getRowLength(v)*e.lineHeight+"px";g!=p.element.style.height&&(p.element.style.height=g);if(u){var y=u[v];y==null&&(y=u[v]=t.getFoldWidget(v))}if(y){p.foldWidget||(p.foldWidget=r.createElement("span"),p.element.appendChild(p.foldWidget));var m="ace_fold-widget ace_"+y;y=="start"&&v==o&&v<s.end.row?m+=" ace_closed":m+=" ace_open",p.foldWidget.className!=m&&(p.foldWidget.className=m);var g=e.lineHeight+"px";p.foldWidget.style.height!=g&&(p.foldWidget.style.height=g)}else p.foldWidget&&(p.element.removeChild(p.foldWidget),p.foldWidget=null);var b=c=h?h.getText(t,v):v+l;b!=p.textNode.data&&(p.textNode.data=b),v++}this.element.style.height=e.minHeight+"px";if(this.$fixedWidth||t.$useWrapMode)c=t.getLength()+l;var w=h?h.getWidth(t,c,e):c.toString().length*e.characterWidth,E=this.$padding||this.$computePadding();w+=E.left+E.right,w!==this.gutterWidth&&!isNaN(w)&&(this.gutterWidth=w,this.element.style.width=Math.ceil(this.gutterWidth)+"px",this._emit("changeGutterWidth",w))},this.$fixedWidth=!1,this.$showLineNumbers=!0,this.$renderer="",this.setShowLineNumbers=function(e){this.$renderer=!e&&{getWidth:function(){return""},getText:function(){return""}}},this.getShowLineNumbers=function(){return this.$showLineNumbers},this.$showFoldWidgets=!0,this.setShowFoldWidgets=function(e){e?r.addCssClass(this.element,"ace_folding-enabled"):r.removeCssClass(this.element,"ace_folding-enabled"),this.$showFoldWidgets=e,this.$padding=null},this.getShowFoldWidgets=function(){return this.$showFoldWidgets},this.$computePadding=function(){if(!this.element.firstChild)return{left:0,right:0};var e=r.computedStyle(this.element.firstChild);return this.$padding={},this.$padding.left=parseInt(e.paddingLeft)+1||0,this.$padding.right=parseInt(e.paddingRight)||0,this.$padding},this.getRegion=function(e){var t=this.$padding||this.$computePadding(),n=this.element.getBoundingClientRect();if(e.x<t.left+n.left)return"markers";if(this.$showFoldWidgets&&e.x>n.right-t.right)return"foldWidgets"}}).call(u.prototype),t.Gutter=u}),define("ace/layer/marker",["require","exports","module","ace/range","ace/lib/dom"],function(e,t,n){"use strict";var r=e("../range").Range,i=e("../lib/dom"),s=function(e){this.element=i.createElement("div"),this.element.className="ace_layer ace_marker-layer",e.appendChild(this.element)};(function(){function e(e,t,n,r){return(e?1:0)|(t?2:0)|(n?4:0)|(r?8:0)}this.$padding=0,this.setPadding=function(e){this.$padding=e},this.setSession=function(e){this.session=e},this.setMarkers=function(e){this.markers=e},this.update=function(e){var e=e||this.config;if(!e)return;this.config=e;var t=[];for(var n in this.markers){var r=this.markers[n];if(!r.range){r.update(t,this,this.session,e);continue}var i=r.range.clipRows(e.firstRow,e.lastRow);if(i.isEmpty())continue;i=i.toScreenRange(this.session);if(r.renderer){var s=this.$getTop(i.start.row,e),o=this.$padding+i.start.column*e.characterWidth;r.renderer(t,i,o,s,e)}else r.type=="fullLine"?this.drawFullLineMarker(t,i,r.clazz,e):r.type=="screenLine"?this.drawScreenLineMarker(t,i,r.clazz,e):i.isMultiLine()?r.type=="text"?this.drawTextMarker(t,i,r.clazz,e):this.drawMultiLineMarker(t,i,r.clazz,e):this.drawSingleLineMarker(t,i,r.clazz+" ace_start"+" ace_br15",e)}this.element.innerHTML=t.join("")},this.$getTop=function(e,t){return(e-t.firstRowScreen)*t.lineHeight},this.drawTextMarker=function(t,n,i,s,o){var u=this.session,a=n.start.row,f=n.end.row,l=a,c=0,h=0,p=u.getScreenLastRowColumn(l),d=new r(l,n.start.column,l,h);for(;l<=f;l++)d.start.row=d.end.row=l,d.start.column=l==a?n.start.column:u.getRowWrapIndent(l),d.end.column=p,c=h,h=p,p=l+1<f?u.getScreenLastRowColumn(l+1):l==f?0:n.end.column,this.drawSingleLineMarker(t,d,i+(l==a?" ace_start":"")+" ace_br"+e(l==a||l==a+1&&n.start.column,c<h,h>p,l==f),s,l==f?0:1,o)},this.drawMultiLineMarker=function(e,t,n,r,i){var s=this.$padding,o=r.lineHeight,u=this.$getTop(t.start.row,r),a=s+t.start.column*r.characterWidth;i=i||"",e.push("<div class='",n," ace_br1 ace_start' style='","height:",o,"px;","right:0;","top:",u,"px;","left:",a,"px;",i,"'></div>"),u=this.$getTop(t.end.row,r);var f=t.end.column*r.characterWidth;e.push("<div class='",n," ace_br12' style='","height:",o,"px;","width:",f,"px;","top:",u,"px;","left:",s,"px;",i,"'></div>"),o=(t.end.row-t.start.row-1)*r.lineHeight;if(o<=0)return;u=this.$getTop(t.start.row+1,r);var l=(t.start.column?1:0)|(t.end.column?0:8);e.push("<div class='",n,l?" ace_br"+l:"","' style='","height:",o,"px;","right:0;","top:",u,"px;","left:",s,"px;",i,"'></div>")},this.drawSingleLineMarker=function(e,t,n,r,i,s){var o=r.lineHeight,u=(t.end.column+(i||0)-t.start.column)*r.characterWidth,a=this.$getTop(t.start.row,r),f=this.$padding+t.start.column*r.characterWidth;e.push("<div class='",n,"' style='","height:",o,"px;","width:",u,"px;","top:",a,"px;","left:",f,"px;",s||"","'></div>")},this.drawFullLineMarker=function(e,t,n,r,i){var s=this.$getTop(t.start.row,r),o=r.lineHeight;t.start.row!=t.end.row&&(o+=this.$getTop(t.end.row,r)-s),e.push("<div class='",n,"' style='","height:",o,"px;","top:",s,"px;","left:0;right:0;",i||"","'></div>")},this.drawScreenLineMarker=function(e,t,n,r,i){var s=this.$getTop(t.start.row,r),o=r.lineHeight;e.push("<div class='",n,"' style='","height:",o,"px;","top:",s,"px;","left:0;right:0;",i||"","'></div>")}}).call(s.prototype),t.Marker=s}),define("ace/layer/text",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/lib/useragent","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../lib/dom"),s=e("../lib/lang"),o=e("../lib/useragent"),u=e("../lib/event_emitter").EventEmitter,a=function(e){this.element=i.createElement("div"),this.element.className="ace_layer ace_text-layer",e.appendChild(this.element),this.$updateEolChar=this.$updateEolChar.bind(this)};(function(){r.implement(this,u),this.EOF_CHAR="\u00b6",this.EOL_CHAR_LF="\u00ac",this.EOL_CHAR_CRLF="\u00a4",this.EOL_CHAR=this.EOL_CHAR_LF,this.TAB_CHAR="\u2014",this.SPACE_CHAR="\u00b7",this.$padding=0,this.$updateEolChar=function(){var e=this.session.doc.getNewLineCharacter()=="\n"?this.EOL_CHAR_LF:this.EOL_CHAR_CRLF;if(this.EOL_CHAR!=e)return this.EOL_CHAR=e,!0},this.setPadding=function(e){this.$padding=e,this.element.style.padding="0 "+e+"px"},this.getLineHeight=function(){return this.$fontMetrics.$characterSize.height||0},this.getCharacterWidth=function(){return this.$fontMetrics.$characterSize.width||0},this.$setFontMetrics=function(e){this.$fontMetrics=e,this.$fontMetrics.on("changeCharacterSize",function(e){this._signal("changeCharacterSize",e)}.bind(this)),this.$pollSizeChanges()},this.checkForSizeChanges=function(){this.$fontMetrics.checkForSizeChanges()},this.$pollSizeChanges=function(){return this.$pollSizeChangesTimer=this.$fontMetrics.$pollSizeChanges()},this.setSession=function(e){this.session=e,e&&this.$computeTabString()},this.showInvisibles=!1,this.setShowInvisibles=function(e){return this.showInvisibles==e?!1:(this.showInvisibles=e,this.$computeTabString(),!0)},this.displayIndentGuides=!0,this.setDisplayIndentGuides=function(e){return this.displayIndentGuides==e?!1:(this.displayIndentGuides=e,this.$computeTabString(),!0)},this.$tabStrings=[],this.onChangeTabSize=this.$computeTabString=function(){var e=this.session.getTabSize();this.tabSize=e;var t=this.$tabStrings=[0];for(var n=1;n<e+1;n++)this.showInvisibles?t.push("<span class='ace_invisible ace_invisible_tab'>"+s.stringRepeat(this.TAB_CHAR,n)+"</span>"):t.push(s.stringRepeat(" ",n));if(this.displayIndentGuides){this.$indentGuideRe=/\s\S| \t|\t |\s$/;var r="ace_indent-guide",i="",o="";if(this.showInvisibles){r+=" ace_invisible",i=" ace_invisible_space",o=" ace_invisible_tab";var u=s.stringRepeat(this.SPACE_CHAR,this.tabSize),a=s.stringRepeat(this.TAB_CHAR,this.tabSize)}else var u=s.stringRepeat(" ",this.tabSize),a=u;this.$tabStrings[" "]="<span class='"+r+i+"'>"+u+"</span>",this.$tabStrings["	"]="<span class='"+r+o+"'>"+a+"</span>"}},this.updateLines=function(e,t,n){(this.config.lastRow!=e.lastRow||this.config.firstRow!=e.firstRow)&&this.scrollLines(e),this.config=e;var r=Math.max(t,e.firstRow),i=Math.min(n,e.lastRow),s=this.element.childNodes,o=0;for(var u=e.firstRow;u<r;u++){var a=this.session.getFoldLine(u);if(a){if(a.containsRow(r)){r=a.start.row;break}u=a.end.row}o++}var u=r,a=this.session.getNextFoldLine(u),f=a?a.start.row:Infinity;for(;;){u>f&&(u=a.end.row+1,a=this.session.getNextFoldLine(u,a),f=a?a.start.row:Infinity);if(u>i)break;var l=s[o++];if(l){var c=[];this.$renderLine(c,u,!this.$useLineGroups(),u==f?a:!1),l.style.height=e.lineHeight*this.session.getRowLength(u)+"px",l.innerHTML=c.join("")}u++}},this.scrollLines=function(e){var t=this.config;this.config=e;if(!t||t.lastRow<e.firstRow)return this.update(e);if(e.lastRow<t.firstRow)return this.update(e);var n=this.element;if(t.firstRow<e.firstRow)for(var r=this.session.getFoldedRowCount(t.firstRow,e.firstRow-1);r>0;r--)n.removeChild(n.firstChild);if(t.lastRow>e.lastRow)for(var r=this.session.getFoldedRowCount(e.lastRow+1,t.lastRow);r>0;r--)n.removeChild(n.lastChild);if(e.firstRow<t.firstRow){var i=this.$renderLinesFragment(e,e.firstRow,t.firstRow-1);n.firstChild?n.insertBefore(i,n.firstChild):n.appendChild(i)}if(e.lastRow>t.lastRow){var i=this.$renderLinesFragment(e,t.lastRow+1,e.lastRow);n.appendChild(i)}},this.$renderLinesFragment=function(e,t,n){var r=this.element.ownerDocument.createDocumentFragment(),s=t,o=this.session.getNextFoldLine(s),u=o?o.start.row:Infinity;for(;;){s>u&&(s=o.end.row+1,o=this.session.getNextFoldLine(s,o),u=o?o.start.row:Infinity);if(s>n)break;var a=i.createElement("div"),f=[];this.$renderLine(f,s,!1,s==u?o:!1),a.innerHTML=f.join("");if(this.$useLineGroups())a.className="ace_line_group",r.appendChild(a),a.style.height=e.lineHeight*this.session.getRowLength(s)+"px";else while(a.firstChild)r.appendChild(a.firstChild);s++}return r},this.update=function(e){this.config=e;var t=[],n=e.firstRow,r=e.lastRow,i=n,s=this.session.getNextFoldLine(i),o=s?s.start.row:Infinity;for(;;){i>o&&(i=s.end.row+1,s=this.session.getNextFoldLine(i,s),o=s?s.start.row:Infinity);if(i>r)break;this.$useLineGroups()&&t.push("<div class='ace_line_group' style='height:",e.lineHeight*this.session.getRowLength(i),"px'>"),this.$renderLine(t,i,!1,i==o?s:!1),this.$useLineGroups()&&t.push("</div>"),i++}this.element.innerHTML=t.join("")},this.$textToken={text:!0,rparen:!0,lparen:!0},this.$renderToken=function(e,t,n,r){var i=this,o=/\t|&|<|>|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\u3000\uFEFF\uFFF9-\uFFFC])|[\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3000-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]/g,u=function(e,n,r,o,u){if(n)return i.showInvisibles?"<span class='ace_invisible ace_invisible_space'>"+s.stringRepeat(i.SPACE_CHAR,e.length)+"</span>":e;if(e=="&")return"&#38;";if(e=="<")return"&#60;";if(e==">")return"&#62;";if(e=="	"){var a=i.session.getScreenTabSize(t+o);return t+=a-1,i.$tabStrings[a]}if(e=="\u3000"){var f=i.showInvisibles?"ace_cjk ace_invisible ace_invisible_space":"ace_cjk",l=i.showInvisibles?i.SPACE_CHAR:"";return t+=1,"<span class='"+f+"' style='width:"+i.config.characterWidth*2+"px'>"+l+"</span>"}return r?"<span class='ace_invisible ace_invisible_space ace_invalid'>"+i.SPACE_CHAR+"</span>":(t+=1,"<span class='ace_cjk' style='width:"+i.config.characterWidth*2+"px'>"+e+"</span>")},a=r.replace(o,u);if(!this.$textToken[n.type]){var f="ace_"+n.type.replace(/\./g," ace_"),l="";n.type=="fold"&&(l=" style='width:"+n.value.length*this.config.characterWidth+"px;' "),e.push("<span class='",f,"'",l,">",a,"</span>")}else e.push(a);return t+r.length},this.renderIndentGuide=function(e,t,n){var r=t.search(this.$indentGuideRe);return r<=0||r>=n?t:t[0]==" "?(r-=r%this.tabSize,e.push(s.stringRepeat(this.$tabStrings[" "],r/this.tabSize)),t.substr(r)):t[0]=="	"?(e.push(s.stringRepeat(this.$tabStrings["	"],r)),t.substr(r)):t},this.$renderWrappedLine=function(e,t,n,r){var i=0,o=0,u=n[0],a=0;for(var f=0;f<t.length;f++){var l=t[f],c=l.value;if(f==0&&this.displayIndentGuides){i=c.length,c=this.renderIndentGuide(e,c,u);if(!c)continue;i-=c.length}if(i+c.length<u)a=this.$renderToken(e,a,l,c),i+=c.length;else{while(i+c.length>=u)a=this.$renderToken(e,a,l,c.substring(0,u-i)),c=c.substring(u-i),i=u,r||e.push("</div>","<div class='ace_line' style='height:",this.config.lineHeight,"px'>"),e.push(s.stringRepeat("\u00a0",n.indent)),o++,a=0,u=n[o]||Number.MAX_VALUE;c.length!=0&&(i+=c.length,a=this.$renderToken(e,a,l,c))}}},this.$renderSimpleLine=function(e,t){var n=0,r=t[0],i=r.value;this.displayIndentGuides&&(i=this.renderIndentGuide(e,i)),i&&(n=this.$renderToken(e,n,r,i));for(var s=1;s<t.length;s++)r=t[s],i=r.value,n=this.$renderToken(e,n,r,i)},this.$renderLine=function(e,t,n,r){!r&&r!=0&&(r=this.session.getFoldLine(t));if(r)var i=this.$getFoldLineTokens(t,r);else var i=this.session.getTokens(t);n||e.push("<div class='ace_line' style='height:",this.config.lineHeight*(this.$useLineGroups()?1:this.session.getRowLength(t)),"px'>");if(i.length){var s=this.session.getRowSplitData(t);s&&s.length?this.$renderWrappedLine(e,i,s,n):this.$renderSimpleLine(e,i)}this.showInvisibles&&(r&&(t=r.end.row),e.push("<span class='ace_invisible ace_invisible_eol'>",t==this.session.getLength()-1?this.EOF_CHAR:this.EOL_CHAR,"</span>")),n||e.push("</div>")},this.$getFoldLineTokens=function(e,t){function i(e,t,n){var i=0,s=0;while(s+e[i].value.length<t){s+=e[i].value.length,i++;if(i==e.length)return}if(s!=t){var o=e[i].value.substring(t-s);o.length>n-t&&(o=o.substring(0,n-t)),r.push({type:e[i].type,value:o}),s=t+o.length,i+=1}while(s<n&&i<e.length){var o=e[i].value;o.length+s>n?r.push({type:e[i].type,value:o.substring(0,n-s)}):r.push(e[i]),s+=o.length,i+=1}}var n=this.session,r=[],s=n.getTokens(e);return t.walk(function(e,t,o,u,a){e!=null?r.push({type:"fold",value:e}):(a&&(s=n.getTokens(t)),s.length&&i(s,u,o))},t.end.row,this.session.getLine(t.end.row).length),r},this.$useLineGroups=function(){return this.session.getUseWrapMode()},this.destroy=function(){clearInterval(this.$pollSizeChangesTimer),this.$measureNode&&this.$measureNode.parentNode.removeChild(this.$measureNode),delete this.$measureNode}}).call(a.prototype),t.Text=a}),define("ace/layer/cursor",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";var r=e("../lib/dom"),i,s=function(e){this.element=r.createElement("div"),this.element.className="ace_layer ace_cursor-layer",e.appendChild(this.element),i===undefined&&(i=!("opacity"in this.element.style)),this.isVisible=!1,this.isBlinking=!0,this.blinkInterval=1e3,this.smoothBlinking=!1,this.cursors=[],this.cursor=this.addCursor(),r.addCssClass(this.element,"ace_hidden-cursors"),this.$updateCursors=(i?this.$updateVisibility:this.$updateOpacity).bind(this)};(function(){this.$updateVisibility=function(e){var t=this.cursors;for(var n=t.length;n--;)t[n].style.visibility=e?"":"hidden"},this.$updateOpacity=function(e){var t=this.cursors;for(var n=t.length;n--;)t[n].style.opacity=e?"":"0"},this.$padding=0,this.setPadding=function(e){this.$padding=e},this.setSession=function(e){this.session=e},this.setBlinking=function(e){e!=this.isBlinking&&(this.isBlinking=e,this.restartTimer())},this.setBlinkInterval=function(e){e!=this.blinkInterval&&(this.blinkInterval=e,this.restartTimer())},this.setSmoothBlinking=function(e){e!=this.smoothBlinking&&!i&&(this.smoothBlinking=e,r.setCssClass(this.element,"ace_smooth-blinking",e),this.$updateCursors(!0),this.$updateCursors=this.$updateOpacity.bind(this),this.restartTimer())},this.addCursor=function(){var e=r.createElement("div");return e.className="ace_cursor",this.element.appendChild(e),this.cursors.push(e),e},this.removeCursor=function(){if(this.cursors.length>1){var e=this.cursors.pop();return e.parentNode.removeChild(e),e}},this.hideCursor=function(){this.isVisible=!1,r.addCssClass(this.element,"ace_hidden-cursors"),this.restartTimer()},this.showCursor=function(){this.isVisible=!0,r.removeCssClass(this.element,"ace_hidden-cursors"),this.restartTimer()},this.restartTimer=function(){var e=this.$updateCursors;clearInterval(this.intervalId),clearTimeout(this.timeoutId),this.smoothBlinking&&r.removeCssClass(this.element,"ace_smooth-blinking"),e(!0);if(!this.isBlinking||!this.blinkInterval||!this.isVisible)return;this.smoothBlinking&&setTimeout(function(){r.addCssClass(this.element,"ace_smooth-blinking")}.bind(this));var t=function(){this.timeoutId=setTimeout(function(){e(!1)},.6*this.blinkInterval)}.bind(this);this.intervalId=setInterval(function(){e(!0),t()},this.blinkInterval),t()},this.getPixelPosition=function(e,t){if(!this.config||!this.session)return{left:0,top:0};e||(e=this.session.selection.getCursor());var n=this.session.documentToScreenPosition(e),r=this.$padding+n.column*this.config.characterWidth,i=(n.row-(t?this.config.firstRowScreen:0))*this.config.lineHeight;return{left:r,top:i}},this.update=function(e){this.config=e;var t=this.session.$selectionMarkers,n=0,r=0;if(t===undefined||t.length===0)t=[{cursor:null}];for(var n=0,i=t.length;n<i;n++){var s=this.getPixelPosition(t[n].cursor,!0);if((s.top>e.height+e.offset||s.top<0)&&n>1)continue;var o=(this.cursors[r++]||this.addCursor()).style;this.drawCursor?this.drawCursor(o,s,e,t[n],this.session):(o.left=s.left+"px",o.top=s.top+"px",o.width=e.characterWidth+"px",o.height=e.lineHeight+"px")}while(this.cursors.length>r)this.removeCursor();var u=this.session.getOverwrite();this.$setOverwrite(u),this.$pixelPos=s,this.restartTimer()},this.drawCursor=null,this.$setOverwrite=function(e){e!=this.overwrite&&(this.overwrite=e,e?r.addCssClass(this.element,"ace_overwrite-cursors"):r.removeCssClass(this.element,"ace_overwrite-cursors"))},this.destroy=function(){clearInterval(this.intervalId),clearTimeout(this.timeoutId)}}).call(s.prototype),t.Cursor=s}),define("ace/scrollbar",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/event","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/dom"),s=e("./lib/event"),o=e("./lib/event_emitter").EventEmitter,u=function(e){this.element=i.createElement("div"),this.element.className="ace_scrollbar ace_scrollbar"+this.classSuffix,this.inner=i.createElement("div"),this.inner.className="ace_scrollbar-inner",this.element.appendChild(this.inner),e.appendChild(this.element),this.setVisible(!1),this.skipEvent=!1,s.addListener(this.element,"scroll",this.onScroll.bind(this)),s.addListener(this.element,"mousedown",s.preventDefault)};(function(){r.implement(this,o),this.setVisible=function(e){this.element.style.display=e?"":"none",this.isVisible=e}}).call(u.prototype);var a=function(e,t){u.call(this,e),this.scrollTop=0,t.$scrollbarWidth=this.width=i.scrollbarWidth(e.ownerDocument),this.inner.style.width=this.element.style.width=(this.width||15)+5+"px"};r.inherits(a,u),function(){this.classSuffix="-v",this.onScroll=function(){this.skipEvent||(this.scrollTop=this.element.scrollTop,this._emit("scroll",{data:this.scrollTop})),this.skipEvent=!1},this.getWidth=function(){return this.isVisible?this.width:0},this.setHeight=function(e){this.element.style.height=e+"px"},this.setInnerHeight=function(e){this.inner.style.height=e+"px"},this.setScrollHeight=function(e){this.inner.style.height=e+"px"},this.setScrollTop=function(e){this.scrollTop!=e&&(this.skipEvent=!0,this.scrollTop=this.element.scrollTop=e)}}.call(a.prototype);var f=function(e,t){u.call(this,e),this.scrollLeft=0,this.height=t.$scrollbarWidth,this.inner.style.height=this.element.style.height=(this.height||15)+5+"px"};r.inherits(f,u),function(){this.classSuffix="-h",this.onScroll=function(){this.skipEvent||(this.scrollLeft=this.element.scrollLeft,this._emit("scroll",{data:this.scrollLeft})),this.skipEvent=!1},this.getHeight=function(){return this.isVisible?this.height:0},this.setWidth=function(e){this.element.style.width=e+"px"},this.setInnerWidth=function(e){this.inner.style.width=e+"px"},this.setScrollWidth=function(e){this.inner.style.width=e+"px"},this.setScrollLeft=function(e){this.scrollLeft!=e&&(this.skipEvent=!0,this.scrollLeft=this.element.scrollLeft=e)}}.call(f.prototype),t.ScrollBar=a,t.ScrollBarV=a,t.ScrollBarH=f,t.VScrollBar=a,t.HScrollBar=f}),define("ace/renderloop",["require","exports","module","ace/lib/event"],function(e,t,n){"use strict";var r=e("./lib/event"),i=function(e,t){this.onRender=e,this.pending=!1,this.changes=0,this.window=t||window};(function(){this.schedule=function(e){this.changes=this.changes|e;if(!this.pending&&this.changes){this.pending=!0;var t=this;r.nextFrame(function(){t.pending=!1;var e;while(e=t.changes)t.changes=0,t.onRender(e)},this.window)}}}).call(i.prototype),t.RenderLoop=i}),define("ace/layer/font_metrics",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/lib/useragent","ace/lib/event_emitter"],function(e,t,n){var r=e("../lib/oop"),i=e("../lib/dom"),s=e("../lib/lang"),o=e("../lib/useragent"),u=e("../lib/event_emitter").EventEmitter,a=0,f=t.FontMetrics=function(e){this.el=i.createElement("div"),this.$setMeasureNodeStyles(this.el.style,!0),this.$main=i.createElement("div"),this.$setMeasureNodeStyles(this.$main.style),this.$measureNode=i.createElement("div"),this.$setMeasureNodeStyles(this.$measureNode.style),this.el.appendChild(this.$main),this.el.appendChild(this.$measureNode),e.appendChild(this.el),a||this.$testFractionalRect(),this.$measureNode.innerHTML=s.stringRepeat("X",a),this.$characterSize={width:0,height:0},this.checkForSizeChanges()};(function(){r.implement(this,u),this.$characterSize={width:0,height:0},this.$testFractionalRect=function(){var e=i.createElement("div");this.$setMeasureNodeStyles(e.style),e.style.width="0.2px",document.documentElement.appendChild(e);var t=e.getBoundingClientRect().width;t>0&&t<1?a=50:a=100,e.parentNode.removeChild(e)},this.$setMeasureNodeStyles=function(e,t){e.width=e.height="auto",e.left=e.top="0px",e.visibility="hidden",e.position="absolute",e.whiteSpace="pre",o.isIE<8?e["font-family"]="inherit":e.font="inherit",e.overflow=t?"hidden":"visible"},this.checkForSizeChanges=function(){var e=this.$measureSizes();if(e&&(this.$characterSize.width!==e.width||this.$characterSize.height!==e.height)){this.$measureNode.style.fontWeight="bold";var t=this.$measureSizes();this.$measureNode.style.fontWeight="",this.$characterSize=e,this.charSizes=Object.create(null),this.allowBoldFonts=t&&t.width===e.width&&t.height===e.height,this._emit("changeCharacterSize",{data:e})}},this.$pollSizeChanges=function(){if(this.$pollSizeChangesTimer)return this.$pollSizeChangesTimer;var e=this;return this.$pollSizeChangesTimer=setInterval(function(){e.checkForSizeChanges()},500)},this.setPolling=function(e){e?this.$pollSizeChanges():this.$pollSizeChangesTimer&&(clearInterval(this.$pollSizeChangesTimer),this.$pollSizeChangesTimer=0)},this.$measureSizes=function(){if(a===50){var e=null;try{e=this.$measureNode.getBoundingClientRect()}catch(t){e={width:0,height:0}}var n={height:e.height,width:e.width/a}}else var n={height:this.$measureNode.clientHeight,width:this.$measureNode.clientWidth/a};return n.width===0||n.height===0?null:n},this.$measureCharWidth=function(e){this.$main.innerHTML=s.stringRepeat(e,a);var t=this.$main.getBoundingClientRect();return t.width/a},this.getCharacterWidth=function(e){var t=this.charSizes[e];return t===undefined&&(t=this.charSizes[e]=this.$measureCharWidth(e)/this.$characterSize.width),t},this.destroy=function(){clearInterval(this.$pollSizeChangesTimer),this.el&&this.el.parentNode&&this.el.parentNode.removeChild(this.el)}}).call(f.prototype)}),define("ace/virtual_renderer",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/config","ace/lib/useragent","ace/layer/gutter","ace/layer/marker","ace/layer/text","ace/layer/cursor","ace/scrollbar","ace/scrollbar","ace/renderloop","ace/layer/font_metrics","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/dom"),s=e("./config"),o=e("./lib/useragent"),u=e("./layer/gutter").Gutter,a=e("./layer/marker").Marker,f=e("./layer/text").Text,l=e("./layer/cursor").Cursor,c=e("./scrollbar").HScrollBar,h=e("./scrollbar").VScrollBar,p=e("./renderloop").RenderLoop,d=e("./layer/font_metrics").FontMetrics,v=e("./lib/event_emitter").EventEmitter,m='.ace_editor {position: relative;overflow: hidden;font: 12px/normal \'Monaco\', \'Menlo\', \'Ubuntu Mono\', \'Consolas\', \'source-code-pro\', monospace;direction: ltr;}.ace_scroller {position: absolute;overflow: hidden;top: 0;bottom: 0;background-color: inherit;-ms-user-select: none;-moz-user-select: none;-webkit-user-select: none;user-select: none;cursor: text;}.ace_content {position: absolute;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;min-width: 100%;}.ace_dragging .ace_scroller:before{position: absolute;top: 0;left: 0;right: 0;bottom: 0;content: \'\';background: rgba(250, 250, 250, 0.01);z-index: 1000;}.ace_dragging.ace_dark .ace_scroller:before{background: rgba(0, 0, 0, 0.01);}.ace_selecting, .ace_selecting * {cursor: text !important;}.ace_gutter {position: absolute;overflow : hidden;width: auto;top: 0;bottom: 0;left: 0;cursor: default;z-index: 4;-ms-user-select: none;-moz-user-select: none;-webkit-user-select: none;user-select: none;}.ace_gutter-active-line {position: absolute;left: 0;right: 0;}.ace_scroller.ace_scroll-left {box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset;}.ace_gutter-cell {padding-left: 19px;padding-right: 6px;background-repeat: no-repeat;}.ace_gutter-cell.ace_error {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABOFBMVEX/////////QRswFAb/Ui4wFAYwFAYwFAaWGAfDRymzOSH/PxswFAb/SiUwFAYwFAbUPRvjQiDllog5HhHdRybsTi3/Tyv9Tir+Syj/UC3////XurebMBIwFAb/RSHbPx/gUzfdwL3kzMivKBAwFAbbvbnhPx66NhowFAYwFAaZJg8wFAaxKBDZurf/RB6mMxb/SCMwFAYwFAbxQB3+RB4wFAb/Qhy4Oh+4QifbNRcwFAYwFAYwFAb/QRzdNhgwFAYwFAbav7v/Uy7oaE68MBK5LxLewr/r2NXewLswFAaxJw4wFAbkPRy2PyYwFAaxKhLm1tMwFAazPiQwFAaUGAb/QBrfOx3bvrv/VC/maE4wFAbRPBq6MRO8Qynew8Dp2tjfwb0wFAbx6eju5+by6uns4uH9/f36+vr/GkHjAAAAYnRSTlMAGt+64rnWu/bo8eAA4InH3+DwoN7j4eLi4xP99Nfg4+b+/u9B/eDs1MD1mO7+4PHg2MXa347g7vDizMLN4eG+Pv7i5evs/v79yu7S3/DV7/498Yv24eH+4ufQ3Ozu/v7+y13sRqwAAADLSURBVHjaZc/XDsFgGIBhtDrshlitmk2IrbHFqL2pvXf/+78DPokj7+Fz9qpU/9UXJIlhmPaTaQ6QPaz0mm+5gwkgovcV6GZzd5JtCQwgsxoHOvJO15kleRLAnMgHFIESUEPmawB9ngmelTtipwwfASilxOLyiV5UVUyVAfbG0cCPHig+GBkzAENHS0AstVF6bacZIOzgLmxsHbt2OecNgJC83JERmePUYq8ARGkJx6XtFsdddBQgZE2nPR6CICZhawjA4Fb/chv+399kfR+MMMDGOQAAAABJRU5ErkJggg==");background-repeat: no-repeat;background-position: 2px center;}.ace_gutter-cell.ace_warning {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAmVBMVEX///8AAAD///8AAAAAAABPSzb/5sAAAAB/blH/73z/ulkAAAAAAAD85pkAAAAAAAACAgP/vGz/rkDerGbGrV7/pkQICAf////e0IsAAAD/oED/qTvhrnUAAAD/yHD/njcAAADuv2r/nz//oTj/p064oGf/zHAAAAA9Nir/tFIAAAD/tlTiuWf/tkIAAACynXEAAAAAAAAtIRW7zBpBAAAAM3RSTlMAABR1m7RXO8Ln31Z36zT+neXe5OzooRDfn+TZ4p3h2hTf4t3k3ucyrN1K5+Xaks52Sfs9CXgrAAAAjklEQVR42o3PbQ+CIBQFYEwboPhSYgoYunIqqLn6/z8uYdH8Vmdnu9vz4WwXgN/xTPRD2+sgOcZjsge/whXZgUaYYvT8QnuJaUrjrHUQreGczuEafQCO/SJTufTbroWsPgsllVhq3wJEk2jUSzX3CUEDJC84707djRc5MTAQxoLgupWRwW6UB5fS++NV8AbOZgnsC7BpEAAAAABJRU5ErkJggg==");background-position: 2px center;}.ace_gutter-cell.ace_info {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAJ0Uk5TAAB2k804AAAAPklEQVQY02NgIB68QuO3tiLznjAwpKTgNyDbMegwisCHZUETUZV0ZqOquBpXj2rtnpSJT1AEnnRmL2OgGgAAIKkRQap2htgAAAAASUVORK5CYII=");background-position: 2px center;}.ace_dark .ace_gutter-cell.ace_info {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAChoaGAgIAqKiq+vr6tra1ZWVmUlJSbm5s8PDxubm56enrdgzg3AAAAAXRSTlMAQObYZgAAAClJREFUeNpjYMAPdsMYHegyJZFQBlsUlMFVCWUYKkAZMxZAGdxlDMQBAG+TBP4B6RyJAAAAAElFTkSuQmCC");}.ace_scrollbar {position: absolute;right: 0;bottom: 0;z-index: 6;}.ace_scrollbar-inner {position: absolute;cursor: text;left: 0;top: 0;}.ace_scrollbar-v{overflow-x: hidden;overflow-y: scroll;top: 0;}.ace_scrollbar-h {overflow-x: scroll;overflow-y: hidden;left: 0;}.ace_print-margin {position: absolute;height: 100%;}.ace_text-input {position: absolute;z-index: 0;width: 0.5em;height: 1em;opacity: 0;background: transparent;-moz-appearance: none;appearance: none;border: none;resize: none;outline: none;overflow: hidden;font: inherit;padding: 0 1px;margin: 0 -1px;text-indent: -1em;-ms-user-select: text;-moz-user-select: text;-webkit-user-select: text;user-select: text;white-space: pre!important;}.ace_text-input.ace_composition {background: inherit;color: inherit;z-index: 1000;opacity: 1;text-indent: 0;}.ace_layer {z-index: 1;position: absolute;overflow: hidden;word-wrap: normal;white-space: pre;height: 100%;width: 100%;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;pointer-events: none;}.ace_gutter-layer {position: relative;width: auto;text-align: right;pointer-events: auto;}.ace_text-layer {font: inherit !important;}.ace_cjk {display: inline-block;text-align: center;}.ace_cursor-layer {z-index: 4;}.ace_cursor {z-index: 4;position: absolute;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;border-left: 2px solid;transform: translatez(0);}.ace_slim-cursors .ace_cursor {border-left-width: 1px;}.ace_overwrite-cursors .ace_cursor {border-left-width: 0;border-bottom: 1px solid;}.ace_hidden-cursors .ace_cursor {opacity: 0.2;}.ace_smooth-blinking .ace_cursor {-webkit-transition: opacity 0.18s;transition: opacity 0.18s;}.ace_editor.ace_multiselect .ace_cursor {border-left-width: 1px;}.ace_marker-layer .ace_step, .ace_marker-layer .ace_stack {position: absolute;z-index: 3;}.ace_marker-layer .ace_selection {position: absolute;z-index: 5;}.ace_marker-layer .ace_bracket {position: absolute;z-index: 6;}.ace_marker-layer .ace_active-line {position: absolute;z-index: 2;}.ace_marker-layer .ace_selected-word {position: absolute;z-index: 4;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;}.ace_line .ace_fold {-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;display: inline-block;height: 11px;margin-top: -2px;vertical-align: middle;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII="),url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACJJREFUeNpi+P//fxgTAwPDBxDxD078RSX+YeEyDFMCIMAAI3INmXiwf2YAAAAASUVORK5CYII=");background-repeat: no-repeat, repeat-x;background-position: center center, top left;color: transparent;border: 1px solid black;border-radius: 2px;cursor: pointer;pointer-events: auto;}.ace_dark .ace_fold {}.ace_fold:hover{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII="),url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACBJREFUeNpi+P//fz4TAwPDZxDxD5X4i5fLMEwJgAADAEPVDbjNw87ZAAAAAElFTkSuQmCC");}.ace_tooltip {background-color: #FFF;background-image: -webkit-linear-gradient(top, transparent, rgba(0, 0, 0, 0.1));background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.1));border: 1px solid gray;border-radius: 1px;box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);color: black;max-width: 100%;padding: 3px 4px;position: fixed;z-index: 999999;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;cursor: default;white-space: pre;word-wrap: break-word;line-height: normal;font-style: normal;font-weight: normal;letter-spacing: normal;pointer-events: none;}.ace_folding-enabled > .ace_gutter-cell {padding-right: 13px;}.ace_fold-widget {-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;margin: 0 -12px 0 1px;display: none;width: 11px;vertical-align: top;background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42mWKsQ0AMAzC8ixLlrzQjzmBiEjp0A6WwBCSPgKAXoLkqSot7nN3yMwR7pZ32NzpKkVoDBUxKAAAAABJRU5ErkJggg==");background-repeat: no-repeat;background-position: center;border-radius: 3px;border: 1px solid transparent;cursor: pointer;}.ace_folding-enabled .ace_fold-widget {display: inline-block;   }.ace_fold-widget.ace_end {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42m3HwQkAMAhD0YzsRchFKI7sAikeWkrxwScEB0nh5e7KTPWimZki4tYfVbX+MNl4pyZXejUO1QAAAABJRU5ErkJggg==");}.ace_fold-widget.ace_closed {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAGCAYAAAAG5SQMAAAAOUlEQVR42jXKwQkAMAgDwKwqKD4EwQ26sSOkVWjgIIHAzPiCgaqiqnJHZnKICBERHN194O5b9vbLuAVRL+l0YWnZAAAAAElFTkSuQmCCXA==");}.ace_fold-widget:hover {border: 1px solid rgba(0, 0, 0, 0.3);background-color: rgba(255, 255, 255, 0.2);box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);}.ace_fold-widget:active {border: 1px solid rgba(0, 0, 0, 0.4);background-color: rgba(0, 0, 0, 0.05);box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);}.ace_dark .ace_fold-widget {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHklEQVQIW2P4//8/AzoGEQ7oGCaLLAhWiSwB146BAQCSTPYocqT0AAAAAElFTkSuQmCC");}.ace_dark .ace_fold-widget.ace_end {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH0lEQVQIW2P4//8/AxQ7wNjIAjDMgC4AxjCVKBirIAAF0kz2rlhxpAAAAABJRU5ErkJggg==");}.ace_dark .ace_fold-widget.ace_closed {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAHElEQVQIW2P4//+/AxAzgDADlOOAznHAKgPWAwARji8UIDTfQQAAAABJRU5ErkJggg==");}.ace_dark .ace_fold-widget:hover {box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);background-color: rgba(255, 255, 255, 0.1);}.ace_dark .ace_fold-widget:active {box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);}.ace_fold-widget.ace_invalid {background-color: #FFB4B4;border-color: #DE5555;}.ace_fade-fold-widgets .ace_fold-widget {-webkit-transition: opacity 0.4s ease 0.05s;transition: opacity 0.4s ease 0.05s;opacity: 0;}.ace_fade-fold-widgets:hover .ace_fold-widget {-webkit-transition: opacity 0.05s ease 0.05s;transition: opacity 0.05s ease 0.05s;opacity:1;}.ace_underline {text-decoration: underline;}.ace_bold {font-weight: bold;}.ace_nobold .ace_bold {font-weight: normal;}.ace_italic {font-style: italic;}.ace_error-marker {background-color: rgba(255, 0, 0,0.2);position: absolute;z-index: 9;}.ace_highlight-marker {background-color: rgba(255, 255, 0,0.2);position: absolute;z-index: 8;}.ace_br1 {border-top-left-radius    : 3px;}.ace_br2 {border-top-right-radius   : 3px;}.ace_br3 {border-top-left-radius    : 3px; border-top-right-radius:    3px;}.ace_br4 {border-bottom-right-radius: 3px;}.ace_br5 {border-top-left-radius    : 3px; border-bottom-right-radius: 3px;}.ace_br6 {border-top-right-radius   : 3px; border-bottom-right-radius: 3px;}.ace_br7 {border-top-left-radius    : 3px; border-top-right-radius:    3px; border-bottom-right-radius: 3px;}.ace_br8 {border-bottom-left-radius : 3px;}.ace_br9 {border-top-left-radius    : 3px; border-bottom-left-radius:  3px;}.ace_br10{border-top-right-radius   : 3px; border-bottom-left-radius:  3px;}.ace_br11{border-top-left-radius    : 3px; border-top-right-radius:    3px; border-bottom-left-radius:  3px;}.ace_br12{border-bottom-right-radius: 3px; border-bottom-left-radius:  3px;}.ace_br13{border-top-left-radius    : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius:  3px;}.ace_br14{border-top-right-radius   : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius:  3px;}.ace_br15{border-top-left-radius    : 3px; border-top-right-radius:    3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}';i.importCssString(m,"ace_editor.css");var g=function(e,t){var n=this;this.container=e||i.createElement("div"),this.$keepTextAreaAtCursor=!o.isOldIE,i.addCssClass(this.container,"ace_editor"),this.setTheme(t),this.$gutter=i.createElement("div"),this.$gutter.className="ace_gutter",this.container.appendChild(this.$gutter),this.scroller=i.createElement("div"),this.scroller.className="ace_scroller",this.container.appendChild(this.scroller),this.content=i.createElement("div"),this.content.className="ace_content",this.scroller.appendChild(this.content),this.$gutterLayer=new u(this.$gutter),this.$gutterLayer.on("changeGutterWidth",this.onGutterResize.bind(this)),this.$markerBack=new a(this.content);var r=this.$textLayer=new f(this.content);this.canvas=r.element,this.$markerFront=new a(this.content),this.$cursorLayer=new l(this.content),this.$horizScroll=!1,this.$vScroll=!1,this.scrollBar=this.scrollBarV=new h(this.container,this),this.scrollBarH=new c(this.container,this),this.scrollBarV.addEventListener("scroll",function(e){n.$scrollAnimation||n.session.setScrollTop(e.data-n.scrollMargin.top)}),this.scrollBarH.addEventListener("scroll",function(e){n.$scrollAnimation||n.session.setScrollLeft(e.data-n.scrollMargin.left)}),this.scrollTop=0,this.scrollLeft=0,this.cursorPos={row:0,column:0},this.$fontMetrics=new d(this.container),this.$textLayer.$setFontMetrics(this.$fontMetrics),this.$textLayer.addEventListener("changeCharacterSize",function(e){n.updateCharacterSize(),n.onResize(!0,n.gutterWidth,n.$size.width,n.$size.height),n._signal("changeCharacterSize",e)}),this.$size={width:0,height:0,scrollerHeight:0,scrollerWidth:0,$dirty:!0},this.layerConfig={width:1,padding:0,firstRow:0,firstRowScreen:0,lastRow:0,lineHeight:0,characterWidth:0,minHeight:1,maxHeight:1,offset:0,height:1,gutterOffset:1},this.scrollMargin={left:0,right:0,top:0,bottom:0,v:0,h:0},this.$loop=new p(this.$renderChanges.bind(this),this.container.ownerDocument.defaultView),this.$loop.schedule(this.CHANGE_FULL),this.updateCharacterSize(),this.setPadding(4),s.resetOptions(this),s._emit("renderer",this)};(function(){this.CHANGE_CURSOR=1,this.CHANGE_MARKER=2,this.CHANGE_GUTTER=4,this.CHANGE_SCROLL=8,this.CHANGE_LINES=16,this.CHANGE_TEXT=32,this.CHANGE_SIZE=64,this.CHANGE_MARKER_BACK=128,this.CHANGE_MARKER_FRONT=256,this.CHANGE_FULL=512,this.CHANGE_H_SCROLL=1024,r.implement(this,v),this.updateCharacterSize=function(){this.$textLayer.allowBoldFonts!=this.$allowBoldFonts&&(this.$allowBoldFonts=this.$textLayer.allowBoldFonts,this.setStyle("ace_nobold",!this.$allowBoldFonts)),this.layerConfig.characterWidth=this.characterWidth=this.$textLayer.getCharacterWidth(),this.layerConfig.lineHeight=this.lineHeight=this.$textLayer.getLineHeight(),this.$updatePrintMargin()},this.setSession=function(e){this.session&&this.session.doc.off("changeNewLineMode",this.onChangeNewLineMode),this.session=e,e&&this.scrollMargin.top&&e.getScrollTop()<=0&&e.setScrollTop(-this.scrollMargin.top),this.$cursorLayer.setSession(e),this.$markerBack.setSession(e),this.$markerFront.setSession(e),this.$gutterLayer.setSession(e),this.$textLayer.setSession(e);if(!e)return;this.$loop.schedule(this.CHANGE_FULL),this.session.$setFontMetrics(this.$fontMetrics),this.onChangeNewLineMode=this.onChangeNewLineMode.bind(this),this.onChangeNewLineMode(),this.session.doc.on("changeNewLineMode",this.onChangeNewLineMode)},this.updateLines=function(e,t,n){t===undefined&&(t=Infinity),this.$changedLines?(this.$changedLines.firstRow>e&&(this.$changedLines.firstRow=e),this.$changedLines.lastRow<t&&(this.$changedLines.lastRow=t)):this.$changedLines={firstRow:e,lastRow:t};if(this.$changedLines.lastRow<this.layerConfig.firstRow){if(!n)return;this.$changedLines.lastRow=this.layerConfig.lastRow}if(this.$changedLines.firstRow>this.layerConfig.lastRow)return;this.$loop.schedule(this.CHANGE_LINES)},this.onChangeNewLineMode=function(){this.$loop.schedule(this.CHANGE_TEXT),this.$textLayer.$updateEolChar()},this.onChangeTabSize=function(){this.$loop.schedule(this.CHANGE_TEXT|this.CHANGE_MARKER),this.$textLayer.onChangeTabSize()},this.updateText=function(){this.$loop.schedule(this.CHANGE_TEXT)},this.updateFull=function(e){e?this.$renderChanges(this.CHANGE_FULL,!0):this.$loop.schedule(this.CHANGE_FULL)},this.updateFontSize=function(){this.$textLayer.checkForSizeChanges()},this.$changes=0,this.$updateSizeAsync=function(){this.$loop.pending?this.$size.$dirty=!0:this.onResize()},this.onResize=function(e,t,n,r){if(this.resizing>2)return;this.resizing>0?this.resizing++:this.resizing=e?1:0;var i=this.container;r||(r=i.clientHeight||i.scrollHeight),n||(n=i.clientWidth||i.scrollWidth);var s=this.$updateCachedSize(e,t,n,r);if(!this.$size.scrollerHeight||!n&&!r)return this.resizing=0;e&&(this.$gutterLayer.$padding=null),e?this.$renderChanges(s|this.$changes,!0):this.$loop.schedule(s|this.$changes),this.resizing&&(this.resizing=0),this.scrollBarV.scrollLeft=this.scrollBarV.scrollTop=null},this.$updateCachedSize=function(e,t,n,r){r-=this.$extraHeight||0;var i=0,s=this.$size,o={width:s.width,height:s.height,scrollerHeight:s.scrollerHeight,scrollerWidth:s.scrollerWidth};r&&(e||s.height!=r)&&(s.height=r,i|=this.CHANGE_SIZE,s.scrollerHeight=s.height,this.$horizScroll&&(s.scrollerHeight-=this.scrollBarH.getHeight()),this.scrollBarV.element.style.bottom=this.scrollBarH.getHeight()+"px",i|=this.CHANGE_SCROLL);if(n&&(e||s.width!=n)){i|=this.CHANGE_SIZE,s.width=n,t==null&&(t=this.$showGutter?this.$gutter.offsetWidth:0),this.gutterWidth=t,this.scrollBarH.element.style.left=this.scroller.style.left=t+"px",s.scrollerWidth=Math.max(0,n-t-this.scrollBarV.getWidth()),this.scrollBarH.element.style.right=this.scroller.style.right=this.scrollBarV.getWidth()+"px",this.scroller.style.bottom=this.scrollBarH.getHeight()+"px";if(this.session&&this.session.getUseWrapMode()&&this.adjustWrapLimit()||e)i|=this.CHANGE_FULL}return s.$dirty=!n||!r,i&&this._signal("resize",o),i},this.onGutterResize=function(){var e=this.$showGutter?this.$gutter.offsetWidth:0;e!=this.gutterWidth&&(this.$changes|=this.$updateCachedSize(!0,e,this.$size.width,this.$size.height)),this.session.getUseWrapMode()&&this.adjustWrapLimit()?this.$loop.schedule(this.CHANGE_FULL):this.$size.$dirty?this.$loop.schedule(this.CHANGE_FULL):(this.$computeLayerConfig(),this.$loop.schedule(this.CHANGE_MARKER))},this.adjustWrapLimit=function(){var e=this.$size.scrollerWidth-this.$padding*2,t=Math.floor(e/this.characterWidth);return this.session.adjustWrapLimit(t,this.$showPrintMargin&&this.$printMarginColumn)},this.setAnimatedScroll=function(e){this.setOption("animatedScroll",e)},this.getAnimatedScroll=function(){return this.$animatedScroll},this.setShowInvisibles=function(e){this.setOption("showInvisibles",e)},this.getShowInvisibles=function(){return this.getOption("showInvisibles")},this.getDisplayIndentGuides=function(){return this.getOption("displayIndentGuides")},this.setDisplayIndentGuides=function(e){this.setOption("displayIndentGuides",e)},this.setShowPrintMargin=function(e){this.setOption("showPrintMargin",e)},this.getShowPrintMargin=function(){return this.getOption("showPrintMargin")},this.setPrintMarginColumn=function(e){this.setOption("printMarginColumn",e)},this.getPrintMarginColumn=function(){return this.getOption("printMarginColumn")},this.getShowGutter=function(){return this.getOption("showGutter")},this.setShowGutter=function(e){return this.setOption("showGutter",e)},this.getFadeFoldWidgets=function(){return this.getOption("fadeFoldWidgets")},this.setFadeFoldWidgets=function(e){this.setOption("fadeFoldWidgets",e)},this.setHighlightGutterLine=function(e){this.setOption("highlightGutterLine",e)},this.getHighlightGutterLine=function(){return this.getOption("highlightGutterLine")},this.$updateGutterLineHighlight=function(){var e=this.$cursorLayer.$pixelPos,t=this.layerConfig.lineHeight;if(this.session.getUseWrapMode()){var n=this.session.selection.getCursor();n.column=0,e=this.$cursorLayer.getPixelPosition(n,!0),t*=this.session.getRowLength(n.row)}this.$gutterLineHighlight.style.top=e.top-this.layerConfig.offset+"px",this.$gutterLineHighlight.style.height=t+"px"},this.$updatePrintMargin=function(){if(!this.$showPrintMargin&&!this.$printMarginEl)return;if(!this.$printMarginEl){var e=i.createElement("div");e.className="ace_layer ace_print-margin-layer",this.$printMarginEl=i.createElement("div"),this.$printMarginEl.className="ace_print-margin",e.appendChild(this.$printMarginEl),this.content.insertBefore(e,this.content.firstChild)}var t=this.$printMarginEl.style;t.left=this.characterWidth*this.$printMarginColumn+this.$padding+"px",t.visibility=this.$showPrintMargin?"visible":"hidden",this.session&&this.session.$wrap==-1&&this.adjustWrapLimit()},this.getContainerElement=function(){return this.container},this.getMouseEventTarget=function(){return this.scroller},this.getTextAreaContainer=function(){return this.container},this.$moveTextAreaToCursor=function(){if(!this.$keepTextAreaAtCursor)return;var e=this.layerConfig,t=this.$cursorLayer.$pixelPos.top,n=this.$cursorLayer.$pixelPos.left;t-=e.offset;var r=this.textarea.style,i=this.lineHeight;if(t<0||t>e.height-i){r.top=r.left="0";return}var s=this.characterWidth;if(this.$composition){var o=this.textarea.value.replace(/^\x01+/,"");s*=this.session.$getStringScreenWidth(o)[0]+2,i+=2}n-=this.scrollLeft,n>this.$size.scrollerWidth-s&&(n=this.$size.scrollerWidth-s),n+=this.gutterWidth,r.height=i+"px",r.width=s+"px",r.left=Math.min(n,this.$size.scrollerWidth-s)+"px",r.top=Math.min(t,this.$size.height-i)+"px"},this.getFirstVisibleRow=function(){return this.layerConfig.firstRow},this.getFirstFullyVisibleRow=function(){return this.layerConfig.firstRow+(this.layerConfig.offset===0?0:1)},this.getLastFullyVisibleRow=function(){var e=this.layerConfig,t=e.lastRow,n=this.session.documentToScreenRow(t,0)*e.lineHeight;return n-this.session.getScrollTop()>e.height-e.lineHeight?t-1:t},this.getLastVisibleRow=function(){return this.layerConfig.lastRow},this.$padding=null,this.setPadding=function(e){this.$padding=e,this.$textLayer.setPadding(e),this.$cursorLayer.setPadding(e),this.$markerFront.setPadding(e),this.$markerBack.setPadding(e),this.$loop.schedule(this.CHANGE_FULL),this.$updatePrintMargin()},this.setScrollMargin=function(e,t,n,r){var i=this.scrollMargin;i.top=e|0,i.bottom=t|0,i.right=r|0,i.left=n|0,i.v=i.top+i.bottom,i.h=i.left+i.right,i.top&&this.scrollTop<=0&&this.session&&this.session.setScrollTop(-i.top),this.updateFull()},this.getHScrollBarAlwaysVisible=function(){return this.$hScrollBarAlwaysVisible},this.setHScrollBarAlwaysVisible=function(e){this.setOption("hScrollBarAlwaysVisible",e)},this.getVScrollBarAlwaysVisible=function(){return this.$vScrollBarAlwaysVisible},this.setVScrollBarAlwaysVisible=function(e){this.setOption("vScrollBarAlwaysVisible",e)},this.$updateScrollBarV=function(){var e=this.layerConfig.maxHeight,t=this.$size.scrollerHeight;!this.$maxLines&&this.$scrollPastEnd&&(e-=(t-this.lineHeight)*this.$scrollPastEnd,this.scrollTop>e-t&&(e=this.scrollTop+t,this.scrollBarV.scrollTop=null)),this.scrollBarV.setScrollHeight(e+this.scrollMargin.v),this.scrollBarV.setScrollTop(this.scrollTop+this.scrollMargin.top)},this.$updateScrollBarH=function(){this.scrollBarH.setScrollWidth(this.layerConfig.width+2*this.$padding+this.scrollMargin.h),this.scrollBarH.setScrollLeft(this.scrollLeft+this.scrollMargin.left)},this.$frozen=!1,this.freeze=function(){this.$frozen=!0},this.unfreeze=function(){this.$frozen=!1},this.$renderChanges=function(e,t){this.$changes&&(e|=this.$changes,this.$changes=0);if(!this.session||!this.container.offsetWidth||this.$frozen||!e&&!t){this.$changes|=e;return}if(this.$size.$dirty)return this.$changes|=e,this.onResize(!0);this.lineHeight||this.$textLayer.checkForSizeChanges(),this._signal("beforeRender");var n=this.layerConfig;if(e&this.CHANGE_FULL||e&this.CHANGE_SIZE||e&this.CHANGE_TEXT||e&this.CHANGE_LINES||e&this.CHANGE_SCROLL||e&this.CHANGE_H_SCROLL){e|=this.$computeLayerConfig();if(n.firstRow!=this.layerConfig.firstRow&&n.firstRowScreen==this.layerConfig.firstRowScreen){var r=this.scrollTop+(n.firstRow-this.layerConfig.firstRow)*this.lineHeight;r>0&&(this.scrollTop=r,e|=this.CHANGE_SCROLL,e|=this.$computeLayerConfig())}n=this.layerConfig,this.$updateScrollBarV(),e&this.CHANGE_H_SCROLL&&this.$updateScrollBarH(),this.$gutterLayer.element.style.marginTop=-n.offset+"px",this.content.style.marginTop=-n.offset+"px",this.content.style.width=n.width+2*this.$padding+"px",this.content.style.height=n.minHeight+"px"}e&this.CHANGE_H_SCROLL&&(this.content.style.marginLeft=-this.scrollLeft+"px",this.scroller.className=this.scrollLeft<=0?"ace_scroller":"ace_scroller ace_scroll-left");if(e&this.CHANGE_FULL){this.$textLayer.update(n),this.$showGutter&&this.$gutterLayer.update(n),this.$markerBack.update(n),this.$markerFront.update(n),this.$cursorLayer.update(n),this.$moveTextAreaToCursor(),this.$highlightGutterLine&&this.$updateGutterLineHighlight(),this._signal("afterRender");return}if(e&this.CHANGE_SCROLL){e&this.CHANGE_TEXT||e&this.CHANGE_LINES?this.$textLayer.update(n):this.$textLayer.scrollLines(n),this.$showGutter&&this.$gutterLayer.update(n),this.$markerBack.update(n),this.$markerFront.update(n),this.$cursorLayer.update(n),this.$highlightGutterLine&&this.$updateGutterLineHighlight(),this.$moveTextAreaToCursor(),this._signal("afterRender");return}e&this.CHANGE_TEXT?(this.$textLayer.update(n),this.$showGutter&&this.$gutterLayer.update(n)):e&this.CHANGE_LINES?(this.$updateLines()||e&this.CHANGE_GUTTER&&this.$showGutter)&&this.$gutterLayer.update(n):(e&this.CHANGE_TEXT||e&this.CHANGE_GUTTER)&&this.$showGutter&&this.$gutterLayer.update(n),e&this.CHANGE_CURSOR&&(this.$cursorLayer.update(n),this.$moveTextAreaToCursor(),this.$highlightGutterLine&&this.$updateGutterLineHighlight()),e&(this.CHANGE_MARKER|this.CHANGE_MARKER_FRONT)&&this.$markerFront.update(n),e&(this.CHANGE_MARKER|this.CHANGE_MARKER_BACK)&&this.$markerBack.update(n),this._signal("afterRender")},this.$autosize=function(){var e=this.session.getScreenLength()*this.lineHeight,t=this.$maxLines*this.lineHeight,n=Math.min(t,Math.max((this.$minLines||1)*this.lineHeight,e))+this.scrollMargin.v+(this.$extraHeight||0);this.$horizScroll&&(n+=this.scrollBarH.getHeight()),this.$maxPixelHeight&&n>this.$maxPixelHeight&&(n=this.$maxPixelHeight);var r=e>t;if(n!=this.desiredHeight||this.$size.height!=this.desiredHeight||r!=this.$vScroll){r!=this.$vScroll&&(this.$vScroll=r,this.scrollBarV.setVisible(r));var i=this.container.clientWidth;this.container.style.height=n+"px",this.$updateCachedSize(!0,this.$gutterWidth,i,n),this.desiredHeight=n,this._signal("autosize")}},this.$computeLayerConfig=function(){var e=this.session,t=this.$size,n=t.height<=2*this.lineHeight,r=this.session.getScreenLength(),i=r*this.lineHeight,s=this.$getLongestLine(),o=!n&&(this.$hScrollBarAlwaysVisible||t.scrollerWidth-s-2*this.$padding<0),u=this.$horizScroll!==o;u&&(this.$horizScroll=o,this.scrollBarH.setVisible(o));var a=this.$vScroll;this.$maxLines&&this.lineHeight>1&&this.$autosize();var f=this.scrollTop%this.lineHeight,l=t.scrollerHeight+this.lineHeight,c=!this.$maxLines&&this.$scrollPastEnd?(t.scrollerHeight-this.lineHeight)*this.$scrollPastEnd:0;i+=c;var h=this.scrollMargin;this.session.setScrollTop(Math.max(-h.top,Math.min(this.scrollTop,i-t.scrollerHeight+h.bottom))),this.session.setScrollLeft(Math.max(-h.left,Math.min(this.scrollLeft,s+2*this.$padding-t.scrollerWidth+h.right)));var p=!n&&(this.$vScrollBarAlwaysVisible||t.scrollerHeight-i+c<0||this.scrollTop>h.top),d=a!==p;d&&(this.$vScroll=p,this.scrollBarV.setVisible(p));var v=Math.ceil(l/this.lineHeight)-1,m=Math.max(0,Math.round((this.scrollTop-f)/this.lineHeight)),g=m+v,y,b,w=this.lineHeight;m=e.screenToDocumentRow(m,0);var E=e.getFoldLine(m);E&&(m=E.start.row),y=e.documentToScreenRow(m,0),b=e.getRowLength(m)*w,g=Math.min(e.screenToDocumentRow(g,0),e.getLength()-1),l=t.scrollerHeight+e.getRowLength(g)*w+b,f=this.scrollTop-y*w;var S=0;this.layerConfig.width!=s&&(S=this.CHANGE_H_SCROLL);if(u||d)S=this.$updateCachedSize(!0,this.gutterWidth,t.width,t.height),this._signal("scrollbarVisibilityChanged"),d&&(s=this.$getLongestLine());return this.layerConfig={width:s,padding:this.$padding,firstRow:m,firstRowScreen:y,lastRow:g,lineHeight:w,characterWidth:this.characterWidth,minHeight:l,maxHeight:i,offset:f,gutterOffset:Math.max(0,Math.ceil((f+t.height-t.scrollerHeight)/w)),height:this.$size.scrollerHeight},S},this.$updateLines=function(){var e=this.$changedLines.firstRow,t=this.$changedLines.lastRow;this.$changedLines=null;var n=this.layerConfig;if(e>n.lastRow+1)return;if(t<n.firstRow)return;if(t===Infinity){this.$showGutter&&this.$gutterLayer.update(n),this.$textLayer.update(n);return}return this.$textLayer.updateLines(n,e,t),!0},this.$getLongestLine=function(){var e=this.session.getScreenWidth();return this.showInvisibles&&!this.session.$useWrapMode&&(e+=1),Math.max(this.$size.scrollerWidth-2*this.$padding,Math.round(e*this.characterWidth))},this.updateFrontMarkers=function(){this.$markerFront.setMarkers(this.session.getMarkers(!0)),this.$loop.schedule(this.CHANGE_MARKER_FRONT)},this.updateBackMarkers=function(){this.$markerBack.setMarkers(this.session.getMarkers()),this.$loop.schedule(this.CHANGE_MARKER_BACK)},this.addGutterDecoration=function(e,t){this.$gutterLayer.addGutterDecoration(e,t)},this.removeGutterDecoration=function(e,t){this.$gutterLayer.removeGutterDecoration(e,t)},this.updateBreakpoints=function(e){this.$loop.schedule(this.CHANGE_GUTTER)},this.setAnnotations=function(e){this.$gutterLayer.setAnnotations(e),this.$loop.schedule(this.CHANGE_GUTTER)},this.updateCursor=function(){this.$loop.schedule(this.CHANGE_CURSOR)},this.hideCursor=function(){this.$cursorLayer.hideCursor()},this.showCursor=function(){this.$cursorLayer.showCursor()},this.scrollSelectionIntoView=function(e,t,n){this.scrollCursorIntoView(e,n),this.scrollCursorIntoView(t,n)},this.scrollCursorIntoView=function(e,t,n){if(this.$size.scrollerHeight===0)return;var r=this.$cursorLayer.getPixelPosition(e),i=r.left,s=r.top,o=n&&n.top||0,u=n&&n.bottom||0,a=this.$scrollAnimation?this.session.getScrollTop():this.scrollTop;a+o>s?(t&&a+o>s+this.lineHeight&&(s-=t*this.$size.scrollerHeight),s===0&&(s=-this.scrollMargin.top),this.session.setScrollTop(s)):a+this.$size.scrollerHeight-u<s+this.lineHeight&&(t&&a+this.$size.scrollerHeight-u<s-this.lineHeight&&(s+=t*this.$size.scrollerHeight),this.session.setScrollTop(s+this.lineHeight-this.$size.scrollerHeight));var f=this.scrollLeft;f>i?(i<this.$padding+2*this.layerConfig.characterWidth&&(i=-this.scrollMargin.left),this.session.setScrollLeft(i)):f+this.$size.scrollerWidth<i+this.characterWidth?this.session.setScrollLeft(Math.round(i+this.characterWidth-this.$size.scrollerWidth)):f<=this.$padding&&i-f<this.characterWidth&&this.session.setScrollLeft(0)},this.getScrollTop=function(){return this.session.getScrollTop()},this.getScrollLeft=function(){return this.session.getScrollLeft()},this.getScrollTopRow=function(){return this.scrollTop/this.lineHeight},this.getScrollBottomRow=function(){return Math.max(0,Math.floor((this.scrollTop+this.$size.scrollerHeight)/this.lineHeight)-1)},this.scrollToRow=function(e){this.session.setScrollTop(e*this.lineHeight)},this.alignCursor=function(e,t){typeof e=="number"&&(e={row:e,column:0});var n=this.$cursorLayer.getPixelPosition(e),r=this.$size.scrollerHeight-this.lineHeight,i=n.top-r*(t||0);return this.session.setScrollTop(i),i},this.STEPS=8,this.$calcSteps=function(e,t){var n=0,r=this.STEPS,i=[],s=function(e,t,n){return n*(Math.pow(e-1,3)+1)+t};for(n=0;n<r;++n)i.push(s(n/this.STEPS,e,t-e));return i},this.scrollToLine=function(e,t,n,r){var i=this.$cursorLayer.getPixelPosition({row:e,column:0}),s=i.top;t&&(s-=this.$size.scrollerHeight/2);var o=this.scrollTop;this.session.setScrollTop(s),n!==!1&&this.animateScrolling(o,r)},this.animateScrolling=function(e,t){var n=this.scrollTop;if(!this.$animatedScroll)return;var r=this;if(e==n)return;if(this.$scrollAnimation){var i=this.$scrollAnimation.steps;if(i.length){e=i[0];if(e==n)return}}var s=r.$calcSteps(e,n);this.$scrollAnimation={from:e,to:n,steps:s},clearInterval(this.$timer),r.session.setScrollTop(s.shift()),r.session.$scrollTop=n,this.$timer=setInterval(function(){s.length?(r.session.setScrollTop(s.shift()),r.session.$scrollTop=n):n!=null?(r.session.$scrollTop=-1,r.session.setScrollTop(n),n=null):(r.$timer=clearInterval(r.$timer),r.$scrollAnimation=null,t&&t())},10)},this.scrollToY=function(e){this.scrollTop!==e&&(this.$loop.schedule(this.CHANGE_SCROLL),this.scrollTop=e)},this.scrollToX=function(e){this.scrollLeft!==e&&(this.scrollLeft=e),this.$loop.schedule(this.CHANGE_H_SCROLL)},this.scrollTo=function(e,t){this.session.setScrollTop(t),this.session.setScrollLeft(t)},this.scrollBy=function(e,t){t&&this.session.setScrollTop(this.session.getScrollTop()+t),e&&this.session.setScrollLeft(this.session.getScrollLeft()+e)},this.isScrollableBy=function(e,t){if(t<0&&this.session.getScrollTop()>=1-this.scrollMargin.top)return!0;if(t>0&&this.session.getScrollTop()+this.$size.scrollerHeight-this.layerConfig.maxHeight<-1+this.scrollMargin.bottom)return!0;if(e<0&&this.session.getScrollLeft()>=1-this.scrollMargin.left)return!0;if(e>0&&this.session.getScrollLeft()+this.$size.scrollerWidth-this.layerConfig.width<-1+this.scrollMargin.right)return!0},this.pixelToScreenCoordinates=function(e,t){var n=this.scroller.getBoundingClientRect(),r=(e+this.scrollLeft-n.left-this.$padding)/this.characterWidth,i=Math.floor((t+this.scrollTop-n.top)/this.lineHeight),s=Math.round(r);return{row:i,column:s,side:r-s>0?1:-1}},this.screenToTextCoordinates=function(e,t){var n=this.scroller.getBoundingClientRect(),r=Math.round((e+this.scrollLeft-n.left-this.$padding)/this.characterWidth),i=(t+this.scrollTop-n.top)/this.lineHeight;return this.session.screenToDocumentPosition(i,Math.max(r,0))},this.textToScreenCoordinates=function(e,t){var n=this.scroller.getBoundingClientRect(),r=this.session.documentToScreenPosition(e,t),i=this.$padding+Math.round(r.column*this.characterWidth),s=r.row*this.lineHeight;return{pageX:n.left+i-this.scrollLeft,pageY:n.top+s-this.scrollTop}},this.visualizeFocus=function(){i.addCssClass(this.container,"ace_focus")},this.visualizeBlur=function(){i.removeCssClass(this.container,"ace_focus")},this.showComposition=function(e){this.$composition||(this.$composition={keepTextAreaAtCursor:this.$keepTextAreaAtCursor,cssText:this.textarea.style.cssText}),this.$keepTextAreaAtCursor=!0,i.addCssClass(this.textarea,"ace_composition"),this.textarea.style.cssText="",this.$moveTextAreaToCursor()},this.setCompositionText=function(e){this.$moveTextAreaToCursor()},this.hideComposition=function(){if(!this.$composition)return;i.removeCssClass(this.textarea,"ace_composition"),this.$keepTextAreaAtCursor=this.$composition.keepTextAreaAtCursor,this.textarea.style.cssText=this.$composition.cssText,this.$composition=null},this.setTheme=function(e,t){function o(r){if(n.$themeId!=e)return t&&t();if(!r.cssClass)return;i.importCssString(r.cssText,r.cssClass,n.container.ownerDocument),n.theme&&i.removeCssClass(n.container,n.theme.cssClass);var s="padding"in r?r.padding:"padding"in(n.theme||{})?4:n.$padding;n.$padding&&s!=n.$padding&&n.setPadding(s),n.$theme=r.cssClass,n.theme=r,i.addCssClass(n.container,r.cssClass),i.setCssClass(n.container,"ace_dark",r.isDark),n.$size&&(n.$size.width=0,n.$updateSizeAsync()),n._dispatchEvent("themeLoaded",{theme:r}),t&&t()}var n=this;this.$themeId=e,n._dispatchEvent("themeChange",{theme:e});if(!e||typeof e=="string"){var r=e||this.$options.theme.initialValue;s.loadModule(["theme",r],o)}else o(e)},this.getTheme=function(){return this.$themeId},this.setStyle=function(e,t){i.setCssClass(this.container,e,t!==!1)},this.unsetStyle=function(e){i.removeCssClass(this.container,e)},this.setCursorStyle=function(e){this.scroller.style.cursor!=e&&(this.scroller.style.cursor=e)},this.setMouseCursor=function(e){this.scroller.style.cursor=e},this.destroy=function(){this.$textLayer.destroy(),this.$cursorLayer.destroy()}}).call(g.prototype),s.defineOptions(g.prototype,"renderer",{animatedScroll:{initialValue:!1},showInvisibles:{set:function(e){this.$textLayer.setShowInvisibles(e)&&this.$loop.schedule(this.CHANGE_TEXT)},initialValue:!1},showPrintMargin:{set:function(){this.$updatePrintMargin()},initialValue:!0},printMarginColumn:{set:function(){this.$updatePrintMargin()},initialValue:80},printMargin:{set:function(e){typeof e=="number"&&(this.$printMarginColumn=e),this.$showPrintMargin=!!e,this.$updatePrintMargin()},get:function(){return this.$showPrintMargin&&this.$printMarginColumn}},showGutter:{set:function(e){this.$gutter.style.display=e?"block":"none",this.$loop.schedule(this.CHANGE_FULL),this.onGutterResize()},initialValue:!0},fadeFoldWidgets:{set:function(e){i.setCssClass(this.$gutter,"ace_fade-fold-widgets",e)},initialValue:!1},showFoldWidgets:{set:function(e){this.$gutterLayer.setShowFoldWidgets(e)},initialValue:!0},showLineNumbers:{set:function(e){this.$gutterLayer.setShowLineNumbers(e),this.$loop.schedule(this.CHANGE_GUTTER)},initialValue:!0},displayIndentGuides:{set:function(e){this.$textLayer.setDisplayIndentGuides(e)&&this.$loop.schedule(this.CHANGE_TEXT)},initialValue:!0},highlightGutterLine:{set:function(e){if(!this.$gutterLineHighlight){this.$gutterLineHighlight=i.createElement("div"),this.$gutterLineHighlight.className="ace_gutter-active-line",this.$gutter.appendChild(this.$gutterLineHighlight);return}this.$gutterLineHighlight.style.display=e?"":"none",this.$cursorLayer.$pixelPos&&this.$updateGutterLineHighlight()},initialValue:!1,value:!0},hScrollBarAlwaysVisible:{set:function(e){(!this.$hScrollBarAlwaysVisible||!this.$horizScroll)&&this.$loop.schedule(this.CHANGE_SCROLL)},initialValue:!1},vScrollBarAlwaysVisible:{set:function(e){(!this.$vScrollBarAlwaysVisible||!this.$vScroll)&&this.$loop.schedule(this.CHANGE_SCROLL)},initialValue:!1},fontSize:{set:function(e){typeof e=="number"&&(e+="px"),this.container.style.fontSize=e,this.updateFontSize()},initialValue:12},fontFamily:{set:function(e){this.container.style.fontFamily=e,this.updateFontSize()}},maxLines:{set:function(e){this.updateFull()}},minLines:{set:function(e){this.updateFull()}},maxPixelHeight:{set:function(e){this.updateFull()},initialValue:0},scrollPastEnd:{set:function(e){e=+e||0;if(this.$scrollPastEnd==e)return;this.$scrollPastEnd=e,this.$loop.schedule(this.CHANGE_SCROLL)},initialValue:0,handlesSet:!0},fixedWidthGutter:{set:function(e){this.$gutterLayer.$fixedWidth=!!e,this.$loop.schedule(this.CHANGE_GUTTER)}},theme:{set:function(e){this.setTheme(e)},get:function(){return this.$themeId||this.theme},initialValue:"./theme/textmate",handlesSet:!0}}),t.VirtualRenderer=g}),define("ace/worker/worker_client",["require","exports","module","ace/lib/oop","ace/lib/net","ace/lib/event_emitter","ace/config"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../lib/net"),s=e("../lib/event_emitter").EventEmitter,o=e("../config"),u=function(t,n,r,i){this.$sendDeltaQueue=this.$sendDeltaQueue.bind(this),this.changeListener=this.changeListener.bind(this),this.onMessage=this.onMessage.bind(this),e.nameToUrl&&!e.toUrl&&(e.toUrl=e.nameToUrl);if(o.get("packaged")||!e.toUrl)i=i||o.moduleUrl(n,"worker");else{var s=this.$normalizePath;i=i||s(e.toUrl("ace/worker/worker.js",null,"_"));var u={};t.forEach(function(t){u[t]=s(e.toUrl(t,null,"_").replace(/(\.js)?(\?.*)?$/,""))})}try{this.$worker=new Worker(i)}catch(a){if(!(a instanceof window.DOMException))throw a;var f=this.$workerBlob(i),l=window.URL||window.webkitURL,c=l.createObjectURL(f);this.$worker=new Worker(c),l.revokeObjectURL(c)}this.$worker.postMessage({init:!0,tlns:u,module:n,classname:r}),this.callbackId=1,this.callbacks={},this.$worker.onmessage=this.onMessage};(function(){r.implement(this,s),this.onMessage=function(e){var t=e.data;switch(t.type){case"event":this._signal(t.name,{data:t.data});break;case"call":var n=this.callbacks[t.id];n&&(n(t.data),delete this.callbacks[t.id]);break;case"error":this.reportError(t.data);break;case"log":window.console&&console.log&&console.log.apply(console,t.data)}},this.reportError=function(e){window.console&&console.error&&console.error(e)},this.$normalizePath=function(e){return i.qualifyURL(e)},this.terminate=function(){this._signal("terminate",{}),this.deltaQueue=null,this.$worker.terminate(),this.$worker=null,this.$doc&&this.$doc.off("change",this.changeListener),this.$doc=null},this.send=function(e,t){this.$worker.postMessage({command:e,args:t})},this.call=function(e,t,n){if(n){var r=this.callbackId++;this.callbacks[r]=n,t.push(r)}this.send(e,t)},this.emit=function(e,t){try{this.$worker.postMessage({event:e,data:{data:t.data}})}catch(n){console.error(n.stack)}},this.attachToDocument=function(e){this.$doc&&this.terminate(),this.$doc=e,this.call("setValue",[e.getValue()]),e.on("change",this.changeListener)},this.changeListener=function(e){this.deltaQueue||(this.deltaQueue=[],setTimeout(this.$sendDeltaQueue,0)),e.action=="insert"?this.deltaQueue.push(e.start,e.lines):this.deltaQueue.push(e.start,e.end)},this.$sendDeltaQueue=function(){var e=this.deltaQueue;if(!e)return;this.deltaQueue=null,e.length>50&&e.length>this.$doc.getLength()>>1?this.call("setValue",[this.$doc.getValue()]):this.emit("change",{data:e})},this.$workerBlob=function(e){var t="importScripts('"+i.qualifyURL(e)+"');";try{return new Blob([t],{type:"application/javascript"})}catch(n){var r=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder,s=new r;return s.append(t),s.getBlob("application/javascript")}}}).call(u.prototype);var a=function(e,t,n){this.$sendDeltaQueue=this.$sendDeltaQueue.bind(this),this.changeListener=this.changeListener.bind(this),this.callbackId=1,this.callbacks={},this.messageBuffer=[];var r=null,i=!1,u=Object.create(s),a=this;this.$worker={},this.$worker.terminate=function(){},this.$worker.postMessage=function(e){a.messageBuffer.push(e),r&&(i?setTimeout(f):f())},this.setEmitSync=function(e){i=e};var f=function(){var e=a.messageBuffer.shift();e.command?r[e.command].apply(r,e.args):e.event&&u._signal(e.event,e.data)};u.postMessage=function(e){a.onMessage({data:e})},u.callback=function(e,t){this.postMessage({type:"call",id:t,data:e})},u.emit=function(e,t){this.postMessage({type:"event",name:e,data:t})},o.loadModule(["worker",t],function(e){r=new e[n](u);while(a.messageBuffer.length)f()})};a.prototype=u.prototype,t.UIWorkerClient=a,t.WorkerClient=u}),define("ace/placeholder",["require","exports","module","ace/range","ace/lib/event_emitter","ace/lib/oop"],function(e,t,n){"use strict";var r=e("./range").Range,i=e("./lib/event_emitter").EventEmitter,s=e("./lib/oop"),o=function(e,t,n,r,i,s){var o=this;this.length=t,this.session=e,this.doc=e.getDocument(),this.mainClass=i,this.othersClass=s,this.$onUpdate=this.onUpdate.bind(this),this.doc.on("change",this.$onUpdate),this.$others=r,this.$onCursorChange=function(){setTimeout(function(){o.onCursorChange()})},this.$pos=n;var u=e.getUndoManager().$undoStack||e.getUndoManager().$undostack||{length:-1};this.$undoStackDepth=u.length,this.setup(),e.selection.on("changeCursor",this.$onCursorChange)};(function(){s.implement(this,i),this.setup=function(){var e=this,t=this.doc,n=this.session;this.selectionBefore=n.selection.toJSON(),n.selection.inMultiSelectMode&&n.selection.toSingleRange(),this.pos=t.createAnchor(this.$pos.row,this.$pos.column);var i=this.pos;i.$insertRight=!0,i.detach(),i.markerId=n.addMarker(new r(i.row,i.column,i.row,i.column+this.length),this.mainClass,null,!1),this.others=[],this.$others.forEach(function(n){var r=t.createAnchor(n.row,n.column);r.$insertRight=!0,r.detach(),e.others.push(r)}),n.setUndoSelect(!1)},this.showOtherMarkers=function(){if(this.othersActive)return;var e=this.session,t=this;this.othersActive=!0,this.others.forEach(function(n){n.markerId=e.addMarker(new r(n.row,n.column,n.row,n.column+t.length),t.othersClass,null,!1)})},this.hideOtherMarkers=function(){if(!this.othersActive)return;this.othersActive=!1;for(var e=0;e<this.others.length;e++)this.session.removeMarker(this.others[e].markerId)},this.onUpdate=function(e){if(this.$updating)return this.updateAnchors(e);var t=e;if(t.start.row!==t.end.row)return;if(t.start.row!==this.pos.row)return;this.$updating=!0;var n=e.action==="insert"?t.end.column-t.start.column:t.start.column-t.end.column,i=t.start.column>=this.pos.column&&t.start.column<=this.pos.column+this.length+1,s=t.start.column-this.pos.column;this.updateAnchors(e),i&&(this.length+=n);if(i&&!this.session.$fromUndo)if(e.action==="insert")for(var o=this.others.length-1;o>=0;o--){var u=this.others[o],a={row:u.row,column:u.column+s};this.doc.insertMergedLines(a,e.lines)}else if(e.action==="remove")for(var o=this.others.length-1;o>=0;o--){var u=this.others[o],a={row:u.row,column:u.column+s};this.doc.remove(new r(a.row,a.column,a.row,a.column-n))}this.$updating=!1,this.updateMarkers()},this.updateAnchors=function(e){this.pos.onChange(e);for(var t=this.others.length;t--;)this.others[t].onChange(e);this.updateMarkers()},this.updateMarkers=function(){if(this.$updating)return;var e=this,t=this.session,n=function(n,i){t.removeMarker(n.markerId),n.markerId=t.addMarker(new r(n.row,n.column,n.row,n.column+e.length),i,null,!1)};n(this.pos,this.mainClass);for(var i=this.others.length;i--;)n(this.others[i],this.othersClass)},this.onCursorChange=function(e){if(this.$updating||!this.session)return;var t=this.session.selection.getCursor();t.row===this.pos.row&&t.column>=this.pos.column&&t.column<=this.pos.column+this.length?(this.showOtherMarkers(),this._emit("cursorEnter",e)):(this.hideOtherMarkers(),this._emit("cursorLeave",e))},this.detach=function(){this.session.removeMarker(this.pos&&this.pos.markerId),this.hideOtherMarkers(),this.doc.removeEventListener("change",this.$onUpdate),this.session.selection.removeEventListener("changeCursor",this.$onCursorChange),this.session.setUndoSelect(!0),this.session=null},this.cancel=function(){if(this.$undoStackDepth===-1)return;var e=this.session.getUndoManager(),t=(e.$undoStack||e.$undostack).length-this.$undoStackDepth;for(var n=0;n<t;n++)e.undo(!0);this.selectionBefore&&this.session.selection.fromJSON(this.selectionBefore)}}).call(o.prototype),t.PlaceHolder=o}),define("ace/mouse/multi_select_handler",["require","exports","module","ace/lib/event","ace/lib/useragent"],function(e,t,n){function s(e,t){return e.row==t.row&&e.column==t.column}function o(e){var t=e.domEvent,n=t.altKey,o=t.shiftKey,u=t.ctrlKey,a=e.getAccelKey(),f=e.getButton();u&&i.isMac&&(f=t.button);if(e.editor.inMultiSelectMode&&f==2){e.editor.textInput.onContextMenu(e.domEvent);return}if(!u&&!n&&!a){f===0&&e.editor.inMultiSelectMode&&e.editor.exitMultiSelectMode();return}if(f!==0)return;var l=e.editor,c=l.selection,h=l.inMultiSelectMode,p=e.getDocumentPosition(),d=c.getCursor(),v=e.inSelection()||c.isEmpty()&&s(p,d),m=e.x,g=e.y,y=function(e){m=e.clientX,g=e.clientY},b=l.session,w=l.renderer.pixelToScreenCoordinates(m,g),E=w,S;if(l.$mouseHandler.$enableJumpToDef)u&&n||a&&n?S=o?"block":"add":n&&l.$blockSelectEnabled&&(S="block");else if(a&&!n){S="add";if(!h&&o)return}else n&&l.$blockSelectEnabled&&(S="block");S&&i.isMac&&t.ctrlKey&&l.$mouseHandler.cancelContextMenu();if(S=="add"){if(!h&&v)return;if(!h){var x=c.toOrientedRange();l.addSelectionMarker(x)}var T=c.rangeList.rangeAtPoint(p);l.$blockScrolling++,l.inVirtualSelectionMode=!0,o&&(T=null,x=c.ranges[0]||x,l.removeSelectionMarker(x)),l.once("mouseup",function(){var e=c.toOrientedRange();T&&e.isEmpty()&&s(T.cursor,e.cursor)?c.substractPoint(e.cursor):(o?c.substractPoint(x.cursor):x&&(l.removeSelectionMarker(x),c.addRange(x)),c.addRange(e)),l.$blockScrolling--,l.inVirtualSelectionMode=!1})}else if(S=="block"){e.stop(),l.inVirtualSelectionMode=!0;var N,C=[],k=function(){var e=l.renderer.pixelToScreenCoordinates(m,g),t=b.screenToDocumentPosition(e.row,e.column);if(s(E,e)&&s(t,c.lead))return;E=e,l.$blockScrolling++,l.selection.moveToPosition(t),l.renderer.scrollCursorIntoView(),l.removeSelectionMarkers(C),C=c.rectangularRangeBlock(E,w),l.$mouseHandler.$clickSelection&&C.length==1&&C[0].isEmpty()&&(C[0]=l.$mouseHandler.$clickSelection.clone()),C.forEach(l.addSelectionMarker,l),l.updateSelectionMarkers(),l.$blockScrolling--};l.$blockScrolling++,h&&!a?c.toSingleRange():!h&&a&&(N=c.toOrientedRange(),l.addSelectionMarker(N)),o?w=b.documentToScreenPosition(c.lead):c.moveToPosition(p),l.$blockScrolling--,E={row:-1,column:-1};var L=function(e){clearInterval(O),l.removeSelectionMarkers(C),C.length||(C=[c.toOrientedRange()]),l.$blockScrolling++,N&&(l.removeSelectionMarker(N),c.toSingleRange(N));for(var t=0;t<C.length;t++)c.addRange(C[t]);l.inVirtualSelectionMode=!1,l.$mouseHandler.$clickSelection=null,l.$blockScrolling--},A=k;r.capture(l.container,y,L);var O=setInterval(function(){A()},20);return e.preventDefault()}}var r=e("../lib/event"),i=e("../lib/useragent");t.onMouseDown=o}),define("ace/commands/multi_select_commands",["require","exports","module","ace/keyboard/hash_handler"],function(e,t,n){t.defaultCommands=[{name:"addCursorAbove",exec:function(e){e.selectMoreLines(-1)},bindKey:{win:"Ctrl-Alt-Up",mac:"Ctrl-Alt-Up"},scrollIntoView:"cursor",readOnly:!0},{name:"addCursorBelow",exec:function(e){e.selectMoreLines(1)},bindKey:{win:"Ctrl-Alt-Down",mac:"Ctrl-Alt-Down"},scrollIntoView:"cursor",readOnly:!0},{name:"addCursorAboveSkipCurrent",exec:function(e){e.selectMoreLines(-1,!0)},bindKey:{win:"Ctrl-Alt-Shift-Up",mac:"Ctrl-Alt-Shift-Up"},scrollIntoView:"cursor",readOnly:!0},{name:"addCursorBelowSkipCurrent",exec:function(e){e.selectMoreLines(1,!0)},bindKey:{win:"Ctrl-Alt-Shift-Down",mac:"Ctrl-Alt-Shift-Down"},scrollIntoView:"cursor",readOnly:!0},{name:"selectMoreBefore",exec:function(e){e.selectMore(-1)},bindKey:{win:"Ctrl-Alt-Left",mac:"Ctrl-Alt-Left"},scrollIntoView:"cursor",readOnly:!0},{name:"selectMoreAfter",exec:function(e){e.selectMore(1)},bindKey:{win:"Ctrl-Alt-Right",mac:"Ctrl-Alt-Right"},scrollIntoView:"cursor",readOnly:!0},{name:"selectNextBefore",exec:function(e){e.selectMore(-1,!0)},bindKey:{win:"Ctrl-Alt-Shift-Left",mac:"Ctrl-Alt-Shift-Left"},scrollIntoView:"cursor",readOnly:!0},{name:"selectNextAfter",exec:function(e){e.selectMore(1,!0)},bindKey:{win:"Ctrl-Alt-Shift-Right",mac:"Ctrl-Alt-Shift-Right"},scrollIntoView:"cursor",readOnly:!0},{name:"splitIntoLines",exec:function(e){e.multiSelect.splitIntoLines()},bindKey:{win:"Ctrl-Alt-L",mac:"Ctrl-Alt-L"},readOnly:!0},{name:"alignCursors",exec:function(e){e.alignCursors()},bindKey:{win:"Ctrl-Alt-A",mac:"Ctrl-Alt-A"},scrollIntoView:"cursor"},{name:"findAll",exec:function(e){e.findAll()},bindKey:{win:"Ctrl-Alt-K",mac:"Ctrl-Alt-G"},scrollIntoView:"cursor",readOnly:!0}],t.multiSelectCommands=[{name:"singleSelection",bindKey:"esc",exec:function(e){e.exitMultiSelectMode()},scrollIntoView:"cursor",readOnly:!0,isAvailable:function(e){return e&&e.inMultiSelectMode}}];var r=e("../keyboard/hash_handler").HashHandler;t.keyboardHandler=new r(t.multiSelectCommands)}),define("ace/multi_select",["require","exports","module","ace/range_list","ace/range","ace/selection","ace/mouse/multi_select_handler","ace/lib/event","ace/lib/lang","ace/commands/multi_select_commands","ace/search","ace/edit_session","ace/editor","ace/config"],function(e,t,n){function h(e,t,n){return c.$options.wrap=!0,c.$options.needle=t,c.$options.backwards=n==-1,c.find(e)}function v(e,t){return e.row==t.row&&e.column==t.column}function m(e){if(e.$multiselectOnSessionChange)return;e.$onAddRange=e.$onAddRange.bind(e),e.$onRemoveRange=e.$onRemoveRange.bind(e),e.$onMultiSelect=e.$onMultiSelect.bind(e),e.$onSingleSelect=e.$onSingleSelect.bind(e),e.$multiselectOnSessionChange=t.onSessionChange.bind(e),e.$checkMultiselectChange=e.$checkMultiselectChange.bind(e),e.$multiselectOnSessionChange(e),e.on("changeSession",e.$multiselectOnSessionChange),e.on("mousedown",o),e.commands.addCommands(f.defaultCommands),g(e)}function g(e){function r(t){n&&(e.renderer.setMouseCursor(""),n=!1)}var t=e.textInput.getElement(),n=!1;u.addListener(t,"keydown",function(t){var i=t.keyCode==18&&!(t.ctrlKey||t.shiftKey||t.metaKey);e.$blockSelectEnabled&&i?n||(e.renderer.setMouseCursor("crosshair"),n=!0):n&&r()}),u.addListener(t,"keyup",r),u.addListener(t,"blur",r)}var r=e("./range_list").RangeList,i=e("./range").Range,s=e("./selection").Selection,o=e("./mouse/multi_select_handler").onMouseDown,u=e("./lib/event"),a=e("./lib/lang"),f=e("./commands/multi_select_commands");t.commands=f.defaultCommands.concat(f.multiSelectCommands);var l=e("./search").Search,c=new l,p=e("./edit_session").EditSession;(function(){this.getSelectionMarkers=function(){return this.$selectionMarkers}}).call(p.prototype),function(){this.ranges=null,this.rangeList=null,this.addRange=function(e,t){if(!e)return;if(!this.inMultiSelectMode&&this.rangeCount===0){var n=this.toOrientedRange();this.rangeList.add(n),this.rangeList.add(e);if(this.rangeList.ranges.length!=2)return this.rangeList.removeAll(),t||this.fromOrientedRange(e);this.rangeList.removeAll(),this.rangeList.add(n),this.$onAddRange(n)}e.cursor||(e.cursor=e.end);var r=this.rangeList.add(e);return this.$onAddRange(e),r.length&&this.$onRemoveRange(r),this.rangeCount>1&&!this.inMultiSelectMode&&(this._signal("multiSelect"),this.inMultiSelectMode=!0,this.session.$undoSelect=!1,this.rangeList.attach(this.session)),t||this.fromOrientedRange(e)},this.toSingleRange=function(e){e=e||this.ranges[0];var t=this.rangeList.removeAll();t.length&&this.$onRemoveRange(t),e&&this.fromOrientedRange(e)},this.substractPoint=function(e){var t=this.rangeList.substractPoint(e);if(t)return this.$onRemoveRange(t),t[0]},this.mergeOverlappingRanges=function(){var e=this.rangeList.merge();e.length?this.$onRemoveRange(e):this.ranges[0]&&this.fromOrientedRange(this.ranges[0])},this.$onAddRange=function(e){this.rangeCount=this.rangeList.ranges.length,this.ranges.unshift(e),this._signal("addRange",{range:e})},this.$onRemoveRange=function(e){this.rangeCount=this.rangeList.ranges.length;if(this.rangeCount==1&&this.inMultiSelectMode){var t=this.rangeList.ranges.pop();e.push(t),this.rangeCount=0}for(var n=e.length;n--;){var r=this.ranges.indexOf(e[n]);this.ranges.splice(r,1)}this._signal("removeRange",{ranges:e}),this.rangeCount===0&&this.inMultiSelectMode&&(this.inMultiSelectMode=!1,this._signal("singleSelect"),this.session.$undoSelect=!0,this.rangeList.detach(this.session)),t=t||this.ranges[0],t&&!t.isEqual(this.getRange())&&this.fromOrientedRange(t)},this.$initRangeList=function(){if(this.rangeList)return;this.rangeList=new r,this.ranges=[],this.rangeCount=0},this.getAllRanges=function(){return this.rangeCount?this.rangeList.ranges.concat():[this.getRange()]},this.splitIntoLines=function(){if(this.rangeCount>1){var e=this.rangeList.ranges,t=e[e.length-1],n=i.fromPoints(e[0].start,t.end);this.toSingleRange(),this.setSelectionRange(n,t.cursor==t.start)}else{var n=this.getRange(),r=this.isBackwards(),s=n.start.row,o=n.end.row;if(s==o){if(r)var u=n.end,a=n.start;else var u=n.start,a=n.end;this.addRange(i.fromPoints(a,a)),this.addRange(i.fromPoints(u,u));return}var f=[],l=this.getLineRange(s,!0);l.start.column=n.start.column,f.push(l);for(var c=s+1;c<o;c++)f.push(this.getLineRange(c,!0));l=this.getLineRange(o,!0),l.end.column=n.end.column,f.push(l),f.forEach(this.addRange,this)}},this.toggleBlockSelection=function(){if(this.rangeCount>1){var e=this.rangeList.ranges,t=e[e.length-1],n=i.fromPoints(e[0].start,t.end);this.toSingleRange(),this.setSelectionRange(n,t.cursor==t.start)}else{var r=this.session.documentToScreenPosition(this.selectionLead),s=this.session.documentToScreenPosition(this.selectionAnchor),o=this.rectangularRangeBlock(r,s);o.forEach(this.addRange,this)}},this.rectangularRangeBlock=function(e,t,n){var r=[],s=e.column<t.column;if(s)var o=e.column,u=t.column;else var o=t.column,u=e.column;var a=e.row<t.row;if(a)var f=e.row,l=t.row;else var f=t.row,l=e.row;o<0&&(o=0),f<0&&(f=0),f==l&&(n=!0);for(var c=f;c<=l;c++){var h=i.fromPoints(this.session.screenToDocumentPosition(c,o),this.session.screenToDocumentPosition(c,u));if(h.isEmpty()){if(p&&v(h.end,p))break;var p=h.end}h.cursor=s?h.start:h.end,r.push(h)}a&&r.reverse();if(!n){var d=r.length-1;while(r[d].isEmpty()&&d>0)d--;if(d>0){var m=0;while(r[m].isEmpty())m++}for(var g=d;g>=m;g--)r[g].isEmpty()&&r.splice(g,1)}return r}}.call(s.prototype);var d=e("./editor").Editor;(function(){this.updateSelectionMarkers=function(){this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.addSelectionMarker=function(e){e.cursor||(e.cursor=e.end);var t=this.getSelectionStyle();return e.marker=this.session.addMarker(e,"ace_selection",t),this.session.$selectionMarkers.push(e),this.session.selectionMarkerCount=this.session.$selectionMarkers.length,e},this.removeSelectionMarker=function(e){if(!e.marker)return;this.session.removeMarker(e.marker);var t=this.session.$selectionMarkers.indexOf(e);t!=-1&&this.session.$selectionMarkers.splice(t,1),this.session.selectionMarkerCount=this.session.$selectionMarkers.length},this.removeSelectionMarkers=function(e){var t=this.session.$selectionMarkers;for(var n=e.length;n--;){var r=e[n];if(!r.marker)continue;this.session.removeMarker(r.marker);var i=t.indexOf(r);i!=-1&&t.splice(i,1)}this.session.selectionMarkerCount=t.length},this.$onAddRange=function(e){this.addSelectionMarker(e.range),this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.$onRemoveRange=function(e){this.removeSelectionMarkers(e.ranges),this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.$onMultiSelect=function(e){if(this.inMultiSelectMode)return;this.inMultiSelectMode=!0,this.setStyle("ace_multiselect"),this.keyBinding.addKeyboardHandler(f.keyboardHandler),this.commands.setDefaultHandler("exec",this.$onMultiSelectExec),this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.$onSingleSelect=function(e){if(this.session.multiSelect.inVirtualMode)return;this.inMultiSelectMode=!1,this.unsetStyle("ace_multiselect"),this.keyBinding.removeKeyboardHandler(f.keyboardHandler),this.commands.removeDefaultHandler("exec",this.$onMultiSelectExec),this.renderer.updateCursor(),this.renderer.updateBackMarkers(),this._emit("changeSelection")},this.$onMultiSelectExec=function(e){var t=e.command,n=e.editor;if(!n.multiSelect)return;if(!t.multiSelectAction){var r=t.exec(n,e.args||{});n.multiSelect.addRange(n.multiSelect.toOrientedRange()),n.multiSelect.mergeOverlappingRanges()}else t.multiSelectAction=="forEach"?r=n.forEachSelection(t,e.args):t.multiSelectAction=="forEachLine"?r=n.forEachSelection(t,e.args,!0):t.multiSelectAction=="single"?(n.exitMultiSelectMode(),r=t.exec(n,e.args||{})):r=t.multiSelectAction(n,e.args||{});return r},this.forEachSelection=function(e,t,n){if(this.inVirtualSelectionMode)return;var r=n&&n.keepOrder,i=n==1||n&&n.$byLines,o=this.session,u=this.selection,a=u.rangeList,f=(r?u:a).ranges,l;if(!f.length)return e.exec?e.exec(this,t||{}):e(this,t||{});var c=u._eventRegistry;u._eventRegistry={};var h=new s(o);this.inVirtualSelectionMode=!0;for(var p=f.length;p--;){if(i)while(p>0&&f[p].start.row==f[p-1].end.row)p--;h.fromOrientedRange(f[p]),h.index=p,this.selection=o.selection=h;var d=e.exec?e.exec(this,t||{}):e(this,t||{});!l&&d!==undefined&&(l=d),h.toOrientedRange(f[p])}h.detach(),this.selection=o.selection=u,this.inVirtualSelectionMode=!1,u._eventRegistry=c,u.mergeOverlappingRanges();var v=this.renderer.$scrollAnimation;return this.onCursorChange(),this.onSelectionChange(),v&&v.from==v.to&&this.renderer.animateScrolling(v.from),l},this.exitMultiSelectMode=function(){if(!this.inMultiSelectMode||this.inVirtualSelectionMode)return;this.multiSelect.toSingleRange()},this.getSelectedText=function(){var e="";if(this.inMultiSelectMode&&!this.inVirtualSelectionMode){var t=this.multiSelect.rangeList.ranges,n=[];for(var r=0;r<t.length;r++)n.push(this.session.getTextRange(t[r]));var i=this.session.getDocument().getNewLineCharacter();e=n.join(i),e.length==(n.length-1)*i.length&&(e="")}else this.selection.isEmpty()||(e=this.session.getTextRange(this.getSelectionRange()));return e},this.$checkMultiselectChange=function(e,t){if(this.inMultiSelectMode&&!this.inVirtualSelectionMode){var n=this.multiSelect.ranges[0];if(this.multiSelect.isEmpty()&&t==this.multiSelect.anchor)return;var r=t==this.multiSelect.anchor?n.cursor==n.start?n.end:n.start:n.cursor;(r.row!=t.row||this.session.$clipPositionToDocument(r.row,r.column).column!=t.column)&&this.multiSelect.toSingleRange(this.multiSelect.toOrientedRange())}},this.findAll=function(e,t,n){t=t||{},t.needle=e||t.needle;if(t.needle==undefined){var r=this.selection.isEmpty()?this.selection.getWordRange():this.selection.getRange();t.needle=this.session.getTextRange(r)}this.$search.set(t);var i=this.$search.findAll(this.session);if(!i.length)return 0;this.$blockScrolling+=1;var s=this.multiSelect;n||s.toSingleRange(i[0]);for(var o=i.length;o--;)s.addRange(i[o],!0);return r&&s.rangeList.rangeAtPoint(r.start)&&s.addRange(r,!0),this.$blockScrolling-=1,i.length},this.selectMoreLines=function(e,t){var n=this.selection.toOrientedRange(),r=n.cursor==n.end,s=this.session.documentToScreenPosition(n.cursor);this.selection.$desiredColumn&&(s.column=this.selection.$desiredColumn);var o=this.session.screenToDocumentPosition(s.row+e,s.column);if(!n.isEmpty())var u=this.session.documentToScreenPosition(r?n.end:n.start),a=this.session.screenToDocumentPosition(u.row+e,u.column);else var a=o;if(r){var f=i.fromPoints(o,a);f.cursor=f.start}else{var f=i.fromPoints(a,o);f.cursor=f.end}f.desiredColumn=s.column;if(!this.selection.inMultiSelectMode)this.selection.addRange(n);else if(t)var l=n.cursor;this.selection.addRange(f),l&&this.selection.substractPoint(l)},this.transposeSelections=function(e){var t=this.session,n=t.multiSelect,r=n.ranges;for(var i=r.length;i--;){var s=r[i];if(s.isEmpty()){var o=t.getWordRange(s.start.row,s.start.column);s.start.row=o.start.row,s.start.column=o.start.column,s.end.row=o.end.row,s.end.column=o.end.column}}n.mergeOverlappingRanges();var u=[];for(var i=r.length;i--;){var s=r[i];u.unshift(t.getTextRange(s))}e<0?u.unshift(u.pop()):u.push(u.shift());for(var i=r.length;i--;){var s=r[i],o=s.clone();t.replace(s,u[i]),s.start.row=o.start.row,s.start.column=o.start.column}},this.selectMore=function(e,t,n){var r=this.session,i=r.multiSelect,s=i.toOrientedRange();if(s.isEmpty()){s=r.getWordRange(s.start.row,s.start.column),s.cursor=e==-1?s.start:s.end,this.multiSelect.addRange(s);if(n)return}var o=r.getTextRange(s),u=h(r,o,e);u&&(u.cursor=e==-1?u.start:u.end,this.$blockScrolling+=1,this.session.unfold(u),this.multiSelect.addRange(u),this.$blockScrolling-=1,this.renderer.scrollCursorIntoView(null,.5)),t&&this.multiSelect.substractPoint(s.cursor)},this.alignCursors=function(){var e=this.session,t=e.multiSelect,n=t.ranges,r=-1,s=n.filter(function(e){if(e.cursor.row==r)return!0;r=e.cursor.row});if(!n.length||s.length==n.length-1){var o=this.selection.getRange(),u=o.start.row,f=o.end.row,l=u==f;if(l){var c=this.session.getLength(),h;do h=this.session.getLine(f);while(/[=:]/.test(h)&&++f<c);do h=this.session.getLine(u);while(/[=:]/.test(h)&&--u>0);u<0&&(u=0),f>=c&&(f=c-1)}var p=this.session.removeFullLines(u,f);p=this.$reAlignText(p,l),this.session.insert({row:u,column:0},p.join("\n")+"\n"),l||(o.start.column=0,o.end.column=p[p.length-1].length),this.selection.setRange(o)}else{s.forEach(function(e){t.substractPoint(e.cursor)});var d=0,v=Infinity,m=n.map(function(t){var n=t.cursor,r=e.getLine(n.row),i=r.substr(n.column).search(/\S/g);return i==-1&&(i=0),n.column>d&&(d=n.column),i<v&&(v=i),i});n.forEach(function(t,n){var r=t.cursor,s=d-r.column,o=m[n]-v;s>o?e.insert(r,a.stringRepeat(" ",s-o)):e.remove(new i(r.row,r.column,r.row,r.column-s+o)),t.start.column=t.end.column=d,t.start.row=t.end.row=r.row,t.cursor=t.end}),t.fromOrientedRange(n[0]),this.renderer.updateCursor(),this.renderer.updateBackMarkers()}},this.$reAlignText=function(e,t){function u(e){return a.stringRepeat(" ",e)}function f(e){return e[2]?u(i)+e[2]+u(s-e[2].length+o)+e[4].replace(/^([=:])\s+/,"$1 "):e[0]}function l(e){return e[2]?u(i+s-e[2].length)+e[2]+u(o," ")+e[4].replace(/^([=:])\s+/,"$1 "):e[0]}function c(e){return e[2]?u(i)+e[2]+u(o)+e[4].replace(/^([=:])\s+/,"$1 "):e[0]}var n=!0,r=!0,i,s,o;return e.map(function(e){var t=e.match(/(\s*)(.*?)(\s*)([=:].*)/);return t?i==null?(i=t[1].length,s=t[2].length,o=t[3].length,t):(i+s+o!=t[1].length+t[2].length+t[3].length&&(r=!1),i!=t[1].length&&(n=!1),i>t[1].length&&(i=t[1].length),s<t[2].length&&(s=t[2].length),o>t[3].length&&(o=t[3].length),t):[e]}).map(t?f:n?r?l:f:c)}}).call(d.prototype),t.onSessionChange=function(e){var t=e.session;t&&!t.multiSelect&&(t.$selectionMarkers=[],t.selection.$initRangeList(),t.multiSelect=t.selection),this.multiSelect=t&&t.multiSelect;var n=e.oldSession;n&&(n.multiSelect.off("addRange",this.$onAddRange),n.multiSelect.off("removeRange",this.$onRemoveRange),n.multiSelect.off("multiSelect",this.$onMultiSelect),n.multiSelect.off("singleSelect",this.$onSingleSelect),n.multiSelect.lead.off("change",this.$checkMultiselectChange),n.multiSelect.anchor.off("change",this.$checkMultiselectChange)),t&&(t.multiSelect.on("addRange",this.$onAddRange),t.multiSelect.on("removeRange",this.$onRemoveRange),t.multiSelect.on("multiSelect",this.$onMultiSelect),t.multiSelect.on("singleSelect",this.$onSingleSelect),t.multiSelect.lead.on("change",this.$checkMultiselectChange),t.multiSelect.anchor.on("change",this.$checkMultiselectChange)),t&&this.inMultiSelectMode!=t.selection.inMultiSelectMode&&(t.selection.inMultiSelectMode?this.$onMultiSelect():this.$onSingleSelect())},t.MultiSelect=m,e("./config").defineOptions(d.prototype,"editor",{enableMultiselect:{set:function(e){m(this),e?(this.on("changeSession",this.$multiselectOnSessionChange),this.on("mousedown",o)):(this.off("changeSession",this.$multiselectOnSessionChange),this.off("mousedown",o))},value:!0},enableBlockSelect:{set:function(e){this.$blockSelectEnabled=e},value:!0}})}),define("ace/mode/folding/fold_mode",["require","exports","module","ace/range"],function(e,t,n){"use strict";var r=e("../../range").Range,i=t.FoldMode=function(){};(function(){this.foldingStartMarker=null,this.foldingStopMarker=null,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);return this.foldingStartMarker.test(r)?"start":t=="markbeginend"&&this.foldingStopMarker&&this.foldingStopMarker.test(r)?"end":""},this.getFoldWidgetRange=function(e,t,n){return null},this.indentationBlock=function(e,t,n){var i=/\S/,s=e.getLine(t),o=s.search(i);if(o==-1)return;var u=n||s.length,a=e.getLength(),f=t,l=t;while(++t<a){var c=e.getLine(t).search(i);if(c==-1)continue;if(c<=o)break;l=t}if(l>f){var h=e.getLine(l).length;return new r(f,u,l,h)}},this.openingBracketBlock=function(e,t,n,i,s){var o={row:n,column:i+1},u=e.$findClosingBracket(t,o,s);if(!u)return;var a=e.foldWidgets[u.row];return a==null&&(a=e.getFoldWidget(u.row)),a=="start"&&u.row>o.row&&(u.row--,u.column=e.getLine(u.row).length),r.fromPoints(o,u)},this.closingBracketBlock=function(e,t,n,i,s){var o={row:n,column:i},u=e.$findOpeningBracket(t,o);if(!u)return;return u.column++,o.column--,r.fromPoints(u,o)}}).call(i.prototype)}),define("ace/theme/textmate",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";t.isDark=!1,t.cssClass="ace-tm",t.cssText='.ace-tm .ace_gutter {background: #f0f0f0;color: #333;}.ace-tm .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-tm .ace_fold {background-color: #6B72E6;}.ace-tm {background-color: #FFFFFF;color: black;}.ace-tm .ace_cursor {color: black;}.ace-tm .ace_invisible {color: rgb(191, 191, 191);}.ace-tm .ace_storage,.ace-tm .ace_keyword {color: blue;}.ace-tm .ace_constant {color: rgb(197, 6, 11);}.ace-tm .ace_constant.ace_buildin {color: rgb(88, 72, 246);}.ace-tm .ace_constant.ace_language {color: rgb(88, 92, 246);}.ace-tm .ace_constant.ace_library {color: rgb(6, 150, 14);}.ace-tm .ace_invalid {background-color: rgba(255, 0, 0, 0.1);color: red;}.ace-tm .ace_support.ace_function {color: rgb(60, 76, 114);}.ace-tm .ace_support.ace_constant {color: rgb(6, 150, 14);}.ace-tm .ace_support.ace_type,.ace-tm .ace_support.ace_class {color: rgb(109, 121, 222);}.ace-tm .ace_keyword.ace_operator {color: rgb(104, 118, 135);}.ace-tm .ace_string {color: rgb(3, 106, 7);}.ace-tm .ace_comment {color: rgb(76, 136, 107);}.ace-tm .ace_comment.ace_doc {color: rgb(0, 102, 255);}.ace-tm .ace_comment.ace_doc.ace_tag {color: rgb(128, 159, 191);}.ace-tm .ace_constant.ace_numeric {color: rgb(0, 0, 205);}.ace-tm .ace_variable {color: rgb(49, 132, 149);}.ace-tm .ace_xml-pe {color: rgb(104, 104, 91);}.ace-tm .ace_entity.ace_name.ace_function {color: #0000A2;}.ace-tm .ace_heading {color: rgb(12, 7, 255);}.ace-tm .ace_list {color:rgb(185, 6, 144);}.ace-tm .ace_meta.ace_tag {color:rgb(0, 22, 142);}.ace-tm .ace_string.ace_regex {color: rgb(255, 0, 0)}.ace-tm .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-tm.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px white;}.ace-tm .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-tm .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-tm .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-tm .ace_marker-layer .ace_active-line {background: rgba(0, 0, 0, 0.07);}.ace-tm .ace_gutter-active-line {background-color : #dcdcdc;}.ace-tm .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-tm .ace_indent-guide {background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y;}';var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)}),define("ace/line_widgets",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/range"],function(e,t,n){"use strict";function o(e){this.session=e,this.session.widgetManager=this,this.session.getRowLength=this.getRowLength,this.session.$getWidgetScreenLength=this.$getWidgetScreenLength,this.updateOnChange=this.updateOnChange.bind(this),this.renderWidgets=this.renderWidgets.bind(this),this.measureWidgets=this.measureWidgets.bind(this),this.session._changedWidgets=[],this.$onChangeEditor=this.$onChangeEditor.bind(this),this.session.on("change",this.updateOnChange),this.session.on("changeFold",this.updateOnFold),this.session.on("changeEditor",this.$onChangeEditor)}var r=e("./lib/oop"),i=e("./lib/dom"),s=e("./range").Range;(function(){this.getRowLength=function(e){var t;return this.lineWidgets?t=this.lineWidgets[e]&&this.lineWidgets[e].rowCount||0:t=0,!this.$useWrapMode||!this.$wrapData[e]?1+t:this.$wrapData[e].length+1+t},this.$getWidgetScreenLength=function(){var e=0;return this.lineWidgets.forEach(function(t){t&&t.rowCount&&!t.hidden&&(e+=t.rowCount)}),e},this.$onChangeEditor=function(e){this.attach(e.editor)},this.attach=function(e){e&&e.widgetManager&&e.widgetManager!=this&&e.widgetManager.detach();if(this.editor==e)return;this.detach(),this.editor=e,e&&(e.widgetManager=this,e.renderer.on("beforeRender",this.measureWidgets),e.renderer.on("afterRender",this.renderWidgets))},this.detach=function(e){var t=this.editor;if(!t)return;this.editor=null,t.widgetManager=null,t.renderer.off("beforeRender",this.measureWidgets),t.renderer.off("afterRender",this.renderWidgets);var n=this.session.lineWidgets;n&&n.forEach(function(e){e&&e.el&&e.el.parentNode&&(e._inDocument=!1,e.el.parentNode.removeChild(e.el))})},this.updateOnFold=function(e,t){var n=t.lineWidgets;if(!n||!e.action)return;var r=e.data,i=r.start.row,s=r.end.row,o=e.action=="add";for(var u=i+1;u<s;u++)n[u]&&(n[u].hidden=o);n[s]&&(o?n[i]?n[s].hidden=o:n[i]=n[s]:(n[i]==n[s]&&(n[i]=undefined),n[s].hidden=o))},this.updateOnChange=function(e){var t=this.session.lineWidgets;if(!t)return;var n=e.start.row,r=e.end.row-n;if(r!==0)if(e.action=="remove"){var i=t.splice(n+1,r);i.forEach(function(e){e&&this.removeLineWidget(e)},this),this.$updateRows()}else{var s=new Array(r);s.unshift(n,0),t.splice.apply(t,s),this.$updateRows()}},this.$updateRows=function(){var e=this.session.lineWidgets;if(!e)return;var t=!0;e.forEach(function(e,n){if(e){t=!1,e.row=n;while(e.$oldWidget)e.$oldWidget.row=n,e=e.$oldWidget}}),t&&(this.session.lineWidgets=null)},this.addLineWidget=function(e){this.session.lineWidgets||(this.session.lineWidgets=new Array(this.session.getLength()));var t=this.session.lineWidgets[e.row];t&&(e.$oldWidget=t,t.el&&t.el.parentNode&&(t.el.parentNode.removeChild(t.el),t._inDocument=!1)),this.session.lineWidgets[e.row]=e,e.session=this.session;var n=this.editor.renderer;e.html&&!e.el&&(e.el=i.createElement("div"),e.el.innerHTML=e.html),e.el&&(i.addCssClass(e.el,"ace_lineWidgetContainer"),e.el.style.position="absolute",e.el.style.zIndex=5,n.container.appendChild(e.el),e._inDocument=!0),e.coverGutter||(e.el.style.zIndex=3),e.pixelHeight||(e.pixelHeight=e.el.offsetHeight),e.rowCount==null&&(e.rowCount=e.pixelHeight/n.layerConfig.lineHeight);var r=this.session.getFoldAt(e.row,0);e.$fold=r;if(r){var s=this.session.lineWidgets;e.row==r.end.row&&!s[r.start.row]?s[r.start.row]=e:e.hidden=!0}return this.session._emit("changeFold",{data:{start:{row:e.row}}}),this.$updateRows(),this.renderWidgets(null,n),this.onWidgetChanged(e),e},this.removeLineWidget=function(e){e._inDocument=!1,e.session=null,e.el&&e.el.parentNode&&e.el.parentNode.removeChild(e.el);if(e.editor&&e.editor.destroy)try{e.editor.destroy()}catch(t){}if(this.session.lineWidgets){var n=this.session.lineWidgets[e.row];if(n==e)this.session.lineWidgets[e.row]=e.$oldWidget,e.$oldWidget&&this.onWidgetChanged(e.$oldWidget);else while(n){if(n.$oldWidget==e){n.$oldWidget=e.$oldWidget;break}n=n.$oldWidget}}this.session._emit("changeFold",{data:{start:{row:e.row}}}),this.$updateRows()},this.getWidgetsAtRow=function(e){var t=this.session.lineWidgets,n=t&&t[e],r=[];while(n)r.push(n),n=n.$oldWidget;return r},this.onWidgetChanged=function(e){this.session._changedWidgets.push(e),this.editor&&this.editor.renderer.updateFull()},this.measureWidgets=function(e,t){var n=this.session._changedWidgets,r=t.layerConfig;if(!n||!n.length)return;var i=Infinity;for(var s=0;s<n.length;s++){var o=n[s];if(!o||!o.el)continue;if(o.session!=this.session)continue;if(!o._inDocument){if(this.session.lineWidgets[o.row]!=o)continue;o._inDocument=!0,t.container.appendChild(o.el)}o.h=o.el.offsetHeight,o.fixedWidth||(o.w=o.el.offsetWidth,o.screenWidth=Math.ceil(o.w/r.characterWidth));var u=o.h/r.lineHeight;o.coverLine&&(u-=this.session.getRowLineCount(o.row),u<0&&(u=0)),o.rowCount!=u&&(o.rowCount=u,o.row<i&&(i=o.row))}i!=Infinity&&(this.session._emit("changeFold",{data:{start:{row:i}}}),this.session.lineWidgetWidth=null),this.session._changedWidgets=[]},this.renderWidgets=function(e,t){var n=t.layerConfig,r=this.session.lineWidgets;if(!r)return;var i=Math.min(this.firstRow,n.firstRow),s=Math.max(this.lastRow,n.lastRow,r.length);while(i>0&&!r[i])i--;this.firstRow=n.firstRow,this.lastRow=n.lastRow,t.$cursorLayer.config=n;for(var o=i;o<=s;o++){var u=r[o];if(!u||!u.el)continue;if(u.hidden){u.el.style.top=-100-(u.pixelHeight||0)+"px";continue}u._inDocument||(u._inDocument=!0,t.container.appendChild(u.el));var a=t.$cursorLayer.getPixelPosition({row:o,column:0},!0).top;u.coverLine||(a+=n.lineHeight*this.session.getRowLineCount(u.row)),u.el.style.top=a-n.offset+"px";var f=u.coverGutter?0:t.gutterWidth;u.fixedWidth||(f-=t.scrollLeft),u.el.style.left=f+"px",u.fullWidth&&u.screenWidth&&(u.el.style.minWidth=n.width+2*n.padding+"px"),u.fixedWidth?u.el.style.right=t.scrollBar.getWidth()+"px":u.el.style.right=""}}}).call(o.prototype),t.LineWidgets=o}),define("ace/ext/error_marker",["require","exports","module","ace/line_widgets","ace/lib/dom","ace/range"],function(e,t,n){"use strict";function o(e,t,n){var r=0,i=e.length-1;while(r<=i){var s=r+i>>1,o=n(t,e[s]);if(o>0)r=s+1;else{if(!(o<0))return s;i=s-1}}return-(r+1)}function u(e,t,n){var r=e.getAnnotations().sort(s.comparePoints);if(!r.length)return;var i=o(r,{row:t,column:-1},s.comparePoints);i<0&&(i=-i-1),i>=r.length?i=n>0?0:r.length-1:i===0&&n<0&&(i=r.length-1);var u=r[i];if(!u||!n)return;if(u.row===t){do u=r[i+=n];while(u&&u.row===t);if(!u)return r.slice()}var a=[];t=u.row;do a[n<0?"unshift":"push"](u),u=r[i+=n];while(u&&u.row==t);return a.length&&a}var r=e("../line_widgets").LineWidgets,i=e("../lib/dom"),s=e("../range").Range;t.showErrorMarker=function(e,t){var n=e.session;n.widgetManager||(n.widgetManager=new r(n),n.widgetManager.attach(e));var s=e.getCursorPosition(),o=s.row,a=n.widgetManager.getWidgetsAtRow(o).filter(function(e){return e.type=="errorMarker"})[0];a?a.destroy():o-=t;var f=u(n,o,t),l;if(f){var c=f[0];s.column=(c.pos&&typeof c.column!="number"?c.pos.sc:c.column)||0,s.row=c.row,l=e.renderer.$gutterLayer.$annotations[s.row]}else{if(a)return;l={text:["Looks good!"],className:"ace_ok"}}e.session.unfold(s.row),e.selection.moveToPosition(s);var h={row:s.row,fixedWidth:!0,coverGutter:!0,el:i.createElement("div"),type:"errorMarker"},p=h.el.appendChild(i.createElement("div")),d=h.el.appendChild(i.createElement("div"));d.className="error_widget_arrow "+l.className;var v=e.renderer.$cursorLayer.getPixelPosition(s).left;d.style.left=v+e.renderer.gutterWidth-5+"px",h.el.className="error_widget_wrapper",p.className="error_widget "+l.className,p.innerHTML=l.text.join("<br>"),p.appendChild(i.createElement("div"));var m=function(e,t,n){if(t===0&&(n==="esc"||n==="return"))return h.destroy(),{command:"null"}};h.destroy=function(){if(e.$mouseHandler.isMousePressed)return;e.keyBinding.removeKeyboardHandler(m),n.widgetManager.removeLineWidget(h),e.off("changeSelection",h.destroy),e.off("changeSession",h.destroy),e.off("mouseup",h.destroy),e.off("change",h.destroy)},e.keyBinding.addKeyboardHandler(m),e.on("changeSelection",h.destroy),e.on("changeSession",h.destroy),e.on("mouseup",h.destroy),e.on("change",h.destroy),e.session.widgetManager.addLineWidget(h),h.el.onmousedown=e.focus.bind(e),e.renderer.scrollCursorIntoView(null,.5,{bottom:h.el.offsetHeight})},i.importCssString("    .error_widget_wrapper {        background: inherit;        color: inherit;        border:none    }    .error_widget {        border-top: solid 2px;        border-bottom: solid 2px;        margin: 5px 0;        padding: 10px 40px;        white-space: pre-wrap;    }    .error_widget.ace_error, .error_widget_arrow.ace_error{        border-color: #ff5a5a    }    .error_widget.ace_warning, .error_widget_arrow.ace_warning{        border-color: #F1D817    }    .error_widget.ace_info, .error_widget_arrow.ace_info{        border-color: #5a5a5a    }    .error_widget.ace_ok, .error_widget_arrow.ace_ok{        border-color: #5aaa5a    }    .error_widget_arrow {        position: absolute;        border: solid 5px;        border-top-color: transparent!important;        border-right-color: transparent!important;        border-left-color: transparent!important;        top: -5px;    }","")}),define("ace/ace",["require","exports","module","ace/lib/fixoldbrowsers","ace/lib/dom","ace/lib/event","ace/editor","ace/edit_session","ace/undomanager","ace/virtual_renderer","ace/worker/worker_client","ace/keyboard/hash_handler","ace/placeholder","ace/multi_select","ace/mode/folding/fold_mode","ace/theme/textmate","ace/ext/error_marker","ace/config"],function(e,t,n){"use strict";e("./lib/fixoldbrowsers");var r=e("./lib/dom"),i=e("./lib/event"),s=e("./editor").Editor,o=e("./edit_session").EditSession,u=e("./undomanager").UndoManager,a=e("./virtual_renderer").VirtualRenderer;e("./worker/worker_client"),e("./keyboard/hash_handler"),e("./placeholder"),e("./multi_select"),e("./mode/folding/fold_mode"),e("./theme/textmate"),e("./ext/error_marker"),t.config=e("./config"),t.require=e,t.edit=function(e){if(typeof e=="string"){var n=e;e=document.getElementById(n);if(!e)throw new Error("ace.edit can't find div #"+n)}if(e&&e.env&&e.env.editor instanceof s)return e.env.editor;var o="";if(e&&/input|textarea/i.test(e.tagName)){var u=e;o=u.value,e=r.createElement("pre"),u.parentNode.replaceChild(e,u)}else e&&(o=r.getInnerText(e),e.innerHTML="");var f=t.createEditSession(o),l=new s(new a(e));l.setSession(f);var c={document:f,editor:l,onResize:l.resize.bind(l,null)};return u&&(c.textarea=u),i.addListener(window,"resize",c.onResize),l.on("destroy",function(){i.removeListener(window,"resize",c.onResize),c.editor.container.env=null}),l.container.env=l.env=c,l},t.createEditSession=function(e,t){var n=new o(e,t);return n.setUndoManager(new u),n},t.EditSession=o,t.UndoManager=u,t.version="1.2.3"});
+            (function() {
+                window.require(["ace/ace"], function(a) {
+                    a && a.config.init(true);
+                    if (!window.ace)
+                        window.ace = a;
+                    for (var key in a) if (a.hasOwnProperty(key))
+                        window.ace[key] = a[key];
+                });
+            })();
+        
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/authz/lib/ace/mode-javascript.js b/themes/src/main/resources/theme/base/admin/resources/js/authz/lib/ace/mode-javascript.js
new file mode 100644
index 0000000..d2b278f
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/js/authz/lib/ace/mode-javascript.js
@@ -0,0 +1 @@
+define("ace/mode/doc_comment_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:"comment.doc.tag",regex:"@[\\w\\d_]+"},s.getTagRule(),{defaultToken:"comment.doc",caseInsensitive:!0}]}};r.inherits(s,i),s.getTagRule=function(e){return{token:"comment.doc.tag.storage.type",regex:"\\b(?:TODO|FIXME|XXX|HACK)\\b"}},s.getStartRule=function(e){return{token:"comment.doc",regex:"\\/\\*(?=\\*)",next:e}},s.getEndRule=function(e){return{token:"comment.doc",regex:"\\*\\/",next:e}},t.DocCommentHighlightRules=s}),define("ace/mode/javascript_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/doc_comment_highlight_rules","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";function a(){var e=o.replace("\\d","\\d\\-"),t={onMatch:function(e,t,n){var r=e.charAt(1)=="/"?2:1;if(r==1)t!=this.nextState?n.unshift(this.next,this.nextState,0):n.unshift(this.next),n[2]++;else if(r==2&&t==this.nextState){n[1]--;if(!n[1]||n[1]<0)n.shift(),n.shift()}return[{type:"meta.tag.punctuation."+(r==1?"":"end-")+"tag-open.xml",value:e.slice(0,r)},{type:"meta.tag.tag-name.xml",value:e.substr(r)}]},regex:"</?"+e+"",next:"jsxAttributes",nextState:"jsx"};this.$rules.start.unshift(t);var n={regex:"{",token:"paren.quasi.start",push:"start"};this.$rules.jsx=[n,t,{include:"reference"},{defaultToken:"string"}],this.$rules.jsxAttributes=[{token:"meta.tag.punctuation.tag-close.xml",regex:"/?>",onMatch:function(e,t,n){return t==n[0]&&n.shift(),e.length==2&&(n[0]==this.nextState&&n[1]--,(!n[1]||n[1]<0)&&n.splice(0,2)),this.next=n[0]||"start",[{type:this.token,value:e}]},nextState:"jsx"},n,f("jsxAttributes"),{token:"entity.other.attribute-name.xml",regex:e},{token:"keyword.operator.attribute-equals.xml",regex:"="},{token:"text.tag-whitespace.xml",regex:"\\s+"},{token:"string.attribute-value.xml",regex:"'",stateName:"jsx_attr_q",push:[{token:"string.attribute-value.xml",regex:"'",next:"pop"},{include:"reference"},{defaultToken:"string.attribute-value.xml"}]},{token:"string.attribute-value.xml",regex:'"',stateName:"jsx_attr_qq",push:[{token:"string.attribute-value.xml",regex:'"',next:"pop"},{include:"reference"},{defaultToken:"string.attribute-value.xml"}]},t],this.$rules.reference=[{token:"constant.language.escape.reference.xml",regex:"(?:&#[0-9]+;)|(?:&#x[0-9a-fA-F]+;)|(?:&[a-zA-Z0-9_:\\.-]+;)"}]}function f(e){return[{token:"comment",regex:/\/\*/,next:[i.getTagRule(),{token:"comment",regex:"\\*\\/",next:e||"pop"},{defaultToken:"comment",caseInsensitive:!0}]},{token:"comment",regex:"\\/\\/",next:[i.getTagRule(),{token:"comment",regex:"$|^",next:e||"pop"},{defaultToken:"comment",caseInsensitive:!0}]}]}var r=e("../lib/oop"),i=e("./doc_comment_highlight_rules").DocCommentHighlightRules,s=e("./text_highlight_rules").TextHighlightRules,o="[a-zA-Z\\$_\u00a1-\uffff][a-zA-Z\\d\\$_\u00a1-\uffff]*",u=function(e){var t=this.createKeywordMapper({"variable.language":"Array|Boolean|Date|Function|Iterator|Number|Object|RegExp|String|Proxy|Namespace|QName|XML|XMLList|ArrayBuffer|Float32Array|Float64Array|Int16Array|Int32Array|Int8Array|Uint16Array|Uint32Array|Uint8Array|Uint8ClampedArray|Error|EvalError|InternalError|RangeError|ReferenceError|StopIteration|SyntaxError|TypeError|URIError|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|eval|isFinite|isNaN|parseFloat|parseInt|JSON|Math|this|arguments|prototype|window|document",keyword:"const|yield|import|get|set|async|await|break|case|catch|continue|default|delete|do|else|finally|for|function|if|in|instanceof|new|return|switch|throw|try|typeof|let|var|while|with|debugger|__parent__|__count__|escape|unescape|with|__proto__|class|enum|extends|super|export|implements|private|public|interface|package|protected|static","storage.type":"const|let|var|function","constant.language":"null|Infinity|NaN|undefined","support.function":"alert","constant.language.boolean":"true|false"},"identifier"),n="case|do|else|finally|in|instanceof|return|throw|try|typeof|yield|void",r="\\\\(?:x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|u{[0-9a-fA-F]{1,6}}|[0-2][0-7]{0,2}|3[0-7][0-7]?|[4-7][0-7]?|.)";this.$rules={no_regex:[i.getStartRule("doc-start"),f("no_regex"),{token:"string",regex:"'(?=.)",next:"qstring"},{token:"string",regex:'"(?=.)',next:"qqstring"},{token:"constant.numeric",regex:/0(?:[xX][0-9a-fA-F]+|[bB][01]+)\b/},{token:"constant.numeric",regex:/[+-]?\d[\d_]*(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?\b/},{token:["storage.type","punctuation.operator","support.function","punctuation.operator","entity.name.function","text","keyword.operator"],regex:"("+o+")(\\.)(prototype)(\\.)("+o+")(\\s*)(=)",next:"function_arguments"},{token:["storage.type","punctuation.operator","entity.name.function","text","keyword.operator","text","storage.type","text","paren.lparen"],regex:"("+o+")(\\.)("+o+")(\\s*)(=)(\\s*)(function)(\\s*)(\\()",next:"function_arguments"},{token:["entity.name.function","text","keyword.operator","text","storage.type","text","paren.lparen"],regex:"("+o+")(\\s*)(=)(\\s*)(function)(\\s*)(\\()",next:"function_arguments"},{token:["storage.type","punctuation.operator","entity.name.function","text","keyword.operator","text","storage.type","text","entity.name.function","text","paren.lparen"],regex:"("+o+")(\\.)("+o+")(\\s*)(=)(\\s*)(function)(\\s+)(\\w+)(\\s*)(\\()",next:"function_arguments"},{token:["storage.type","text","entity.name.function","text","paren.lparen"],regex:"(function)(\\s+)("+o+")(\\s*)(\\()",next:"function_arguments"},{token:["entity.name.function","text","punctuation.operator","text","storage.type","text","paren.lparen"],regex:"("+o+")(\\s*)(:)(\\s*)(function)(\\s*)(\\()",next:"function_arguments"},{token:["text","text","storage.type","text","paren.lparen"],regex:"(:)(\\s*)(function)(\\s*)(\\()",next:"function_arguments"},{token:"keyword",regex:"(?:"+n+")\\b",next:"start"},{token:["support.constant"],regex:/that\b/},{token:["storage.type","punctuation.operator","support.function.firebug"],regex:/(console)(\.)(warn|info|log|error|time|trace|timeEnd|assert)\b/},{token:t,regex:o},{token:"punctuation.operator",regex:/[.](?![.])/,next:"property"},{token:"keyword.operator",regex:/--|\+\+|\.{3}|===|==|=|!=|!==|<+=?|>+=?|!|&&|\|\||\?\:|[!$%&*+\-~\/^]=?/,next:"start"},{token:"punctuation.operator",regex:/[?:,;.]/,next:"start"},{token:"paren.lparen",regex:/[\[({]/,next:"start"},{token:"paren.rparen",regex:/[\])}]/},{token:"comment",regex:/^#!.*$/}],property:[{token:"text",regex:"\\s+"},{token:["storage.type","punctuation.operator","entity.name.function","text","keyword.operator","text","storage.type","text","entity.name.function","text","paren.lparen"],regex:"("+o+")(\\.)("+o+")(\\s*)(=)(\\s*)(function)(?:(\\s+)(\\w+))?(\\s*)(\\()",next:"function_arguments"},{token:"punctuation.operator",regex:/[.](?![.])/},{token:"support.function",regex:/(s(?:h(?:ift|ow(?:Mod(?:elessDialog|alDialog)|Help))|croll(?:X|By(?:Pages|Lines)?|Y|To)?|t(?:op|rike)|i(?:n|zeToContent|debar|gnText)|ort|u(?:p|b(?:str(?:ing)?)?)|pli(?:ce|t)|e(?:nd|t(?:Re(?:sizable|questHeader)|M(?:i(?:nutes|lliseconds)|onth)|Seconds|Ho(?:tKeys|urs)|Year|Cursor|Time(?:out)?|Interval|ZOptions|Date|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(?:ome|andleEvent)|navigate|c(?:har(?:CodeAt|At)|o(?:s|n(?:cat|textual|firm)|mpile)|eil|lear(?:Timeout|Interval)?|a(?:ptureEvents|ll)|reate(?:StyleSheet|Popup|EventObject))|t(?:o(?:GMTString|S(?:tring|ource)|U(?:TCString|pperCase)|Lo(?:caleString|werCase))|est|a(?:n|int(?:Enabled)?))|i(?:s(?:NaN|Finite)|ndexOf|talics)|d(?:isableExternalCapture|ump|etachEvent)|u(?:n(?:shift|taint|escape|watch)|pdateCommands)|j(?:oin|avaEnabled)|p(?:o(?:p|w)|ush|lugins.refresh|a(?:ddings|rse(?:Int|Float)?)|r(?:int|ompt|eference))|e(?:scape|nableExternalCapture|val|lementFromPoint|x(?:p|ec(?:Script|Command)?))|valueOf|UTC|queryCommand(?:State|Indeterm|Enabled|Value)|f(?:i(?:nd|le(?:ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(?:nt(?:size|color)|rward)|loor|romCharCode)|watch|l(?:ink|o(?:ad|g)|astIndexOf)|a(?:sin|nchor|cos|t(?:tachEvent|ob|an(?:2)?)|pply|lert|b(?:s|ort))|r(?:ou(?:nd|teEvents)|e(?:size(?:By|To)|calc|turnValue|place|verse|l(?:oad|ease(?:Capture|Events)))|andom)|g(?:o|et(?:ResponseHeader|M(?:i(?:nutes|lliseconds)|onth)|Se(?:conds|lection)|Hours|Year|Time(?:zoneOffset)?|Da(?:y|te)|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Da(?:y|te)|FullYear)|FullYear|A(?:ttention|llResponseHeaders)))|m(?:in|ove(?:B(?:y|elow)|To(?:Absolute)?|Above)|ergeAttributes|a(?:tch|rgins|x))|b(?:toa|ig|o(?:ld|rderWidths)|link|ack))\b(?=\()/},{token:"support.function.dom",regex:/(s(?:ub(?:stringData|mit)|plitText|e(?:t(?:NamedItem|Attribute(?:Node)?)|lect))|has(?:ChildNodes|Feature)|namedItem|c(?:l(?:ick|o(?:se|neNode))|reate(?:C(?:omment|DATASection|aption)|T(?:Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(?:ntityReference|lement)|Attribute))|tabIndex|i(?:nsert(?:Row|Before|Cell|Data)|tem)|open|delete(?:Row|C(?:ell|aption)|T(?:Head|Foot)|Data)|focus|write(?:ln)?|a(?:dd|ppend(?:Child|Data))|re(?:set|place(?:Child|Data)|move(?:NamedItem|Child|Attribute(?:Node)?)?)|get(?:NamedItem|Element(?:sBy(?:Name|TagName|ClassName)|ById)|Attribute(?:Node)?)|blur)\b(?=\()/},{token:"support.constant",regex:/(s(?:ystemLanguage|cr(?:ipts|ollbars|een(?:X|Y|Top|Left))|t(?:yle(?:Sheets)?|atus(?:Text|bar)?)|ibling(?:Below|Above)|ource|uffixes|e(?:curity(?:Policy)?|l(?:ection|f)))|h(?:istory|ost(?:name)?|as(?:h|Focus))|y|X(?:MLDocument|SLDocument)|n(?:ext|ame(?:space(?:s|URI)|Prop))|M(?:IN_VALUE|AX_VALUE)|c(?:haracterSet|o(?:n(?:structor|trollers)|okieEnabled|lorDepth|mp(?:onents|lete))|urrent|puClass|l(?:i(?:p(?:boardData)?|entInformation)|osed|asses)|alle(?:e|r)|rypto)|t(?:o(?:olbar|p)|ext(?:Transform|Indent|Decoration|Align)|ags)|SQRT(?:1_2|2)|i(?:n(?:ner(?:Height|Width)|put)|ds|gnoreCase)|zIndex|o(?:scpu|n(?:readystatechange|Line)|uter(?:Height|Width)|p(?:sProfile|ener)|ffscreenBuffering)|NEGATIVE_INFINITY|d(?:i(?:splay|alog(?:Height|Top|Width|Left|Arguments)|rectories)|e(?:scription|fault(?:Status|Ch(?:ecked|arset)|View)))|u(?:ser(?:Profile|Language|Agent)|n(?:iqueID|defined)|pdateInterval)|_content|p(?:ixelDepth|ort|ersonalbar|kcs11|l(?:ugins|atform)|a(?:thname|dding(?:Right|Bottom|Top|Left)|rent(?:Window|Layer)?|ge(?:X(?:Offset)?|Y(?:Offset)?))|r(?:o(?:to(?:col|type)|duct(?:Sub)?|mpter)|e(?:vious|fix)))|e(?:n(?:coding|abledPlugin)|x(?:ternal|pando)|mbeds)|v(?:isibility|endor(?:Sub)?|Linkcolor)|URLUnencoded|P(?:I|OSITIVE_INFINITY)|f(?:ilename|o(?:nt(?:Size|Family|Weight)|rmName)|rame(?:s|Element)|gColor)|E|whiteSpace|l(?:i(?:stStyleType|n(?:eHeight|kColor))|o(?:ca(?:tion(?:bar)?|lName)|wsrc)|e(?:ngth|ft(?:Context)?)|a(?:st(?:M(?:odified|atch)|Index|Paren)|yer(?:s|X)|nguage))|a(?:pp(?:MinorVersion|Name|Co(?:deName|re)|Version)|vail(?:Height|Top|Width|Left)|ll|r(?:ity|guments)|Linkcolor|bove)|r(?:ight(?:Context)?|e(?:sponse(?:XML|Text)|adyState))|global|x|m(?:imeTypes|ultiline|enubar|argin(?:Right|Bottom|Top|Left))|L(?:N(?:10|2)|OG(?:10E|2E))|b(?:o(?:ttom|rder(?:Width|RightWidth|BottomWidth|Style|Color|TopWidth|LeftWidth))|ufferDepth|elow|ackground(?:Color|Image)))\b/},{token:"identifier",regex:o},{regex:"",token:"empty",next:"no_regex"}],start:[i.getStartRule("doc-start"),f("start"),{token:"string.regexp",regex:"\\/",next:"regex"},{token:"text",regex:"\\s+|^$",next:"start"},{token:"empty",regex:"",next:"no_regex"}],regex:[{token:"regexp.keyword.operator",regex:"\\\\(?:u[\\da-fA-F]{4}|x[\\da-fA-F]{2}|.)"},{token:"string.regexp",regex:"/[sxngimy]*",next:"no_regex"},{token:"invalid",regex:/\{\d+\b,?\d*\}[+*]|[+*$^?][+*]|[$^][?]|\?{3,}/},{token:"constant.language.escape",regex:/\(\?[:=!]|\)|\{\d+\b,?\d*\}|[+*]\?|[()$^+*?.]/},{token:"constant.language.delimiter",regex:/\|/},{token:"constant.language.escape",regex:/\[\^?/,next:"regex_character_class"},{token:"empty",regex:"$",next:"no_regex"},{defaultToken:"string.regexp"}],regex_character_class:[{token:"regexp.charclass.keyword.operator",regex:"\\\\(?:u[\\da-fA-F]{4}|x[\\da-fA-F]{2}|.)"},{token:"constant.language.escape",regex:"]",next:"regex"},{token:"constant.language.escape",regex:"-"},{token:"empty",regex:"$",next:"no_regex"},{defaultToken:"string.regexp.charachterclass"}],function_arguments:[{token:"variable.parameter",regex:o},{token:"punctuation.operator",regex:"[, ]+"},{token:"punctuation.operator",regex:"$"},{token:"empty",regex:"",next:"no_regex"}],qqstring:[{token:"constant.language.escape",regex:r},{token:"string",regex:"\\\\$",next:"qqstring"},{token:"string",regex:'"|$',next:"no_regex"},{defaultToken:"string"}],qstring:[{token:"constant.language.escape",regex:r},{token:"string",regex:"\\\\$",next:"qstring"},{token:"string",regex:"'|$",next:"no_regex"},{defaultToken:"string"}]};if(!e||!e.noES6)this.$rules.no_regex.unshift({regex:"[{}]",onMatch:function(e,t,n){this.next=e=="{"?this.nextState:"";if(e=="{"&&n.length)n.unshift("start",t);else if(e=="}"&&n.length){n.shift(),this.next=n.shift();if(this.next.indexOf("string")!=-1||this.next.indexOf("jsx")!=-1)return"paren.quasi.end"}return e=="{"?"paren.lparen":"paren.rparen"},nextState:"start"},{token:"string.quasi.start",regex:/`/,push:[{token:"constant.language.escape",regex:r},{token:"paren.quasi.start",regex:/\${/,push:"start"},{token:"string.quasi.end",regex:/`/,next:"pop"},{defaultToken:"string.quasi"}]}),(!e||!e.noJSX)&&a.call(this);this.embedRules(i,"doc-",[i.getEndRule("no_regex")]),this.normalizeRules()};r.inherits(u,s),t.JavaScriptHighlightRules=u}),define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"],function(e,t,n){"use strict";var r=e("../range").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return/^\s+$/.test(e)?/^\s*\}/.test(t):!1},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\s*\})/);if(!i)return 0;var s=i[1].length,o=e.findMatchingBracket({row:t,column:s});if(!o||o.row==t)return 0;var u=this.$getIndent(e.getLine(o.row));e.replace(new r(t,0,t,s-1),u)},this.$getIndent=function(e){return e.match(/^\s*/)[0]}}).call(i.prototype),t.MatchingBraceOutdent=i}),define("ace/mode/behaviour/cstyle",["require","exports","module","ace/lib/oop","ace/mode/behaviour","ace/token_iterator","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../behaviour").Behaviour,s=e("../../token_iterator").TokenIterator,o=e("../../lib/lang"),u=["text","paren.rparen","punctuation.operator"],a=["text","paren.rparen","punctuation.operator","comment"],f,l={},c=function(e){var t=-1;e.multiSelect&&(t=e.selection.index,l.rangeCount!=e.multiSelect.rangeCount&&(l={rangeCount:e.multiSelect.rangeCount}));if(l[t])return f=l[t];f=l[t]={autoInsertedBrackets:0,autoInsertedRow:-1,autoInsertedLineEnd:"",maybeInsertedBrackets:0,maybeInsertedRow:-1,maybeInsertedLineStart:"",maybeInsertedLineEnd:""}},h=function(e,t,n,r){var i=e.end.row-e.start.row;return{text:n+t+r,selection:[0,e.start.column+1,i,e.end.column+(i?0:1)]}},p=function(){this.add("braces","insertion",function(e,t,n,r,i){var s=n.getCursorPosition(),u=r.doc.getLine(s.row);if(i=="{"){c(n);var a=n.getSelectionRange(),l=r.doc.getTextRange(a);if(l!==""&&l!=="{"&&n.getWrapBehavioursEnabled())return h(a,l,"{","}");if(p.isSaneInsertion(n,r))return/[\]\}\)]/.test(u[s.column])||n.inMultiSelectMode?(p.recordAutoInsert(n,r,"}"),{text:"{}",selection:[1,1]}):(p.recordMaybeInsert(n,r,"{"),{text:"{",selection:[1,1]})}else if(i=="}"){c(n);var d=u.substring(s.column,s.column+1);if(d=="}"){var v=r.$findOpeningBracket("}",{column:s.column+1,row:s.row});if(v!==null&&p.isAutoInsertedClosing(s,u,i))return p.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}else{if(i=="\n"||i=="\r\n"){c(n);var m="";p.isMaybeInsertedClosing(s,u)&&(m=o.stringRepeat("}",f.maybeInsertedBrackets),p.clearMaybeInsertedClosing());var d=u.substring(s.column,s.column+1);if(d==="}"){var g=r.findMatchingBracket({row:s.row,column:s.column+1},"}");if(!g)return null;var y=this.$getIndent(r.getLine(g.row))}else{if(!m){p.clearMaybeInsertedClosing();return}var y=this.$getIndent(u)}var b=y+r.getTabString();return{text:"\n"+b+"\n"+y+m,selection:[1,b.length,1,b.length]}}p.clearMaybeInsertedClosing()}}),this.add("braces","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="{"){c(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.end.column,i.end.column+1);if(u=="}")return i.end.column++,i;f.maybeInsertedBrackets--}}),this.add("parens","insertion",function(e,t,n,r,i){if(i=="("){c(n);var s=n.getSelectionRange(),o=r.doc.getTextRange(s);if(o!==""&&n.getWrapBehavioursEnabled())return h(s,o,"(",")");if(p.isSaneInsertion(n,r))return p.recordAutoInsert(n,r,")"),{text:"()",selection:[1,1]}}else if(i==")"){c(n);var u=n.getCursorPosition(),a=r.doc.getLine(u.row),f=a.substring(u.column,u.column+1);if(f==")"){var l=r.$findOpeningBracket(")",{column:u.column+1,row:u.row});if(l!==null&&p.isAutoInsertedClosing(u,a,i))return p.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}}),this.add("parens","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="("){c(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u==")")return i.end.column++,i}}),this.add("brackets","insertion",function(e,t,n,r,i){if(i=="["){c(n);var s=n.getSelectionRange(),o=r.doc.getTextRange(s);if(o!==""&&n.getWrapBehavioursEnabled())return h(s,o,"[","]");if(p.isSaneInsertion(n,r))return p.recordAutoInsert(n,r,"]"),{text:"[]",selection:[1,1]}}else if(i=="]"){c(n);var u=n.getCursorPosition(),a=r.doc.getLine(u.row),f=a.substring(u.column,u.column+1);if(f=="]"){var l=r.$findOpeningBracket("]",{column:u.column+1,row:u.row});if(l!==null&&p.isAutoInsertedClosing(u,a,i))return p.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}}),this.add("brackets","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="["){c(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u=="]")return i.end.column++,i}}),this.add("string_dquotes","insertion",function(e,t,n,r,i){if(i=='"'||i=="'"){c(n);var s=i,o=n.getSelectionRange(),u=r.doc.getTextRange(o);if(u!==""&&u!=="'"&&u!='"'&&n.getWrapBehavioursEnabled())return h(o,u,s,s);if(!u){var a=n.getCursorPosition(),f=r.doc.getLine(a.row),l=f.substring(a.column-1,a.column),p=f.substring(a.column,a.column+1),d=r.getTokenAt(a.row,a.column),v=r.getTokenAt(a.row,a.column+1);if(l=="\\"&&d&&/escape/.test(d.type))return null;var m=d&&/string|escape/.test(d.type),g=!v||/string|escape/.test(v.type),y;if(p==s)y=m!==g;else{if(m&&!g)return null;if(m&&g)return null;var b=r.$mode.tokenRe;b.lastIndex=0;var w=b.test(l);b.lastIndex=0;var E=b.test(l);if(w||E)return null;if(p&&!/[\s;,.})\]\\]/.test(p))return null;y=!0}return{text:y?s+s:"",selection:[1,1]}}}}),this.add("string_dquotes","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&(s=='"'||s=="'")){c(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u==s)return i.end.column++,i}})};p.isSaneInsertion=function(e,t){var n=e.getCursorPosition(),r=new s(t,n.row,n.column);if(!this.$matchTokenType(r.getCurrentToken()||"text",u)){var i=new s(t,n.row,n.column+1);if(!this.$matchTokenType(i.getCurrentToken()||"text",u))return!1}return r.stepForward(),r.getCurrentTokenRow()!==n.row||this.$matchTokenType(r.getCurrentToken()||"text",a)},p.$matchTokenType=function(e,t){return t.indexOf(e.type||e)>-1},p.recordAutoInsert=function(e,t,n){var r=e.getCursorPosition(),i=t.doc.getLine(r.row);this.isAutoInsertedClosing(r,i,f.autoInsertedLineEnd[0])||(f.autoInsertedBrackets=0),f.autoInsertedRow=r.row,f.autoInsertedLineEnd=n+i.substr(r.column),f.autoInsertedBrackets++},p.recordMaybeInsert=function(e,t,n){var r=e.getCursorPosition(),i=t.doc.getLine(r.row);this.isMaybeInsertedClosing(r,i)||(f.maybeInsertedBrackets=0),f.maybeInsertedRow=r.row,f.maybeInsertedLineStart=i.substr(0,r.column)+n,f.maybeInsertedLineEnd=i.substr(r.column),f.maybeInsertedBrackets++},p.isAutoInsertedClosing=function(e,t,n){return f.autoInsertedBrackets>0&&e.row===f.autoInsertedRow&&n===f.autoInsertedLineEnd[0]&&t.substr(e.column)===f.autoInsertedLineEnd},p.isMaybeInsertedClosing=function(e,t){return f.maybeInsertedBrackets>0&&e.row===f.maybeInsertedRow&&t.substr(e.column)===f.maybeInsertedLineEnd&&t.substr(0,e.column)==f.maybeInsertedLineStart},p.popAutoInsertedClosing=function(){f.autoInsertedLineEnd=f.autoInsertedLineEnd.substr(1),f.autoInsertedBrackets--},p.clearMaybeInsertedClosing=function(){f&&(f.maybeInsertedBrackets=0,f.maybeInsertedRow=-1)},r.inherits(p,i),t.CstyleBehaviour=p}),define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(e){e&&(this.foldingStartMarker=new RegExp(this.foldingStartMarker.source.replace(/\|[^|]*?$/,"|"+e.start)),this.foldingStopMarker=new RegExp(this.foldingStopMarker.source.replace(/\|[^|]*?$/,"|"+e.end)))};r.inherits(o,s),function(){this.foldingStartMarker=/(\{|\[)[^\}\]]*$|^\s*(\/\*)/,this.foldingStopMarker=/^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/,this.singleLineBlockCommentRe=/^\s*(\/\*).*\*\/\s*$/,this.tripleStarBlockCommentRe=/^\s*(\/\*\*\*).*\*\/\s*$/,this.startRegionRe=/^\s*(\/\*|\/\/)#?region\b/,this._getFoldWidgetBase=this.getFoldWidget,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);if(this.singleLineBlockCommentRe.test(r)&&!this.startRegionRe.test(r)&&!this.tripleStarBlockCommentRe.test(r))return"";var i=this._getFoldWidgetBase(e,t,n);return!i&&this.startRegionRe.test(r)?"start":i},this.getFoldWidgetRange=function(e,t,n,r){var i=e.getLine(n);if(this.startRegionRe.test(i))return this.getCommentRegionBlock(e,i,n);var s=i.match(this.foldingStartMarker);if(s){var o=s.index;if(s[1])return this.openingBracketBlock(e,s[1],n,o);var u=e.getCommentFoldRange(n,o+s[0].length,1);return u&&!u.isMultiLine()&&(r?u=this.getSectionRange(e,n):t!="all"&&(u=null)),u}if(t==="markbegin")return;var s=i.match(this.foldingStopMarker);if(s){var o=s.index+s[0].length;return s[1]?this.closingBracketBlock(e,s[1],n,o):e.getCommentFoldRange(n,o,-1)}},this.getSectionRange=function(e,t){var n=e.getLine(t),r=n.search(/\S/),s=t,o=n.length;t+=1;var u=t,a=e.getLength();while(++t<a){n=e.getLine(t);var f=n.search(/\S/);if(f===-1)continue;if(r>f)break;var l=this.getFoldWidgetRange(e,"all",t);if(l){if(l.start.row<=s)break;if(l.isMultiLine())t=l.end.row;else if(r==f)break}u=t}return new i(s,o,u,e.getLine(u).length)},this.getCommentRegionBlock=function(e,t,n){var r=t.search(/\s*$/),s=e.getLength(),o=n,u=/^\s*(?:\/\*|\/\/|--)#?(end)?region\b/,a=1;while(++n<s){t=e.getLine(n);var f=u.exec(t);if(!f)continue;f[1]?a--:a++;if(!a)break}var l=n;if(l>o)return new i(o,r,l,t.length)}}.call(o.prototype)}),define("ace/mode/javascript",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/javascript_highlight_rules","ace/mode/matching_brace_outdent","ace/range","ace/worker/worker_client","ace/mode/behaviour/cstyle","ace/mode/folding/cstyle"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./javascript_highlight_rules").JavaScriptHighlightRules,o=e("./matching_brace_outdent").MatchingBraceOutdent,u=e("../range").Range,a=e("../worker/worker_client").WorkerClient,f=e("./behaviour/cstyle").CstyleBehaviour,l=e("./folding/cstyle").FoldMode,c=function(){this.HighlightRules=s,this.$outdent=new o,this.$behaviour=new f,this.foldingRules=new l};r.inherits(c,i),function(){this.lineCommentStart="//",this.blockComment={start:"/*",end:"*/"},this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t),i=this.getTokenizer().getLineTokens(t,e),s=i.tokens,o=i.state;if(s.length&&s[s.length-1].type=="comment")return r;if(e=="start"||e=="no_regex"){var u=t.match(/^.*(?:\bcase\b.*\:|[\{\(\[])\s*$/);u&&(r+=n)}else if(e=="doc-start"){if(o=="start"||o=="no_regex")return"";var u=t.match(/^\s*(\/?)\*/);u&&(u[1]&&(r+=" "),r+="* ")}return r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)},this.createWorker=function(e){var t=new a(["ace"],"ace/mode/javascript_worker","JavaScriptWorker");return t.attachToDocument(e.getDocument()),t.on("annotate",function(t){e.setAnnotations(t.data)}),t.on("terminate",function(){e.clearAnnotations()}),t},this.$id="ace/mode/javascript"}.call(c.prototype),t.Mode=c})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/authz/lib/ace/ui-ace.min.js b/themes/src/main/resources/theme/base/admin/resources/js/authz/lib/ace/ui-ace.min.js
new file mode 100644
index 0000000..b914093
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/js/authz/lib/ace/ui-ace.min.js
@@ -0,0 +1,7 @@
+/**
+ * angular-ui-ace - This directive allows you to add ACE editor elements.
+ * @version v0.2.3 - 2015-01-29
+ * @link http://angular-ui.github.com
+ * @license MIT
+ */
+"use strict";angular.module("ui.ace",[]).constant("uiAceConfig",{}).directive("uiAce",["uiAceConfig",function(a){if(angular.isUndefined(window.ace))throw new Error("ui-ace need ace to work... (o rly?)");var b=function(a,b,c){if(angular.isDefined(c.workerPath)){var d=window.ace.require("ace/config");d.set("workerPath",c.workerPath)}angular.isDefined(c.require)&&c.require.forEach(function(a){window.ace.require(a)}),angular.isDefined(c.showGutter)&&a.renderer.setShowGutter(c.showGutter),angular.isDefined(c.useWrapMode)&&b.setUseWrapMode(c.useWrapMode),angular.isDefined(c.showInvisibles)&&a.renderer.setShowInvisibles(c.showInvisibles),angular.isDefined(c.showIndentGuides)&&a.renderer.setDisplayIndentGuides(c.showIndentGuides),angular.isDefined(c.useSoftTabs)&&b.setUseSoftTabs(c.useSoftTabs),angular.isDefined(c.showPrintMargin)&&a.setShowPrintMargin(c.showPrintMargin),angular.isDefined(c.disableSearch)&&c.disableSearch&&a.commands.addCommands([{name:"unfind",bindKey:{win:"Ctrl-F",mac:"Command-F"},exec:function(){return!1},readOnly:!0}]),angular.isString(c.theme)&&a.setTheme("ace/theme/"+c.theme),angular.isString(c.mode)&&b.setMode("ace/mode/"+c.mode),angular.isDefined(c.firstLineNumber)&&(angular.isNumber(c.firstLineNumber)?b.setOption("firstLineNumber",c.firstLineNumber):angular.isFunction(c.firstLineNumber)&&b.setOption("firstLineNumber",c.firstLineNumber()));var e,f;if(angular.isDefined(c.advanced))for(e in c.advanced)f={name:e,value:c.advanced[e]},a.setOption(f.name,f.value);if(angular.isDefined(c.rendererOptions))for(e in c.rendererOptions)f={name:e,value:c.rendererOptions[e]},a.renderer.setOption(f.name,f.value);angular.forEach(c.callbacks,function(b){angular.isFunction(b)&&b(a)})};return{restrict:"EA",require:"?ngModel",link:function(c,d,e,f){var g,h,i=a.ace||{},j=angular.extend({},i,c.$eval(e.uiAce)),k=window.ace.edit(d[0]),l=k.getSession(),m=function(){var a=arguments[0],b=Array.prototype.slice.call(arguments,1);angular.isDefined(a)&&c.$evalAsync(function(){if(!angular.isFunction(a))throw new Error("ui-ace use a function as callback.");a(b)})},n={onChange:function(a){return function(b){var d=l.getValue();!f||d===f.$viewValue||c.$$phase||c.$root.$$phase||c.$evalAsync(function(){f.$setViewValue(d)}),m(a,b,k)}},onBlur:function(a){return function(){m(a,k)}}};e.$observe("readonly",function(a){k.setReadOnly(!!a||""===a)}),f&&(f.$formatters.push(function(a){if(angular.isUndefined(a)||null===a)return"";if(angular.isObject(a)||angular.isArray(a))throw new Error("ui-ace cannot use an object or an array as a model");return a}),f.$render=function(){l.setValue(f.$viewValue)});var o=function(a,d){a!==d&&(j=angular.extend({},i,c.$eval(e.uiAce)),j.callbacks=[j.onLoad],j.onLoad!==i.onLoad&&j.callbacks.unshift(i.onLoad),l.removeListener("change",g),g=n.onChange(j.onChange),l.on("change",g),k.removeListener("blur",h),h=n.onBlur(j.onBlur),k.on("blur",h),b(k,l,j))};c.$watch(e.uiAce,o,!0),o(i),d.on("$destroy",function(){k.session.$stopWorker(),k.destroy()}),c.$watch(function(){return[d[0].offsetWidth,d[0].offsetHeight]},function(){k.resize(),k.renderer.updateFull()},!0)}}}]);
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js b/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
index 01472c4..d1041c7 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/controllers/clients.js
@@ -364,8 +364,12 @@ module.controller('ClientCertificateImportCtrl', function($scope, $location, $ht
         "Certificate PEM"
     ];
 
+    if (callingContext == 'jwt-credentials') {
+        $scope.keyFormats.push('JSON Web Key Set (JWK)');
+    }
+
     $scope.hideKeystoreSettings = function() {
-        return $scope.uploadKeyFormat == 'Certificate PEM';
+        return $scope.uploadKeyFormat == 'Certificate PEM' || $scope.uploadKeyFormat == 'JSON Web Key Set (JWK)';
     }
 
     $scope.uploadKeyFormat = $scope.keyFormats[0];
@@ -970,8 +974,19 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, templates,
         return false;
     }
 
+    function configureAuthorizationServices() {
+        if ($scope.client.authorizationServicesEnabled) {
+            if ($scope.accessType == 'public') {
+                $scope.accessType = 'confidential';
+            }
+            $scope.client.publicClient = false;
+            $scope.client.serviceAccountsEnabled = true;
+        }
+    }
+
     $scope.$watch('client', function() {
         $scope.changed = isChanged();
+        configureAuthorizationServices();
     }, true);
 
     $scope.$watch('newRedirectUri', function() {
@@ -1067,9 +1082,7 @@ module.controller('ClientDetailCtrl', function($scope, realm, client, templates,
                 realm : realm.realm,
                 client : client.id
             }, $scope.client, function() {
-                $scope.changed = false;
-                client = angular.copy($scope.client);
-                $location.url("/realms/" + realm.realm + "/clients/" + client.id);
+                $route.reload();
                 Notifications.success("Your changes have been saved to the client.");
             });
         }
@@ -1690,6 +1703,8 @@ module.controller('ClientProtocolMapperCreateCtrl', function($scope, realm, serv
         changed: false,
         mapperTypes: serverInfo.protocolMapperTypes[protocol]
     }
+    
+    $scope.model.mapperType = $scope.model.mapperTypes[0];
 
     $scope.$watch(function() {
         return $location.path();
@@ -1954,6 +1969,8 @@ module.controller('ClientTemplateProtocolMapperCreateCtrl', function($scope, rea
         changed: false,
         mapperTypes: serverInfo.protocolMapperTypes[protocol]
     }
+    
+    $scope.model.mapperType = $scope.model.mapperTypes[0];
 
     $scope.$watch(function() {
         return $location.path();
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js b/themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
index 54c8000..f42ce55 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/controllers/realm.js
@@ -44,6 +44,10 @@ module.controller('GlobalCtrl', function($scope, $http, Auth, Current, $location
             return getAccess('view-identity-providers') || getAccess('manage-identity-providers') || this.manageIdentityProviders;
         },
 
+        get viewAuthorization() {
+            return getAccess('view-authorization') || this.manageAuthorization;
+        },
+
         get manageRealm() {
             return getAccess('manage-realm');
         },
@@ -64,6 +68,10 @@ module.controller('GlobalCtrl', function($scope, $http, Auth, Current, $location
             return getAccess('manage-identity-providers');
         },
 
+        get manageAuthorization() {
+            return getAccess('manage-authorization');
+        },
+
         get impersonation() {
             return getAccess('impersonation');
         }
@@ -421,68 +429,84 @@ module.controller('RealmCacheCtrl', function($scope, realm, RealmClearUserCache,
 
 });
 
-module.controller('RealmPasswordPolicyCtrl', function($scope, Realm, realm, $http, $location, Dialog, Notifications, PasswordPolicy) {
-    console.log('RealmPasswordPolicyCtrl');
+module.controller('RealmPasswordPolicyCtrl', function($scope, Realm, realm, $http, $location, $route, Dialog, Notifications, serverInfo) {
+    var parse = function(policyString) {
+        var policies = [];
+        if (!policyString || policyString.length == 0){
+            return policies;
+        }
 
-    $scope.realm = realm;
+        var policyArray = policyString.split(" and ");
 
-    var oldCopy = angular.copy($scope.realm);
+        for (var i = 0; i < policyArray.length; i ++){
+            var policyToken = policyArray[i];
+            var id;
+            var value;
+            if (policyToken.indexOf('(') == -1) {
+                id = policyToken.trim();
+            } else {
+                id = policyToken.substring(0, policyToken.indexOf('('));
+                value = policyToken.substring(policyToken.indexOf('(') + 1, policyToken.indexOf(')')).trim();
+            }
+
+            for (var j = 0; j < serverInfo.passwordPolicies.length; j++) {
+                if (serverInfo.passwordPolicies[j].id == id) {
+                    var p = serverInfo.passwordPolicies[j];
+                    p.value = value && value || p.defaultValue;
+                    policies.push(p);
+                }
+            }
+        }
+        return policies;
+    };
 
-    $scope.allPolicies = PasswordPolicy.allPolicies;
-    $scope.policyMessages = PasswordPolicy.policyMessages;
+    var toString = function(policies) {
+        if (!policies || policies.length == 0) {
+            return "";
+        }
+        var policyString = "";
+        for (var i = 0; i < policies.length; i++) {
+            policyString += policies[i].id;
+            if (policies[i].value && policies[i].value != policies[i].defaultValue) {
+                policyString += '(' + policies[i].value + ')';
+            }
+            policyString += " and ";
+        }
+        policyString = policyString.substring(0, policyString.length - 5);
+        return policyString;
+    }
 
-    $scope.policy = PasswordPolicy.parse(realm.passwordPolicy);
-    var oldPolicy = angular.copy($scope.policy);
+    $scope.realm = realm;
+    $scope.serverInfo = serverInfo;
+    $scope.changed = false; $scope.policy = parse(realm.passwordPolicy);
 
     $scope.addPolicy = function(policy){
+        policy.value = policy.defaultValue;
         if (!$scope.policy) {
             $scope.policy = [];
         }
-        if (policy.name === 'regexPattern') {
-            for (var i in $scope.allPolicies) {
-                var p = $scope.allPolicies[i];
-                if (p.name === 'regexPattern') {
-                    $scope.allPolicies[i] = { name: 'regexPattern', value: '' };
-                }
-            }
-        }
         $scope.policy.push(policy);
+        $scope.changed = true;
     }
 
     $scope.removePolicy = function(index){
         $scope.policy.splice(index, 1);
+        $scope.changed = true;
     }
 
-    $scope.changed = false;
-
-    $scope.$watch('realm', function() {
-        if (!angular.equals($scope.realm, oldCopy)) {
-            $scope.changed = true;
-        }
-    }, true);
-
-    $scope.$watch('policy', function(oldVal, newVal) {
-        if (!angular.equals($scope.policy, oldPolicy)) {
-            $scope.realm.passwordPolicy = PasswordPolicy.toString($scope.policy);
-            $scope.changed = true;
-        }
-    }, true);
-
     $scope.save = function() {
         $scope.changed = false;
+        $scope.realm.passwordPolicy = toString($scope.policy);
+        console.debug($scope.realm.passwordPolicy);
 
         Realm.update($scope.realm, function () {
             $location.url("/realms/" + realm.realm + "/authentication/password-policy");
             Notifications.success("Your changes have been saved to the realm.");
-            oldCopy = angular.copy($scope.realm);
-            oldPolicy = angular.copy($scope.policy);
         });
     };
 
     $scope.reset = function() {
-        $scope.realm = angular.copy(oldCopy);
-        $scope.policy = angular.copy(oldPolicy);
-        $scope.changed = false;
+        $route.reload();
     };
 });
 
@@ -1458,13 +1482,19 @@ module.controller('RealmAdminEventsCtrl', function($scope, RealmAdminEvents, rea
     	id : realm.realm,
         max : 5,
         first : 0
-    }
+    };
 
     $scope.adminEnabledEventOperationsOptions = {
         'multiple': true,
         'simple_tags': true,
         'tags': serverInfo.enums['operationType']
     };
+
+    $scope.adminEnabledEventResourceTypesOptions = {
+        'multiple': true,
+        'simple_tags': true,
+        'tags': serverInfo.enums['resourceType']
+    };
     
     $scope.update = function() {
     	$scope.query.first = 0;
@@ -1474,12 +1504,13 @@ module.controller('RealmAdminEventsCtrl', function($scope, RealmAdminEvents, rea
            }
         }
         $scope.events = RealmAdminEvents.query($scope.query);
-    }
+    };
     
     $scope.reset = function() {
     	$scope.query.first = 0;
     	$scope.query.max = 5;
     	$scope.query.operationTypes = '';
+    	$scope.query.resourceTypes = '';
     	$scope.query.resourcePath = '';
     	$scope.query.authRealm = '';
     	$scope.query.authClient = '';
@@ -1489,7 +1520,7 @@ module.controller('RealmAdminEventsCtrl', function($scope, RealmAdminEvents, rea
     	$scope.query.dateTo = '';
     	
     	$scope.update();
-    }
+    };
     
     $scope.queryUpdate = function() {
         for (var i in $scope.query) {
@@ -2118,9 +2149,23 @@ module.controller('AuthenticationConfigCreateCtrl', function($scope, realm, flow
 
 });
 
-module.controller('ClientInitialAccessCtrl', function($scope, realm, clientInitialAccess, ClientInitialAccess, Dialog, Notifications, $route) {
+module.controller('ClientInitialAccessCtrl', function($scope, realm, clientInitialAccess, clientRegTrustedHosts, ClientInitialAccess, ClientRegistrationTrustedHost, Dialog, Notifications, $route, $location) {
     $scope.realm = realm;
     $scope.clientInitialAccess = clientInitialAccess;
+    $scope.clientRegTrustedHosts = clientRegTrustedHosts;
+
+    $scope.updateHost = function(hostname) {
+        $location.url('/realms/' + realm.realm + '/client-reg-trusted-hosts/' + hostname);
+    };
+
+    $scope.removeHost = function(hostname) {
+        Dialog.confirmDelete(hostname, 'trusted host for client registration', function() {
+            ClientRegistrationTrustedHost.remove({ realm: realm.realm, hostname: hostname }, function() {
+                Notifications.success("The trusted host for client registration was deleted.");
+                $route.reload();
+            });
+        });
+    };
 
     $scope.remove = function(id) {
         Dialog.confirmDelete(id, 'initial access token', function() {
@@ -2132,6 +2177,57 @@ module.controller('ClientInitialAccessCtrl', function($scope, realm, clientIniti
     }
 });
 
+module.controller('ClientRegistrationTrustedHostDetailCtrl', function($scope, realm, clientRegTrustedHost, ClientRegistrationTrustedHost, Dialog, Notifications, $route, $location) {
+    $scope.realm = realm;
+
+    $scope.create = !clientRegTrustedHost.hostName;
+    $scope.changed = false;
+
+    if ($scope.create) {
+        $scope.count = 5;
+    } else {
+        $scope.hostName = clientRegTrustedHost.hostName;
+        $scope.count = clientRegTrustedHost.count;
+        $scope.remainingCount = clientRegTrustedHost.remainingCount;
+    }
+
+    $scope.save = function() {
+        if ($scope.create) {
+            ClientRegistrationTrustedHost.save({
+                realm: realm.realm
+            }, { hostName: $scope.hostName, count: $scope.count, remainingCount: $scope.count }, function (data) {
+                Notifications.success("The trusted host was created.");
+                $location.url('/realms/' + realm.realm + '/client-reg-trusted-hosts/' + $scope.hostName);
+            });
+        } else {
+            ClientRegistrationTrustedHost.update({
+                realm: realm.realm, hostname: $scope.hostName
+            }, { hostName: $scope.hostName, count: $scope.count, remainingCount: $scope.count }, function (data) {
+                Notifications.success("The trusted host was updated.");
+                $route.reload();
+            });
+        }
+    };
+
+    $scope.cancel = function() {
+        $location.url('/realms/' + realm.realm + '/client-initial-access');
+    };
+
+    $scope.resetRemainingCount = function() {
+        $scope.save();
+    }
+
+    $scope.$watch('count', function(newVal, oldVal) {
+        if (oldVal == newVal) {
+            return;
+        }
+
+        $scope.changed = true;
+    });
+
+});
+
+
 module.controller('ClientInitialAccessCreateCtrl', function($scope, realm, ClientInitialAccess, TimeUnit, Dialog, $location, $translate) {
     $scope.expirationUnit = 'Days';
     $scope.expiration = TimeUnit.toUnit(0, $scope.expirationUnit);
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js b/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
index f09eb63..88c57a7 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js
@@ -246,9 +246,9 @@ module.controller('UserListCtrl', function($scope, realm, User, UserImpersonatio
 
     $scope.query = {
         realm: realm.realm,
-        max : 5,
+        max : 20,
         first : 0
-    }
+    };
 
     $scope.impersonate = function(userId) {
         UserImpersonation.save({realm : realm.realm, user: userId}, function (data) {
@@ -365,7 +365,7 @@ module.controller('UserDetailCtrl', function($scope, realm, user, BruteForceUser
         console.log('realm brute force? ' + realm.bruteForceProtected)
         $scope.temporarilyDisabled = false;
         var isDisabled = function () {
-            BruteForceUser.get({realm: realm.realm, username: user.username}, function(data) {
+            BruteForceUser.get({realm: realm.realm, userId: user.id}, function(data) {
                 console.log('here in isDisabled ' + data.disabled);
                 $scope.temporarilyDisabled = data.disabled;
             });
@@ -375,7 +375,7 @@ module.controller('UserDetailCtrl', function($scope, realm, user, BruteForceUser
         isDisabled();
 
         $scope.unlockUser = function() {
-            BruteForceUser.delete({realm: realm.realm, username: user.username}, function(data) {
+            BruteForceUser.delete({realm: realm.realm, userId: user.id}, function(data) {
                 isDisabled();
             });
         }
@@ -592,31 +592,221 @@ module.controller('UserCredentialsCtrl', function($scope, realm, user, RequiredA
     };
 });
 
-module.controller('UserFederationCtrl', function($scope, $location, $route, realm, UserFederationProviders, UserFederationInstances, Notifications, Dialog) {
+module.controller('UserFederationCtrl', function($scope, $location, $route, realm, serverInfo, Components, UserFederationProviders, UserFederationInstances, Notifications, Dialog) {
     console.log('UserFederationCtrl ++++****');
     $scope.realm = realm;
-    $scope.providers = UserFederationProviders.query({realm: realm.realm});
+    $scope.providers = serverInfo.componentTypes['org.keycloak.storage.UserStorageProvider'];
+    for (var i = 0; i < $scope.providers.length; i++) {
+        $scope.providers[i].isUserFederationProvider = false;
+    }
+    UserFederationProviders.query({realm: realm.realm}, function(data) {
+        for (var i = 0; i < data.length; i++) {
+            data[i].isUserFederationProvider = true;
+            $scope.providers.push(data[i]);
+        }
+    });
 
     $scope.addProvider = function(provider) {
         console.log('Add provider: ' + provider.id);
-        $location.url("/create/user-federation/" + realm.realm + "/providers/" + provider.id);
+        if (provider.isUserFederationProvider) {
+            $location.url("/create/user-federation/" + realm.realm + "/providers/" + provider.id);
+        } else {
+            $location.url("/create/user-storage/" + realm.realm + "/providers/" + provider.id);
+            
+        }
     };
 
-    $scope.instances = UserFederationInstances.query({realm: realm.realm});
+    $scope.getInstanceLink = function(instance) {
+        if (instance.isUserFederationProvider) {
+            return "/realms/" + realm.realm + "/user-federation/providers/" + instance.providerName + "/" + instance.id;
+        } else {
+            return "/realms/" + realm.realm + "/user-storage/providers/" + instance.providerId + "/" + instance.id;
+        }
+    }
 
-    $scope.removeUserFederation = function(instance) {
-        Dialog.confirmDelete(instance.displayName, 'user federation provider', function() {
-            UserFederationInstances.remove({
-                realm : realm.realm,
-                instance : instance.id
-            }, function() {
-                $route.reload();
-                Notifications.success("The provider has been deleted.");
-            });
+    $scope.getInstanceName = function(instance) {
+        if (instance.isUserFederationProvider) {
+            return instance.displayName;
+        } else {
+            return instance.name;
+        }
+    }
+    $scope.getInstanceProvider = function(instance) {
+        if (instance.isUserFederationProvider) {
+            return instance.providerName;
+        } else {
+            return instance.providerId;
+        }
+    }
+
+    $scope.getInstancePriority = function(instance) {
+        if (instance.isUserFederationProvider) {
+            return instance.priority;
+        } else {
+            return instance.config['priority'][0];
+        }
+    }
+
+    Components.query({realm: realm.realm,
+        parent: realm.id,
+        type: 'org.keycloak.storage.UserStorageProvider'
+    }, function(data) {
+        $scope.instances = data;
+        for (var i = 0; i < data.length; i++) {
+            data[i].isUserFederationProvider = false;
+        }
+        UserFederationInstances.query({realm: realm.realm}, function(data) {
+            for (var i = 0; i < data.length; i++) {
+                data[i].isUserFederationProvider = true;
+                $scope.instances.push(data[i]);
+            }
+            
         });
+    });
+
+    $scope.removeInstance = function(instance) {
+        if (instance.isUserFederationProvider) {
+            Dialog.confirmDelete(instance.displayName, 'user federation provider', function() {
+                UserFederationInstances.remove({
+                    realm : realm.realm,
+                    instance : instance.id
+                }, function() {
+                    $route.reload();
+                    Notifications.success("The provider has been deleted.");
+                });
+            });
+
+        } else {
+            Dialog.confirmDelete(instance.name, 'user storage provider', function() {
+                Components.remove({
+                    realm : realm.realm,
+                    componentId : instance.id
+                }, function() {
+                    $route.reload();
+                    Notifications.success("The provider has been deleted.");
+                });
+            });
+        }
+    };
+});
+
+module.controller('GenericUserStorageCtrl', function($scope, $location, Notifications, $route, Dialog, realm, serverInfo, instance, providerId, Components) {
+    console.log('GenericUserStorageCtrl');
+    console.log('providerId: ' + providerId);
+    $scope.create = !instance.providerId;
+    console.log('create: ' + $scope.create);
+    var providers = serverInfo.componentTypes['org.keycloak.storage.UserStorageProvider'];
+    console.log('providers length ' + providers.length);
+    var providerFactory = null;
+    for (var i = 0; i < providers.length; i++) {
+        var p = providers[i];
+        console.log('provider: ' + p.id);
+        if (p.id == providerId) {
+            $scope.providerFactory = p;
+            providerFactory = p;
+            break;
+        }
+
+    }
+    $scope.provider = instance;
+
+    console.log("providerFactory: " + providerFactory.id);
+
+    function initUserStorageSettings() {
+        if ($scope.create) {
+            instance.name = providerFactory.id;
+            instance.providerId = providerFactory.id;
+            instance.providerType = 'org.keycloak.storage.UserStorageProvider';
+            instance.parentId = realm.id;
+            instance.config = {
+
+            };
+            instance.config['priority'] = ["0"];
+
+            if (providerFactory.properties) {
+
+                for (var i = 0; i < providerFactory.properties.length; i++) {
+                    var configProperty = providerFactory.properties[i];
+                    if (configProperty.defaultValue) {
+                        instance.config[configProperty.name] = [configProperty.defaultValue];
+                    } else {
+                        instance.config[configProperty.name] = [''];
+                    }
+
+                }
+            }
+
+        } else {
+            /*
+            console.log('Manage instance');
+            console.log(instance.name);
+            console.log(instance.providerId);
+            console.log(instance.providerType);
+            console.log(instance.parentId);
+            for (var k in instance.config) {
+                console.log('config[' + k + "] =");
+            }
+            */
+        }
+
+        $scope.changed = false;
+    }
+
+    initUserStorageSettings();
+    $scope.instance = angular.copy(instance);
+    $scope.realm = realm;
+
+     $scope.$watch('instance', function() {
+        if (!angular.equals($scope.instance, instance)) {
+            $scope.changed = true;
+        }
+
+    }, true);
+
+    $scope.save = function() {
+        $scope.changed = false;
+        if ($scope.create) {
+            Components.save({realm: realm.realm}, $scope.instance,  function (data, headers) {
+                var l = headers().location;
+                var id = l.substring(l.lastIndexOf("/") + 1);
+
+                $location.url("/realms/" + realm.realm + "/user-storage/providers/" + $scope.instance.providerId + "/" + id);
+                Notifications.success("The provider has been created.");
+            }, function (errorResponse) {
+                if (errorResponse.data && errorResponse.data['error_description']) {
+                    Notifications.error(errorResponse.data['error_description']);
+                }
+            });
+        } else {
+            Components.update({realm: realm.realm,
+                    componentId: instance.id
+                },
+                $scope.instance,  function () {
+                    $route.reload();
+                    Notifications.success("The provider has been updated.");
+                }, function (errorResponse) {
+                    if (errorResponse.data && errorResponse.data['error_description']) {
+                        Notifications.error(errorResponse.data['error_description']);
+                    }
+                });
+        }
+    };
+
+    $scope.reset = function() {
+        initUserStorageSettings();
+        $scope.instance = angular.copy(instance);
+    };
+
+    $scope.cancel = function() {
+        if ($scope.create) {
+            $location.url("/realms/" + realm.realm + "/user-storage");
+        } else {
+            $route.reload();
+        }
     };
 });
 
+
 module.controller('UserFederationTabCtrl', function(Dialog, $scope, Current, Notifications, $location) {
     $scope.removeUserFederation = function() {
         Dialog.confirmDelete($scope.instance.displayName, 'user federation provider', function() {
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/loaders.js b/themes/src/main/resources/theme/base/admin/resources/js/loaders.js
index e949a9d..4b76863 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/loaders.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/loaders.js
@@ -126,6 +126,15 @@ module.factory('UserLoader', function(Loader, User, $route, $q) {
     });
 });
 
+module.factory('ComponentLoader', function(Loader, Components, $route, $q) {
+    return Loader.get(Components, function() {
+        return {
+            realm : $route.current.params.realm,
+            componentId: $route.current.params.componentId
+        }
+    });
+});
+
 module.factory('UserFederationInstanceLoader', function(Loader, UserFederationInstances, $route, $q) {
     return Loader.get(UserFederationInstances, function() {
         return {
@@ -501,6 +510,23 @@ module.factory('ClientInitialAccessLoader', function(Loader, ClientInitialAccess
     });
 });
 
+module.factory('ClientRegistrationTrustedHostListLoader', function(Loader, ClientRegistrationTrustedHost, $route) {
+    return Loader.query(ClientRegistrationTrustedHost, function() {
+        return {
+            realm: $route.current.params.realm
+        }
+    });
+});
+
+module.factory('ClientRegistrationTrustedHostLoader', function(Loader, ClientRegistrationTrustedHost, $route) {
+    return Loader.get(ClientRegistrationTrustedHost, function() {
+        return {
+            realm: $route.current.params.realm,
+            hostname : $route.current.params.hostname
+        }
+    });
+});
+
 
 
 
diff --git a/themes/src/main/resources/theme/base/admin/resources/js/services.js b/themes/src/main/resources/theme/base/admin/resources/js/services.js
index a19b738..6d8fdcd 100755
--- a/themes/src/main/resources/theme/base/admin/resources/js/services.js
+++ b/themes/src/main/resources/theme/base/admin/resources/js/services.js
@@ -158,6 +158,8 @@ module.factory('Notifications', function($rootScope, $timeout) {
     $rootScope.notification = notifications.current;
 
 	notifications.message = function(type, header, message) {
+        notifications.current.remove();
+        
         notifications.current.type = type;
         notifications.current.header = header;
         notifications.current.message = message;
@@ -227,15 +229,15 @@ module.factory('RealmAdminEvents', function($resource) {
 });
 
 module.factory('BruteForce', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/attack-detection/brute-force/usernames', {
+    return $resource(authUrl + '/admin/realms/:realm/attack-detection/brute-force/users', {
         realm : '@realm'
     });
 });
 
 module.factory('BruteForceUser', function($resource) {
-    return $resource(authUrl + '/admin/realms/:realm/attack-detection/brute-force/usernames/:username', {
+    return $resource(authUrl + '/admin/realms/:realm/attack-detection/brute-force/users/:userId', {
         realm : '@realm',
-        username : '@username'
+        userId : '@userId'
     });
 });
 
@@ -296,6 +298,18 @@ module.factory('ClientInitialAccess', function($resource) {
     });
 });
 
+module.factory('ClientRegistrationTrustedHost', function($resource) {
+    return $resource(authUrl + '/admin/realms/:realm/clients-trusted-hosts/:hostname', {
+        realm : '@realm',
+        hostname : '@hostname'
+    }, {
+         update : {
+             method : 'PUT'
+         }
+       }
+    );
+});
+
 
 module.factory('ClientProtocolMapper', function($resource) {
     return $resource(authUrl + '/admin/realms/:realm/clients/:client/protocol-mappers/models/:id', {
@@ -1236,90 +1250,6 @@ module.factory('TimeUnit2', function() {
     return t;
 });
 
-
-module.factory('PasswordPolicy', function() {
-    var p = {};
-
-    p.policyMessages = {
-        hashAlgorithm: 	"Default hashing algorithm.  Default is 'pbkdf2'.",
-        hashIterations: 	"Number of hashing iterations.  Default is 1.  Recommended is 50000.",
-        length:         	"Minimal password length (integer type). Default value is 8.",
-        digits:         	"Minimal number (integer type) of digits in password. Default value is 1.",
-        lowerCase:      	"Minimal number (integer type) of lowercase characters in password. Default value is 1.",
-        upperCase:      	"Minimal number (integer type) of uppercase characters in password. Default value is 1.",
-        specialChars:   	"Minimal number (integer type) of special characters in password. Default value is 1.",
-        notUsername:    	"Block passwords that are equal to the username",
-        regexPattern:  	    "Block passwords that do not match the regex pattern (string type).",
-        passwordHistory:  	"Block passwords that are equal to previous passwords. Default value is 3.",
-        forceExpiredPasswordChange:  	"Force password change when password credential is expired. Default value is 365 days."
-    }
-
-    p.allPolicies = [
-        { name: 'hashAlgorithm', value: 'pbkdf2' },
-        { name: 'hashIterations', value: 1 },
-        { name: 'length', value: 8 },
-        { name: 'digits', value: 1 },
-        { name: 'lowerCase', value: 1 },
-        { name: 'upperCase', value: 1 },
-        { name: 'specialChars', value: 1 },
-        { name: 'notUsername', value: 1 },
-        { name: 'regexPattern', value: ''},
-        { name: 'passwordHistory', value: 3 },
-        { name: 'forceExpiredPasswordChange', value: 365 }
-    ];
-
-    p.parse = function(policyString) {
-        var policies = [];
-        var re, policyEntry;
-
-        if (!policyString || policyString.length == 0){
-            return policies;
-        }
-
-        var policyArray = policyString.split(" and ");
-
-        for (var i = 0; i < policyArray.length; i ++){
-            var policyToken = policyArray[i];
-            
-            if(policyToken.indexOf('hashAlgorithm') === 0 || policyToken.indexOf('regexPattern') === 0) {
-            	re = /(\w+)\((.*)\)/;
-            	policyEntry = re.exec(policyToken);
-                if (null !== policyEntry) {
-                	policies.push({ name: policyEntry[1], value: policyEntry[2] });
-                }
-            } else {
-            	re = /(\w+)\(*(\d*)\)*/;
-            	policyEntry = re.exec(policyToken);
-                if (null !== policyEntry) {
-                	policies.push({ name: policyEntry[1], value: parseInt(policyEntry[2]) });
-                }
-            }
-        }
-        return policies;
-    };
-
-    p.toString = function(policies) {
-        if (!policies || policies.length == 0) {
-            return "";
-        }
-        var policyString = "";
-
-        for (var i = 0; i < policies.length; i++) {
-            policyString += policies[i].name;
-            if ( policies[i].value ){
-                policyString += '(' + policies[i].value + ')';
-            }
-            policyString += " and ";
-        }
-
-        policyString = policyString.substring(0, policyString.length - 5);
-
-        return policyString;
-    };
-
-    return p;
-});
-
 module.filter('removeSelectedPolicies', function() {
     return function(policies, selectedPolicies) {
         var result = [];
@@ -1327,7 +1257,7 @@ module.filter('removeSelectedPolicies', function() {
             var policy = policies[i];
             var policyAvailable = true;
             for(var j in selectedPolicies) {
-                if(policy.name === selectedPolicies[j].name && policy.name !== 'regexPattern') {
+                if(policy.id === selectedPolicies[j].id && !policy.multipleSupported) {
                     policyAvailable = false;
                 }
             }
@@ -1711,3 +1641,16 @@ module.factory('DefaultGroups', function($resource) {
         }
     });
 });
+
+module.factory('Components', function($resource) {
+    return $resource(authUrl + '/admin/realms/:realm/components/:componentId', {
+        realm : '@realm',
+        componentId : '@componentId'
+    }, {
+        update : {
+            method : 'PUT'
+        }
+    });
+});
+
+
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authentication-flows.html b/themes/src/main/resources/theme/base/admin/resources/partials/authentication-flows.html
index 697f0a3..da867b0 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/authentication-flows.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authentication-flows.html
@@ -35,7 +35,7 @@
             <td class="kc-sorter">
                     <button data-ng-hide="flow.builtIn" data-ng-disabled="$first" class="btn btn-default btn-sm" data-ng-click="raisePriority(execution)"><i class="fa fa-angle-up"></i></button>
                     <button data-ng-hide="flow.builtIn" data-ng-disabled="$last" class="btn btn-default btn-sm" data-ng-click="lowerPriority(execution)"><i class="fa fa-angle-down"></i></button>
-                    <span>{{execution.displayName|capitalize}}</span>
+                    <span>{{execution.displayName|capitalize}}<span ng-if="execution.alias">({{execution.alias}})</span></span>
             </td>
             <td ng-repeat="lev in execution.postLevels"></td>
             <td ng-repeat="choice in execution.requirementChoices">
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/permission/provider/resource-server-policy-resource-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/permission/provider/resource-server-policy-resource-detail.html
new file mode 100644
index 0000000..a8d4512
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/permission/provider/resource-server-policy-resource-detail.html
@@ -0,0 +1,95 @@
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+
+    <ol class="breadcrumb">
+        <li><a href="#/realms/{{realm.realm}}/clients">{{:: 'clients' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}">{{client.clientId}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server">{{:: 'authz-authorization' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/permission">{{:: 'authz-permissions' | translate}}</a></li>
+        <li data-ng-show="create">{{:: 'authz-add-resource-permission' | translate}}</li>
+        <li data-ng-hide="create">{{originalPolicy.name}}</li>
+    </ol>
+
+    <h1 data-ng-show="create">{{:: 'authz-add-resource-permission' | translate}}</h1>
+    <h1 data-ng-hide="create">{{originalPolicy.name|capitalize}}<i class="pficon pficon-delete clickable" data-ng-click="remove()"></i></h1>
+
+    <form class="form-horizontal" name="clientForm" novalidate>
+        <fieldset class="border-top">
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="name">{{:: 'name' | translate}} <span class="required">*</span></label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="name" name="name" data-ng-model="policy.name" autofocus required data-ng-blur="checkNewNameAvailability()">
+                </div>
+                <kc-tooltip>{{:: 'authz-permission-name.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="description">{{:: 'description' | translate}} </label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="description" name="description" data-ng-model="policy.description">
+                </div>
+                <kc-tooltip>{{:: 'authz-permission-description.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="policy.config.default">{{:: 'authz-permission-resource-apply-to-resource-type' | translate}}</label>
+                <div class="col-md-6">
+                    <input ng-model="policy.config.default" id="policy.config.default" onoffswitch data-ng-click="applyToResourceType()"/>
+                </div>
+                <kc-tooltip>{{:: 'authz-permission-resource-apply-to-resource-type.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix" data-ng-hide="policy.config.default">
+                <label class="col-md-2 control-label" for="reqActions">{{:: 'authz-resources' | translate}} <span class="required">*</span></label>
+
+                <div class="col-md-6">
+                    <select ui-select2="{ minimumInputLength: 1}" id="reqActions" data-ng-model="policy.config.resources" data-placeholder="{{:: 'authz-select-resource' | translate}}..." multiple data-ng-required="!policy.config.default">
+                        <option ng-repeat="resource in resources" value="{{resource._id}}" ng-selected="true">{{resource.name}}</option>
+                    </select>
+                </div>
+                <kc-tooltip>{{:: 'authz-permission-resource-resource.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix" data-ng-show="policy.config.default">
+                <label class="col-md-2 control-label" for="policy.config.defaultResourceType">{{:: 'authz-resource-type' | translate}} <span class="required">*</span></label>
+
+                <div class="col-md-6">
+                    <input class="form-control" type="text" id="policy.config.defaultResourceType" name="policy.config.defaultResourceType" data-ng-model="policy.config.defaultResourceType" data-ng-required="policy.config.default">
+                </div>
+
+                <kc-tooltip>{{:: 'authz-permission-resource-type.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix">
+                <label class="col-md-2 control-label" for="reqActions">{{:: 'authz-policy-apply-policy' | translate}} <span class="required">*</span></label>
+
+                <div class="col-md-6">
+                    <select ui-select2 id="reqActions" data-ng-model="policy.config.applyPolicies" data-placeholder="{{:: 'authz-select-a-policy' | translate}}..." multiple required>
+                        <option ng-repeat="policy in policies" value="{{policy.id}}" ng-selected="true">{{policy.name}}</option>
+                    </select>
+                </div>
+
+                <kc-tooltip>{{:: 'authz-policy-apply-policy.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix">
+                <label class="col-md-2 control-label" for="policy.decisionStrategy">{{:: 'authz-policy-decision-strategy' | translate}}</label>
+
+                <div class="col-sm-2">
+                    <select class="form-control" id="policy.decisionStrategy"
+                            data-ng-model="policy.decisionStrategy"
+                            ng-change="selectDecisionStrategy()">
+                        <option value="UNANIMOUS">{{:: 'authz-policy-decision-strategy-unanimous' | translate}}</option>
+                        <option value="AFFIRMATIVE">{{:: 'authz-policy-decision-strategy-affirmative' | translate}}</option>
+                        <option value="CONSENSUS">{{:: 'authz-policy-decision-strategy-consensus' | translate}}</option>
+                    </select>
+                </div>
+
+                <kc-tooltip>{{:: 'authz-policy-decision-strategy.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <input type="hidden" data-ng-model="policy.type"/>
+        </fieldset>
+
+        <div class="form-group" data-ng-show="access.manageAuthorization">
+            <div class="col-md-10 col-md-offset-2">
+                <button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
+                <button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
+            </div>
+        </div>
+    </form>
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/permission/provider/resource-server-policy-scope-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/permission/provider/resource-server-policy-scope-detail.html
new file mode 100644
index 0000000..3d1660b
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/permission/provider/resource-server-policy-scope-detail.html
@@ -0,0 +1,108 @@
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+
+    <ol class="breadcrumb">
+        <li><a href="#/realms/{{realm.realm}}/clients">{{:: 'clients' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}">{{client.clientId}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server">{{:: 'authz-authorization' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/permission">{{:: 'authz-permissions' | translate}}</a></li>
+        <li data-ng-show="create">{{:: 'authz-add-scope-permission' | translate}}</li>
+        <li data-ng-hide="create">{{originalPolicy.name}}</li>
+    </ol>
+
+    <h1 data-ng-show="create">{{:: 'authz-add-scope-permission' | translate}}</h1>
+    <h1 data-ng-hide="create">{{originalPolicy.name|capitalize}}<i class="pficon pficon-delete clickable" data-ng-click="remove()"></i></h1>
+
+    <form class="form-horizontal" name="clientForm" novalidate>
+        <fieldset class="border-top">
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="name">{{:: 'name' | translate}} <span class="required">*</span></label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="name" name="name" data-ng-model="policy.name" autofocus required data-ng-blur="checkNewNameAvailability()">
+                </div>
+                <kc-tooltip>{{:: 'authz-permission-name.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="description">{{:: 'description' | translate}} </label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="description" name="description" data-ng-model="policy.description">
+                </div>
+                <kc-tooltip>{{:: 'authz-permission-description.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix">
+                <label class="col-md-2 control-label" for="reqActions">{{:: 'authz-resource' | translate}}</label>
+
+                <div class="col-md-6">
+                    <select class="form-control" id="reqActions"
+                            ng-model="policy.config.resources"
+                            ng-change="resolveScopes(policy)"
+                            data-ng-options="resource._id as resource.name for resource in resources">
+                        <option value="">{{:: 'authz-any-resource' | translate}}...</option>
+                    </select>
+                </div>
+                <kc-tooltip>{{:: 'authz-permission-scope-resource.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix" data-ng-show="policy.config.resources">
+                <label class="col-md-2 control-label" for="reqActions">{{:: 'authz-scopes' | translate}} <span class="required">*</span></label>
+
+                <div class="col-md-6">
+                    <select ui-select2 id="reqActions"
+                            data-ng-model="policy.config.scopes"
+                            data-placeholder="{{:: 'authz-any-scope' | translate}}..." multiple
+                            data-ng-required="policy.config.resources != ''"
+                            data-ng-options="scope.id as scope.name for scope in scopes track by scope.id"/>
+                </div>
+
+                <kc-tooltip>{{:: 'authz-permission-scope-scope.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix" data-ng-show="!policy.config.resources">
+                <label class="col-md-2 control-label" for="reqActions">{{:: 'authz-scopes' | translate}} <span class="required">*</span></label>
+
+                <div class="col-md-6">
+                    <select ui-select2="{ minimumInputLength: 1}" id="reqActions"
+                            data-ng-model="policy.config.scopes"
+                            data-placeholder="{{:: 'authz-any-scope' | translate}}..." multiple
+                            data-ng-required="policy.config.resources == ''"
+                            data-ng-options="scope.id as scope.name for scope in scopes track by scope.id"/>
+                    </select>
+                </div>
+                <kc-tooltip>{{:: 'authz-permission-scope-scope.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix">
+                <label class="col-md-2 control-label" for="reqActions">{{:: 'authz-policy-apply-policy' | translate}} <span class="required">*</span></label>
+
+                <div class="col-md-6">
+                    <select ui-select2 id="reqActions" data-ng-model="policy.config.applyPolicies" data-placeholder="{{:: 'authz-select-a-policy' | translate}}..." multiple required>
+                        <option ng-repeat="policy in policies" value="{{policy.id}}" ng-selected="true">{{policy.name}}</option>
+                    </select>
+                </div>
+
+                <kc-tooltip>{{:: 'authz-policy-apply-policy.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix">
+                <label class="col-md-2 control-label" for="policy.decisionStrategy">{{:: 'authz-policy-decision-strategy' | translate}}</label>
+
+                <div class="col-sm-2">
+                    <select class="form-control" id="policy.decisionStrategy"
+                            data-ng-model="policy.decisionStrategy"
+                            ng-change="selectDecisionStrategy()">
+                        <option value="UNANIMOUS">{{:: 'authz-policy-decision-strategy-unanimous' | translate}}</option>
+                        <option value="AFFIRMATIVE">{{:: 'authz-policy-decision-strategy-affirmative' | translate}}</option>
+                        <option value="CONSENSUS">{{:: 'authz-policy-decision-strategy-consensus' | translate}}</option>
+                    </select>
+                </div>
+
+                <kc-tooltip>{{:: 'authz-policy-decision-strategy.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <input type="hidden" data-ng-model="policy.type"/>
+        </fieldset>
+
+        <div class="form-group" data-ng-show="access.manageAuthorization">
+            <div class="col-md-10 col-md-offset-2">
+                <button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
+                <button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
+            </div>
+        </div>
+    </form>
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/permission/resource-server-permission-list.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/permission/resource-server-permission-list.html
new file mode 100644
index 0000000..a41fe18
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/permission/resource-server-permission-list.html
@@ -0,0 +1,61 @@
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+
+    <kc-tabs-resource-server></kc-tabs-resource-server>
+
+    <table class="table table-striped table-bordered">
+        <thead>
+            <tr>
+                <th class="kc-table-actions" colspan="5">
+                    <div class="form-inline">
+                        <div class="form-group">
+                            {{:: 'filter' | translate}}:&nbsp;&nbsp;
+                            <div class="input-group">
+                                <input type="text" placeholder="{{:: 'name' | translate}}" data-ng-model="search.name" class="form-control search" onkeyup="if(event.keyCode == 13){$(this).next('I').click();}">
+                            </div>
+                            <div class="input-group">
+                                <select class="form-control search" data-ng-model="search.type"
+                                        ng-options="p.type as p.name group by p.group for p in policyProviders track by p.type">
+                                    <option value="" selected ng-click="search.type = ''">{{:: 'authz-all-types' | translate}}</option>
+                                </select>
+                            </div>
+                        </div>
+                        <div class="pull-right">
+                            <select class="form-control" ng-model="policyType"
+                                    ng-options="p.name for p in policyProviders track by p.type"
+                                    data-ng-change="addPolicy(policyType);">
+                                <option value="" disabled selected>{{:: 'authz-create-permission' | translate}}...</option>
+                            </select>
+                        </div>
+                    </div>
+                </th>
+            </tr>
+            <tr data-ng-hide="policies.length == 0">
+                <th>{{:: 'name' | translate}}</th>
+                <th>{{:: 'description' | translate}}</th>
+                <th>{{:: 'type' | translate}}</th>
+                <th>{{:: 'authz-associated-policies' | translate}}</th>
+            </tr>
+        </thead>
+        <tbody>
+            <tr ng-repeat="policy in policies | filter: {name: search.name, type: search.type} | orderBy:'name'">
+                <td><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/permission/{{policy.type}}/{{policy.id}}">{{policy.name}}</a></td>
+                <td>{{policy.description}}</td>
+                <td>{{policy.type}}</td>
+                <td>
+                    <span data-ng-show="!policy.associatedPolicies.length">{{:: 'authz-no-policy-assigned' | translate}}</span>
+                    <span data-ng-show="policy.associatedPolicies.length > 0">
+                        <span ng-repeat="policy in policy.associatedPolicies">
+                            <a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/policy/{{policy.type}}/{{policy.id}}">{{policy.name}}</a>{{$last ? '' : ', '}}
+                        </span>
+                    </span>
+                </td>
+            </tr>
+            <tr data-ng-show="(policies | filter:search).length == 0">
+                <td class="text-muted" colspan="3" data-ng-show="search.name">{{:: 'no-results' | translate}}</td>
+                <td class="text-muted" colspan="3" data-ng-hide="search.name">{{:: 'authz-no-permissions-available' | translate}}</td>
+            </tr>
+        </tbody>
+    </table>
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-aggregate-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-aggregate-detail.html
new file mode 100644
index 0000000..7888f21
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-aggregate-detail.html
@@ -0,0 +1,84 @@
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+
+    <ol class="breadcrumb">
+        <li><a href="#/realms/{{realm.realm}}/clients">{{:: 'clients' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}">{{client.clientId}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server">{{:: 'authz-authorization' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/policy">{{:: 'authz-policies' | translate}}</a></li>
+        <li data-ng-show="create">{{:: 'authz-add-aggregated-policy' | translate}}</li>
+        <li data-ng-hide="create">{{:: 'authz-aggregated' | translate}}</li>
+        <li data-ng-hide="create">{{originalPolicy.name}}</li>
+    </ol>
+
+    <h1 data-ng-show="create">{{:: 'authz-add-aggregated-policy' | translate}}</h1>
+    <h1 data-ng-hide="create">{{originalPolicy.name|capitalize}}<i class="pficon pficon-delete clickable" data-ng-show="!create"
+                                                         data-ng-click="remove()"></i></h1>
+
+    <form class="form-horizontal" name="clientForm" novalidate>
+        <fieldset class="border-top">
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="name">{{:: 'name' | translate}} <span class="required">*</span></label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="name" name="name" data-ng-model="policy.name" autofocus required data-ng-blur="checkNewNameAvailability()">
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-name.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="description">{{:: 'description' | translate}} </label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="description" name="description" data-ng-model="policy.description">
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-description.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix">
+                <label class="col-md-2 control-label" for="reqActions">{{:: 'authz-policy-apply-policy' | translate}} <span class="required">*</span></label>
+
+                <div class="col-md-6">
+                    <select ui-select2 id="reqActions" data-ng-model="policy.config.applyPolicies" data-placeholder="{{:: 'authz-select-a-policy' | translate}}..." multiple required>
+                        <option ng-repeat="policy in policies" value="{{policy.id}}" ng-selected="true">{{policy.name}}</option>
+                    </select>
+                </div>
+
+                <kc-tooltip>{{:: 'authz-policy-apply-policy.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix">
+                <label class="col-md-2 control-label" for="policy.decisionStrategy">{{:: 'authz-policy-decision-strategy' | translate}}</label>
+
+                <div class="col-sm-2">
+                    <select class="form-control" id="policy.decisionStrategy"
+                            data-ng-model="policy.decisionStrategy"
+                            ng-change="selectDecisionStrategy()">
+                        <option value="UNANIMOUS">{{:: 'authz-policy-decision-strategy-unanimous' | translate}}</option>
+                        <option value="AFFIRMATIVE">{{:: 'authz-policy-decision-strategy-affirmative' | translate}}</option>
+                        <option value="CONSENSUS">{{:: 'authz-policy-decision-strategy-consensus' | translate}}</option>
+                    </select>
+                </div>
+
+                <kc-tooltip>{{:: 'authz-policy-decision-strategy.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix">
+                <label class="col-md-2 control-label" for="policy.logic">{{:: 'authz-policy-logic' | translate}}</label>
+
+                <div class="col-sm-1">
+                    <select class="form-control" id="policy.logic"
+                            data-ng-model="policy.logic">
+                        <option value="POSITIVE">{{:: 'authz-policy-logic-positive' | translate}}</option>
+                        <option value="NEGATIVE">{{:: 'authz-policy-logic-negative' | translate}}</option>
+                    </select>
+                </div>
+
+                <kc-tooltip>{{:: 'authz-policy-logic.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <input type="hidden" data-ng-model="policy.type"/>
+        </fieldset>
+
+        <div class="form-group" data-ng-show="access.manageAuthorization">
+            <div class="col-md-10 col-md-offset-2">
+                <button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
+                <button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
+            </div>
+        </div>
+    </form>
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-drools-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-drools-detail.html
new file mode 100644
index 0000000..a121f17
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-drools-detail.html
@@ -0,0 +1,124 @@
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+
+    <ol class="breadcrumb">
+        <li><a href="#/realms/{{realm.realm}}/clients">{{:: 'clients' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}">{{client.clientId}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server">{{:: 'authz-authorization' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/policy">{{:: 'authz-policies' | translate}}</a></li>
+        <li data-ng-show="create">{{:: 'authz-add-drools-policy' | translate}}</li>
+        <li data-ng-hide="create">Drools</li>
+        <li data-ng-hide="create">{{originalPolicy.name}}</li>
+    </ol>
+
+    <h1 data-ng-show="create">{{:: 'authz-add-drools-policy' | translate}}</h1>
+    <h1 data-ng-hide="create">{{originalPolicy.name|capitalize}}<i class="pficon pficon-delete clickable" data-ng-show="!create"
+                                                         data-ng-click="remove()"></i></h1>
+
+    <form class="form-horizontal" name="clientForm" novalidate>
+        <fieldset class="border-top">
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="name">{{:: 'name' | translate}} <span class="required">*</span></label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="name" name="name" data-ng-model="policy.name" autofocus required data-ng-blur="checkNewNameAvailability()">
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-name.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="description">{{:: 'description' | translate}} </label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="description" name="description" data-ng-model="policy.description">
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-description.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="policy.config.mavenArtifactGroupId">{{:: 'authz-policy-drools-maven-artifact' | translate}} <span class="required" data-ng-show="create">*</span></label>
+                <button data-ng-click="resolveModules()" class="btn btn-primary">{{:: 'authz-policy-drools-maven-artifact-resolve' | translate}}</button>
+                <div class="col-sm-3">
+                    <input class="form-control" type="text" id="policy.config.mavenArtifactGroupId" name="policy.config.mavenArtifactGroupId" data-ng-model="policy.config.mavenArtifactGroupId" placeholder="Group Identifier" required>
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-drools-maven-artifact.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="policy.config.mavenArtifactId"></label>
+                <div class="col-sm-3">
+                    <input class="form-control" type="text" id="policy.config.mavenArtifactId" name="policy.config.mavenArtifactId" data-ng-model="policy.config.mavenArtifactId" autofocus placeholder="Artifact Identifier" required>
+                </div>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="policy.config.mavenArtifactVersion"></label>
+                <div class="col-sm-3">
+                    <input class="form-control" type="text" id="policy.config.mavenArtifactVersion" name="policy.config.mavenArtifactVersion" data-ng-model="policy.config.mavenArtifactVersion" autofocus placeholder="Version" required>
+                </div>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="policy.config.moduleName">{{:: 'authz-policy-drools-module' | translate}} <span class="required" data-ng-show="create">*</span></label>
+                <div class="col-sm-3">
+                    <div>
+                        <select class="form-control" id="policy.config.moduleName"
+                                ng-model="policy.config.moduleName"
+                                ng-options="moduleName as moduleName for moduleName in drools.moduleNames"
+                                ng-change="resolveSessions()"
+                                ng-disabled="!drools.moduleNames.length"
+                                required>
+                        </select>
+                    </div>
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-drools-module.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="policy.config.sessionName">{{:: 'authz-policy-drools-session' | translate}} <span class="required" data-ng-show="create">*</span></label>
+                <div class="col-sm-3">
+                    <div>
+                        <select class="form-control" id="policy.config.sessionName"
+                                ng-model="policy.config.sessionName"
+                                ng-options="sessionName as sessionName for sessionName in drools.moduleSessions"
+                                ng-disabled="!drools.moduleSessions.length"
+                                required>
+                        </select>
+                    </div>
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-drools-session.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="policy.config.scannerPeriod">{{:: 'authz-policy-drools-update-period' | translate}}</label>
+                <div class="col-md-6 time-selector">
+                    <input class="form-control" type="number" required min="1" max="31536000" data-ng-model="policy.config.scannerPeriod" id="policy.config.scannerPeriod"
+                           name="policy.config.scannerPeriod"
+                           ng-disabled="!policy.config.sessionName"/>
+                    <select class="form-control" name="policy.config.scannerPeriodUnit"
+                            data-ng-model="policy.config.scannerPeriodUnit"
+                            ng-disabled="!policy.config.sessionName">
+                        <option>{{:: 'seconds' | translate}}</option>
+                        <option>{{:: 'minutes' | translate}}</option>
+                        <option>{{:: 'hours' | translate}}</option>
+                        <option>{{:: 'days' | translate}}</option>
+                    </select>
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-drools-update-period.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix">
+                <label class="col-md-2 control-label" for="policy.logic">{{:: 'authz-policy-logic' | translate}}</label>
+
+                <div class="col-sm-1">
+                    <select class="form-control" id="policy.logic"
+                            data-ng-model="policy.logic">
+                        <option value="POSITIVE">{{:: 'authz-policy-logic-positive' | translate}}</option>
+                        <option value="NEGATIVE">{{:: 'authz-policy-logic-negative' | translate}}</option>
+                    </select>
+                </div>
+
+                <kc-tooltip>{{:: 'authz-policy-logic.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <input type="hidden" data-ng-model="policy.type"/>
+        </fieldset>
+
+        <div class="form-group" data-ng-show="access.manageAuthorization">
+            <div class="col-md-10 col-md-offset-2">
+                <button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
+                <button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
+            </div>
+        </div>
+    </form>
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-js-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-js-detail.html
new file mode 100644
index 0000000..fb2fbc4
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-js-detail.html
@@ -0,0 +1,67 @@
+<style>
+    .ace_editor { height: 200px; }
+</style>
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+
+    <ol class="breadcrumb">
+        <li><a href="#/realms/{{realm.realm}}/clients">{{:: 'clients' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}">{{client.clientId}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server">{{:: 'authz-authorization' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/policy">{{:: 'authz-policies' | translate}}</a></li>
+        <li data-ng-show="create">{{:: 'authz-add-js-policy' | translate}}</li>
+        <li data-ng-hide="create">JavaScript</li>
+        <li data-ng-hide="create">{{originalPolicy.name}}</li>
+    </ol>
+
+    <h1 data-ng-show="create">{{:: 'authz-add-js-policy' | translate}}</h1>
+    <h1 data-ng-hide="create">{{originalPolicy.name|capitalize}}<i class="pficon pficon-delete clickable" data-ng-click="remove()"></i></h1>
+
+    <form class="form-horizontal" name="clientForm" novalidate>
+        <fieldset class="border-top">
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="name">{{:: 'name' | translate}} <span class="required">*</span></label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="name" name="name" data-ng-model="policy.name" autofocus required data-ng-blur="checkNewNameAvailability()">
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-name.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="description">{{:: 'description' | translate}} </label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="description" name="description" data-ng-model="policy.description">
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-description.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="description">{{:: 'authz-policy-js-code' | translate}} </label>
+                <div class="col-sm-6">
+                    <div ui-ace="{ onLoad : initEditor }" data-ng-model="policy.config.code"></div>
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-js-code.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix">
+                <label class="col-md-2 control-label" for="policy.logic">{{:: 'authz-policy-logic' | translate}}</label>
+
+                <div class="col-sm-1">
+                    <select class="form-control" id="policy.logic"
+                            data-ng-model="policy.logic">
+                        <option value="POSITIVE">{{:: 'authz-policy-logic-positive' | translate}}</option>
+                        <option value="NEGATIVE">{{:: 'authz-policy-logic-negative' | translate}}</option>
+                    </select>
+                </div>
+
+                <kc-tooltip>{{:: 'authz-policy-logic.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <input type="hidden" data-ng-model="policy.type"/>
+        </fieldset>
+
+        <div class="form-group" data-ng-show="access.manageAuthorization">
+            <div class="col-md-10 col-md-offset-2">
+                <button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
+                <button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
+            </div>
+        </div>
+    </form>
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-role-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-role-detail.html
new file mode 100644
index 0000000..f9c2aca
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-role-detail.html
@@ -0,0 +1,166 @@
+<!--
+  ~ JBoss, Home of Professional Open Source.
+  ~ Copyright 2016 Red Hat, Inc., and individual contributors
+  ~ as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+
+    <ol class="breadcrumb">
+        <li><a href="#/realms/{{realm.realm}}/clients">{{:: 'clients' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}">{{client.clientId}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server">{{:: 'authz-authorization' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/policy">{{:: 'authz-policies' | translate}}</a></li>
+        <li data-ng-show="create">{{:: 'authz-add-role-policy' | translate}}</li>
+        <li data-ng-hide="create">{{:: 'roles' | translate}}</li>
+        <li data-ng-hide="create">{{originalPolicy.name}}</li>
+    </ol>
+
+    <h1 data-ng-show="create">{{:: 'authz-add-role-policy' | translate}}</h1>
+    <h1 data-ng-hide="create">{{originalPolicy.name|capitalize}}<i class="pficon pficon-delete clickable" data-ng-show="!create"
+                                                         data-ng-click="remove()"></i></h1>
+
+    <form class="form-horizontal" name="clientForm" novalidate>
+        <fieldset class="border-top">
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="name">{{:: 'name' | translate}} <span class="required">*</span></label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="name" name="name" data-ng-model="policy.name" autofocus required data-ng-blur="checkNewNameAvailability()">
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-name.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="description">{{:: 'description' | translate}} </label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="description" name="description" data-ng-model="policy.description">
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-description.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix">
+                <label class="col-md-2 control-label" for="roles">{{:: 'realm-roles' | translate}} <span class="required">*</span></label>
+
+                <div class="col-md-4">
+                    <select ui-select2="{ minimumInputLength: 1}" id="roles" data-ng-model="selectedRole" data-ng-change="selectRole(selectedRole);" data-placeholder="{{:: 'select-a-role' | translate}}..."
+                            ng-options="role as role.name for role in roles" data-ng-required="selectedRoles.length == 0">
+                        <option></option>
+                    </select>
+                </div>
+
+                <kc-tooltip>{{:: 'authz-policy-role-realm-roles.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix" style="margin-top: -15px;">
+                <label class="col-md-2 control-label"></label>
+                <div class="col-sm-4" data-ng-show="hasRealmRole()">
+                    <table class="table table-striped table-bordered">
+                        <thead>
+                        <tr>
+                            <th class="col-sm-5">{{:: 'name' | translate}}</th>
+                            <th>{{:: 'authz-required' | translate}}</th>
+                            <th>{{:: 'actions' | translate}}</th>
+                        </tr>
+                        </thead>
+                        <tbody>
+                        <tr ng-repeat="role in selectedRoles | orderBy:'name'" ng-if="!role.clientRole">
+                            <td>{{role.name}}</td>
+                            <td><input type="checkbox" ng-model="role.required" id="{{role.id}}"></td>
+                            <td class="kc-action-cell">
+                                <button class="btn btn-default btn-block btn-sm" ng-click="removeFromList(role);">{{:: 'remove' | translate}}</button>
+                            </td>
+                        </tr>
+                        <tr data-ng-show="!selectedRoles.length">
+                            <td class="text-muted" colspan="3">{{:: 'authz-no-roles-assigned' | translate}}</td>
+                        </tr>
+                        </tbody>
+                    </table>
+                </div>
+            </div>
+            <div class="form-group clearfix">
+                <label class="col-md-2 control-label" for="clients">{{:: 'clients' | translate}}</label>
+
+                <div class="col-md-4">
+                    <select class="form-control" id="clients"
+                            ng-model="selectedClient"
+                            ng-change="selectClient()"
+                            data-ng-options="current as current.clientId for current in clients">
+                        <option value="">{{:: 'selectOne' | translate}}...</option>
+                    </select>
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-role-clients.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix">
+                <label class="col-md-2 control-label" for="clientRoles">{{:: 'client-roles' | translate}} <span class="required">*</span></label>
+
+                <div class="col-md-4">
+                    <select ui-select2="{ minimumInputLength: 1}" id="clientRoles" data-ng-model="selectedRole" data-ng-change="selectRole(selectedRole);" data-placeholder="{{:: 'select-a-role' | translate}}..."
+                            ng-options="role as role.name for role in clientRoles" data-ng-required="selectedRoles.length == 0" data-ng-disabled="!selectedClient">
+                        <option></option>
+                    </select>
+                </div>
+
+                <kc-tooltip>{{:: 'authz-policy-role-client-roles.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix" style="margin-top: -15px;">
+                <label class="col-md-2 control-label"></label>
+                <div class="col-sm-4" data-ng-show="hasClientRole()">
+                    <table class="table table-striped table-bordered">
+                        <thead>
+                            <tr>
+                                <th class="col-sm-5">{{:: 'name' | translate}}</th>
+                                <th class="col-sm-5">{{:: 'client' | translate}}</th>
+                                <th>{{:: 'authz-required' | translate}}</th>
+                                <th>{{:: 'actions' | translate}}</th>
+                            </tr>
+                        </thead>
+                        <tbody>
+                            <tr ng-repeat="role in selectedRoles | orderBy:'name'" ng-if="role.clientRole">
+                                <td>{{role.name}}</td>
+                                <td>{{role.container.name}}</td>
+                                <td><input type="checkbox" ng-model="role.required" id="{{role.id}}"></td>
+                                <td class="kc-action-cell">
+                                    <button class="btn btn-default btn-block btn-sm" ng-click="removeFromList(role);">{{:: 'remove' | translate}}</button>
+                                </td>
+                            </tr>
+                            <tr data-ng-show="!selectedRoles.length">
+                                <td class="text-muted" colspan="3">{{:: 'authz-no-roles-assigned' | translate}}</td>
+                            </tr>
+                        </tbody>
+                    </table>
+                </div>
+            </div>
+            <div class="form-group clearfix">
+                <label class="col-md-2 control-label" for="policy.logic">{{:: 'authz-policy-logic' | translate}}</label>
+
+                <div class="col-sm-1">
+                    <select class="form-control" id="policy.logic"
+                            data-ng-model="policy.logic">
+                        <option value="POSITIVE">{{:: 'authz-policy-logic-positive' | translate}}</option>
+                        <option value="NEGATIVE">{{:: 'authz-policy-logic-negative' | translate}}</option>
+                    </select>
+                </div>
+
+                <kc-tooltip>{{:: 'authz-policy-logic.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <input type="hidden" data-ng-model="policy.type"/>
+        </fieldset>
+        <div class="form-group" data-ng-show="access.manageAuthorization">
+            <div class="col-md-10 col-md-offset-2">
+                <button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
+                <button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
+            </div>
+        </div>
+    </form>
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-time-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-time-detail.html
new file mode 100644
index 0000000..fc4af74
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-time-detail.html
@@ -0,0 +1,77 @@
+<style>
+    .ace_editor { height: 200px; }
+</style>
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+
+    <ol class="breadcrumb">
+        <li><a href="#/realms/{{realm.realm}}/clients">{{:: 'clients' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}">{{client.clientId}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server">{{:: 'authz-authorization' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/policy">{{:: 'authz-policies' | translate}}</a></li>
+        <li data-ng-show="create">{{:: 'authz-add-time-policy' | translate}}</li>
+        <li data-ng-hide="create">{{:: 'time' | translate}}</li>
+        <li data-ng-hide="create">{{originalPolicy.name}}</li>
+    </ol>
+
+
+    <h1 data-ng-show="create">{{:: 'authz-add-time-policy' | translate}}</h1>
+    <h1 data-ng-hide="create">{{originalPolicy.name|capitalize}}<i class="pficon pficon-delete clickable" data-ng-click="remove()"></i></h1>
+
+    <form class="form-horizontal" name="clientForm" novalidate>
+        <fieldset class="border-top">
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="name">{{:: 'name' | translate}} <span class="required">*</span></label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="name" name="name" data-ng-model="policy.name" autofocus required data-ng-blur="checkNewNameAvailability()">
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-name.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="description">{{:: 'description' | translate}} </label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="description" name="description" data-ng-model="policy.description">
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-description.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="policy.config.nbf">{{:: 'not-before' | translate}}</label>
+
+                <div class="col-md-6 time-selector">
+                    <input class="form-control" style="width: 150px" type="text" id="policy.config.nbf" name="notBefore" data-ng-model="policy.config.nbf" placeholder="yyyy-MM-dd hh:mm:ss">
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-time-not-before.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="policy.config.noa">{{:: 'authz-policy-time-not-on-after' | translate}}</label>
+
+                <div class="col-md-6 time-selector">
+                    <input class="form-control" style="width: 150px" type="text" id="policy.config.noa" name="policy.config.noa" data-ng-model="policy.config.noa" placeholder="yyyy-MM-dd hh:mm:ss">
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-time-not-on-after.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix">
+                <label class="col-md-2 control-label" for="policy.logic">{{:: 'authz-policy-logic' | translate}}</label>
+
+                <div class="col-sm-1">
+                    <select class="form-control" id="policy.logic"
+                            data-ng-model="policy.logic">
+                        <option value="POSITIVE">{{:: 'authz-policy-logic-positive' | translate}}</option>
+                        <option value="NEGATIVE">{{:: 'authz-policy-logic-negative' | translate}}</option>
+                    </select>
+                </div>
+
+                <kc-tooltip>{{:: 'authz-policy-logic.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <input type="hidden" data-ng-model="policy.type"/>
+        </fieldset>
+
+        <div class="form-group" data-ng-show="access.manageAuthorization">
+            <div class="col-md-10 col-md-offset-2">
+                <button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
+                <button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
+            </div>
+        </div>
+    </form>
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-user-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-user-detail.html
new file mode 100644
index 0000000..de85b71
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/provider/resource-server-policy-user-detail.html
@@ -0,0 +1,91 @@
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+
+    <ol class="breadcrumb">
+        <li><a href="#/realms/{{realm.realm}}/clients">{{:: 'clients' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}">{{client.clientId}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server">{{:: 'authz-authorization' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/policy">{{:: 'authz-policies' | translate}}</a></li>
+        <li data-ng-show="create">{{:: 'authz-add-user-policy' | translate}}</li>
+        <li data-ng-hide="create">{{:: 'user' | translate}}</li>
+        <li data-ng-hide="create">{{originalPolicy.name}}</li>
+    </ol>
+
+    <h1 data-ng-show="create">{{:: 'authz-add-user-policy' | translate}}</h1>
+    <h1 data-ng-hide="create">{{originalPolicy.name|capitalize}}<i class="pficon pficon-delete clickable" data-ng-show="!create"
+                                                         data-ng-click="remove()"></i></h1>
+
+    <form class="form-horizontal" name="clientForm" novalidate>
+        <fieldset class="border-top">
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="name">{{:: 'name' | translate}} <span class="required">*</span></label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="name" name="name" data-ng-model="policy.name" autofocus required data-ng-blur="checkNewNameAvailability()">
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-name.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="description">{{:: 'description' | translate}} </label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="description" name="description" data-ng-model="policy.description">
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-description.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix">
+                <label class="col-md-2 control-label" for="users">{{:: 'users' | translate}} <span class="required">*</span></label>
+
+                <div class="col-md-6">
+                    <input type="hidden" ui-select2="usersUiSelect" id="users" data-ng-model="selectedUser" data-ng-change="selectUser(selectedUser);" data-placeholder="Select an user..." data-ng-required="selectedUsers.length == 0"">
+                    </input>
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-user-users.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix" style="margin-top: -15px;">
+                <label class="col-md-2 control-label"></label>
+                <div class="col-sm-3">
+                    <table class="table table-striped table-bordered">
+                        <thead>
+                            <tr data-ng-hide="!selectedUsers.length">
+                                <th>{{:: 'username' | translate}}</th>
+                                <th>{{:: 'actions' | translate}}</th>
+                            </tr>
+                        </thead>
+                        <tbody>
+                            <tr ng-repeat="user in selectedUsers | orderBy:'username'">
+                                <td>{{user.username}}</td>
+                                <td class="kc-action-cell">
+                                    <button class="btn btn-default btn-block btn-sm" ng-click="removeFromList(selectedUsers, $index);">{{:: 'remove' | translate}}</button>
+                                </td>
+                            </tr>
+                            <tr data-ng-show="!selectedUsers.length">
+                                <td class="text-muted" colspan="3">{{:: 'authz-no-users-assigned' | translate}}</td>
+                            </tr>
+                        </tbody>
+                    </table>
+                </div>
+            </div>
+            <div class="form-group clearfix">
+                <label class="col-md-2 control-label" for="policy.logic">{{:: 'authz-policy-logic' | translate}}</label>
+
+                <div class="col-sm-1">
+                    <select class="form-control" id="policy.logic"
+                            data-ng-model="policy.logic">
+                        <option value="POSITIVE">{{:: 'authz-policy-logic-positive' | translate}}</option>
+                        <option value="NEGATIVE">{{:: 'authz-policy-logic-negative' | translate}}</option>
+                    </select>
+                </div>
+
+                <kc-tooltip>{{:: 'authz-policy-logic.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <input type="hidden" data-ng-model="policy.type"/>
+        </fieldset>
+
+        <div class="form-group" data-ng-show="access.manageAuthorization">
+            <div class="col-md-10 col-md-offset-2">
+                <button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
+                <button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
+            </div>
+        </div>
+    </form>
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/resource-server-policy-evaluate.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/resource-server-policy-evaluate.html
new file mode 100644
index 0000000..d884150
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/resource-server-policy-evaluate.html
@@ -0,0 +1,279 @@
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+
+    <ol class="breadcrumb">
+        <li><a href="#/realms/{{realm.realm}}/clients">{{:: 'clients' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}">{{client.clientId}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server">{{:: 'authz-authorization' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/evaluate">{{:: 'authz-policy-evaluation' | translate}}</a></li>
+    </ol>
+
+    <kc-tabs-resource-server></kc-tabs-resource-server>
+
+    <div data-ng-show="showResult">
+        <br>
+        <a href="" data-ng-click="showRequestTab()">{{:: 'authz-evaluation-new' | translate}}</a>
+        |
+        <a href="" data-ng-click="reevaluate()">{{:: 'authz-evaluation-re-evaluate' | translate}}</a>
+        |
+        <a href="" data-ng-click="showAuthzData()">{{:: 'authz-show-authorization-data' | translate}}</a>
+    </div>
+
+    <div data-ng-show="evaluationResult && !showResult">
+        <br>
+        <a href="" data-ng-click="showResultTab()">{{:: 'authz-evaluation-previous' | translate}}</a>
+    </div>
+
+    <div data-ng-show="showRpt">
+        <div class="form-group">
+            <label class="col-sm-1 control-label" for="rpt">{{:: 'authz-evaluation-authorization-data' | translate}}</label>
+            <div class="col-md-6">
+                <textarea id="rpt" class="form-control" rows="20">{{evaluationResult.rpt | json}}</textarea>
+            </div>
+            <kc-tooltip>{{:: 'authz-evaluation-authorization-data.tooltip' | translate}}</kc-tooltip>
+        </div>
+    </div>
+
+    <div data-ng-hide="showResult">
+        <form class="form-horizontal" name="clientForm" novalidate>
+            <fieldset>
+                <fieldset class="border-top">
+                    <legend><span class="text">{{:: 'authz-evaluation-identity-information' | translate}}</span>
+                        <kc-tooltip>{{:: 'authz-evaluation-identity-information.tooltip' | translate}}</kc-tooltip>
+                    </legend>
+                    <div class="form-group">
+                        <label class="col-md-2 control-label" for="client">{{:: 'client' | translate}}</label>
+
+                        <div class="col-sm-2">
+                            <div>
+                                <select class="form-control" id="client"
+                                        ng-model="authzRequest.clientId"
+                                        ng-options="client.id as client.clientId for client in clients track by client.id">
+                                    <option value="">{{:: 'authz-select-client' | translate}}...</option>
+                                </select>
+                            </div>
+                        </div>
+                        <kc-tooltip>{{:: 'authz-evaluation-client.tooltip' | translate}}</kc-tooltip>
+                    </div>
+                    <div class="form-group clearfix">
+                        <label class="col-md-2 control-label" for="users">{{:: 'user' | translate}} <span class="required"
+                                                                                     data-ng-show="!authzRequest.roleIds || authzRequest.roleIds.length == 0">*</span></label>
+
+                        <div class="col-md-6">
+                            <input type="hidden" ui-select2="usersUiSelect" id="users" data-ng-model="selectedUser" data-ng-change="selectUser(selectedUser);" data-placeholder="{{:: 'authz-select-user' | translate}}..."
+                                   data-ng-required="!authzRequest.roleIds || authzRequest.roleIds.length == 0">
+                            </input>
+                        </div>
+
+                        <kc-tooltip>{{:: 'authz-evaluation-user.tooltip' | translate}}</kc-tooltip>
+                    </div>
+
+                    <div class="form-group clearfix">
+                        <label class="col-md-2 control-label" for="reqActions">{{:: 'roles' | translate}} <span class="required"
+                                                                                           data-ng-show="!authzRequest.userId || authzRequest.userId == null">*</span></label>
+
+                        <div class="col-md-6">
+                            <select ui-select2="{ minimumInputLength: 1}"
+                                    data-ng-model="authzRequest.roleIds"
+                                    data-placeholder="{{:: 'authz-any-role' | translate}}..." multiple
+                                    data-ng-required="!authzRequest.userId || authzRequest.userId == null">
+                                <option ng-repeat="role in roles track by role.id" value="{{role.name}}">{{role.name}}
+                                </option>
+                            </select>
+                        </div>
+
+                        <kc-tooltip>{{:: 'authz-evaluation-role.tooltip' | translate}}</kc-tooltip>
+                    </div>
+                </fieldset>
+                <fieldset>
+                    <legend collapsed><span class="text">{{:: 'authz-evaluation-contextual-info' | translate}}</span>
+                        <kc-tooltip>{{:: 'authz-evaluation-contextual-info.tooltip' | translate}}</kc-tooltip>
+                    </legend>
+                    <div class="form-group clearfix block">
+                        <label class="col-md-2 control-label" for="newRedirectUri">{{:: 'authz-evaluation-contextual-attributes' | translate}}</label>
+
+                        <div class="col-sm-6">
+                            <table class="table table-striped table-bordered">
+                                <thead>
+                                    <tr>
+                                        <th>{{:: 'key' | translate}}</th>
+                                        <th>{{:: 'value' | translate}}</th>
+                                        <th>{{:: 'actions' | translate}}</th>
+                                    </tr>
+                                </thead>
+                                <tbody>
+                                    <tr ng-repeat="(key, value) in (authzRequest.context.attributes)">
+                                        <td>{{getContextAttributeName(key)}}</td>
+                                        <td>
+                                            <select class="form-control" id="attribute-{{key}}"
+                                                    data-ng-model="authzRequest.context.attributes[key]"
+                                                    data-ng-show="getContextAttribute(key).values"
+                                                    ng-options="value1.key as value1.name for value1 in getContextAttribute(key).values">
+                                            </select>
+                                            <input ng-model="authzRequest.context.attributes[key]" class="form-control"
+                                                   type="text" name="{{key}}" id="attribute-{{key}}"
+                                                   data-ng-hide="getContextAttribute(key).values"/>
+                                        </td>
+                                        <td class="kc-action-cell">
+                                            <button class="btn btn-default btn-block btn-sm"
+                                                    data-ng-click="removeContextAttribute(key)">{{:: 'delete' | translate}}
+                                            </button>
+                                        </td>
+                                    </tr>
+                                    <tr>
+                                        <td>
+                                            <select class="form-control" id="newContextAttribute.key"
+                                                    data-ng-model="newContextAttribute"
+                                                    ng-change="selectDefaultContextAttribute()"
+                                                    data-ng-hide="!isDefaultContextAttribute()"
+                                                    ng-options="attribute as attribute.name for attribute in defaultContextAttributes track by attribute.key">
+                                            </select>
+                                            <input ng-model="newContextAttribute.key" class="form-control" type="text"
+                                                   id="newAttributeKey" data-ng-hide="isDefaultContextAttribute()"/>
+                                        </td>
+                                        <td>
+                                            <select class="form-control" id="newContextAttribute.value"
+                                                    data-ng-model="newContextAttribute.value"
+                                                    data-ng-show="newContextAttribute.values"
+                                                    ng-options="value.key as value.name for value in newContextAttribute.values track by value.key">
+                                            </select>
+                                            <input ng-model="newContextAttribute.value" class="form-control" type="text"
+                                                   id="newAttributeValue" data-ng-show="!newContextAttribute.values"/>
+                                        </td>
+                                        <td class="kc-action-cell">
+                                            <button class="btn btn-default btn-block btn-sm"
+                                                    data-ng-click="addContextAttribute()"
+                                                    data-ng-disabled="!newContextAttribute.key || newContextAttribute.key == ''">
+                                                {{:: 'add' | translate}}
+                                            </button>
+                                        </td>
+                                    </tr>
+                                </tbody>
+                            </table>
+                        </div>
+
+                        <kc-tooltip>{{:: 'authz-evaluation-contextual-attributes.tooltip' | translate}}</kc-tooltip>
+                    </div>
+                </fieldset>
+                <fieldset>
+                    <legend><span class="text">{{:: 'authz-permissions' | translate}}</span>
+                        <kc-tooltip>{{:: 'authz-evaluation-permissions.tooltip' | translate}}</kc-tooltip>
+                    </legend>
+                    <div class="form-group">
+                        <label class="col-md-2 control-label" for="applyResourceType">{{:: 'authz-permission-resource-apply-to-resource-type' | translate}}</label>
+
+                        <div class="col-md-6">
+                            <input ng-model="applyResourceType" id="applyResourceType" onoffswitch
+                                   data-ng-click="setApplyToResourceType()"/>
+                        </div>
+                        <kc-tooltip>{{:: 'authz-permission-resource-apply-to-resource-type.tooltip' | translate}}
+                        </kc-tooltip>
+                    </div>
+                    <div class="form-group clearfix" data-ng-hide="applyResourceType">
+                        <label class="col-md-2 control-label" for="reqActions">{{:: 'authz-resources' | translate}} <span class="required">*</span></label>
+
+                        <div class="col-md-6">
+                            <select ui-select2="{ minimumInputLength: 1, allowClear:true }"
+                                    ng-model="newResource._id"
+                                    data-placeholder="Select a resource..."
+                                    data-ng-required="!applyResourceType && authzRequest.resources.length == 0 && !authzRequest.entitlements"
+                                    data-ng-click="resolveScopes()"
+                                    ng-options="resource._id as resource.name for resource in resources track by resource._id">
+                                <option value=""></option>
+                            </select>
+                        </div>
+                        <kc-tooltip>{{:: 'authz-permission-resource-resource.tooltip' | translate}}</kc-tooltip>
+                    </div>
+                    <div class="form-group clearfix" data-ng-show="applyResourceType">
+                        <label class="col-md-2 control-label" for="newResource.type">{{:: 'authz-resource-type' | translate}} <span
+                                class="required">*</span></label>
+
+                        <div class="col-md-6">
+                            <input class="form-control" type="text" id="newResource.type" name="newResource.type"
+                                   data-ng-model="authzRequest.resources[0].type"
+                                   data-ng-required="applyResourceType && !authzRequest.resources[0].type && !authzRequest.entitlements">
+                        </div>
+
+                        <kc-tooltip>{{:: 'authz-permission-resource-type.tooltip' | translate}}</kc-tooltip>
+                    </div>
+                    <div class="form-group clearfix" data-ng-show="applyResourceType || newResource._id == null">
+                        <label class="col-md-2 control-label" for="newResource.scopes">{{:: 'authz-scopes' | translate}}</label>
+
+                        <div class="col-md-6">
+                            <select ui-select2="{ minimumInputLength: 1}"
+                                    id="newResource.scopes"
+                                    multiple
+                                    data-ng-model="newResource.scopes"
+                                    data-placeholder="{{:: 'authz-select-scope' | translate}}..."
+                                    data-ng-options="scope.name as scope.name for scope in scopes track by scope.name"/>
+                        </div>
+
+                        <kc-tooltip>{{:: 'authz-permission-scope-scope.tooltip' | translate}}</kc-tooltip>
+                    </div>
+                    <div class="form-group clearfix" data-ng-show="newResource._id != null">
+                        <label class="col-md-2 control-label" for="newResource.scopes">{{:: 'authz-scopes' | translate}}</label>
+
+                        <div class="col-md-6">
+                            <select ui-select2
+                                    id="newResource.scopes"
+                                    data-ng-model="newResource.scopes"
+                                    data-placeholder="{{:: 'authz-any-scope' | translate}}..." multiple>
+                                <option ng-repeat="scope in scopes" value="{{scope.name}}">{{scope.name}}</option>
+                            </select>
+                        </div>
+
+                        <kc-tooltip>{{:: 'authz-permission-scope-scope.tooltip' | translate}}</kc-tooltip>
+                    </div>
+                    <div class="form-group clearfix block" data-ng-show="!applyResourceType">
+                        <label class="col-md-2 control-label" for="newRedirectUri"></label>
+
+                        <div class="col-sm-6">
+                            <button data-ng-click="addResource()" class="btn btn-primary">Add</button>
+                            <table class="table table-striped table-bordered">
+                                <thead>
+                                    <tr>
+                                        <th>{{:: 'authz-resource' | translate}}</th>
+                                        <th>{{:: 'authz-scopes' | translate}}</th>
+                                        <th>{{:: 'actions' | translate}}</th>
+                                    </tr>
+                                </thead>
+                                <tbody>
+                                    <tr data-ng-show="!authzRequest.resources || authzRequest.resources.length == 0">
+                                        <td colspan="3">
+                                            {{:: 'authz-no-resources' | translate}}
+                                        </td>
+                                    </tr>
+                                    <tr ng-repeat="resource in authzRequest.resources">
+                                        <td>{{resource.name ? resource.name : 'authz-evaluation-any-resource-with-scopes' | translate}}</td>
+                                        <td>
+                                            <span data-ng-show="!resource.scopes.length">{{:: 'authz-any-scope' | translate}}.</span>
+                                        <span data-ng-show="resource.scopes.length > 0">
+                                            <span ng-repeat="scope in resource.scopes">
+                                                {{scope}} {{$last ? '' : ', '}}
+                                            </span>
+                                        </span>
+                                        </td>
+                                        <td class="kc-action-cell">
+                                            <button class="btn btn-default btn-block btn-sm"
+                                                    data-ng-click="removeResource($index)">{{:: 'delete' | translate}}
+                                            </button>
+                                        </td>
+                                    </tr>
+                                </tbody>
+                            </table>
+                        </div>
+                    </div>
+                </fieldset>
+
+                <div class="form-group">
+                    <div class="col-md-10 col-md-offset-2">
+                        <button kc-save data-ng-click="evaluate()">{{:: 'authz-evaluation-evaluate' | translate}}</button>
+                        <button kc-reset data-ng-disabled="!changed">{{:: 'reset' | translate}}</button>
+                    </div>
+                </div>
+            </fieldset>
+        </form>
+    </div>
+    <div data-ng-include="resultUrl" data-ng-show="showResult && !showRpt"/>
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/resource-server-policy-evaluate-result.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/resource-server-policy-evaluate-result.html
new file mode 100644
index 0000000..8e9061c
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/resource-server-policy-evaluate-result.html
@@ -0,0 +1,66 @@
+<fieldset>
+    <form class="form-horizontal" name="clientForm" novalidate>
+        <span data-ng-show="evaluationResult.results.length == 0"><strong>{{:: 'authz-evaluation-no-result' | translate}}</strong></span>
+        <fieldset class="border-top" data-ng-repeat="result in evaluationResult.results">
+            <legend collapsed><span class="text">{{result.resource.name}}</span>
+            </legend>
+            <div class="form-group">
+                <label class="col-md-2 control-label">{{:: 'authz-result' | translate}}</label>
+
+                <div class="col-sm-2">
+                    <div>
+                        <span style="color: green"
+                              data-ng-show="result.status == 'PERMIT'"><strong>{{result.status}}</strong></span>
+                        <span style="color: red"
+                              data-ng-hide="result.status == 'PERMIT'"><strong>{{result.status}}</strong></span>
+                    </div>
+                </div>
+                <kc-tooltip>{{:: 'authz-evaluation-result.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label">{{:: 'authz-scopes' | translate}}</label>
+
+                <div class="col-sm-2">
+                    <span data-ng-show="result.allowedScopes.length == 0">{{:: 'authz-no-scopes-available' | translate}}</span>
+
+                    <div>
+                        <ul>
+                            <li data-ng-repeat="scope in result.allowedScopes">
+                                {{scope.name}}
+                            </li>
+                        </ul>
+                    </div>
+                </div>
+                <kc-tooltip>{{:: 'authz-evaluation-scopes.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group" data-ng-show="!evaluationResult.entitlements">
+                <label class="col-md-2 control-label">{{:: 'authz-policies' | translate}}</label>
+
+                <div class="col-sm-6">
+                    <span data-ng-show="result.policies.length == 0">{{:: 'authz-evaluation-no-policies-resource' | translate}}</span>
+                    <div>
+                        <div>
+                            <li data-ng-repeat="policyResult in result.policies">
+                                <strong><a
+                                        href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/permission/{{policyResult.policy.type}}/{{policyResult.policy.id}}">{{policyResult.policy.name}}</a></strong>
+                                decision was <span style="color: green" data-ng-show="policyResult.status == 'PERMIT'"><strong>{{policyResult.status}}</strong></span>
+                                <span style="color: red" data-ng-hide="policyResult.status == 'PERMIT'"><strong>{{policyResult.status}}</strong></span>
+                                by <strong>{{policyResult.policy.decisionStrategy}}</strong> decision. {{policyResult.scopes.length > 0 ? 'Denied Scopes:' : ''}} <span data-ng-repeat="scope in policyResult.scopes"><strong style="color: red">{{scope.name}}{{$last ? '' : ', '}}</strong></span>{{policyResult.scopes.length > 0 ? '.' : ''}}
+                                <ul>
+                                    <li data-ng-repeat="subPolicy in policyResult.associatedPolicies">
+                                        <strong><a
+                                                href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/policy/{{subPolicy.policy.type}}/{{subPolicy.policy.id}}">{{subPolicy.policy.name}}</a></strong>
+                                        voted to <span style="color: green"
+                                                       data-ng-show="subPolicy.status == 'PERMIT'"><strong>{{subPolicy.status}}</strong></span>
+                                        <span style="color: red" data-ng-hide="subPolicy.status == 'PERMIT'"><strong>{{subPolicy.status}}</strong></span>.</a>
+                                    </li>
+                                </ul>
+                            </li>
+                        </ul>
+                    </div>
+                </div>
+                <kc-tooltip>{{:: 'authz-evaluation-policies.tooltip' | translate}}</kc-tooltip>
+            </div>
+        </fieldset>
+    </form>
+</fieldset>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/resource-server-policy-list.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/resource-server-policy-list.html
new file mode 100644
index 0000000..34240b6
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/policy/resource-server-policy-list.html
@@ -0,0 +1,52 @@
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+
+    <kc-tabs-resource-server></kc-tabs-resource-server>
+
+    <table class="table table-striped table-bordered">
+        <thead>
+            <tr>
+                <th class="kc-table-actions" colspan="5">
+                    <div class="form-inline">
+                        <div class="form-group">
+                            {{:: 'filter' | translate}}:&nbsp;&nbsp;
+                            <div class="input-group">
+                                <input type="text" placeholder="{{:: 'name' | translate}}" data-ng-model="search.name" class="form-control search" onkeyup="if(event.keyCode == 13){$(this).next('I').click();}">
+                            </div>
+                            <div class="input-group">
+                                <select class="form-control search" data-ng-model="search.type"
+                                        ng-options="p.type as p.name group by p.group for p in policyProviders track by p.type">
+                                    <option value="" selected ng-click="search.type = ''">{{:: 'authz-all-types' | translate}}</option>
+                                </select>
+                            </div>
+                        </div>
+                        <div class="pull-right">
+                            <select class="form-control" ng-model="policyType"
+                                    ng-options="p.name group by p.group for p in policyProviders track by p.type"
+                                    data-ng-change="addPolicy(policyType);">
+                                <option value="" disabled selected>{{:: 'authz-create-policy' | translate}}...</option>
+                            </select>
+                        </div>
+                    </div>
+                </th>
+            </tr>
+            <tr data-ng-hide="policies.length == 0">
+                <th>{{:: 'name' | translate}}</th>
+                <th>{{:: 'description' | translate}}</th>
+                <th>{{:: 'type' | translate}}</th>
+            </tr>
+        </thead>
+        <tbody>
+            <tr ng-repeat="policy in policies | filter: {name: search.name, type: search.type} | orderBy:'name'">
+                <td><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/policy/{{policy.type}}/{{policy.id}}">{{policy.name}}</a></td>
+                <td>{{policy.description}}</td>
+                <td>{{policy.type}}</td>
+            </tr>
+            <tr data-ng-show="(policies | filter:search).length == 0">
+                <td class="text-muted" colspan="3" data-ng-show="search.name">{{:: 'no-results' | translate}}</td>
+                <td class="text-muted" colspan="3" data-ng-hide="search.name">{{:: 'authz-no-policies-available' | translate}}</td>
+            </tr>
+        </tbody>
+    </table>
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/resource-server-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/resource-server-detail.html
new file mode 100644
index 0000000..1110043
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/resource-server-detail.html
@@ -0,0 +1,79 @@
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+
+    <kc-tabs-resource-server></kc-tabs-resource-server>
+
+    <form class="form-horizontal" name="clientForm" novalidate>
+        <fieldset>
+            <div class="form-group">
+                <label for="import-file" class="col-sm-2 control-label">{{:: 'import' | translate}}</label>
+                <div class="col-md-6">
+                    <div class="controls kc-button-input-file" data-ng-show="!importing">
+                        <label for="import-file" class="btn btn-default">{{:: 'select-file' | translate}} <i class="pficon pficon-import"></i></label>
+                        <input id="import-file" type="file" class="hidden" kc-on-read-file="onFileSelect($fileContent)">
+                    </div>
+                    <div class="col-md-6" data-ng-show="importing">
+                        <input type="button" class="btn btn-default" data-ng-click="viewImportDetails()" value="{{:: 'view-details' | translate}}"/>
+                    </div>
+                </div>
+                <kc-tooltip>{{:: 'authz-import-config.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <div class="col-md-10 col-md-offset-2" data-ng-show="importing">
+                    <button class="btn btn-default" data-ng-click="import()" data-ng-disabled="!changed">Import</button>
+                    <button kc-cancel data-ng-click="reset()">Cancel</button>
+                </div>
+            </div>
+        </fieldset>
+        <fieldset class="border-top" data-ng-hide="importing">
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="server.policyEnforcementMode">{{:: 'authz-policy-enforcement-mode' | translate}}</label>
+                <div class="col-md-2">
+                    <select class="form-control" id="server.policyEnforcementMode" data-ng-model="server.policyEnforcementMode">
+                        <option value="ENFORCING">{{:: 'authz-policy-enforcement-mode-enforcing' | translate}}</option>
+                        <option value="PERMISSIVE">{{:: 'authz-policy-enforcement-mode-permissive' | translate}}</option>
+                        <option value="DISABLED">{{:: 'authz-policy-enforcement-mode-disabled' | translate}}</option>
+                    </select>
+                </div>
+                <kc-tooltip>{{:: 'authz-policy-enforcement-mode.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="server.allowRemoteResourceManagement">{{:: 'authz-remote-resource-management' | translate}}</label>
+                <div class="col-md-6">
+                    <input ng-model="server.allowRemoteResourceManagement" id="server.allowRemoteResourceManagement" onoffswitch />
+                </div>
+                <kc-tooltip>{{:: 'authz-remote-resource-management.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group" data-ng-show="access.manageAuthorization">
+                <div class="col-md-10 col-md-offset-2">
+                    <button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
+                    <button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
+                </div>
+            </div>
+        </fieldset>
+
+        <fieldset class="border-top" data-ng-show="server.id">
+            <legend><span class="text">{{:: 'authz-export-settings' | translate}}</span>
+                <kc-tooltip>{{:: 'authz-export-settings.tooltip' | translate}}</kc-tooltip>
+            </legend>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="server.allowRemoteResourceManagement">{{:: 'authz-export-settings' | translate}}</label>
+                <div class="col-md-6">
+                    <button data-ng-click="export()" class="btn btn-primary" data-ng-hide="settings">{{:: 'export' | translate}}</button>
+                    <button data-ng-click="downloadSettings()" class="btn btn-primary" data-ng-show="settings">{{:: 'download' | translate}}</button>
+                    <button data-ng-click="cancelExport()" class="btn btn-primary" data-ng-show="settings">{{:: 'cancel' | translate}}</button>
+                </div>
+                <kc-tooltip>{{:: 'authz-export-settings.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <fieldset class="margin-top">
+                <div class="form-group" ng-show="settings">
+                    <div class="col-sm-12">
+                        <a class="btn btn-primary btn-lg" data-ng-click="download()" type="submit" ng-show="installation">{{:: 'download' | translate}}</a>
+                        <textarea class="form-control" rows="20" kc-select-action="click">{{settings}}</textarea>
+                    </div>
+                </div>
+            </fieldset>
+        </fieldset>
+    </form>
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/resource-server-list.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/resource-server-list.html
new file mode 100644
index 0000000..3b4130e
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/resource-server-list.html
@@ -0,0 +1,49 @@
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+    <h1>
+        <span>Resource Servers</span>
+        <kc-tooltip>Resource Servers are applications serving resources to their users. These resources can be a RESTFul API, web pages or any other kind of resource that must be managed and protected by a set of authorization policies.</kc-tooltip>
+    </h1>
+
+    <table class="table table-striped table-bordered">
+        <thead>
+            <tr>
+                <th class="kc-table-actions" colspan="5">
+                    <div class="form-inline">
+                        <div class="form-group">
+                            <div class="input-group">
+                                <input type="text" placeholder="Search..." data-ng-model="search.clientId" class="form-control search" onkeyup="if(event.keyCode == 13){$(this).next('I').click();}">
+                                <div class="input-group-addon">
+                                    <i class="fa fa-search" type="submit"></i>
+                                </div>
+                            </div>
+                        </div>
+
+                        <div class="pull-right">
+                            <a id="createServer" class="btn btn-default" href="#/realms/{{realm.realm}}/authz/resource-server/create">Create</a>
+                        </div>
+                    </div>
+                </th>
+            </tr>
+            <tr data-ng-hide="servers.length == 0">
+                <th>Name</th>
+                <th>Policy Enforcement Mode</th>
+                <th>Allows Remote Resource Management ?</th>
+                <th>Allows Entitlement ?</th>
+            </tr>
+        </thead>
+        <tbody>
+            <tr ng-repeat="server in servers | filter:search | orderBy:'clientId'">
+                <td><a href="#/realms/{{realm.realm}}/authz/resource-server/{{server.id}}">{{server.name}}</a></td>
+                <td>{{server.policyEnforcementMode | toCamelCase}}</td>
+                <td>{{server.allowRemoteResourceManagement}}</td>
+                <td>{{server.allowEntitlements}}</td>
+            </tr>
+            <tr data-ng-show="(servers | filter:search).length == 0">
+                <td class="text-muted" colspan="3" data-ng-show="search.clientId">No results</td>
+                <td class="text-muted" colspan="3" data-ng-hide="search.clientId">No servers available</td>
+            </tr>
+        </tbody>
+    </table>
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/resource-server-resource-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/resource-server-resource-detail.html
new file mode 100644
index 0000000..f61c6e9
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/resource-server-resource-detail.html
@@ -0,0 +1,75 @@
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+
+    <ol class="breadcrumb">
+        <li><a href="#/realms/{{realm.realm}}/clients">{{:: 'clients' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}">{{client.clientId}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server">{{:: 'authz-authorization' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/resource">{{:: 'authz-resource' | translate}}</a></li>
+        <li data-ng-show="create">{{:: 'authz-add-resource' | translate}}</li>
+        <li data-ng-hide="create">{{originalResource.name}}</li>
+    </ol>
+
+    <h1 data-ng-show="create">{{:: 'authz-add-resource' | translate}}</h1>
+    <h1 data-ng-hide="create">{{originalResource.name|capitalize}}<i class="pficon pficon-delete clickable" data-ng-show="!create"
+                                                         data-ng-click="remove()"></i></h1>
+
+    <form class="form-horizontal" name="clientForm" novalidate>
+        <fieldset class="border-top">
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="name">{{:: 'name' | translate}} <span class="required" data-ng-show="create">*</span></label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="name" name="name" data-ng-model="resource.name" autofocus required data-ng-blur="checkNewNameAvailability()">
+                </div>
+                <kc-tooltip>{{:: 'authz-resource-name.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group" data-ng-hide="create">
+                <label class="col-md-2 control-label" for="resource.owner.name">{{:: 'authz-owner' | translate}} </label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="resource.owner.name" name="name" data-ng-model="resource.owner.name" autofocus disabled>
+                </div>
+                <kc-tooltip>{{:: 'authz-resource-owner.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="type">{{:: 'type' | translate}} </label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="type" name="name" data-ng-model="resource.type" autofocus>
+                </div>
+                <kc-tooltip>{{:: 'authz-resource-type.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="uri">{{:: 'authz-uri' | translate}} </label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="uri" name="name" data-ng-model="resource.uri" autofocus>
+                </div>
+                <kc-tooltip>{{:: 'authz-resource-uri.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix">
+                <label class="col-md-2 control-label" for="reqActions">{{:: 'authz-scopes' | translate}}</label>
+
+                <div class="col-md-6">
+                    <select ui-select2 id="reqActions" ng-model="resource.scopes" data-placeholder="{{:: 'authz-select-scope' | translate}}..." multiple>
+                        <option ng-repeat="scope in scopes" value="{{scope.name}}" ng-selected="true">{{scope.name}}</option>
+                    </select>
+                </div>
+
+                <kc-tooltip>{{:: 'authz-resource-scopes.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="iconUri">{{:: 'authz-icon-uri' | translate}} </label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="iconUri" name="name" data-ng-model="resource.icon_uri" autofocus>
+                </div>
+                <kc-tooltip>{{:: 'authz-icon-uri.tooltip' | translate}}</kc-tooltip>
+            </div>
+        </fieldset>
+
+        <div class="form-group" data-ng-show="access.manageAuthorization">
+            <div class="col-md-10 col-md-offset-2">
+                <button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
+                <button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
+            </div>
+        </div>
+    </form>
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/resource-server-resource-list.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/resource-server-resource-list.html
new file mode 100644
index 0000000..40b2cf9
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/resource-server-resource-list.html
@@ -0,0 +1,85 @@
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+
+    <kc-tabs-resource-server></kc-tabs-resource-server>
+
+    <table class="table table-striped table-bordered">
+        <thead>
+            <tr>
+                <th class="kc-table-actions" colspan="7">
+                    <div class="form-inline">
+                        {{:: 'filter' | translate}}:&nbsp;&nbsp;
+                        <div class="form-group">
+                            <div class="input-group">
+                                <input type="text" placeholder="{{:: 'name' | translate}}" data-ng-model="search.name" class="form-control search" onkeyup="if(event.keyCode == 13){$(this).next('I').click();}">
+                                <div class="input-group-addon">
+                                    <i class="fa fa-search" type="submit"></i>
+                                </div>
+                            </div>
+                            <div class="input-group">
+                                <input type="text" placeholder="{{:: 'authz-owner' | translate}}" data-ng-model="search.owner.name" class="form-control search" onkeyup="if(event.keyCode == 13){$(this).next('I').click();}">
+                                <div class="input-group-addon">
+                                    <i class="fa fa-search" type="submit"></i>
+                                </div>
+                            </div>
+                            <div class="input-group">
+                                <select class="form-control search" data-ng-model="search.type"
+                                        ng-options="r.type as r.type for r in resources | unique : 'type'">
+                                    <option value="" selected ng-click="search.type = ''">{{:: 'type' | translate}}</option>
+                                </select>
+                            </div>
+                        </div>
+
+                        <div class="pull-right">
+                            <a id="createResource" class="btn btn-default" href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/resource/create">{{:: 'create' | translate}}</a>
+                        </div>
+                    </div>
+                </th>
+            </tr>
+            <tr data-ng-hide="resources.length == 0">
+                <th>{{:: 'name' | translate}}</th>
+                <th>{{:: 'type' | translate}}</th>
+                <th>{{:: 'authz-uri' | translate}}</th>
+                <th>{{:: 'authz-owner' | translate}}</th>
+                <th>{{:: 'authz-scopes' | translate}}</th>
+                <th>{{:: 'authz-permissions' | translate}}</th>
+                <th>{{:: 'actions' | translate}}</th>
+            </tr>
+        </thead>
+        <tbody>
+            <tr ng-repeat="resource in resources | filter:search | orderBy:'name'">
+                <td><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/resource/{{resource._id}}">{{resource.name}}</a></td>
+                <td>
+                    <span data-ng-show="resource.type">{{resource.type}}</span>
+                    <span data-ng-show="!resource.type">{{:: 'authz-no-type-defined' | translate}}</span>
+                </td>
+                <td>{{resource.uri}}</td>
+                <td>{{resource.owner.name}}</td>
+                <td>
+                    <span data-ng-show="!resource.scopes.length">{{:: 'authz-no-scopes-assigned' | translate}}</span>
+                    <span data-ng-show="resource.scopes.length > 0">
+                        <span ng-repeat="scope in resource.scopes">
+                            <a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/scope/{{scope.id}}">{{scope.name}}</a>{{$last ? '' : ', '}}
+                        </span>
+                    </span>
+                </td>
+                <td>
+                    <span data-ng-show="!resource.policies.length">{{:: 'authz-no-permission-assigned' | translate}}</span>
+                    <span data-ng-show="resource.policies.length > 0">
+                        <span ng-repeat="policy in resource.policies">
+                            <a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/permission/{{policy.type}}/{{policy.id}}">{{policy.name}}</a>{{$last ? '' : ', '}}
+                        </span>
+                    </span>
+                </td>
+                <td class="kc-action-cell" style="vertical-align: middle">
+                    <button class="btn btn-default btn-block btn-sm" ng-click="createPolicy(resource);">{{:: 'authz-create-permission' | translate}}</button>
+                </td>
+            </tr>
+            <tr data-ng-show="(resources | filter:search).length == 0">
+                <td class="text-muted" colspan="6" data-ng-show="search.name">{{:: 'no-results' | translate}}</td>
+                <td class="text-muted" colspan="6" data-ng-hide="search.name">{{:: 'authz-no-resources-available' | translate}}</td>
+            </tr>
+        </tbody>
+    </table>
+</div>
+
+<kc-menu></kc-menu>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/resource-server-scope-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/resource-server-scope-detail.html
new file mode 100644
index 0000000..fac9c9c
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/resource-server-scope-detail.html
@@ -0,0 +1,43 @@
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+
+    <ol class="breadcrumb">
+        <li><a href="#/realms/{{realm.realm}}/clients">{{:: 'clients' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}">{{client.clientId}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server">{{:: 'authz-authorization' | translate}}</a></li>
+        <li><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/scope">{{:: 'authz-scope' | translate}}</a></li>
+        <li data-ng-show="create">{{:: 'authz-add-scope' | translate}}</li>
+        <li data-ng-hide="create">{{originalScope.name}}</li>
+    </ol>
+
+    <h1 data-ng-show="create">{{:: 'authz-add-scope' | translate}}</h1>
+    <h1 data-ng-hide="create">{{originalScope.name|capitalize}}<i class="pficon pficon-delete clickable" data-ng-show="!create"
+                                                         data-ng-hide="changed" data-ng-click="remove()"></i></h1>
+
+    <form class="form-horizontal" name="clientForm" novalidate>
+        <fieldset class="border-top">
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="name">{{:: 'name' | translate}} </label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="name" name="name" data-ng-model="scope.name" autofocus data-ng-blur="checkNewNameAvailability()">
+                </div>
+                <kc-tooltip>{{:: 'authz-scope-name.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group">
+                <label class="col-md-2 control-label" for="name">{{:: 'authz-icon-uri' | translate}} </label>
+                <div class="col-sm-6">
+                    <input class="form-control" type="text" id="name" name="name" data-ng-model="scope.iconUri" autofocus>
+                </div>
+                <kc-tooltip>{{:: 'authz-icon-uri.tooltip' | translate}}</kc-tooltip>
+            </div>
+        </fieldset>
+
+        <div class="form-group" data-ng-show="access.manageAuthorization">
+            <div class="col-md-10 col-md-offset-2">
+                <button kc-save data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
+                <button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
+            </div>
+        </div>
+    </form>
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/authz/resource-server-scope-list.html b/themes/src/main/resources/theme/base/admin/resources/partials/authz/resource-server-scope-list.html
new file mode 100644
index 0000000..39cfc77
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/authz/resource-server-scope-list.html
@@ -0,0 +1,63 @@
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+
+    <kc-tabs-resource-server></kc-tabs-resource-server>
+
+    <table class="table table-striped table-bordered">
+        <thead>
+            <tr>
+                <th class="kc-table-actions" colspan="5">
+                    <div class="form-inline">
+                        <div class="form-group">
+                            <div class="input-group">
+                                <input type="text" placeholder="{{:: 'search.placeholder' | translate}}" data-ng-model="search.name" class="form-control search" onkeyup="if(event.keyCode == 13){$(this).next('I').click();}">
+                                <div class="input-group-addon">
+                                    <i class="fa fa-search" type="submit"></i>
+                                </div>
+                            </div>
+                        </div>
+
+                        <div class="pull-right">
+                            <a id="createScope" class="btn btn-default" href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/scope/create">{{:: 'create' | translate}}</a>
+                        </div>
+                    </div>
+                </th>
+            </tr>
+            <tr data-ng-hide="scopes.length == 0">
+                <th>{{:: 'name' | translate}}</th>
+                <th>{{:: 'authz-resources' | translate}}</th>
+                <th>{{:: 'authz-permissions' | translate}}</th>
+                <th>{{:: 'actions' | translate}}</th>
+            </tr>
+        </thead>
+        <tbody>
+            <tr ng-repeat="scope in scopes | filter:search | orderBy:'name'">
+                <td><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/scope/{{scope.id}}">{{scope.name}}</a></td>
+                <td>
+                    <span data-ng-show="!scope.resources.length">{{:: 'authz-no-resources-assigned' | translate}}</span>
+                    <span data-ng-show="scope.resources.length > 0">
+                        <span ng-repeat="resource in scope.resources">
+                            <a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/resource/{{resource._id}}">{{resource.name}}</a>{{$last ? '' : ', '}}
+                        </span>
+                    </span>
+                </td>
+                <td>
+                    <span data-ng-show="!scope.policies.length">{{:: 'authz-no-permission-assigned' | translate}}</span>
+                    <span data-ng-show="scope.policies.length > 0">
+                        <span ng-repeat="policy in scope.policies">
+                            <a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/permission/{{policy.type}}/{{policy.id}}">{{policy.name}}</a>{{$last ? '' : ', '}}
+                        </span>
+                    </span>
+                </td>
+                <td class="kc-action-cell" style="vertical-align: middle">
+                    <button class="btn btn-default btn-block btn-sm" ng-click="createPolicy(scope);">{{:: 'authz-create-permission' | translate}}</button>
+                </td>
+            </tr>
+            <tr data-ng-show="(scopes | filter:search).length == 0">
+                <td class="text-muted" colspan="3" data-ng-show="search.name">{{:: 'no-results' | translate}}</td>
+                <td class="text-muted" colspan="3" data-ng-hide="search.name">{{:: 'authz-no-scopes-available' | translate}}</td>
+            </tr>
+        </tbody>
+    </table>
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt.html
index 8c581d7..0cb1999 100644
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt.html
@@ -1,13 +1,26 @@
 <div>
     <form class="form-horizontal no-margin-top" name="keyForm" novalidate kc-read-only="!access.manageClients" data-ng-controller="ClientSignedJWTCtrl">
         <div class="form-group">
-            <label class="col-md-2 control-label" for="signingCert">{{:: 'certificate' | translate}}</label>
-            <kc-tooltip>{{:: 'certificate.tooltip' | translate}}</kc-tooltip>
 
-            <div class="col-sm-10" data-ng-show="signingKeyInfo.certificate">
-                <textarea type="text" id="signingCert" name="signingCert" class="form-control" rows="5" kc-select-action="click" readonly>{{signingKeyInfo.certificate}}</textarea>
+            <div data-ng-show="signingKeyInfo.certificate">
+                <label class="col-md-2 control-label" for="signingCert">{{:: 'certificate' | translate}}</label>
+                <kc-tooltip>{{:: 'certificate.tooltip' | translate}}</kc-tooltip>
+
+                <div class="col-sm-10" data-ng-show="signingKeyInfo.certificate">
+                    <textarea type="text" id="signingCert" name="signingCert" class="form-control" rows="5" kc-select-action="click" readonly>{{signingKeyInfo.certificate}}</textarea>
+                </div>
             </div>
-            <div class="col-sm-10" data-ng-hide="signingKeyInfo.certificate">
+
+            <div data-ng-show="signingKeyInfo.publicKey">
+                <label class="col-md-2 control-label" for="publicKey">{{:: 'publicKey' | translate}}</label>
+                <kc-tooltip>{{:: 'publicKey.tooltip' | translate}}</kc-tooltip>
+
+                <div class="col-sm-10" data-ng-show="signingKeyInfo.publicKey">
+                    <textarea type="text" id="publicKey" name="publicKey" class="form-control" rows="5" kc-select-action="click" readonly>{{signingKeyInfo.publicKey}}</textarea>
+                </div>
+            </div>
+
+            <div class="col-sm-10" data-ng-hide="signingKeyInfo.certificate || signingKeyInfo.publicKey">
                 {{:: 'no-client-certificate-configured' | translate}}
             </div>
         </div>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt-key-import.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt-key-import.html
index 1e8d6a9..9968a31 100644
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt-key-import.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-credentials-jwt-key-import.html
@@ -26,14 +26,14 @@
                 </div>
                 <kc-tooltip>{{:: 'archive-format.tooltip' | translate}}</kc-tooltip>
             </div>
-            <div class="form-group">
+            <div class="form-group" data-ng-hide="hideKeystoreSettings()">
                 <label class="col-md-2 control-label" for="uploadKeyAlias">{{:: 'key-alias' | translate}}</label>
                 <div class="col-md-6">
                     <input class="form-control" type="text" id="uploadKeyAlias" name="uploadKeyAlias" data-ng-model="uploadKeyAlias" autofocus required>
                 </div>
                 <kc-tooltip>{{:: 'jwt-import.key-alias.tooltip' | translate}}</kc-tooltip>
             </div>
-            <div class="form-group">
+            <div class="form-group" data-ng-hide="hideKeystoreSettings()">
                 <label class="col-md-2 control-label" for="uploadStorePassword">{{:: 'store-password' | translate}}</label>
                 <div class="col-md-6">
                     <input class="form-control" type="password" id="uploadStorePassword" name="uploadStorePassword" data-ng-model="uploadStorePassword" autofocus required>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
index ef1f7b4..1378f78 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-detail.html
@@ -110,6 +110,13 @@
                     <input ng-model="client.serviceAccountsEnabled" name="serviceAccountsEnabled" id="serviceAccountsEnabled" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
                 </div>
             </div>
+            <div class="form-group" data-ng-show="protocol == 'openid-connect'">
+                <label class="col-md-2 control-label" for="authorizationServicesEnabled">{{:: 'authz-authorization-services-enabled' | translate}}</label>
+                <kc-tooltip>{{:: 'authz-authorization-services-enabled.tooltip' | translate}}</kc-tooltip>
+                <div class="col-md-6">
+                    <input ng-model="client.authorizationServicesEnabled" name="authorizationServicesEnabled" id="authorizationServicesEnabled" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
+                </div>
+            </div>
             <div class="form-group clearfix block" data-ng-show="protocol == 'saml'">
                 <label class="col-md-2 control-label" for="samlServerSignature">{{:: 'include-authnstatement' | translate}}</label>
                 <div class="col-sm-6">
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-initial-access.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-initial-access.html
index 11b3dcf..4bc9d68 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/client-initial-access.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-initial-access.html
@@ -1,6 +1,59 @@
 <div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
     <kc-tabs-realm></kc-tabs-realm>
 
+    <div class="form-group">
+        <legend>{{:: 'trusted-hosts-legend' | translate}}</legend>
+        <kc-tooltip>{{:: 'trusted-hosts-legend.tooltip' | translate}}</kc-tooltip>
+    </div>
+
+    <table class="table table-striped table-bordered">
+        <thead>
+        <tr>
+            <th class="kc-table-actions" colspan="6">
+                <div class="form-inline">
+
+                    <div class="form-group">
+                        <div class="input-group">
+                            <input type="text" placeholder="{{:: 'search.placeholder' | translate}}" data-ng-model="search1.host" class="form-control search" onkeyup="if(event.keyCode == 13){$(this).next('I').click();}">
+                            <div class="input-group-addon">
+                                <i class="fa fa-search" type="submit"></i>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="pull-right" data-ng-show="access.manageClients">
+                        <a id="createClientTrustedHost" class="btn btn-default" href="#/realms/{{realm.realm}}/client-reg-trusted-hosts/create">{{:: 'create' | translate}}</a>
+                    </div>
+                </div>
+            </th>
+        </tr>
+        <tr data-ng-hide="clientRegTrustedHosts.length == 0">
+            <th>{{:: 'hostname' | translate}}</th>
+            <th>{{:: 'count' | translate}}</th>
+            <th>{{:: 'remainingCount' | translate}}</th>
+            <th colspan="2">{{:: 'actions' | translate}}</th>
+        </tr>
+        </thead>
+        <tbody>
+        <tr ng-repeat="host in clientRegTrustedHosts | filter:search1 | orderBy:'timestamp'">
+            <td>{{host.hostName}}</td>
+            <td>{{host.count}}</td>
+            <td>{{host.remainingCount}}</td>
+            <td class="kc-action-cell" data-ng-click="updateHost(host.hostName)">{{:: 'update' | translate}}</td>
+            <td class="kc-action-cell" data-ng-click="removeHost(host.hostName)">{{:: 'delete' | translate}}</td>
+        </tr>
+        <tr data-ng-show="(clientRegTrustedHosts | filter:search1).length == 0">
+            <td class="text-muted" colspan="3" data-ng-show="search1.host">{{:: 'no-results' | translate}}</td>
+            <td class="text-muted" colspan="3" data-ng-hide="search1.host">{{:: 'no-client-trusted-hosts-available' | translate}}</td>
+        </tr>
+        </tbody>
+    </table>
+
+
+    <div class="form-group">
+        <legend>{{:: 'initial-access-tokens' | translate}}</legend>
+        <kc-tooltip>{{:: 'initial-access-tokens.tooltip' | translate}}</kc-tooltip>
+    </div>
     <table class="table table-striped table-bordered">
         <thead>
         <tr>
@@ -8,7 +61,7 @@
                 <div class="form-inline">
                     <div class="form-group">
                         <div class="input-group">
-                            <input type="text" placeholder="{{:: 'search.placeholder' | translate}}" data-ng-model="search.id" class="form-control search" onkeyup="if(event.keyCode == 13){$(this).next('I').click();}">
+                            <input type="text" placeholder="{{:: 'search.placeholder' | translate}}" data-ng-model="search2.id" class="form-control search" onkeyup="if(event.keyCode == 13){$(this).next('I').click();}">
                             <div class="input-group-addon">
                                 <i class="fa fa-search" type="submit"></i>
                             </div>
@@ -21,7 +74,7 @@
                 </div>
             </th>
         </tr>
-        <tr data-ng-hide="clients.length == 0">
+        <tr data-ng-hide="clientInitialAccess.length == 0">
             <th>{{:: 'id' | translate}}</th>
             <th>{{:: 'created' | translate}}</th>
             <th>{{:: 'expires' | translate}}</th>
@@ -31,7 +84,7 @@
         </tr>
         </thead>
         <tbody>
-        <tr ng-repeat="ia in clientInitialAccess | filter:search | orderBy:'timestamp'">
+        <tr ng-repeat="ia in clientInitialAccess | filter:search2 | orderBy:'timestamp'">
             <td>{{ia.id}}</td>
             <td>{{(ia.timestamp * 1000)|date:'shortDate'}}&nbsp;{{(ia.timestamp * 1000)|date:'mediumTime'}}</td>
             <td><span data-ng-show="ia.expiration > 0">{{((ia.timestamp + ia.expiration) * 1000)|date:'shortDate'}}&nbsp;{{((ia.timestamp + ia.expiration) * 1000)|date:'mediumTime'}}</span></td>
@@ -39,9 +92,9 @@
             <td>{{ia.remainingCount}}</td>
             <td class="kc-action-cell" data-ng-click="remove(ia.id)">{{:: 'delete' | translate}}</td>
         </tr>
-        <tr data-ng-show="(clients | filter:search).length == 0">
-            <td class="text-muted" colspan="3" data-ng-show="search.clientId">{{:: 'no-results' | translate}}</td>
-            <td class="text-muted" colspan="3" data-ng-hide="search.clientId">{{:: 'no-clients-available' | translate}}</td>
+        <tr data-ng-show="(clientInitialAccess | filter:search2).length == 0">
+            <td class="text-muted" colspan="3" data-ng-show="search2.id">{{:: 'no-results' | translate}}</td>
+            <td class="text-muted" colspan="3" data-ng-hide="search2.id">{{:: 'no-initial-access-available' | translate}}</td>
         </tr>
         </tbody>
     </table>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-reg-trusted-host-create.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-reg-trusted-host-create.html
new file mode 100644
index 0000000..cb07613
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-reg-trusted-host-create.html
@@ -0,0 +1,55 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+
+    <ol class="breadcrumb">
+        <li><a href="#/realms/{{realm.realm}}/client-initial-access">{{:: 'initial-access-tokens' | translate}}</a></li>
+        <li>{{:: 'add-client-reg-trusted-host' | translate}}</li>
+    </ol>
+
+    <h1>{{:: 'add-client-reg-trusted-host' | translate}}</h1>
+
+    <form class="form-horizontal" name="createForm" novalidate kc-read-only="!access.manageRealm">
+
+        <div class="form-group">
+            <label class="col-md-2 control-label" for="hostName">{{:: 'hostname' | translate}} </label>
+            <div class="col-sm-6">
+                <input class="form-control" type="text" id="hostName" name="hostName" data-ng-model="hostName">
+            </div>
+            <kc-tooltip>{{:: 'client-reg-hostname.tooltip' | translate}}</kc-tooltip>
+        </div>
+
+        <div class="form-group">
+            <label class="col-md-2 control-label" for="count">{{:: 'count' | translate}} </label>
+            <div class="col-sm-6">
+                <input class="form-control" type="text" id="count" name="count" required min="1" max="10000" data-ng-model="count">
+            </div>
+            <kc-tooltip>{{:: 'client-reg-count.tooltip' | translate}}</kc-tooltip>
+        </div>
+
+        <div class="form-group">
+            <div class="col-md-10 col-md-offset-2" data-ng-show="access.manageRealm">
+                <button kc-save>{{:: 'save' | translate}}</button>
+                <button kc-cancel data-ng-click="cancel()">{{:: 'cancel' | translate}}</button>
+            </div>
+        </div>
+    </form>
+
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/client-reg-trusted-host-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/client-reg-trusted-host-detail.html
new file mode 100644
index 0000000..5644fc1
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/client-reg-trusted-host-detail.html
@@ -0,0 +1,64 @@
+<!--
+  ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+  ~ and other contributors as indicated by the @author tags.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~ http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+
+    <ol class="breadcrumb">
+        <li><a href="#/realms/{{realm.realm}}/client-initial-access">{{:: 'initial-access-tokens' | translate}}</a></li>
+        <li>{{hostName}}</li>
+    </ol>
+
+    <h1>{{hostName}}</h1>
+
+    <form class="form-horizontal" name="createForm" novalidate kc-read-only="!access.manageRealm">
+
+        <div class="form-group">
+            <label class="col-md-2 control-label" for="hostName">{{:: 'hostname' | translate}} </label>
+            <div class="col-sm-6">
+                <input class="form-control" type="text" id="hostName" name="hostName" data-ng-model="hostName" readonly>
+            </div>
+            <kc-tooltip>{{:: 'client-reg-hostname.tooltip' | translate}}</kc-tooltip>
+        </div>
+
+        <div class="form-group">
+            <label class="col-md-2 control-label" for="count">{{:: 'count' | translate}} </label>
+            <div class="col-sm-6">
+                <input class="form-control" type="text" id="count" name="count" required min="1" max="10000" data-ng-model="count">
+            </div>
+            <kc-tooltip>{{:: 'client-reg-count.tooltip' | translate}}</kc-tooltip>
+        </div>
+
+        <div class="form-group">
+            <label class="col-md-2 control-label" for="remainingCount">{{:: 'remainingCount' | translate}} </label>
+            <div class="col-sm-6">
+                <input class="form-control" type="text" id="remainingCount" name="remainingCount" data-ng-model="remainingCount" readonly>
+            </div>
+            <kc-tooltip>{{:: 'client-reg-remainingCount.tooltip' | translate}}</kc-tooltip>
+        </div>
+
+        <div class="form-group">
+            <div class="col-md-10 col-md-offset-2" data-ng-show="access.manageRealm">
+                <button class="btn btn-primary" data-ng-click="resetRemainingCount()" data-ng-hide="changed">{{:: 'reset-remaining-count' | translate}}</button>
+                <button data-ng-show="changed" kc-save>{{:: 'save' | translate}}</button>
+                <button kc-cancel data-ng-click="cancel()">{{:: 'cancel' | translate}}</button>
+            </div>
+        </div>
+    </form>
+
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/password-policy.html b/themes/src/main/resources/theme/base/admin/resources/partials/password-policy.html
index 926ee80..e929cad 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/password-policy.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/password-policy.html
@@ -7,12 +7,12 @@
         <table class="table table-striped table-bordered">
             <caption class="hidden">{{:: 'table-of-password-policies' | translate}}</caption>
             <thead>
-            <tr ng-show="(allPolicies|removeSelectedPolicies:policy).length > 0">
+            <tr ng-show="(serverInfo.passwordPolicies|removeSelectedPolicies:policy).length > 0">
                 <th colspan="5" class="kc-table-actions">
                     <div class="pull-right">
                         <div>
                             <select class="form-control" ng-model="selectedPolicy"
-                                    ng-options="(p.name|capitalize) for p in (allPolicies|removeSelectedPolicies:policy)"
+                                    ng-options="policy as policy.displayName for policy in (serverInfo.passwordPolicies|removeSelectedPolicies:policy) track by policy.id"
                                     data-ng-change="addPolicy(selectedPolicy); selectedPolicy = null">
                                 <option value="" disabled selected>{{:: 'add-policy.placeholder' | translate}}</option>
                             </select>
@@ -28,10 +28,9 @@
             </thead>
             <tbody>
             <tr ng-repeat="p in policy">
-                <td>{{p.name|capitalize}}</td>
+                <td>{{p.displayName}}</td>
                 <td>
-                    <input class="form-control" ng-model="p.value" ng-show="p.name != 'notUsername' "
-                           placeholder="{{:: 'no-value-assigned.placeholder' | translate}}" min="1" required>
+                    <input type="text" class="form-control" ng-model="p.value" ng-show="p.configType" data-ng-required="!p.configType && !p.defaultValue">
                 </td>
                 <td class="kc-action-cell" ng-click="removePolicy($index)">{{:: 'delete' | translate}}</td>
             </tr>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/realm-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/realm-detail.html
index 6a694f1..48fa3a2 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/realm-detail.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/realm-detail.html
@@ -32,6 +32,14 @@
             </div>
 
             <div class="form-group">
+                <label class="col-md-2 control-label">{{:: 'endpoints' | translate}}</label>
+                <div class="col-md-6">
+                    <a class="form-control" ng-href="{{authUrl}}/realms/{{realm.id}}/.well-known/openid-configuration" target="_blank">OpenID Endpoint Configuration</a>
+                </div>
+                <kc-tooltip>{{:: 'realm-detail.oidc-endpoints.tooltip' | translate}}</kc-tooltip>
+            </div>
+
+            <div class="form-group">
                 <div class="col-md-10 col-md-offset-2" data-ng-show="createRealm && access.manageRealm">
                     <button kc-save data-ng-show="changed">{{:: 'save' | translate}}</button>
                     <button kc-cancel data-ng-click="cancel()">{{:: 'cancel' | translate}}</button>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/realm-events-admin.html b/themes/src/main/resources/theme/base/admin/resources/partials/realm-events-admin.html
index d380d11..04a6311 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/realm-events-admin.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/realm-events-admin.html
@@ -33,11 +33,17 @@
                     </div>
                     <form class="form-horizontal" data-ng-show="filter">
                         <div class="form-group">
-      			            <label class="col-sm-2 control-label" for="adminEnabledEventOperations">{{:: 'operation-types' | translate}}</label>
-                    	    <div class="col-sm-5">
+                            <label class="col-sm-2 control-label" for="adminEnabledEventOperations">{{:: 'operation-types' | translate}}</label>
+                            <div class="col-sm-5">
                                 <input ui-select2="adminEnabledEventOperationsOptions" id="adminEnabledEventOperations" ng-model="query.operationTypes" data-placeholder="{{:: 'select-operations.placeholder' | translate}}"/>
-			                </div>
-			            </div>
+                            </div>
+                        </div>
+                        <div class="form-group">
+                            <label class="col-sm-2 control-label" for="adminEnabledEventResourceTypes">{{:: 'resource-types' | translate}}</label>
+                            <div class="col-sm-5">
+                                <input ui-select2="adminEnabledEventResourceTypesOptions" id="adminEnabledEventResourceTypes" ng-model="query.resourceTypes" data-placeholder="{{:: 'select-resource-types.placeholder' | translate}}"/>
+                            </div>
+                        </div>
                         <div class="form-group">
                             <label class="col-sm-2 control-label" for="resource">{{:: 'resource-path' | translate}}</label>
                             <div class="col-sm-4">
@@ -93,6 +99,7 @@
             <tr>
                 <th width="100px">{{:: 'time' | translate}}</th>
                 <th width="180px">{{:: 'operation-type' | translate}}</th>
+                <th width="180px">{{:: 'resource-type' | translate}}</th>
                 <th width="180px">{{:: 'resource-path' | translate}}</th>
                 <th>{{:: 'details' | translate}}</th>
             </tr>
@@ -110,6 +117,7 @@
                 <tr data-ng-repeat="event in events">
                     <td>{{event.time|date:'shortDate'}}<br>{{event.time|date:'mediumTime'}}</td>
                     <td data-ng-class="events-error">{{event.operationType}}</td>
+                    <td data-ng-class="events-error">{{event.resourceType}}</td>
                     <td>{{event.resourcePath}}</td>
                     <td>
                         <button type="button" class="btn btn-default btn-xs" data-ng-click="viewAuth(event)">
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html b/themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html
index 6939b26..c06e5b5 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/user-detail.html
@@ -77,7 +77,7 @@
                 </div>
             </div>
             <div class="form-group clearfix block" data-ng-show="!create && user.federationLink">
-                <label class="col-md-2 control-label" for="userEnabled">{{:: 'federation-link' | translate}}</label>
+                <label class="col-md-2 control-label">{{:: 'federation-link' | translate}}</label>
                 <div class="col-md-6">
                     <a href="{{federationLink}}">{{federationLinkName}}</a>
                 </div>
@@ -117,7 +117,7 @@
                 <label class="col-md-2 control-label" for="impersonate">{{:: 'impersonate-user' | translate}}</label>
 
                 <div class="col-md-6">
-                    <button id="impersonate" data-ng-show="access.impersonation" class="btn btn-default" data-ng-click="impersonate()">{{:: 'impersonate' | translate}}</button>
+                    <button id="impersonate" data-ng-show="access.impersonation" kc-read-only-ignore class="btn btn-default" data-ng-click="impersonate()">{{:: 'impersonate' | translate}}</button>
                 </div>
                 <kc-tooltip>{{:: 'impersonate-user.tooltip' | translate}}</kc-tooltip>
             </div>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/user-federation.html b/themes/src/main/resources/theme/base/admin/resources/partials/user-federation.html
index fe8b1be..cdf18b8 100755
--- a/themes/src/main/resources/theme/base/admin/resources/partials/user-federation.html
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/user-federation.html
@@ -27,11 +27,11 @@
         </thead>
         <tbody>
         <tr ng-repeat="instance in instances">
-            <td><a href="#/realms/{{realm.realm}}/user-federation/providers/{{instance.providerName}}/{{instance.id}}">{{instance.displayName}}</a></td>
-            <td>{{instance.providerName|capitalize}}</td>
-            <td>{{instance.priority}}</td>
-            <td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/user-federation/providers/{{instance.providerName}}/{{instance.id}}">{{:: 'edit' | translate}}</td>
-            <td class="kc-action-cell" data-ng-click="removeUserFederation(instance)">{{:: 'delete' | translate}}</td>
+            <td><a href="#{{getInstanceLink(instance)}}">{{getInstanceName(instance)}}</a></td>
+            <td>{{getInstanceProvider(instance)|capitalize}}</td>
+            <td>{{getInstancePriority(instance)}}</td>
+            <td class="kc-action-cell" kc-open="{{getInstanceLink(instance)}}">{{:: 'edit' | translate}}</td>
+            <td class="kc-action-cell" data-ng-click="removeInstance(instance)">{{:: 'delete' | translate}}</td>
          </tr>
         <tr data-ng-show="!instances || instances.length == 0">
             <td class="text-muted">{{:: 'no-user-federation-providers-configured' | translate}}</td>
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/user-storage.html b/themes/src/main/resources/theme/base/admin/resources/partials/user-storage.html
new file mode 100755
index 0000000..156a1ff
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/user-storage.html
@@ -0,0 +1,43 @@
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+    <h1>
+        <span>{{:: 'user-storage' | translate}}</span>
+    </h1>
+
+    <table class="table table-striped table-bordered">
+        <thead>
+        <tr ng-show="providers.length > 0 && access.manageUsers">
+            <th colspan="5" class="kc-table-actions">
+                <div class="pull-right">
+                    <div>
+                        <select class="form-control" ng-model="selectedProvider"
+                                ng-options="p.id for p in providers"
+                                data-ng-change="addProvider(selectedProvider); selectedProvider = null">
+                            <option value="" disabled selected>{{:: 'add-provider.placeholder' | translate}}</option>
+                        </select>
+                    </div>
+                </div>
+            </th>
+        </tr>
+        <tr data-ng-show="instances && instances.length > 0">
+            <th>{{:: 'id' | translate}}</th>
+            <th>{{:: 'provider-name' | translate}}</th>
+            <th>{{:: 'priority' | translate}}</th>
+            <th colspan="2">{{:: 'actions' | translate}}</th>
+        </tr>
+        </thead>
+        <tbody>
+        <tr ng-repeat="instance in instances">
+            <td><a href="#/realms/{{realm.realm}}/user-storage/providers/{{instance.providerId}}/{{instance.id}}">{{instance.name}}</a></td>
+            <td>{{instance.providerId|capitalize}}</td>
+            <td>{{instance.config['priority'][0]}}</td>
+            <td class="kc-action-cell" kc-open="/realms/{{realm.realm}}/user-storage/providers/{{instance.providerId}}/{{instance.id}}">{{:: 'edit' | translate}}</td>
+            <td class="kc-action-cell" data-ng-click="removeUserStorage(instance)">{{:: 'delete' | translate}}</td>
+         </tr>
+        <tr data-ng-show="!instances || instances.length == 0">
+            <td class="text-muted">{{:: 'no-user-storage-providers-configured' | translate}}</td>
+        </tr>
+        </tbody>
+    </table>
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/user-storage-generic.html b/themes/src/main/resources/theme/base/admin/resources/partials/user-storage-generic.html
new file mode 100755
index 0000000..e3ff5f6
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/partials/user-storage-generic.html
@@ -0,0 +1,54 @@
+<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
+    <ol class="breadcrumb">
+        <li><a href="#/realms/{{realm.realm}}/user-federation">{{:: 'user-federation' | translate}}</a></li>
+        <li data-ng-hide="create">{{instance.name|capitalize}}</li>
+        <li data-ng-show="create">{{:: 'add-user-storage-provider' | translate}}</li>
+    </ol>
+
+    <kc-tabs-user-storage></kc-tabs-user-storage>
+
+    <form class="form-horizontal" name="realmForm" novalidate kc-read-only="!access.manageRealm">
+        <fieldset>
+            <legend><span class="text">{{:: 'required-settings' | translate}}</span></legend>
+            <div class="form-group clearfix" data-ng-show="!create">
+                <label class="col-md-2 control-label" for="providerId">{{:: 'provider-id' | translate}} </label>
+                <div class="col-md-6">
+                    <input class="form-control" id="providerId" type="text" ng-model="instance.id" readonly>
+                </div>
+            </div>
+            <div class="form-group clearfix">
+                <label class="col-md-2 control-label" for="consoleDisplayName">{{:: 'console-display-name' | translate}} </label>
+                <div class="col-md-6">
+                    <input class="form-control" id="consoleDisplayName" type="text" ng-model="instance.name" placeholder="{{:: 'defaults-to-id' | translate}}">
+                </div>
+                <kc-tooltip>{{:: 'console-display-name.tooltip' | translate}}</kc-tooltip>
+            </div>
+            <div class="form-group clearfix">
+                <label class="col-md-2 control-label" for="priority">{{:: 'priority' | translate}} </label>
+                <div class="col-md-6">
+                    <input class="form-control" id="priority" type="text" ng-model="instance.config['priority'][0]">
+                </div>
+                <kc-tooltip>{{:: 'priority.tooltip' | translate}}</kc-tooltip>
+            </div>
+
+            <kc-component-config realm="realm" config="instance.config" properties="providerFactory.properties"></kc-component-config>
+
+        </fieldset>
+
+        <div class="form-group">
+            <div class="col-md-10 col-md-offset-2" data-ng-show="create && access.manageUsers">
+                <button kc-save>{{:: 'save' | translate}}</button>
+                <button kc-cancel data-ng-click="cancel()">{{:: 'cancel' | translate}}</button>
+            </div>
+        </div>
+
+        <div class="form-group">
+            <div class="col-md-10 col-md-offset-2" data-ng-show="!create && access.manageUsers">
+                <button kc-save  data-ng-disabled="!changed">{{:: 'save' | translate}}</button>
+                <button kc-reset data-ng-disabled="!changed">{{:: 'cancel' | translate}}</button>
+            </div>
+        </div>
+    </form>
+</div>
+
+<kc-menu></kc-menu>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/templates/authz/kc-authz-modal.html b/themes/src/main/resources/theme/base/admin/resources/templates/authz/kc-authz-modal.html
new file mode 100644
index 0000000..18acf86
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/templates/authz/kc-authz-modal.html
@@ -0,0 +1,11 @@
+<div class="modal-header">
+    <button type="button" class="close" ng-click="cancel()">
+        <span class="pficon pficon-close"></span>
+    </button>
+    <h4 class="modal-title">{{title}}</h4>
+</div>
+<div class="modal-body" ng-bind-html="message"></div>
+<div class="modal-footer">
+    <button type="button" data-ng-class="btns.cancel.cssClass" ng-click="cancel()">{{btns.cancel.label}}</button>
+    <button type="button" data-ng-class="btns.ok.cssClass" ng-click="ok()">{{btns.ok.label}}</button>
+</div>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/templates/authz/kc-tabs-resource-server.html b/themes/src/main/resources/theme/base/admin/resources/templates/authz/kc-tabs-resource-server.html
new file mode 100755
index 0000000..4b24d3f
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/templates/authz/kc-tabs-resource-server.html
@@ -0,0 +1,13 @@
+<div data-ng-controller="ClientTabCtrl">
+
+    <kc-tabs-client></kc-tabs-client>
+
+    <ul class="nav nav-tabs nav-tabs-pf"  data-ng-hide="create && !path[4]" style="margin-left: 15px">
+        <li ng-class="{active: !path[6]}"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/">{{:: 'settings' | translate}}</a></li>
+        <li ng-class="{active: path[6] == 'resource'}" data-ng-hide="create"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/resource">{{:: 'authz-resources' | translate}}</a></li>
+        <li ng-class="{active: path[6] == 'scope'}" data-ng-hide="create"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/scope">{{:: 'authz-authz-scopes' | translate}}</a></li>
+        <li ng-class="{active: path[6] == 'policy'}" data-ng-hide="create"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/policy">{{:: 'authz-policies' | translate}}</a></li>
+        <li ng-class="{active: path[6] == 'permission'}" data-ng-hide="create"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/permission">{{:: 'authz-permissions' | translate}}</a></li>
+        <li ng-class="{active: path[6] == 'evaluate'}" data-ng-hide="create"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server/evaluate">{{:: 'authz-evaluate' | translate}}</a></li>
+    </ul>
+</div>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/templates/kc-component-config.html b/themes/src/main/resources/theme/base/admin/resources/templates/kc-component-config.html
new file mode 100755
index 0000000..97d8876
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/templates/kc-component-config.html
@@ -0,0 +1,43 @@
+<div>
+    <div data-ng-repeat="option in properties" class="form-group" data-ng-controller="ProviderConfigCtrl">
+        <label class="col-md-2 control-label">{{:: option.label | translate}}</label>
+
+        <div class="col-md-6" data-ng-hide="option.type == 'boolean' || option.type == 'List' || option.type == 'Role' || option.type == 'ClientList' || option.type == 'Password' || option.type=='Script'">
+            <input class="form-control" type="text" data-ng-model="config[ option.name ][0]" >
+        </div>
+        <div class="col-md-6" data-ng-show="option.type == 'Password'">
+            <input class="form-control" type="password" data-ng-model="config[ option.name ][0]" >
+        </div>
+        <div class="col-md-6" data-ng-show="option.type == 'boolean'">
+            <input ng-model="config[ option.name ][0]" value="'true'" name="option.name" id="option.name" onoffswitchstring on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}"/>
+        </div>
+        <div class="col-md-6" data-ng-show="option.type == 'List'">
+            <select ng-model="config[ option.name ][0]" ng-options="data for data in option.defaultValue">
+                <option value="" selected> {{:: 'selectOne' | translate}} </option>
+            </select>
+        </div>
+        <div class="col-md-6" data-ng-show="option.type == 'Role'">
+            <div class="row">
+                <div class="col-md-8">
+                    <input class="form-control" type="text" data-ng-model="config[ option.name ][0]" >
+                </div>
+                <div class="col-md-2">
+                    <button type="submit" data-ng-click="openRoleSelector(option.name, config)" class="btn btn-default" tooltip-placement="top" tooltip-trigger="mouseover mouseout" tooltip="{{:: 'selectRole.tooltip' | translate}}">{{:: 'selectRole.label' | translate}}</button>
+                </div>
+            </div>
+        </div>
+        <div class="col-md-4" data-ng-show="option.type == 'ClientList'">
+            <select ng-model="config[ option.name ][0]" ng-options="client.clientId as client.clientId for client in clients">
+                <option value="" selected> {{:: 'selectOne' | translate}} </option>
+            </select>
+        </div>
+
+        <div class="col-md-6" data-ng-show="option.type == 'Script'">
+            <div ng-model="config[option.name][0]" placeholder="Enter your script..." ui-ace="{ useWrapMode: true, showGutter: true, theme:'github', mode: 'javascript'}">
+                {{config[option.name]}}
+            </div>
+        </div>
+
+        <kc-tooltip>{{:: option.helpText | translate}}</kc-tooltip>
+    </div>
+</div>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/templates/kc-menu.html b/themes/src/main/resources/theme/base/admin/resources/templates/kc-menu.html
index e766bcb..96fb247 100755
--- a/themes/src/main/resources/theme/base/admin/resources/templates/kc-menu.html
+++ b/themes/src/main/resources/theme/base/admin/resources/templates/kc-menu.html
@@ -25,6 +25,7 @@
     || path[2] == 'theme-settings'
     || path[2] == 'token-settings'
     || path[2] == 'cache-settings'
+    || path[2] == 'client-initial-access'
     || path[2] == 'defense'
     || path[2] == 'keys-settings' || path[2] == 'smtp-settings' || path[2] == 'ldap-settings' || path[2] == 'auth-settings') && path[3] != 'clients') && 'active'">
                 <a href="#/realms/{{realm.realm}}"><span class="pficon pficon-settings"></span> {{:: 'realm-settings' | translate}}</a>
diff --git a/themes/src/main/resources/theme/base/admin/resources/templates/kc-provider-config.html b/themes/src/main/resources/theme/base/admin/resources/templates/kc-provider-config.html
index 87acc2a..2b5f00e 100755
--- a/themes/src/main/resources/theme/base/admin/resources/templates/kc-provider-config.html
+++ b/themes/src/main/resources/theme/base/admin/resources/templates/kc-provider-config.html
@@ -2,7 +2,7 @@
     <div data-ng-repeat="option in properties" class="form-group" data-ng-controller="ProviderConfigCtrl">
         <label class="col-md-2 control-label">{{:: option.label | translate}}</label>
 
-        <div class="col-md-6" data-ng-hide="option.type == 'boolean' || option.type == 'List' || option.type == 'Role' || option.type == 'ClientList' || option.type == 'Password'">
+        <div class="col-md-6" data-ng-hide="option.type == 'boolean' || option.type == 'List' || option.type == 'Role' || option.type == 'ClientList' || option.type == 'Password' || option.type=='Script'">
             <input class="form-control" type="text" data-ng-model="config[ option.name ]" >
         </div>
         <div class="col-md-6" data-ng-show="option.type == 'Password'">
@@ -32,6 +32,12 @@
             </select>
         </div>
 
+        <div class="col-md-6" data-ng-show="option.type == 'Script'">
+            <div ng-model="config[option.name]" placeholder="Enter your script..." ui-ace="{ useWrapMode: true, showGutter: true, theme:'github', mode: 'javascript'}">
+                {{config[option.name]}}
+            </div>
+        </div>
+
         <kc-tooltip>{{:: option.helpText | translate}}</kc-tooltip>
     </div>
 </div>
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client.html b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client.html
index 58388ff..a0d88c6 100755
--- a/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client.html
+++ b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-client.html
@@ -6,7 +6,7 @@
         <i id="removeClient" class="pficon pficon-delete clickable" data-ng-show="access.manageClients" data-ng-click="removeClient()"></i>
     </h1>
 
-    <ul class="nav nav-tabs nav-tabs-pf"  data-ng-hide="create && !path[4]">
+    <ul class="nav nav-tabs"  data-ng-hide="create && !path[4]">
         <li ng-class="{active: !path[4]}"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}">{{:: 'settings' | translate}}</a></li>
         <li ng-class="{active: path[4] == 'credentials'}" data-ng-show="!client.publicClient && client.protocol != 'saml'"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/credentials">{{:: 'credentials' | translate}}</a></li>
         <li ng-class="{active: path[4] == 'saml'}" data-ng-show="client.protocol == 'saml' && (client.attributes['saml.client.signature'] == 'true' || client.attributes['saml.encrypt'] == 'true')"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/saml/keys">{{:: 'saml-keys' | translate}}</a></li>
@@ -19,6 +19,7 @@
             <a href="#/realms/{{realm.realm}}/clients/{{client.id}}/scope-mappings">{{:: 'scope' | translate}}</a>
             <kc-tooltip>{{:: 'scope.tooltip' | translate}}</kc-tooltip>
         </li>
+        <li ng-class="{active: path[4] == 'authz'}" data-ng-show="client.authorizationServicesEnabled"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/authz/resource-server">{{:: 'authz-authorization' | translate}}</a></li>
         <li ng-class="{active: path[4] == 'revocation'}"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/revocation">{{:: 'revocation' | translate}}</a></li>
     <!--    <li ng-class="{active: path[4] == 'identity-provider'}" data-ng-show="realm.identityFederationEnabled"><a href="#/realms/{{realm.realm}}/clients/{{client.id}}/identity-provider">Identity Provider</a></li> -->
         <li ng-class="{active: path[4] == 'sessions'}" data-ng-show="!client.bearerOnly">
@@ -38,7 +39,7 @@
             <kc-tooltip>{{:: 'installation.tooltip' | translate}}</kc-tooltip>
         </li>
 
-        <li ng-class="{active: path[4] == 'service-account-roles'}" data-ng-show="client.serviceAccountsEnabled">
+        <li ng-class="{active: path[4] == 'service-account-roles'}" data-ng-show="client.serviceAccountsEnabled && !(client.bearerOnly || client.publicClient)">
             <a href="#/realms/{{realm.realm}}/clients/{{client.id}}/service-account-roles">{{:: 'service-account-roles' | translate}}</a>
             <kc-tooltip>{{:: 'service-account-roles.tooltip' | translate}}</kc-tooltip>
         </li>
diff --git a/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-user-storage.html b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-user-storage.html
new file mode 100644
index 0000000..03e1ddc
--- /dev/null
+++ b/themes/src/main/resources/theme/base/admin/resources/templates/kc-tabs-user-storage.html
@@ -0,0 +1,11 @@
+<div data-ng-controller="UserStorageTabCtrl">
+    <h1 data-ng-hide="create">
+        {{instance.name|capitalize}}
+        <i class="pficon pficon-delete clickable" data-ng-show="!create && access.manageUsers" data-ng-click="removeUserStorage()"></i>
+    </h1>
+    <h1 data-ng-show="create">{{:: 'add-user-storage-provider' | translate}}</h1>
+
+    <ul class="nav nav-tabs" data-ng-hide="create">
+        <li ng-class="{active: !path[6]}"><a href="#/realms/{{realm.realm}}/user-storage/providers/{{instance.providerName}}/{{instance.id}}">{{:: 'settings' | translate}}</a></li>
+    </ul>
+</div>
diff --git a/themes/src/main/resources/theme/base/admin/theme.properties b/themes/src/main/resources/theme/base/admin/theme.properties
index 0b3e00e..67fb523 100644
--- a/themes/src/main/resources/theme/base/admin/theme.properties
+++ b/themes/src/main/resources/theme/base/admin/theme.properties
@@ -1,2 +1,2 @@
 import=common/keycloak
-locales=ca,de,en,es,fr,it,pt-BR
\ No newline at end of file
+locales=ca,de,en,es,fr,it,pt-BR,ru
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/email/messages/messages_fr.properties b/themes/src/main/resources/theme/base/email/messages/messages_fr.properties
index 08af3a6..f8b2b97 100755
--- a/themes/src/main/resources/theme/base/email/messages/messages_fr.properties
+++ b/themes/src/main/resources/theme/base/email/messages/messages_fr.properties
@@ -1,12 +1,12 @@
 emailVerificationSubject=V\u00e9rification du courriel
 emailVerificationBody=Quelqu''un vient de cr\u00e9er un compte "{2}" avec votre courriel. Si c''est bien vous, veuillez cliquer sur le lien ci-dessous afin de v\u00e9rifier votre adresse de courriel\n\n{0}\n\nCe lien expire dans {1} minute(s).\n\nSinon ignorer ce message.
-emailVerificationBodyHtml=<p>Quelqu''un a cr\u00e9er un compte "{2}" avec votre courriel. Si c''est bien vous, veuillez cliquer sur le lien ci-dessous afin de v\u00e9rifier votre adresse de courriel</p><p><a href="{0}">{0}</a></p><p>Ce lien expire dans {1} minute(s).</p><p>Sinon veuillez ignorer ce message.</p>
+emailVerificationBodyHtml=<p>Quelqu''un vient de cr\u00e9er un compte "{2}" avec votre courriel. Si c''est bien vous, veuillez cliquer sur le lien ci-dessous afin de v\u00e9rifier votre adresse de courriel</p><p><a href="{0}">{0}</a></p><p>Ce lien expire dans {1} minute(s).</p><p>Sinon veuillez ignorer ce message.</p>
 passwordResetSubject=R\u00e9initialiser le mot de passe
 passwordResetBody=Quelqu''un vient de demander une r\u00e9initialisation de mot de passe pour votre compte {2}. Si c''est bien vous, veuillez cliquer sur le lien ci-dessous pour le mettre \u00e0 jour .\n\n{0}\n\nCe lien expire dans {1} minute(s).\n\nSinon ignorer ce message, aucun changement ne sera effectu\u00e9 sur votre compte.
-passwordResetBodyHtml=<p>Quelqu''un vient de demander une reinitialisation de mot de passe pour votre compte {2}. Si c''est bien vous, veuillez cliquer sur le lien ci-dessous pour le mettre \u00e0 jour.</p><p><a href="{0}">{0}</a></p><p>Ce lien expire dans {1} minute(s).</p><p>Sinon ignorer ce message, aucun changement ne sera effectu\u00e9 sur votre compte.</p>
+passwordResetBodyHtml=<p>Quelqu''un vient de demander une r\u00e9initialisation de mot de passe pour votre compte {2}. Si c''est bien vous, veuillez cliquer sur le lien ci-dessous pour le mettre \u00e0 jour.</p><p><a href="{0}">{0}</a></p><p>Ce lien expire dans {1} minute(s).</p><p>Sinon ignorer ce message, aucun changement ne sera effectu\u00e9 sur votre compte.</p>
 executeActionsSubject=Mettre \u00e0 jour votre compte
-executeActionsBody=Votre adminitrateur vient de demander une mise \u00e0 jour de votre compte {2}. Veuillez cliquer sur le lien ci-dessous afin commencer le processus.\n\n{0}\n\nCe lien expire dans {1} minute(s).\n\nSi vous n''\u00eates pas au courant de cette requ\u00eate, ignorer ce message, aucun changement ne sera effectu\u00e9 sur votre compte.
-executeActionsBodyHtml=<p>Votre adminitrateur vient de demander une mise \u00e0 jour de votre compte {2}. Veuillez cliquer sur le lien ci-dessous afin commencer le processus.</p><p><a href="{0}">{0}</a></p><p>Ce lien expire dans {1} minute(s).</p><p>Si vous n''\u00eates pas au courant de cette requ\u00eate, ignorer ce message, aucun changement ne sera effectu\u00e9 sur votre compte.</p>
+executeActionsBody=Votre administrateur vient de demander une mise \u00e0 jour de votre compte {2}. Veuillez cliquer sur le lien ci-dessous afin de commencer le processus.\n\n{0}\n\nCe lien expire dans {1} minute(s).\n\nSi vous n''\u00eates pas au courant de cette requ\u00eate, ignorer ce message, aucun changement ne sera effectu\u00e9 sur votre compte.
+executeActionsBodyHtml=<p>Votre administrateur vient de demander une mise \u00e0 jour de votre compte {2}. Veuillez cliquer sur le lien ci-dessous afin de commencer le processus.</p><p><a href="{0}">{0}</a></p><p>Ce lien expire dans {1} minute(s).</p><p>Si vous n''\u00eates pas au courant de cette requ\u00eate, ignorer ce message, aucun changement ne sera effectu\u00e9 sur votre compte.</p>
 eventLoginErrorSubject=Erreur de connexion
 eventLoginErrorBody=Une tentative de connexion a \u00e9t\u00e9 d\u00e9tect\u00e9e sur votre compte sur {0} depuis {1}. Si ce n''est pas vous, veuillez contacter votre administrateur.
 eventLoginErrorBodyHtml=<p>Une tentative de connexion a \u00e9t\u00e9 d\u00e9tect\u00e9e sur votre compte sur {0} depuis {1}. Si ce n''est pas vous, veuillez contacter votre administrateur.</p>
@@ -15,7 +15,7 @@ eventRemoveTotpBody=Le TOTP a \u00e9t\u00e9 supprim\u00e9 de votre compte {0} de
 eventRemoveTotpBodyHtml=<p>Le TOTP a \u00e9t\u00e9 supprim\u00e9 de votre compte {0} depuis {1}. Si ce n''est pas vous, veuillez contacter votre administrateur.</p>
 eventUpdatePasswordSubject=Mise \u00e0 jour du mot de passe
 eventUpdatePasswordBody=Votre mot de passe a chang\u00e9 pour votre compte {0} depuis {1}. Si ce n''est pas vous, veuillez contacter votre administrateur.
-eventUpdatePasswordBodyHtml=<p>Votre mot de passe \u00e0 chang\u00e9 pour votre compte {0} depuis {1}. Si ce n''est pas vous, veuillez contacter votre administrateur.</p>
+eventUpdatePasswordBodyHtml=<p>Votre mot de passe a chang\u00e9 pour votre compte {0} depuis {1}. Si ce n''est pas vous, veuillez contacter votre administrateur.</p>
 eventUpdateTotpSubject=Mise \u00e0 jour du TOTP
 eventUpdateTotpBody=Le TOTP a \u00e9t\u00e9 mis \u00e0 jour pour votre compte sur {0} depuis {1}. Si ce n''est pas vous, veuillez contacter votre administrateur.
 eventUpdateTotpBodyHtml=<p>Le TOTP a \u00e9t\u00e9 mis \u00e0 jour pour votre compte sur {0} depuis {1}. Si ce n''est pas vous, veuillez contacter votre administrateur.</p>
diff --git a/themes/src/main/resources/theme/base/email/messages/messages_ru.properties b/themes/src/main/resources/theme/base/email/messages/messages_ru.properties
new file mode 100644
index 0000000..7663fa4
--- /dev/null
+++ b/themes/src/main/resources/theme/base/email/messages/messages_ru.properties
@@ -0,0 +1,24 @@
+emailVerificationSubject=\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 email
+emailVerificationBody=\u041A\u0442\u043E-\u0442\u043E \u0441\u043E\u0437\u0434\u0430\u043B \u0443\u0447\u0435\u0442\u043D\u0443\u044E \u0437\u0430\u043F\u0438\u0441\u044C {2} \u0441 \u044D\u0442\u0438\u043C email. \u0415\u0441\u043B\u0438 \u044D\u0442\u043E \u0431\u044B\u043B\u0438 \u0432\u044B, \u043D\u0430\u0436\u043C\u0438\u0442\u0435 \u043D\u0430 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0443\u044E \u0441\u0441\u044B\u043B\u043A\u0443 \u0434\u043B\u044F \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F \u0432\u0430\u0448\u0435\u0433\u043E email\n\n{0}\n\n\u042D\u0442\u0430 \u0441\u0441\u044B\u043B\u043A\u0430 \u0443\u0441\u0442\u0430\u0440\u0435\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 {1} \u043C\u0438\u043D\u0443\u0442.\n\n\u0415\u0441\u043B\u0438 \u0412\u044B \u043D\u0435 \u0441\u043E\u0437\u0434\u0430\u0432\u0430\u043B\u0438 \u0443\u0447\u0435\u0442\u043D\u0443\u044E \u0437\u0430\u043F\u0438\u0441\u044C, \u043F\u0440\u043E\u0441\u0442\u043E \u043F\u0440\u043E\u0438\u0433\u043D\u043E\u0440\u0438\u0440\u0443\u0439\u0442\u0435 \u044D\u0442\u043E \u043F\u0438\u0441\u044C\u043C\u043E.
+emailVerificationBodyHtml=<p>\u041A\u0442\u043E-\u0442\u043E \u0441\u043E\u0437\u0434\u0430\u043B \u0443\u0447\u0435\u0442\u043D\u0443\u044E \u0437\u0430\u043F\u0438\u0441\u044C {2} \u0441 \u044D\u0442\u0438\u043C email. \u0415\u0441\u043B\u0438 \u044D\u0442\u043E \u0431\u044B\u043B\u0438 \u0412\u044B, \u043D\u0430\u0436\u043C\u0438\u0442\u0435 \u043F\u043E \u0441\u0441\u044B\u043B\u043A\u0435 \u0434\u043B\u044F \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F \u0432\u0430\u0448\u0435\u0433\u043E email</p><p><a href="{0}">{0}</a></p><p>\u042D\u0442\u0430 \u0441\u0441\u044B\u043B\u043A\u0430 \u0443\u0441\u0442\u0430\u0440\u0435\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 {1} \u043C\u0438\u043D\u0443\u0442.</p><p>\u0415\u0441\u043B\u0438 \u0412\u044B \u043D\u0435 \u0441\u043E\u0437\u0434\u0430\u0432\u0430\u043B\u0438 \u0443\u0447\u0435\u0442\u043D\u0443\u044E \u0437\u0430\u043F\u0438\u0441\u044C, \u043F\u0440\u043E\u0441\u0442\u043E \u043F\u0440\u043E\u0438\u0433\u043D\u043E\u0440\u0438\u0440\u0443\u0439\u0442\u0435 \u044D\u0442\u043E \u043F\u0438\u0441\u044C\u043C\u043E.</p>
+identityProviderLinkSubject=\u0421\u0441\u044B\u043B\u043A\u0430 {0}
+identityProviderLinkBody=\u041A\u0442\u043E-\u0442\u043E \u0445\u043E\u0447\u0435\u0442 \u0441\u0432\u044F\u0437\u0430\u0442\u044C \u0432\u0430\u0448\u0443 \u0443\u0447\u0435\u0442\u043D\u0443\u044E \u0437\u0430\u043F\u0438\u0441\u044C "{1}" \u0441 "{0}" \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u044C\u044E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F {2} . \u0415\u0441\u043B\u0438 \u044D\u0442\u043E \u0431\u044B\u043B\u0438 \u0412\u044B, \u043D\u0430\u0436\u043C\u0438\u0442\u0435 \u043F\u043E \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0435\u0439 \u0441\u0441\u044B\u043B\u043A\u0435, \u0447\u0442\u043E\u0431\u044B \u0441\u0432\u044F\u0437\u0430\u0442\u044C \u0443\u0447\u0435\u0442\u043D\u044B\u0435 \u0437\u0430\u043F\u0438\u0441\u0438\n\n{3}\n\n\u042D\u0442\u0430 \u0441\u0441\u044B\u043B\u043A\u0430 \u0443\u0441\u0442\u0430\u0440\u0435\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 {4} \u043C\u0438\u043D\u0443\u0442.\n\n\u0415\u0441\u043B\u0438 \u044D\u0442\u043E \u043D\u0435 \u0445\u043E\u0442\u0438\u0442\u0435 \u043E\u0431\u044A\u0435\u0434\u0438\u043D\u044F\u0442\u044C \u0443\u0447\u0435\u0442\u043D\u044B\u0435 \u0437\u0430\u043F\u0438\u0441\u0438, \u043F\u0440\u043E\u0441\u0442\u043E \u043F\u0440\u043E\u0438\u0433\u043D\u043E\u0440\u0438\u0443\u0439\u0442\u0435 \u044D\u0442\u043E \u043F\u0438\u0441\u044C\u043C\u043E. \u041F\u043E\u0441\u043B\u0435 \u043E\u0431\u044A\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u044F \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439 \u0412\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u0432\u043E\u0439\u0442\u0438 \u0432  {1} \u0447\u0435\u0440\u0435\u0437 {0}.
+identityProviderLinkBodyHtml=<p>\u041A\u0442\u043E-\u0442\u043E \u0445\u043E\u0447\u0435\u0442 \u0441\u0432\u044F\u0437\u0430\u0442\u044C \u0432\u0430\u0448\u0443 \u0443\u0447\u0435\u0442\u043D\u0443\u044E \u0437\u0430\u043F\u0438\u0441\u044C <b>{1}</b> \u0441 <b>{0}</b> \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u044C\u044E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F {2} . \u0415\u0441\u043B\u0438 \u044D\u0442\u043E \u0431\u044B\u043B\u0438 \u0412\u044B, \u043D\u0430\u0436\u043C\u0438\u0442\u0435 \u043F\u043E \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0435\u0439 \u0441\u0441\u044B\u043B\u043A\u0435, \u0447\u0442\u043E\u0431\u044B \u0441\u0432\u044F\u0437\u0430\u0442\u044C \u0443\u0447\u0435\u0442\u043D\u044B\u0435 \u0437\u0430\u043F\u0438\u0441\u0438</p><p><a href="{3}">{3}</a></p><p>\u042D\u0442\u0430 \u0441\u0441\u044B\u043B\u043A\u0430 \u0443\u0441\u0442\u0430\u0440\u0435\u0435\u0442 \u0447\u0435\u0440\u0435\u0437  {4} \u043C\u0438\u043D\u0443\u0442.</p><p>\u0415\u0441\u043B\u0438 \u044D\u0442\u043E \u043D\u0435 \u0445\u043E\u0442\u0438\u0442\u0435 \u043E\u0431\u044A\u0435\u0434\u0438\u043D\u044F\u0442\u044C \u0443\u0447\u0435\u0442\u043D\u044B\u0435 \u0437\u0430\u043F\u0438\u0441\u0438, \u043F\u0440\u043E\u0441\u0442\u043E \u043F\u0440\u043E\u0438\u0433\u043D\u043E\u0440\u0438\u0443\u0439\u0442\u0435 \u044D\u0442\u043E \u043F\u0438\u0441\u044C\u043C\u043E. \u041F\u043E\u0441\u043B\u0435 \u043E\u0431\u044A\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u044F \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439 \u0412\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u0432\u043E\u0439\u0442\u0438 \u0432  {1} \u0447\u0435\u0440\u0435\u0437 {0}.</p>
+passwordResetSubject=\u0421\u0431\u0440\u043E\u0441 \u043F\u0430\u0440\u043E\u043B\u044F
+passwordResetBody=\u041A\u0442\u043E-\u0442\u043E \u0442\u043E\u043B\u044C\u043A\u043E \u0447\u0442\u043E \u0437\u0430\u043F\u0440\u043E\u0441\u0438\u043B \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0435 \u043F\u0430\u0440\u043E\u043B\u044F \u043E\u0442 \u0412\u0430\u0448\u0435\u0439 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u0438 {2}. \u0415\u0441\u043B\u0438 \u044D\u0442\u043E \u0431\u044B\u043B\u0438 \u0412\u044B, \u043D\u0430\u0436\u043C\u0438\u0442\u0435 \u043D\u0430 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0443\u044E \u0441\u0441\u044B\u043B\u043A\u0443, \u0447\u0442\u043E\u0431\u044B \u0441\u0431\u0440\u043E\u0441\u0438\u0442\u044C \u0435\u0433\u043E.\n\n{0}\n\n\u042D\u0442\u0430 \u0441\u0441\u044B\u043B\u043A\u0430 \u0443\u0441\u0442\u0430\u0440\u0435\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 {1} \u043C\u0438\u043D\u0443\u0442.\n\n\u0415\u0441\u043B\u0438 \u0412\u044B \u043D\u0435 \u0445\u043E\u0442\u0438\u0442\u0435 \u0441\u0431\u0440\u0430\u0441\u044B\u0432\u0430\u0442\u044C \u043F\u0430\u0440\u043E\u043B\u044C, \u043F\u0440\u043E\u0441\u0442\u043E \u043F\u0440\u043E\u0438\u0433\u043D\u043E\u0440\u0438\u0440\u0443\u0439\u0442\u0435 \u044D\u0442\u043E \u043F\u0438\u0441\u044C\u043C\u043E.
+passwordResetBodyHtml=<p>\u041A\u0442\u043E-\u0442\u043E \u0442\u043E\u043B\u044C\u043A\u043E \u0447\u0442\u043E \u0437\u0430\u043F\u0440\u043E\u0441\u0438\u043B \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0435 \u043F\u0430\u0440\u043E\u043B\u044F \u043E\u0442 \u0412\u0430\u0448\u0435\u0439 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u0438 {2}. \u0415\u0441\u043B\u0438 \u044D\u0442\u043E \u0431\u044B\u043B\u0438 \u0412\u044B, \u043D\u0430\u0436\u043C\u0438\u0442\u0435 \u043D\u0430 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0443\u044E \u0441\u0441\u044B\u043B\u043A\u0443, \u0447\u0442\u043E\u0431\u044B \u0441\u0431\u0440\u043E\u0441\u0438\u0442\u044C \u0435\u0433\u043E.</p><p><a href="{0}">{0}</a></p><p>\u042D\u0442\u0430 \u0441\u0441\u044B\u043B\u043A\u0430 \u0443\u0441\u0442\u0430\u0440\u0435\u0435\u0442 \u0447\u0435\u0440\u0435\u0437  {1} \u043C\u0438\u043D\u0443\u0442.</p><p>\u0415\u0441\u043B\u0438 \u0412\u044B \u043D\u0435 \u0445\u043E\u0442\u0438\u0442\u0435 \u0441\u0431\u0440\u0430\u0441\u044B\u0432\u0430\u0442\u044C \u043F\u0430\u0440\u043E\u043B\u044C, \u043F\u0440\u043E\u0441\u0442\u043E \u043F\u0440\u043E\u0438\u0433\u043D\u043E\u0440\u0438\u0440\u0443\u0439\u0442\u0435 \u044D\u0442\u043E \u043F\u0438\u0441\u044C\u043C\u043E \u0438 \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0438\u0437\u043C\u0435\u043D\u0438\u0442\u0441\u044F.</p>
+executeActionsSubject=\u041E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u0412\u0430\u0448\u0435\u0439 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u0438
+executeActionsBody=\u0412\u0430\u0448 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440 \u0442\u043E\u043B\u044C\u043A\u043E \u0447\u0442\u043E \u0437\u0430\u043F\u0440\u043E\u0441\u0438\u043B \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E\u0441\u0442\u044C \u0412\u0430\u043C \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u0441\u0432\u043E\u044E \u0443\u0447\u0435\u0442\u043D\u0443\u044E \u0437\u0430\u043F\u0438\u0441\u044C {2}. \u041D\u0430\u0436\u043C\u0438\u0442\u0435 \u043F\u043E \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0435\u0439 \u0441\u0441\u044B\u043B\u043A\u0435 \u0447\u0442\u043E\u0431\u044B \u043D\u0430\u0447\u0430\u0442\u044C \u044D\u0442\u043E\u0442 \u043F\u0440\u043E\u0446\u0435\u0441\u0441.\n\n{0}\n\n\u042D\u0442\u0430 \u0441\u0441\u044B\u043B\u043A\u0430 \u0443\u0441\u0442\u0430\u0440\u0435\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 {1} \u043C\u0438\u043D\u0443\u0442.\n\n\u0415\u0441\u043B\u0438 \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044C \u043F\u043E\u0434\u043E\u0437\u0440\u0435\u043D\u0438\u044F, \u0447\u0442\u043E \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440 \u043D\u0435 \u043C\u043E\u0433 \u0441\u0434\u0435\u043B\u0430\u0442\u044C \u0442\u0430\u043A\u043E\u0439 \u0437\u0430\u043F\u0440\u043E\u0441, \u043F\u0440\u043E\u0441\u0442\u043E \u043F\u0440\u043E\u0438\u0433\u043D\u043E\u0440\u0438\u0440\u0443\u0439\u0442\u0435 \u044D\u0442\u043E \u043F\u0438\u0441\u044C\u043C\u043E.
+executeActionsBodyHtml=<p>\u0412\u0430\u0448 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440 \u0442\u043E\u043B\u044C\u043A\u043E \u0447\u0442\u043E \u0437\u0430\u043F\u0440\u043E\u0441\u0438\u043B \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E\u0441\u0442\u044C \u0412\u0430\u043C \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u0441\u0432\u043E\u044E \u0443\u0447\u0435\u0442\u043D\u0443\u044E \u0437\u0430\u043F\u0438\u0441\u044C {2}.  \u041D\u0430\u0436\u043C\u0438\u0442\u0435 \u043F\u043E \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0435\u0439 \u0441\u0441\u044B\u043B\u043A\u0435 \u0447\u0442\u043E\u0431\u044B \u043D\u0430\u0447\u0430\u0442\u044C \u044D\u0442\u043E\u0442 \u043F\u0440\u043E\u0446\u0435\u0441\u0441.</p><p><a href="{0}">{0}</a></p><p>\u042D\u0442\u0430 \u0441\u0441\u044B\u043B\u043A\u0430 \u0443\u0441\u0442\u0430\u0440\u0435\u0435\u0442 \u0447\u0435\u0440\u0435\u0437  {1} \u043C\u0438\u043D\u0443\u0442.</p><p>\u0415\u0441\u043B\u0438 \u0443 \u0432\u0430\u0441 \u0435\u0441\u0442\u044C \u043F\u043E\u0434\u043E\u0437\u0440\u0435\u043D\u0438\u044F, \u0447\u0442\u043E \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440 \u043D\u0435 \u043C\u043E\u0433 \u0441\u0434\u0435\u043B\u0430\u0442\u044C \u0442\u0430\u043A\u043E\u0439 \u0437\u0430\u043F\u0440\u043E\u0441, \u043F\u0440\u043E\u0441\u0442\u043E \u043F\u0440\u043E\u0438\u0433\u043D\u043E\u0440\u0438\u0440\u0443\u0439\u0442\u0435 \u044D\u0442\u043E \u043F\u0438\u0441\u044C\u043C\u043E.</p>
+eventLoginErrorSubject=\u041E\u0448\u0438\u0431\u043A\u0430 \u0432\u0445\u043E\u0434\u0430
+eventLoginErrorBody=\u041D\u0435\u0443\u0434\u0430\u0447\u043D\u0430\u044F \u043F\u043E\u043F\u044B\u0442\u043A\u0430 \u0432\u0445\u043E\u0434\u0430 \u0431\u044B\u043B\u0430 \u0437\u0430\u0444\u0438\u043A\u0441\u0438\u0440\u043E\u0432\u0430\u043D\u0430 \u0432 \u0432\u0430\u0448\u0443 \u0443\u0447\u0435\u0442\u043D\u0443\u044E \u0437\u0430\u043F\u0438\u0441\u044C {0} \u0441 {1}. \u0415\u0441\u043B\u0438 \u044D\u0442\u043E \u0431\u044B\u043B\u0438 \u043D\u0435 \u0412\u044B, \u043F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0441\u0432\u044F\u0436\u0438\u0442\u0435\u0441\u044C \u0441 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u043E\u043C.
+eventLoginErrorBodyHtml=<p>\u041D\u0435\u0443\u0434\u0430\u0447\u043D\u0430\u044F \u043F\u043E\u043F\u044B\u0442\u043A\u0430 \u0432\u0445\u043E\u0434\u0430 \u0431\u044B\u043B\u0430 \u0437\u0430\u0444\u0438\u043A\u0441\u0438\u0440\u043E\u0432\u0430\u043D\u0430 \u0432 \u0432\u0430\u0448\u0443 \u0443\u0447\u0435\u0442\u043D\u0443\u044E \u0437\u0430\u043F\u0438\u0441\u044C {0} \u0441 {1}. \u0415\u0441\u043B\u0438 \u044D\u0442\u043E \u0431\u044B\u043B\u0438 \u043D\u0435 \u0412\u044B, \u043F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0441\u0432\u044F\u0436\u0438\u0442\u0435\u0441\u044C \u0441 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u043E\u043C.</p>
+eventRemoveTotpSubject=\u0423\u0434\u0430\u043B\u0438\u0442\u044C TOTP
+eventRemoveTotpBody=TOTP \u0431\u044B\u043B \u0443\u0434\u0430\u043B\u0435\u043D \u0438\u0437 \u0432\u0430\u0448\u0435\u0439 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u0438 {0} c {1}. \u0415\u0441\u043B\u0438 \u044D\u0442\u043E \u0431\u044B\u043B\u0438 \u043D\u0435 \u0412\u044B, \u043F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0441\u0432\u044F\u0436\u0438\u0442\u0435\u0441\u044C \u0441 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u043E\u043C.
+eventRemoveTotpBodyHtml=<p>TOTP \u0431\u044B\u043B \u0443\u0434\u0430\u043B\u0435\u043D \u0438\u0437 \u0432\u0430\u0448\u0435\u0439 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u0438 {0} c {1}. \u0415\u0441\u043B\u0438 \u044D\u0442\u043E \u0431\u044B\u043B\u0438 \u043D\u0435 \u0412\u044B, \u043F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0441\u0432\u044F\u0436\u0438\u0442\u0435\u0441\u044C \u0441 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u043E\u043C.</p>
+eventUpdatePasswordSubject=\u041E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\u0430\u0440\u043E\u043B\u044F
+eventUpdatePasswordBody=\u0412\u0430\u0448 \u043F\u0430\u0440\u043E\u043B\u044C \u0431\u044B\u043B \u0438\u0437\u043C\u0435\u043D\u0435\u043D \u0432 {0} \u0441 {1}. \u0415\u0441\u043B\u0438 \u044D\u0442\u043E \u0431\u044B\u043B\u0438 \u043D\u0435 \u0412\u044B, \u043F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0441\u0432\u044F\u0436\u0438\u0442\u0435\u0441\u044C \u0441 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u043E\u043C.
+eventUpdatePasswordBodyHtml=<p>\u0412\u0430\u0448 \u043F\u0430\u0440\u043E\u043B\u044C \u0431\u044B\u043B \u0438\u0437\u043C\u0435\u043D\u0435\u043D \u0432 {0} \u0441 {1}. \u0415\u0441\u043B\u0438 \u044D\u0442\u043E \u0431\u044B\u043B\u0438 \u043D\u0435 \u0412\u044B, \u043F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0441\u0432\u044F\u0436\u0438\u0442\u0435\u0441\u044C \u0441 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u043E\u043C.</p>
+eventUpdateTotpSubject=\u041E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 TOTP
+eventUpdateTotpBody=TOTP \u0431\u044B\u043B \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D \u0432 \u0432\u0430\u0448\u0435\u0439 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u0438 {0} \u0441 {1}. \u0415\u0441\u043B\u0438 \u044D\u0442\u043E \u0431\u044B\u043B\u0438 \u043D\u0435 \u0412\u044B, \u043F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0441\u0432\u044F\u0436\u0438\u0442\u0435\u0441\u044C \u0441 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u043E\u043C.
+eventUpdateTotpBodyHtml=<p>TOTP \u0431\u044B\u043B \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D \u0432 \u0432\u0430\u0448\u0435\u0439 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u0438 {0} \u0441 {1}. \u0415\u0441\u043B\u0438 \u044D\u0442\u043E \u0431\u044B\u043B\u0438 \u043D\u0435 \u0412\u044B, \u043F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0441\u0432\u044F\u0436\u0438\u0442\u0435\u0441\u044C \u0441 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u043E\u043C.</p>
diff --git a/themes/src/main/resources/theme/base/email/theme.properties b/themes/src/main/resources/theme/base/email/theme.properties
index 27f59f5..503eda7 100644
--- a/themes/src/main/resources/theme/base/email/theme.properties
+++ b/themes/src/main/resources/theme/base/email/theme.properties
@@ -1 +1 @@
-locales=ca,de,en,es,fr,it,pt-BR
\ No newline at end of file
+locales=ca,de,en,es,fr,it,pt-BR,ru
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/base/login/messages/messages_ca.properties b/themes/src/main/resources/theme/base/login/messages/messages_ca.properties
index df76d94..da73218 100755
--- a/themes/src/main/resources/theme/base/login/messages/messages_ca.properties
+++ b/themes/src/main/resources/theme/base/login/messages/messages_ca.properties
@@ -168,7 +168,7 @@ bearerOnlyMessage=Les aplicacions Bearer-only no poden iniciar sessi\u00F3 des d
 directGrantsOnlyMessage=Els clients de tipus Direct-grants-only no poden iniciar sessi\u00F3 des del navegador.
 invalidRedirectUriMessage=L''URI de redirecci\u00F3 no \u00E9s correcta
 unsupportedNameIdFormatMessage=NameIDFormat no suportat
-invlidRequesterMessage=Sol\u00B7licitant no v\u00E0lid
+invalidRequesterMessage=Sol\u00B7licitant no v\u00E0lid
 registrationNotAllowedMessage=El registre no est\u00E0 perm\u00E8s
 resetCredentialNotAllowedMessage=El reinici de les credencials no est\u00E0 perm\u00E8s
 
diff --git a/themes/src/main/resources/theme/base/login/messages/messages_de.properties b/themes/src/main/resources/theme/base/login/messages/messages_de.properties
index 7af21df..3a48f70 100755
--- a/themes/src/main/resources/theme/base/login/messages/messages_de.properties
+++ b/themes/src/main/resources/theme/base/login/messages/messages_de.properties
@@ -163,7 +163,7 @@ bearerOnlyMessage=Bearer-only Clients k\u00F6nnen sich nicht via Browser anmelde
 directGrantsOnlyMessage=Direct-grants-only Clients k\u00F6nnen sich nicht via Browser anmelden.
 invalidRedirectUriMessage=Ung\u00FCltige redirect uri.
 unsupportedNameIdFormatMessage=Nicht unterst\u00FCtztes NameIDFormat.
-invlidRequesterMessage=Ung\u00FCltiger Requester.
+invalidRequesterMessage=Ung\u00FCltiger Requester.
 registrationNotAllowedMessage=Registrierung nicht erlaubt.
 resetCredentialNotAllowedMessage=Reset Credential nicht erlaubt
 
diff --git a/themes/src/main/resources/theme/base/login/messages/messages_en.properties b/themes/src/main/resources/theme/base/login/messages/messages_en.properties
index d0ffefc..725705e 100755
--- a/themes/src/main/resources/theme/base/login/messages/messages_en.properties
+++ b/themes/src/main/resources/theme/base/login/messages/messages_en.properties
@@ -181,7 +181,7 @@ standardFlowDisabledMessage=Client is not allowed to initiate browser login with
 implicitFlowDisabledMessage=Client is not allowed to initiate browser login with given response_type. Implicit flow is disabled for the client.
 invalidRedirectUriMessage=Invalid redirect uri
 unsupportedNameIdFormatMessage=Unsupported NameIDFormat
-invlidRequesterMessage=Invalid requester
+invalidRequesterMessage=Invalid requester
 registrationNotAllowedMessage=Registration not allowed
 resetCredentialNotAllowedMessage=Reset Credential not allowed
 
@@ -216,10 +216,12 @@ locale_fr=Fran\u00e7ais
 locale_it=Italian
 locale_pt_BR=Portugu\u00EAs (Brasil)
 locale_pt-BR=Portugu\u00EAs (Brasil)
+locale_ru=\u0420\u0443\u0441\u0441\u043A\u0438\u0439
 
 backToApplication=&laquo; Back to Application
 missingParameterMessage=Missing parameters\: {0}
 clientNotFoundMessage=Client not found.
+clientDisabledMessage=Client disabled.
 invalidParameterMessage=Invalid parameter\: {0}
 alreadyLoggedIn=You are already logged in.
 
diff --git a/themes/src/main/resources/theme/base/login/messages/messages_es.properties b/themes/src/main/resources/theme/base/login/messages/messages_es.properties
index 48a5e72..550a6a7 100755
--- a/themes/src/main/resources/theme/base/login/messages/messages_es.properties
+++ b/themes/src/main/resources/theme/base/login/messages/messages_es.properties
@@ -168,7 +168,7 @@ bearerOnlyMessage=Las aplicaciones Bearer-only no pueden iniciar sesi\u00F3n des
 directGrantsOnlyMessage=Los clientes de tipo Direct-grants-only no pueden iniciar sesi\u00F3n desde el navegador.
 invalidRedirectUriMessage=La URI de redirecci\u00F3n no es correcta
 unsupportedNameIdFormatMessage=NameIDFormat no soportado
-invlidRequesterMessage=Solicitante no v\u00E1lido
+invalidRequesterMessage=Solicitante no v\u00E1lido
 registrationNotAllowedMessage=El registro no est\u00E1 permitido
 resetCredentialNotAllowedMessage=El renicio de las credenciales no est\u00E1 permitido
 
diff --git a/themes/src/main/resources/theme/base/login/messages/messages_fr.properties b/themes/src/main/resources/theme/base/login/messages/messages_fr.properties
index 4321b23..8dd7926 100755
--- a/themes/src/main/resources/theme/base/login/messages/messages_fr.properties
+++ b/themes/src/main/resources/theme/base/login/messages/messages_fr.properties
@@ -152,7 +152,7 @@ updatePasswordMessage=Vous devez changer votre mot de passe pour activer votre c
 verifyEmailMessage=Vous devez v\u00e9rifier votre courriel pour activer votre compte.
 linkIdpMessage=Vous devez v\u00e9rifier votre courriel pour lier votre compte avec {0}.
 
-emailSentMessage=Vous devriez recevoir rapidement un courriel avec de plus ample instructions.
+emailSentMessage=Vous devriez recevoir rapidement un courriel avec de plus amples instructions.
 emailSendErrorMessage=Erreur lors de l''envoie du courriel, veuillez essayer plus tard.
 
 accountUpdatedMessage=Votre compte a \u00e9t\u00e9 mis \u00e0 jour.
@@ -181,7 +181,7 @@ standardFlowDisabledMessage=Le client n'est pas autoris\u00e9 \u00e0 initier un 
 implicitFlowDisabledMessage=Le client n'est pas autoris\u00e9 \u00e0 initier un connexion avec le navigateur avec ce response_type. Le flux implicite est d\u00e9sactiv\u00e9 pour le client.
 invalidRedirectUriMessage=L''uri de redirection est invalide
 unsupportedNameIdFormatMessage=NameIDFormat non support\u00e9
-invlidRequesterMessage=Demandeur invalide
+invalidRequesterMessage=Demandeur invalide
 registrationNotAllowedMessage=L''enregistrement n''est pas autoris\u00e9
 resetCredentialNotAllowedMessage=La remise \u00e0 z\u00e9ro n''est pas autoris\u00e9
 
diff --git a/themes/src/main/resources/theme/base/login/messages/messages_it.properties b/themes/src/main/resources/theme/base/login/messages/messages_it.properties
index 81c4caa..9875967 100755
--- a/themes/src/main/resources/theme/base/login/messages/messages_it.properties
+++ b/themes/src/main/resources/theme/base/login/messages/messages_it.properties
@@ -160,7 +160,7 @@ bearerOnlyMessage=Alle applicazioni di tipo Bearer-only non e'' consentito di ef
 directGrantsOnlyMessage=Ai client di tipo Direct-grants-only non e'' consentito di effettuare il login tramite browser
 invalidRedirectUriMessage=Redirect uri non valido
 unsupportedNameIdFormatMessage=NameIDFormat non supportato
-invlidRequesterMessage=Richiedente non valido
+invalidRequesterMessage=Richiedente non valido
 registrationNotAllowedMessage=Registrazione non permessa
 resetCredentialNotAllowedMessage=Reset Credential not allowed
 
diff --git a/themes/src/main/resources/theme/base/login/messages/messages_pt_BR.properties b/themes/src/main/resources/theme/base/login/messages/messages_pt_BR.properties
index 08527cc..de2e428 100755
--- a/themes/src/main/resources/theme/base/login/messages/messages_pt_BR.properties
+++ b/themes/src/main/resources/theme/base/login/messages/messages_pt_BR.properties
@@ -181,7 +181,7 @@ standardFlowDisabledMessage=Cliente n\u00E3o tem permiss\u00E3o para iniciar o l
 implicitFlowDisabledMessage=Cliente n\u00E3o tem permiss\u00E3o para iniciar o login com response_type informado. O fluxo padr\u00E3o est\u00E1 desabilitado para o cliente.
 invalidRedirectUriMessage=URI de redirecionamento inv\u00E1lido
 unsupportedNameIdFormatMessage=NameIDFormat n\u00E3o suportado
-invlidRequesterMessage=Solicitante inv\u00E1lido
+invalidRequesterMessage=Solicitante inv\u00E1lido
 registrationNotAllowedMessage=Registro n\u00E3o permitido.
 resetCredentialNotAllowedMessage=N\u00E3o \u00E9 permitido redefinir credencial.
 
diff --git a/themes/src/main/resources/theme/base/login/messages/messages_ru.properties b/themes/src/main/resources/theme/base/login/messages/messages_ru.properties
new file mode 100644
index 0000000..752a3d4
--- /dev/null
+++ b/themes/src/main/resources/theme/base/login/messages/messages_ru.properties
@@ -0,0 +1,218 @@
+doLogIn=\u0412\u0445\u043E\u0434
+doRegister=\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044F
+doCancel=\u041E\u0442\u043C\u0435\u043D\u0430
+doSubmit=\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044C
+doYes=\u0414\u0430
+doNo=\u041D\u0435\u0442
+doContinue=\u041F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u044C
+doAccept=\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044C
+doDecline=\u041E\u0442\u043C\u0435\u043D\u0438\u0442\u044C
+doForgotPassword=\u0417\u0430\u0431\u044B\u043B\u0438 \u043F\u0430\u0440\u043E\u043B\u044C?
+doClickHere=\u041D\u0430\u0436\u043C\u0438\u0442\u0435 \u0441\u044E\u0434\u0430
+doImpersonate=\u0418\u043C\u043F\u0435\u0440\u0441\u043E\u043D\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u0442\u044C\u0441\u044F
+kerberosNotConfigured=Kerberos \u043D\u0435 \u0441\u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043E\u0432\u0430\u043D
+kerberosNotConfiguredTitle=Kerberos \u043D\u0435 \u0441\u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043E\u0432\u0430\u043D
+bypassKerberosDetail=\u041B\u0438\u0431\u043E \u0432\u044B \u043D\u0435 \u0432\u043E\u0448\u043B\u0438 \u0432 \u0441\u0438\u0441\u0442\u0435\u043C\u0443 \u0441 \u043F\u043E\u043C\u043E\u0449\u044C\u044E Kerberos, \u043B\u0438\u0431\u043E \u0432\u0430\u0448 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043D\u0435 \u043D\u0430\u0441\u0442\u0440\u043E\u0435\u043D \u0434\u043B\u044F \u0432\u0445\u043E\u0434\u0430 \u0432 \u0441\u0438\u0441\u0442\u0435\u043C\u0443 Kerberos. \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u043D\u0430\u0436\u043C\u0438\u0442\u0435 \u043A\u043D\u043E\u043F\u043A\u0443 '\u041F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u044C' \u0434\u043B\u044F \u0432\u0445\u043E\u0434\u0430 \u0432 \u0441 \u043F\u043E\u043C\u043E\u0449\u044C\u044E \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u0440\u0435\u0434\u0441\u0442\u0432
+kerberosNotSetUp=Kerberos \u043D\u0435 \u043D\u0430\u0441\u0442\u0440\u043E\u0435\u043D. \u0412\u044B \u043D\u0435 \u043C\u043E\u0436\u0435\u0442\u0435 \u0432\u043E\u0439\u0442\u0438.
+registerWithTitle=\u0417\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C\u0441\u044F \u0441 {0}
+registerWithTitleHtml={0}
+loginTitle=Log in to {0}
+loginTitleHtml={0}
+impersonateTitle={0} \u0418\u043C\u043F\u0435\u0440\u0441\u043E\u043D\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
+impersonateTitleHtml=<strong>{0}</strong> \u0418\u043C\u043F\u0435\u0440\u0441\u043E\u043D\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F</strong>
+realmChoice=Realm
+unknownUser=\u041D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0439 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C
+loginTotpTitle=\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0430 \u043C\u043E\u0431\u0438\u043B\u044C\u043D\u043E\u0433\u043E \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u0430
+loginProfileTitle=\u041E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u0438 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u0438
+loginTimeout=\u0412\u044B \u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0434\u043E\u043B\u0433\u043E \u0431\u0435\u0437\u0434\u0435\u0439\u0441\u0442\u0432\u043E\u0432\u0430\u043B\u0438. \u041F\u0440\u043E\u0446\u0435\u0441\u0441 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u043D\u0430\u0447\u043D\u0435\u0442\u0441\u044F \u0441 \u043D\u0430\u0447\u0430\u043B\u0430.
+oauthGrantTitle=\u0421\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u0442\u044C \u0434\u043E\u0441\u0442\u0443\u043F
+oauthGrantTitleHtml={0}
+errorTitle=\u041C\u044B \u0441\u043E\u0436\u0430\u043B\u0435\u0435\u043C...
+errorTitleHtml=\u041C\u044B <strong>\u0441\u043E\u0436\u0430\u043B\u0435\u0435\u043C</strong> ...
+emailVerifyTitle=\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u0430\u0434\u0440\u0435\u0441\u0430 email
+emailForgotTitle=\u0417\u0430\u0431\u044B\u043B\u0438 \u043F\u0430\u0440\u043E\u043B\u044C?
+updatePasswordTitle=\u041E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\u0430\u0440\u043E\u043B\u044F
+codeSuccessTitle=\u0423\u0441\u043F\u0435\u0448\u043D\u044B\u0439 \u043A\u043E\u0434
+codeErrorTitle=\u041E\u0448\u0438\u0431\u043E\u0447\u043D\u044B\u0439 \u043A\u043E\u0434\: {0}
+
+termsTitle=\u0423\u0441\u043B\u043E\u0432\u0438\u044F \u0438 \u043F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u044F
+termsTitleHtml=\u0423\u0441\u043B\u043E\u0432\u0438\u044F \u0438 \u043F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u044F
+termsText=<p>\u0423\u0441\u043B\u043E\u0432\u0438\u044F \u0438 \u043F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u044F \u0434\u043E\u043B\u0436\u043D\u044B \u0431\u044B\u0442\u044C \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u044B</p>
+
+recaptchaFailed=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u0430\u044F Recaptcha
+recaptchaNotConfigured=Recaptcha \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044F, \u043D\u043E \u043D\u0435 \u0441\u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u0430
+consentDenied=\u0412 \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u0438\u0438 \u043E\u0442\u043A\u0430\u0437\u0430\u043D\u043E.
+
+noAccount=\u041D\u043E\u0432\u044B\u0439 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C?
+username=\u0418\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F
+usernameOrEmail=\u0418\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0438\u043B\u0438 Email
+firstName=\u0418\u043C\u044F
+givenName=\u0412\u044B\u0434\u0430\u043D\u043D\u043E\u0435 \u0438\u043C\u044F
+fullName=\u041F\u043E\u043B\u043D\u043E\u0435 \u0438\u043C\u044F
+lastName=\u0424\u0430\u043C\u0438\u043B\u0438\u044F
+familyName=\u0424\u0430\u043C\u0438\u043B\u0438\u044F
+email=email
+password=\u041F\u0430\u0440\u043E\u043B\u044C
+passwordConfirm=\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u043F\u0430\u0440\u043E\u043B\u044F
+passwordNew=\u041D\u043E\u0432\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C
+passwordNewConfirm=\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u043D\u043E\u0432\u043E\u0433\u043E \u043F\u0430\u0440\u043E\u043B\u044F
+rememberMe=\u0417\u0430\u043F\u043E\u043C\u043D\u0438\u0442\u044C \u043C\u0435\u043D\u044F
+authenticatorCode=\u041E\u0434\u043D\u043E\u0440\u0430\u0437\u043E\u0432\u044B\u0439 \u043A\u043E\u0434
+address=\u0410\u0434\u0440\u0435\u0441
+street=\u0423\u043B\u0438\u0446\u0430
+locality=\u0413\u043E\u0440\u043E\u0434
+region=\u0420\u0435\u0433\u0438\u043E\u043D
+postal_code=\u041F\u043E\u0447\u0442\u043E\u0432\u044B\u0439 \u0438\u043D\u0434\u0435\u043A\u0441
+country=\u0421\u0442\u0440\u0430\u043D\u0430
+emailVerified=Email \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D
+gssDelegationCredential=\u0414\u0435\u043B\u0435\u0433\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0434\u0430\u043D\u043D\u044B\u0445 GSS
+
+loginTotpStep1=\u0423\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0435 <a href="https://fedorahosted.org/freeotp/" target="_blank">FreeOTP</a> \u0438\u043B\u0438 Google Authenticator. \u041E\u0431\u0430 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B \u0432 <a href="https://play.google.com">Google Play</a> \u0438 Apple App Store.
+loginTotpStep2=\u041E\u0442\u043A\u0440\u043E\u0439\u0442\u0435 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u0438 \u043F\u0440\u043E\u0441\u043A\u0430\u043D\u0438\u0440\u0443\u0439\u0442\u0435 \u0431\u0430\u0440\u043A\u043E\u0434, \u043B\u0438\u0431\u043E \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u043A\u043B\u044E\u0447
+loginTotpStep3=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043E\u0434\u043D\u043E\u0440\u0430\u0437\u043E\u0432\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C, \u0432\u044B\u0434\u0430\u043D\u043D\u044B\u0439 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435\u043C, \u0438 \u043D\u0430\u0436\u043C\u0438\u0442\u0435 \u0441\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C \u0434\u043B\u044F \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u0438\u044F \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438
+loginTotpOneTime=\u041E\u0434\u043D\u043E\u0440\u0430\u0437\u043E\u0432\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C
+
+oauthGrantRequest=\u0412\u044B \u0441\u043E\u0433\u043B\u0430\u0441\u0443\u0435\u0442\u0435 \u0434\u043E\u0441\u0442\u0443\u043F \u043A \u044D\u0442\u0438\u043C \u043F\u0440\u0438\u0432\u0435\u043B\u0435\u0433\u0438\u044F\u043C?
+inResource=\u0432
+
+emailVerifyInstruction1=\u0412\u0430\u043C \u0431\u044B\u043B\u043E \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u043E \u043F\u0438\u0441\u044C\u043C\u043E \u0441 \u0438\u043D\u0441\u0442\u0440\u0443\u043A\u0446\u0438\u044F\u043C\u0438 \u0434\u043B\u044F \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F \u0430\u0434\u0440\u0435\u0441\u0430 email.
+emailVerifyInstruction2=\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u0438 \u043F\u0438\u0441\u044C\u043C\u043E \u0441 \u043A\u043E\u0434\u043E\u043C \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F?
+emailVerifyInstruction3=\u0434\u043B\u044F \u043F\u043E\u0432\u0442\u043E\u0440\u043D\u043E\u0439 \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0438 \u043F\u0438\u0441\u044C\u043C\u0430.
+
+emailLinkIdpTitle=\u0421\u0432\u044F\u0437\u0430\u0442\u044C {0}
+emailLinkIdp1=\u0412\u0430\u043C \u0431\u044B\u043B\u043E \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u043E \u043F\u0438\u0441\u044C\u043C\u043E \u0441 \u0438\u043D\u0441\u0442\u0440\u0443\u043A\u0446\u0438\u044F\u043C\u0438 \u043F\u043E \u043E\u0431\u044A\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u044E {0} \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u0438 {1} \u0441 \u0432\u0430\u0448\u0435\u0439 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u044C\u044E {2}.
+emailLinkIdp2=\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u0438 \u043A\u043E\u0434 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F \u043D\u0430 \u0432\u0430\u0448 email?
+emailLinkIdp3=\u0434\u043B\u044F \u043F\u043E\u0432\u0442\u043E\u0440\u043D\u043E\u0439 \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0438 \u043F\u0438\u0441\u044C\u043C\u0430.
+
+backToLogin=&laquo; \u041D\u0430\u0437\u0430\u0434 \u043A\u043E \u0432\u0445\u043E\u0434\u0443
+
+emailInstruction=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0412\u0430\u0448\u0435 \u0438\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0438\u043B\u0438 email \u0438 \u043C\u044B \u0432\u044B\u0448\u043B\u0435\u043C \u0412\u0430\u043C \u0438\u043D\u0441\u0442\u0440\u0443\u043A\u0446\u0438\u0438 \u043F\u043E \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u044E \u043D\u043E\u0432\u043E\u0433\u043E \u043F\u0430\u0440\u043E\u043B\u044F.
+
+copyCodeInstruction=\u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0441\u043A\u043E\u043F\u0438\u0440\u0443\u0439\u0442\u0435 \u044D\u0442\u043E\u0442 \u043A\u043E\u0434 \u0432 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435:
+
+personalInfo=\u041F\u0435\u0440\u0441\u043E\u043D\u0430\u043B\u044C\u043D\u0430\u044F \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F:
+role_admin=\u0410\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440
+role_realm-admin=\u0410\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440 realm
+role_create-realm=\u0421\u043E\u0437\u0434\u0430\u043D\u0438\u0435 realm
+role_create-client=\u0421\u043E\u0437\u0434\u0430\u043D\u0438\u0435 \u043A\u043B\u0438\u0435\u043D\u0442\u0430
+role_view-realm=\u041F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 realm
+role_view-users=\u041F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u0439
+role_view-applications=\u041F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0439
+role_view-clients=\u041F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u043A\u043B\u0438\u0435\u043D\u0442\u043E\u0432
+role_view-events=\u041F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u0441\u043E\u0431\u044B\u0442\u0438\u0439
+role_view-identity-providers=\u041F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440\u043E\u0432 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439
+role_manage-realm=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 realm
+role_manage-users=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F\u043C\u0438
+role_manage-applications=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F\u043C\u0438
+role_manage-identity-providers=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440\u0430\u043C\u0438 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439
+role_manage-clients=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043A\u043B\u0438\u0435\u043D\u0442\u0430\u043C\u0438
+role_manage-events=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0441\u043E\u0431\u044B\u0442\u0438\u044F\u043C\u0438
+role_view-profile=\u041F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u043F\u0440\u043E\u0444\u0438\u043B\u044F
+role_manage-account=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u044C\u044E
+role_read-token=\u0427\u0442\u0435\u043D\u0438\u0435 \u0442\u043E\u043A\u0435\u043D\u0430
+role_offline-access=\u041E\u0444\u0444\u043B\u0430\u0439\u043D \u0434\u043E\u0441\u0442\u0443\u043F
+client_account=\u0423\u0447\u0435\u0442\u043D\u0430\u044F \u0437\u0430\u043F\u0438\u0441\u044C
+client_security-admin-console=\u041A\u043E\u043D\u0441\u043E\u043B\u044C \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430 \u0431\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u043E\u0441\u0442\u0438
+client_admin-cli=\u041A\u043E\u043C\u0430\u043D\u0434\u043D\u044B\u0439 \u0438\u043D\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u0430
+client_realm-management=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 realm
+client_broker=\u0411\u0440\u043E\u043A\u0435\u0440
+
+invalidUserMessage=\u041D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u043E\u0435 \u0438\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0438\u043B\u0438 \u043F\u0430\u0440\u043E\u043B\u044C.
+invalidEmailMessage=\u041D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u044B\u0439 email.
+accountDisabledMessage=\u0423\u0447\u0435\u0442\u043D\u0430\u044F \u0437\u0430\u043F\u0438\u0441\u044C \u0437\u0430\u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u0430\u043D\u0430, \u0441\u0432\u044F\u0436\u0438\u0442\u0435\u0441\u044C \u0441 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u043E\u043C.
+accountTemporarilyDisabledMessage=\u0423\u0447\u0435\u0442\u043D\u0430\u044F \u0437\u0430\u043F\u0438\u0441\u044C \u0432\u0440\u0435\u043C\u0435\u043D\u043D\u043E \u0437\u0430\u0431\u043B\u043E\u043A\u0438\u0440\u043E\u0432\u0430\u043D\u0430, \u0441\u0432\u044F\u0436\u0438\u0442\u0435\u0441\u044C \u0441 \u0430\u0434\u043C\u0438\u043D\u0438\u0441\u0442\u0440\u0430\u0442\u043E\u0440\u043E\u043C \u0438\u043B\u0438 \u043F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u043F\u043E\u0437\u0436\u0435.
+expiredCodeMessage=\u0412\u0445\u043E\u0434 \u043F\u0440\u043E\u0441\u0440\u043E\u0447\u0435\u043D \u043F\u043E \u0442\u0430\u0439\u043C\u0430\u0443\u0442\u0443. \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0432\u043E\u0439\u0434\u0438\u0442\u0435 \u0441\u043D\u043E\u0432\u0430.
+
+missingFirstNameMessage=\u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430 \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u0438\u043C\u044F.
+missingLastNameMessage=\u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430 \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u0444\u0430\u043C\u0438\u043B\u0438\u044E.
+missingEmailMessage=\u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430 \u0432\u0432\u0435\u0434\u0438\u0442\u0435 email.
+missingUsernameMessage=\u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430 \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u0438\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F.
+missingPasswordMessage=\u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430 \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u043F\u0430\u0440\u043E\u043B\u044C.
+missingTotpMessage=\u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430 \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u043A\u043E\u0434 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u0430.
+notMatchPasswordMessage=\u041F\u0430\u0440\u043E\u043B\u0438 \u043D\u0435 \u0441\u043E\u0432\u043F\u0430\u0434\u0430\u044E\u0442.
+
+invalidPasswordExistingMessage=\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0439 \u043F\u0430\u0440\u043E\u043B\u044C.
+invalidPasswordConfirmMessage=\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u0435 \u043F\u0430\u0440\u043E\u043B\u044F \u043D\u0435 \u0441\u043E\u0432\u043F\u0430\u0434\u0430\u0435\u0442.
+invalidTotpMessage=\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u043A\u043E\u0434 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u0430.
+
+usernameExistsMessage=\u0418\u043C\u044F \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0443\u0436\u0435 \u0437\u0430\u043D\u044F\u0442\u043E.
+emailExistsMessage=Email \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442.
+
+federatedIdentityExistsMessage=\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u0441 {0} {1} \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442. \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430 \u0432\u043E\u0439\u0434\u0438\u0442\u0435 \u0432 \u0443\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0443\u0447\u0435\u0442\u043D\u044B\u043C\u0438 \u0437\u0430\u043F\u0438\u0441\u044F\u043C\u0438, \u0447\u0442\u043E\u0431\u044B \u0441\u0432\u044F\u0437\u0430\u0442\u044C \u044D\u0442\u0443 \u0443\u0447\u0435\u0442\u043D\u0443\u044E \u0437\u0430\u043F\u0438\u0441\u044C.
+
+confirmLinkIdpTitle=\u0423\u0447\u0435\u0442\u043D\u0430\u044F \u0437\u0430\u043F\u0438\u0441\u044C \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442
+federatedIdentityConfirmLinkMessage=\u041F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u0441 {0} {1} \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0443\u0435\u0442. \u0425\u043E\u0442\u0438\u0442\u0435 \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u044C?
+federatedIdentityConfirmReauthenticateMessage=\u0410\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0443\u0439\u0442\u0435\u0441\u044C \u043A\u0430\u043A {0} \u0434\u043B\u044F \u0442\u043E\u0433\u043E, \u0447\u0442\u043E\u0431\u044B \u0441\u0432\u044F\u0437\u0430\u0442\u044C \u0412\u0430\u0448\u0443 \u0443\u0447\u0435\u0442\u043D\u0443\u044E \u0437\u0430\u043F\u0438\u0441\u044C \u0441 {1}
+confirmLinkIdpReviewProfile=\u041E\u0431\u0437\u043E\u0440 \u043F\u0440\u043E\u0444\u0438\u043B\u044F
+confirmLinkIdpContinue=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0432 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0449\u0443\u044E \u0443\u0447\u0435\u0442\u043D\u0443\u044E \u0437\u0430\u043F\u0438\u0441\u044C
+
+configureTotpMessage=\u0412\u0430\u043C \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u043D\u0430\u0441\u0442\u0440\u043E\u0438\u0442\u044C \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u0432 \u043C\u043E\u0431\u0438\u043B\u044C\u043D\u043E\u043C \u0443\u0441\u0442\u0440\u043E\u0439\u0441\u0442\u0432\u0435, \u0447\u0442\u043E\u0431\u044B \u0430\u043A\u0442\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0443\u0447\u0435\u0442\u043D\u0443\u044E \u0437\u0430\u043F\u0438\u0441\u044C.
+updateProfileMessage=\u0412\u0430\u043C \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u0441\u0432\u043E\u0439 \u043F\u0440\u043E\u0444\u0438\u043B\u044C, \u0447\u0442\u043E\u0431\u044B \u0430\u043A\u0442\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0412\u0430\u0448\u0443 \u0443\u0447\u0435\u0442\u043D\u0443\u044E \u0437\u0430\u043F\u0438\u0441\u044C.
+updatePasswordMessage=\u0412\u0430\u043C \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u0438\u0437\u043C\u0435\u043D\u0438\u0442\u044C \u043F\u0430\u0440\u043E\u043B\u044C, \u0447\u0442\u043E\u0431\u044B \u0430\u043A\u0442\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0412\u0430\u0448\u0443 \u0443\u0447\u0435\u0442\u043D\u0443\u044E \u0437\u0430\u043F\u0438\u0441\u044C.
+verifyEmailMessage=\u0412\u0430\u043C \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044C \u0412\u0430\u0448 email, \u0447\u0442\u043E\u0431\u044B \u0430\u043A\u0442\u0438\u0432\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0412\u0430\u0448\u0443 \u0443\u0447\u0435\u0442\u043D\u0443\u044E \u0437\u0430\u043F\u0438\u0441\u044C.
+linkIdpMessage=\u0412\u0430\u043C \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044C \u0412\u0430\u0448 email, \u0447\u0442\u043E\u0431\u044B \u0441\u0432\u044F\u0437\u0430\u0442\u044C \u0412\u0430\u0448\u0443 \u0443\u0447\u0435\u0442\u043D\u0443\u044E \u0437\u0430\u043F\u0438\u0441\u044C \u0441 {0}.
+
+emailSentMessage=\u0412 \u0431\u043B\u0438\u0436\u0430\u0439\u0448\u0435\u0435 \u0432\u0440\u0435\u043C\u044F \u0412\u044B \u0434\u043E\u043B\u0436\u043D\u044B \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u043F\u0438\u0441\u044C\u043C\u043E \u0441 \u0434\u0430\u043B\u044C\u043D\u0435\u0439\u0448\u0438\u043C\u0438 \u0438\u043D\u0441\u0442\u0440\u0443\u043A\u0446\u0438\u044F\u043C\u0438.
+emailSendErrorMessage=\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0430\u0435\u0442\u0441\u044F \u043E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u043F\u0438\u0441\u044C\u043C\u043E. \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u043F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0435 \u043F\u043E\u0437\u0436\u0435.
+
+accountUpdatedMessage=\u0412\u0430\u0448\u0430 \u0443\u0447\u0435\u0442\u043D\u0430\u044F \u0437\u0430\u043F\u0438\u0441\u044C \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0430.
+accountPasswordUpdatedMessage=\u0412\u0430\u0448 \u043F\u0430\u0440\u043E\u043B\u044C \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D.
+
+noAccessMessage=\u041D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u0430
+
+invalidPasswordMinLengthMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u043C\u0438\u043D\u0438\u043C\u0430\u043B\u044C\u043D\u0430\u044F \u0434\u043B\u0438\u043D\u0430 {0}.
+invalidPasswordMinDigitsMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u0446\u0438\u0444\u0440\u043E\u0432\u044B\u0445 \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432 \u043D\u0435 \u043C\u0435\u043D\u0435\u0435 {0}.
+invalidPasswordMinLowerCaseCharsMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432 \u0432 \u043D\u0438\u0436\u043D\u0435\u043C \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0435 \u043D\u0435 \u043C\u0435\u043D\u0435\u0435 {0}.
+invalidPasswordMinUpperCaseCharsMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432 \u0432 \u0432\u0435\u0440\u0445\u043D\u0435\u043C \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0435 \u043D\u0435 \u043C\u0435\u043D\u0435\u0435 {0}.
+invalidPasswordMinSpecialCharsMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u0441\u043F\u0435\u0446\u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432 \u043D\u0435 \u043C\u0435\u043D\u0435\u0435 {0}.
+invalidPasswordNotUsernameMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u043D\u0435 \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0432\u043F\u0430\u0434\u0430\u0442\u044C \u0441 \u0438\u043C\u0435\u043D\u0435\u043C \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F.
+invalidPasswordRegexPatternMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u043D\u0435 \u043F\u0440\u043E\u0448\u0435\u043B \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443 \u0440\u0435\u0433\u0443\u043B\u044F\u0440\u043D\u044B\u043C \u0432\u044B\u0440\u0430\u0436\u0435\u043D\u0438\u0435\u043C.
+invalidPasswordHistoryMessage=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C: \u043D\u0435 \u0434\u043E\u043B\u0436\u0435\u043D \u0441\u043E\u0432\u043F\u0430\u0434\u0430\u0442\u044C \u0441 \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u043C\u0438 {0} \u043F\u0430\u0440\u043E\u043B\u044F\u043C\u0438.
+
+failedToProcessResponseMessage=\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u0430\u0442\u044C \u043E\u0442\u0432\u0435\u0442
+httpsRequiredMessage=\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044F HTTPS
+realmNotEnabledMessage=Realm \u043D\u0435 \u0432\u043A\u043B\u044E\u0447\u0435\u043D
+invalidRequestMessage=\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0437\u0430\u043F\u0440\u043E\u0441
+failedLogout=\u0412\u044B\u0439\u0442\u0438 \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C
+unknownLoginRequesterMessage=\u041D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0439 \u043A\u043B\u0438\u0435\u043D\u0442
+loginRequesterNotEnabledMessage=\u041A\u043B\u0438\u0435\u043D\u0442 \u043E\u0442\u043A\u043B\u044E\u0447\u0435\u043D
+bearerOnlyMessage=Bearer-only \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u044F\u043C \u043D\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442\u0441\u044F \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u044F \u0432\u0445\u043E\u0434\u0430 \u0447\u0435\u0440\u0435\u0437 \u0431\u0440\u0430\u0443\u0437\u0435\u0440
+standardFlowDisabledMessage=\u041A\u043B\u0438\u0435\u043D\u0442\u0443 \u043D\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442\u0441\u044F \u0438\u043D\u0438\u0446\u0438\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0432\u0445\u043E\u0434 \u0447\u0435\u0440\u0435\u0437 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0441 \u0434\u0430\u043D\u043D\u044B\u043C response_type. Standard flow \u043E\u0442\u043A\u043B\u044E\u0447\u0435\u043D \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430.
+implicitFlowDisabledMessage=\u041A\u043B\u0438\u0435\u043D\u0442\u0443 \u043D\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442\u0441\u044F \u0438\u043D\u0438\u0446\u0438\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0432\u0445\u043E\u0434 \u0447\u0435\u0440\u0435\u0437 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0441 \u0434\u0430\u043D\u043D\u044B\u043C response_type. Implicit flow \u043E\u0442\u043A\u043B\u044E\u0447\u0435\u043D \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u0438\u0435\u043D\u0442\u0430.
+invalidRedirectUriMessage=\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 uri \u0434\u043B\u044F \u043F\u0435\u0440\u0435\u0430\u0434\u0440\u0435\u0441\u0430\u0446\u0438\u0438
+unsupportedNameIdFormatMessage=\u041D\u0435\u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043C\u044B\u0439 NameIDFormat
+invalidRequesterMessage=\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u0437\u0430\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u044E\u0449\u0438\u0439
+registrationNotAllowedMessage=\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044F \u043D\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u0430
+resetCredentialNotAllowedMessage=\u0421\u0431\u0440\u043E\u0441 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u043E\u043D\u043D\u044B\u0445 \u0434\u0430\u043D\u043D\u044B\u0445 \u043D\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D
+
+permissionNotApprovedMessage=\u0420\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u0438\u0435 \u043D\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u043E.
+noRelayStateInResponseMessage=\u041D\u0435\u0442 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u044F \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u044F \u0432 \u043E\u0442\u0432\u0435\u0442\u0435 \u043E\u0442 \u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440\u0430 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439.
+insufficientPermissionMessage=\u041D\u0435\u0434\u043E\u0441\u0442\u0430\u0442\u043E\u0447\u043D\u043E \u043F\u043E\u043B\u043D\u043E\u043C\u043E\u0447\u0438\u0439 \u0434\u043B\u044F \u0441\u0432\u044F\u0437\u044B\u0432\u0430\u043D\u0438\u044F \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u043E\u0432.
+couldNotProceedWithAuthenticationRequestMessage=\u041D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u0430\u0442\u044C \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u043E\u043D\u043D\u044B\u0439 \u0437\u0430\u043F\u0440\u043E\u0441 \u0432 \u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440\u0435 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439.
+couldNotObtainTokenMessage=\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u0442\u043E\u043A\u0435\u043D \u043E\u0442 \u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440\u0430 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439.
+unexpectedErrorRetrievingTokenMessage=\u041D\u0435\u043F\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043D\u043D\u0430\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u0438\u0438 \u0442\u043E\u043A\u0435\u043D\u0430 \u043E\u0442 \u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440\u0430 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439.
+unexpectedErrorHandlingResponseMessage=\u041D\u0435\u043F\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043D\u043D\u0430\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u043A\u0435 \u043E\u0442\u0432\u0435\u0442\u0430 \u043E\u0442 \u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440\u0430 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439.
+
+identityProviderAuthenticationFailedMessage=\u0410\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u044F \u043F\u0440\u043E\u0432\u0430\u043B\u0435\u043D\u0430. \u041D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0441 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u043E\u043C \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439.
+identityProviderDifferentUserMessage=\u0410\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043E\u0432\u0430\u043D \u043A\u0430\u043A {0}, \u043D\u043E \u043E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F, \u0447\u0442\u043E \u0431\u0443\u0434\u0435\u0442 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u043E\u0432\u0430\u043D \u043A\u0430\u043A {1}
+couldNotSendAuthenticationRequestMessage=\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0430\u0435\u0442\u0441\u044F \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u0437\u0430\u043F\u0440\u043E\u0441 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u043A \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0443 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439.
+unexpectedErrorHandlingRequestMessage=\u041D\u0435\u043F\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043D\u043D\u0430\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u043A\u0435 \u0437\u0430\u043F\u0440\u043E\u0441\u0430 \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439.
+invalidAccessCodeMessage=\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u043A\u043E\u0434 \u0434\u043E\u0441\u0442\u0443\u043F\u0430.
+sessionNotActiveMessage=\u0421\u0435\u0441\u0441\u0438\u044F \u043D\u0435 \u0430\u043A\u0442\u0438\u0432\u043D\u0430.
+invalidCodeMessage=\u041F\u0440\u043E\u0438\u0437\u043E\u0448\u043B\u0430 \u043E\u0448\u0438\u0431\u043A\u0430. \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0432\u043E\u0439\u0434\u0438\u0442\u0435 \u0432 \u0441\u0438\u0441\u0442\u0435\u043C\u0443 \u0441\u043D\u043E\u0432\u0430 \u0447\u0435\u0440\u0435\u0437 \u0432\u0430\u0448\u0435 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435.
+identityProviderUnexpectedErrorMessage=\u041D\u0435\u043F\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043D\u043D\u0430\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0435 \u043F\u043E\u0434\u043B\u0438\u043D\u043D\u043E\u0441\u0442\u0438 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439.
+identityProviderNotFoundMessage=\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043D\u0430\u0439\u0442\u0438 \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0430 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439 \u0441 \u0434\u0430\u043D\u043D\u044B\u043C \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u043E\u043C.
+identityProviderLinkSuccess=\u0412\u0430\u0448\u0430 \u0443\u0447\u0435\u0442\u043D\u0430\u044F \u0437\u0430\u043F\u0438\u0441\u044C \u0431\u044B\u043B\u0430 \u0443\u0441\u043F\u0435\u0448\u043D\u043E \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0430 \u0441 {0} \u0443\u0447\u0435\u0442\u043D\u043E\u0439 \u0437\u0430\u043F\u0438\u0441\u044C\u044E {1} .
+staleCodeMessage=\u042D\u0442\u0430 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0430 \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043B\u044C\u043D\u0430, \u043F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0432\u0435\u0440\u043D\u0438\u0442\u0435\u0441\u044C \u0432 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u0438 \u0441\u043D\u043E\u0432\u0430 \u0432\u043E\u0439\u0434\u0438\u0442\u0435 \u0432 \u0441\u0438\u0441\u0442\u0435\u043C\u0443.
+realmSupportsNoCredentialsMessage=Realm \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043D\u0438\u043A\u0430\u043A\u043E\u0439 \u0442\u0438\u043F \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0434\u0430\u043D\u043D\u044B\u0445.
+identityProviderNotUniqueMessage=Realm \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043D\u0435\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u043E\u0432 \u0443\u0447\u0435\u0442\u043D\u044B\u0445 \u0437\u0430\u043F\u0438\u0441\u0435\u0439. \u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0438\u0442\u044C, \u043A\u0430\u043A\u043E\u0439 \u0438\u043C\u0435\u043D\u043D\u043E \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A \u0434\u043E\u043B\u0436\u0435\u043D \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C\u0441\u044F \u0434\u043B\u044F \u0430\u0443\u0442\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0446\u0438\u0438.
+emailVerifiedMessage=\u0412\u0430\u0448 email \u0431\u044B\u043B \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D.
+staleEmailVerificationLink=\u0421\u0441\u044B\u043B\u043A\u0430, \u043F\u043E \u043A\u043E\u0442\u043E\u0440\u043E\u0439 \u0412\u044B \u043F\u0435\u0440\u0435\u0448\u043B\u0438, \u0443\u0441\u0442\u0430\u0440\u0435\u043B\u0430 \u0438 \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u0442. \u041C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C, \u0432\u044B \u0443\u0436\u0435 \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u043B\u0438 \u0441\u0432\u043E\u0439 email?
+
+backToApplication=&laquo; \u041D\u0430\u0437\u0430\u0434 \u0432 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0435
+missingParameterMessage=\u041F\u0440\u043E\u043F\u0443\u0449\u0435\u043D\u043D\u044B\u0435 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B\: {0}
+clientNotFoundMessage=\u041A\u043B\u0438\u0435\u043D\u0442 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D.
+invalidParameterMessage=\u041D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\: {0}
+alreadyLoggedIn=\u0412\u044B \u0443\u0436\u0435 \u0432\u043E\u0448\u043B\u0438.
+
+p3pPolicy=CP="\u042D\u0442\u043E \u043D\u0435 \u043F\u043E\u043B\u0438\u0442\u0438\u043A\u0430 P3P!"
diff --git a/themes/src/main/resources/theme/base/login/theme.properties b/themes/src/main/resources/theme/base/login/theme.properties
index 27f59f5..503eda7 100644
--- a/themes/src/main/resources/theme/base/login/theme.properties
+++ b/themes/src/main/resources/theme/base/login/theme.properties
@@ -1 +1 @@
-locales=ca,de,en,es,fr,it,pt-BR
\ No newline at end of file
+locales=ca,de,en,es,fr,it,pt-BR,ru
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/admin/resources/css/styles.css b/themes/src/main/resources/theme/keycloak/admin/resources/css/styles.css
index a4eead1..c3a9a64 100755
--- a/themes/src/main/resources/theme/keycloak/admin/resources/css/styles.css
+++ b/themes/src/main/resources/theme/keycloak/admin/resources/css/styles.css
@@ -374,4 +374,9 @@ h1 i {
     width: 80px;
     margin-left: 0;
     padding-left: 0;
+}
+
+.ace_editor {
+    height: 400px;
+    width: 100%;
 }
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/LICENSE b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/LICENSE
new file mode 100644
index 0000000..4760be2
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/LICENSE
@@ -0,0 +1,24 @@
+Copyright (c) 2010, Ajax.org B.V.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of Ajax.org B.V. nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/README.md b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/README.md
new file mode 100644
index 0000000..c1eeca9
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/README.md
@@ -0,0 +1,21 @@
+Ace (Ajax.org Cloud9 Editor)
+============================
+
+Ace is a code editor written in JavaScript.
+
+This repository has only generated files.
+If you want to work on ace please go to https://github.com/ajaxorg/ace instead.
+
+
+here you can find pre-built files for convenience of embedding.
+it contains 4 versions
+ * [src](https://github.com/ajaxorg/ace-builds/tree/master/src)              concatenated but not minified
+ * [src-min](https://github.com/ajaxorg/ace-builds/tree/master/src-min)      concatenated and minified with uglify.js
+ * [src-noconflict](https://github.com/ajaxorg/ace-builds/tree/master/src-noconflict)      uses ace.require instead of require
+ * [src-min-noconflict](https://github.com/ajaxorg/ace-builds/tree/master/src-min-noconflict)      -
+
+
+For a simple way of embedding ace into webpage see [editor.html](https://github.com/ajaxorg/ace-builds/blob/master/editor.html) or list of other [simple examples](https://github.com/ajaxorg/ace-builds/tree/master/demo)
+To see ace in action go to [kitchen-sink-demo](http://ajaxorg.github.com/ace-builds/kitchen-sink.html), [scrollable-page-demo](http://ajaxorg.github.com/ace-builds/demo/scrollable-page.html) or [minimal demo](http://ajaxorg.github.com/ace-builds/editor.html),
+
+
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ace.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ace.js
new file mode 100644
index 0000000..faa3034
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ace.js
@@ -0,0 +1,11 @@
+(function(){function o(n){var i=e;n&&(e[n]||(e[n]={}),i=e[n]);if(!i.define||!i.define.packaged)t.original=i.define,i.define=t,i.define.packaged=!0;if(!i.require||!i.require.packaged)r.original=i.require,i.require=r,i.require.packaged=!0}var ACE_NAMESPACE = "ace",e=function(){return this}();!e&&typeof window!="undefined"&&(e=window);if(!ACE_NAMESPACE&&typeof requirejs!="undefined")return;var t=function(e,n,r){if(typeof e!="string"){t.original?t.original.apply(this,arguments):(console.error("dropping module because define wasn't a string."),console.trace());return}arguments.length==2&&(r=n),t.modules[e]||(t.payloads[e]=r,t.modules[e]=null)};t.modules={},t.payloads={};var n=function(e,t,n){if(typeof t=="string"){var i=s(e,t);if(i!=undefined)return n&&n(),i}else if(Object.prototype.toString.call(t)==="[object Array]"){var o=[];for(var u=0,a=t.length;u<a;++u){var f=s(e,t[u]);if(f==undefined&&r.original)return;o.push(f)}return n&&n.apply(null,o)||!0}},r=function(e,t){var i=n("",e,t);return i==undefined&&r.original?r.original.apply(this,arguments):i},i=function(e,t){if(t.indexOf("!")!==-1){var n=t.split("!");return i(e,n[0])+"!"+i(e,n[1])}if(t.charAt(0)=="."){var r=e.split("/").slice(0,-1).join("/");t=r+"/"+t;while(t.indexOf(".")!==-1&&s!=t){var s=t;t=t.replace(/\/\.\//,"/").replace(/[^\/]+\/\.\.\//,"")}}return t},s=function(e,r){r=i(e,r);var s=t.modules[r];if(!s){s=t.payloads[r];if(typeof s=="function"){var o={},u={id:r,uri:"",exports:o,packaged:!0},a=function(e,t){return n(r,e,t)},f=s(a,o,u);o=f||u.exports,t.modules[r]=o,delete t.payloads[r]}s=t.modules[r]=o||s}return s};o(ACE_NAMESPACE)})(),ace.define("ace/lib/regexp",["require","exports","module"],function(e,t,n){"use strict";function o(e){return(e.global?"g":"")+(e.ignoreCase?"i":"")+(e.multiline?"m":"")+(e.extended?"x":"")+(e.sticky?"y":"")}function u(e,t,n){if(Array.prototype.indexOf)return e.indexOf(t,n);for(var r=n||0;r<e.length;r++)if(e[r]===t)return r;return-1}var r={exec:RegExp.prototype.exec,test:RegExp.prototype.test,match:String.prototype.match,replace:String.prototype.replace,split:String.prototype.split},i=r.exec.call(/()??/,"")[1]===undefined,s=function(){var e=/^/g;return r.test.call(e,""),!e.lastIndex}();if(s&&i)return;RegExp.prototype.exec=function(e){var t=r.exec.apply(this,arguments),n,a;if(typeof e=="string"&&t){!i&&t.length>1&&u(t,"")>-1&&(a=RegExp(this.source,r.replace.call(o(this),"g","")),r.replace.call(e.slice(t.index),a,function(){for(var e=1;e<arguments.length-2;e++)arguments[e]===undefined&&(t[e]=undefined)}));if(this._xregexp&&this._xregexp.captureNames)for(var f=1;f<t.length;f++)n=this._xregexp.captureNames[f-1],n&&(t[n]=t[f]);!s&&this.global&&!t[0].length&&this.lastIndex>t.index&&this.lastIndex--}return t},s||(RegExp.prototype.test=function(e){var t=r.exec.call(this,e);return t&&this.global&&!t[0].length&&this.lastIndex>t.index&&this.lastIndex--,!!t})}),ace.define("ace/lib/es5-shim",["require","exports","module"],function(e,t,n){function r(){}function w(e){try{return Object.defineProperty(e,"sentinel",{}),"sentinel"in e}catch(t){}}function H(e){return e=+e,e!==e?e=0:e!==0&&e!==1/0&&e!==-1/0&&(e=(e>0||-1)*Math.floor(Math.abs(e))),e}function B(e){var t=typeof e;return e===null||t==="undefined"||t==="boolean"||t==="number"||t==="string"}function j(e){var t,n,r;if(B(e))return e;n=e.valueOf;if(typeof n=="function"){t=n.call(e);if(B(t))return t}r=e.toString;if(typeof r=="function"){t=r.call(e);if(B(t))return t}throw new TypeError}Function.prototype.bind||(Function.prototype.bind=function(t){var n=this;if(typeof n!="function")throw new TypeError("Function.prototype.bind called on incompatible "+n);var i=u.call(arguments,1),s=function(){if(this instanceof s){var e=n.apply(this,i.concat(u.call(arguments)));return Object(e)===e?e:this}return n.apply(t,i.concat(u.call(arguments)))};return n.prototype&&(r.prototype=n.prototype,s.prototype=new r,r.prototype=null),s});var i=Function.prototype.call,s=Array.prototype,o=Object.prototype,u=s.slice,a=i.bind(o.toString),f=i.bind(o.hasOwnProperty),l,c,h,p,d;if(d=f(o,"__defineGetter__"))l=i.bind(o.__defineGetter__),c=i.bind(o.__defineSetter__),h=i.bind(o.__lookupGetter__),p=i.bind(o.__lookupSetter__);if([1,2].splice(0).length!=2)if(!function(){function e(e){var t=new Array(e+2);return t[0]=t[1]=0,t}var t=[],n;t.splice.apply(t,e(20)),t.splice.apply(t,e(26)),n=t.length,t.splice(5,0,"XXX"),n+1==t.length;if(n+1==t.length)return!0}())Array.prototype.splice=function(e,t){var n=this.length;e>0?e>n&&(e=n):e==void 0?e=0:e<0&&(e=Math.max(n+e,0)),e+t<n||(t=n-e);var r=this.slice(e,e+t),i=u.call(arguments,2),s=i.length;if(e===n)s&&this.push.apply(this,i);else{var o=Math.min(t,n-e),a=e+o,f=a+s-o,l=n-a,c=n-o;if(f<a)for(var h=0;h<l;++h)this[f+h]=this[a+h];else if(f>a)for(h=l;h--;)this[f+h]=this[a+h];if(s&&e===c)this.length=c,this.push.apply(this,i);else{this.length=c+s;for(h=0;h<s;++h)this[e+h]=i[h]}}return r};else{var v=Array.prototype.splice;Array.prototype.splice=function(e,t){return arguments.length?v.apply(this,[e===void 0?0:e,t===void 0?this.length-e:t].concat(u.call(arguments,2))):[]}}Array.isArray||(Array.isArray=function(t){return a(t)=="[object Array]"});var m=Object("a"),g=m[0]!="a"||!(0 in m);Array.prototype.forEach||(Array.prototype.forEach=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=arguments[1],s=-1,o=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError;while(++s<o)s in r&&t.call(i,r[s],s,n)}),Array.prototype.map||(Array.prototype.map=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=Array(i),o=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var u=0;u<i;u++)u in r&&(s[u]=t.call(o,r[u],u,n));return s}),Array.prototype.filter||(Array.prototype.filter=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=[],o,u=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var f=0;f<i;f++)f in r&&(o=r[f],t.call(u,o,f,n)&&s.push(o));return s}),Array.prototype.every||(Array.prototype.every=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&!t.call(s,r[o],o,n))return!1;return!0}),Array.prototype.some||(Array.prototype.some=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&t.call(s,r[o],o,n))return!0;return!1}),Array.prototype.reduce||(Array.prototype.reduce=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduce of empty array with no initial value");var s=0,o;if(arguments.length>=2)o=arguments[1];else do{if(s in r){o=r[s++];break}if(++s>=i)throw new TypeError("reduce of empty array with no initial value")}while(!0);for(;s<i;s++)s in r&&(o=t.call(void 0,o,r[s],s,n));return o}),Array.prototype.reduceRight||(Array.prototype.reduceRight=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduceRight of empty array with no initial value");var s,o=i-1;if(arguments.length>=2)s=arguments[1];else do{if(o in r){s=r[o--];break}if(--o<0)throw new TypeError("reduceRight of empty array with no initial value")}while(!0);do o in this&&(s=t.call(void 0,s,r[o],o,n));while(o--);return s});if(!Array.prototype.indexOf||[0,1].indexOf(1,2)!=-1)Array.prototype.indexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=0;arguments.length>1&&(i=H(arguments[1])),i=i>=0?i:Math.max(0,r+i);for(;i<r;i++)if(i in n&&n[i]===t)return i;return-1};if(!Array.prototype.lastIndexOf||[0,1].lastIndexOf(0,-3)!=-1)Array.prototype.lastIndexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=r-1;arguments.length>1&&(i=Math.min(i,H(arguments[1]))),i=i>=0?i:r-Math.abs(i);for(;i>=0;i--)if(i in n&&t===n[i])return i;return-1};Object.getPrototypeOf||(Object.getPrototypeOf=function(t){return t.__proto__||(t.constructor?t.constructor.prototype:o)});if(!Object.getOwnPropertyDescriptor){var y="Object.getOwnPropertyDescriptor called on a non-object: ";Object.getOwnPropertyDescriptor=function(t,n){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(y+t);if(!f(t,n))return;var r,i,s;r={enumerable:!0,configurable:!0};if(d){var u=t.__proto__;t.__proto__=o;var i=h(t,n),s=p(t,n);t.__proto__=u;if(i||s)return i&&(r.get=i),s&&(r.set=s),r}return r.value=t[n],r}}Object.getOwnPropertyNames||(Object.getOwnPropertyNames=function(t){return Object.keys(t)});if(!Object.create){var b;Object.prototype.__proto__===null?b=function(){return{__proto__:null}}:b=function(){var e={};for(var t in e)e[t]=null;return e.constructor=e.hasOwnProperty=e.propertyIsEnumerable=e.isPrototypeOf=e.toLocaleString=e.toString=e.valueOf=e.__proto__=null,e},Object.create=function(t,n){var r;if(t===null)r=b();else{if(typeof t!="object")throw new TypeError("typeof prototype["+typeof t+"] != 'object'");var i=function(){};i.prototype=t,r=new i,r.__proto__=t}return n!==void 0&&Object.defineProperties(r,n),r}}if(Object.defineProperty){var E=w({}),S=typeof document=="undefined"||w(document.createElement("div"));if(!E||!S)var x=Object.defineProperty}if(!Object.defineProperty||x){var T="Property description must be an object: ",N="Object.defineProperty called on non-object: ",C="getters & setters can not be defined on this javascript engine";Object.defineProperty=function(t,n,r){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(N+t);if(typeof r!="object"&&typeof r!="function"||r===null)throw new TypeError(T+r);if(x)try{return x.call(Object,t,n,r)}catch(i){}if(f(r,"value"))if(d&&(h(t,n)||p(t,n))){var s=t.__proto__;t.__proto__=o,delete t[n],t[n]=r.value,t.__proto__=s}else t[n]=r.value;else{if(!d)throw new TypeError(C);f(r,"get")&&l(t,n,r.get),f(r,"set")&&c(t,n,r.set)}return t}}Object.defineProperties||(Object.defineProperties=function(t,n){for(var r in n)f(n,r)&&Object.defineProperty(t,r,n[r]);return t}),Object.seal||(Object.seal=function(t){return t}),Object.freeze||(Object.freeze=function(t){return t});try{Object.freeze(function(){})}catch(k){Object.freeze=function(t){return function(n){return typeof n=="function"?n:t(n)}}(Object.freeze)}Object.preventExtensions||(Object.preventExtensions=function(t){return t}),Object.isSealed||(Object.isSealed=function(t){return!1}),Object.isFrozen||(Object.isFrozen=function(t){return!1}),Object.isExtensible||(Object.isExtensible=function(t){if(Object(t)===t)throw new TypeError;var n="";while(f(t,n))n+="?";t[n]=!0;var r=f(t,n);return delete t[n],r});if(!Object.keys){var L=!0,A=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],O=A.length;for(var M in{toString:null})L=!1;Object.keys=function I(e){if(typeof e!="object"&&typeof e!="function"||e===null)throw new TypeError("Object.keys called on a non-object");var I=[];for(var t in e)f(e,t)&&I.push(t);if(L)for(var n=0,r=O;n<r;n++){var i=A[n];f(e,i)&&I.push(i)}return I}}Date.now||(Date.now=function(){return(new Date).getTime()});var _="	\n\f\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\ufeff";if(!String.prototype.trim||_.trim()){_="["+_+"]";var D=new RegExp("^"+_+_+"*"),P=new RegExp(_+_+"*$");String.prototype.trim=function(){return String(this).replace(D,"").replace(P,"")}}var F=function(e){if(e==null)throw new TypeError("can't convert "+e+" to object");return Object(e)}}),ace.define("ace/lib/fixoldbrowsers",["require","exports","module","ace/lib/regexp","ace/lib/es5-shim"],function(e,t,n){"use strict";e("./regexp"),e("./es5-shim")}),ace.define("ace/lib/dom",["require","exports","module"],function(e,t,n){"use strict";var r="http://www.w3.org/1999/xhtml";t.getDocumentHead=function(e){return e||(e=document),e.head||e.getElementsByTagName("head")[0]||e.documentElement},t.createElement=function(e,t){return document.createElementNS?document.createElementNS(t||r,e):document.createElement(e)},t.hasCssClass=function(e,t){var n=(e.className||"").split(/\s+/g);return n.indexOf(t)!==-1},t.addCssClass=function(e,n){t.hasCssClass(e,n)||(e.className+=" "+n)},t.removeCssClass=function(e,t){var n=e.className.split(/\s+/g);for(;;){var r=n.indexOf(t);if(r==-1)break;n.splice(r,1)}e.className=n.join(" ")},t.toggleCssClass=function(e,t){var n=e.className.split(/\s+/g),r=!0;for(;;){var i=n.indexOf(t);if(i==-1)break;r=!1,n.splice(i,1)}return r&&n.push(t),e.className=n.join(" "),r},t.setCssClass=function(e,n,r){r?t.addCssClass(e,n):t.removeCssClass(e,n)},t.hasCssString=function(e,t){var n=0,r;t=t||document;if(t.createStyleSheet&&(r=t.styleSheets)){while(n<r.length)if(r[n++].owningElement.id===e)return!0}else if(r=t.getElementsByTagName("style"))while(n<r.length)if(r[n++].id===e)return!0;return!1},t.importCssString=function(n,r,i){i=i||document;if(r&&t.hasCssString(r,i))return null;var s;r&&(n+="\n/*# sourceURL=ace/css/"+r+" */"),i.createStyleSheet?(s=i.createStyleSheet(),s.cssText=n,r&&(s.owningElement.id=r)):(s=t.createElement("style"),s.appendChild(i.createTextNode(n)),r&&(s.id=r),t.getDocumentHead(i).appendChild(s))},t.importCssStylsheet=function(e,n){if(n.createStyleSheet)n.createStyleSheet(e);else{var r=t.createElement("link");r.rel="stylesheet",r.href=e,t.getDocumentHead(n).appendChild(r)}},t.getInnerWidth=function(e){return parseInt(t.computedStyle(e,"paddingLeft"),10)+parseInt(t.computedStyle(e,"paddingRight"),10)+e.clientWidth},t.getInnerHeight=function(e){return parseInt(t.computedStyle(e,"paddingTop"),10)+parseInt(t.computedStyle(e,"paddingBottom"),10)+e.clientHeight},t.scrollbarWidth=function(e){var n=t.createElement("ace_inner");n.style.width="100%",n.style.minWidth="0px",n.style.height="200px",n.style.display="block";var r=t.createElement("ace_outer"),i=r.style;i.position="absolute",i.left="-10000px",i.overflow="hidden",i.width="200px",i.minWidth="0px",i.height="150px",i.display="block",r.appendChild(n);var s=e.documentElement;s.appendChild(r);var o=n.offsetWidth;i.overflow="scroll";var u=n.offsetWidth;return o==u&&(u=r.clientWidth),s.removeChild(r),o-u};if(typeof document=="undefined"){t.importCssString=function(){};return}window.pageYOffset!==undefined?(t.getPageScrollTop=function(){return window.pageYOffset},t.getPageScrollLeft=function(){return window.pageXOffset}):(t.getPageScrollTop=function(){return document.body.scrollTop},t.getPageScrollLeft=function(){return document.body.scrollLeft}),window.getComputedStyle?t.computedStyle=function(e,t){return t?(window.getComputedStyle(e,"")||{})[t]||"":window.getComputedStyle(e,"")||{}}:t.computedStyle=function(e,t){return t?e.currentStyle[t]:e.currentStyle},t.setInnerHtml=function(e,t){var n=e.cloneNode(!1);return n.innerHTML=t,e.parentNode.replaceChild(n,e),n},"textContent"in document.documentElement?(t.setInnerText=function(e,t){e.textContent=t},t.getInnerText=function(e){return e.textContent}):(t.setInnerText=function(e,t){e.innerText=t},t.getInnerText=function(e){return e.innerText}),t.getParentWindow=function(e){return e.defaultView||e.parentWindow}}),ace.define("ace/lib/oop",["require","exports","module"],function(e,t,n){"use strict";t.inherits=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})},t.mixin=function(e,t){for(var n in t)e[n]=t[n];return e},t.implement=function(e,n){t.mixin(e,n)}}),ace.define("ace/lib/keys",["require","exports","module","ace/lib/fixoldbrowsers","ace/lib/oop"],function(e,t,n){"use strict";e("./fixoldbrowsers");var r=e("./oop"),i=function(){var e={MODIFIER_KEYS:{16:"Shift",17:"Ctrl",18:"Alt",224:"Meta"},KEY_MODS:{ctrl:1,alt:2,option:2,shift:4,"super":8,meta:8,command:8,cmd:8},FUNCTION_KEYS:{8:"Backspace",9:"Tab",13:"Return",19:"Pause",27:"Esc",32:"Space",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"Left",38:"Up",39:"Right",40:"Down",44:"Print",45:"Insert",46:"Delete",96:"Numpad0",97:"Numpad1",98:"Numpad2",99:"Numpad3",100:"Numpad4",101:"Numpad5",102:"Numpad6",103:"Numpad7",104:"Numpad8",105:"Numpad9","-13":"NumpadEnter",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"Numlock",145:"Scrolllock"},PRINTABLE_KEYS:{32:" ",48:"0",49:"1",50:"2",51:"3",52:"4",53:"5",54:"6",55:"7",56:"8",57:"9",59:";",61:"=",65:"a",66:"b",67:"c",68:"d",69:"e",70:"f",71:"g",72:"h",73:"i",74:"j",75:"k",76:"l",77:"m",78:"n",79:"o",80:"p",81:"q",82:"r",83:"s",84:"t",85:"u",86:"v",87:"w",88:"x",89:"y",90:"z",107:"+",109:"-",110:".",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'",111:"/",106:"*"}},t,n;for(n in e.FUNCTION_KEYS)t=e.FUNCTION_KEYS[n].toLowerCase(),e[t]=parseInt(n,10);for(n in e.PRINTABLE_KEYS)t=e.PRINTABLE_KEYS[n].toLowerCase(),e[t]=parseInt(n,10);return r.mixin(e,e.MODIFIER_KEYS),r.mixin(e,e.PRINTABLE_KEYS),r.mixin(e,e.FUNCTION_KEYS),e.enter=e["return"],e.escape=e.esc,e.del=e["delete"],e[173]="-",function(){var t=["cmd","ctrl","alt","shift"];for(var n=Math.pow(2,t.length);n--;)e.KEY_MODS[n]=t.filter(function(t){return n&e.KEY_MODS[t]}).join("-")+"-"}(),e.KEY_MODS[0]="",e.KEY_MODS[-1]="input-",e}();r.mixin(t,i),t.keyCodeToString=function(e){var t=i[e];return typeof t!="string"&&(t=String.fromCharCode(e)),t.toLowerCase()}}),ace.define("ace/lib/useragent",["require","exports","module"],function(e,t,n){"use strict";t.OS={LINUX:"LINUX",MAC:"MAC",WINDOWS:"WINDOWS"},t.getOS=function(){return t.isMac?t.OS.MAC:t.isLinux?t.OS.LINUX:t.OS.WINDOWS};if(typeof navigator!="object")return;var r=(navigator.platform.match(/mac|win|linux/i)||["other"])[0].toLowerCase(),i=navigator.userAgent;t.isWin=r=="win",t.isMac=r=="mac",t.isLinux=r=="linux",t.isIE=navigator.appName=="Microsoft Internet Explorer"||navigator.appName.indexOf("MSAppHost")>=0?parseFloat((i.match(/(?:MSIE |Trident\/[0-9]+[\.0-9]+;.*rv:)([0-9]+[\.0-9]+)/)||[])[1]):parseFloat((i.match(/(?:Trident\/[0-9]+[\.0-9]+;.*rv:)([0-9]+[\.0-9]+)/)||[])[1]),t.isOldIE=t.isIE&&t.isIE<9,t.isGecko=t.isMozilla=(window.Controllers||window.controllers)&&window.navigator.product==="Gecko",t.isOldGecko=t.isGecko&&parseInt((i.match(/rv\:(\d+)/)||[])[1],10)<4,t.isOpera=window.opera&&Object.prototype.toString.call(window.opera)=="[object Opera]",t.isWebKit=parseFloat(i.split("WebKit/")[1])||undefined,t.isChrome=parseFloat(i.split(" Chrome/")[1])||undefined,t.isAIR=i.indexOf("AdobeAIR")>=0,t.isIPad=i.indexOf("iPad")>=0,t.isTouchPad=i.indexOf("TouchPad")>=0,t.isChromeOS=i.indexOf(" CrOS ")>=0}),ace.define("ace/lib/event",["require","exports","module","ace/lib/keys","ace/lib/useragent"],function(e,t,n){"use strict";function a(e,t,n){var a=u(t);if(!i.isMac&&s){s.OSKey&&(a|=8);if(s.altGr){if((3&a)==3)return;s.altGr=0}if(n===18||n===17){var f="location"in t?t.location:t.keyLocation;if(n===17&&f===1)s[n]==1&&(o=t.timeStamp);else if(n===18&&a===3&&f===2){var l=t.timeStamp-o;l<50&&(s.altGr=!0)}}}n in r.MODIFIER_KEYS&&(n=-1),a&8&&n>=91&&n<=93&&(n=-1);if(!a&&n===13){var f="location"in t?t.location:t.keyLocation;if(f===3){e(t,a,-n);if(t.defaultPrevented)return}}if(i.isChromeOS&&a&8){e(t,a,n);if(t.defaultPrevented)return;a&=-9}return!!a||n in r.FUNCTION_KEYS||n in r.PRINTABLE_KEYS?e(t,a,n):!1}function f(){s=Object.create(null),s.count=0,s.lastT=0}var r=e("./keys"),i=e("./useragent"),s=null,o=0;t.addListener=function(e,t,n){if(e.addEventListener)return e.addEventListener(t,n,!1);if(e.attachEvent){var r=function(){n.call(e,window.event)};n._wrapper=r,e.attachEvent("on"+t,r)}},t.removeListener=function(e,t,n){if(e.removeEventListener)return e.removeEventListener(t,n,!1);e.detachEvent&&e.detachEvent("on"+t,n._wrapper||n)},t.stopEvent=function(e){return t.stopPropagation(e),t.preventDefault(e),!1},t.stopPropagation=function(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0},t.preventDefault=function(e){e.preventDefault?e.preventDefault():e.returnValue=!1},t.getButton=function(e){return e.type=="dblclick"?0:e.type=="contextmenu"||i.isMac&&e.ctrlKey&&!e.altKey&&!e.shiftKey?2:e.preventDefault?e.button:{1:0,2:2,4:1}[e.button]},t.capture=function(e,n,r){function i(e){n&&n(e),r&&r(e),t.removeListener(document,"mousemove",n,!0),t.removeListener(document,"mouseup",i,!0),t.removeListener(document,"dragstart",i,!0)}return t.addListener(document,"mousemove",n,!0),t.addListener(document,"mouseup",i,!0),t.addListener(document,"dragstart",i,!0),i},t.addTouchMoveListener=function(e,n){if("ontouchmove"in e){var r,i;t.addListener(e,"touchstart",function(e){var t=e.changedTouches[0];r=t.clientX,i=t.clientY}),t.addListener(e,"touchmove",function(e){var t=1,s=e.changedTouches[0];e.wheelX=-(s.clientX-r)/t,e.wheelY=-(s.clientY-i)/t,r=s.clientX,i=s.clientY,n(e)})}},t.addMouseWheelListener=function(e,n){"onmousewheel"in e?t.addListener(e,"mousewheel",function(e){var t=8;e.wheelDeltaX!==undefined?(e.wheelX=-e.wheelDeltaX/t,e.wheelY=-e.wheelDeltaY/t):(e.wheelX=0,e.wheelY=-e.wheelDelta/t),n(e)}):"onwheel"in e?t.addListener(e,"wheel",function(e){var t=.35;switch(e.deltaMode){case e.DOM_DELTA_PIXEL:e.wheelX=e.deltaX*t||0,e.wheelY=e.deltaY*t||0;break;case e.DOM_DELTA_LINE:case e.DOM_DELTA_PAGE:e.wheelX=(e.deltaX||0)*5,e.wheelY=(e.deltaY||0)*5}n(e)}):t.addListener(e,"DOMMouseScroll",function(e){e.axis&&e.axis==e.HORIZONTAL_AXIS?(e.wheelX=(e.detail||0)*5,e.wheelY=0):(e.wheelX=0,e.wheelY=(e.detail||0)*5),n(e)})},t.addMultiMouseDownListener=function(e,n,r,s){function c(e){t.getButton(e)!==0?o=0:e.detail>1?(o++,o>4&&(o=1)):o=1;if(i.isIE){var c=Math.abs(e.clientX-u)>5||Math.abs(e.clientY-a)>5;if(!f||c)o=1;f&&clearTimeout(f),f=setTimeout(function(){f=null},n[o-1]||600),o==1&&(u=e.clientX,a=e.clientY)}e._clicks=o,r[s]("mousedown",e);if(o>4)o=0;else if(o>1)return r[s](l[o],e)}function h(e){o=2,f&&clearTimeout(f),f=setTimeout(function(){f=null},n[o-1]||600),r[s]("mousedown",e),r[s](l[o],e)}var o=0,u,a,f,l={2:"dblclick",3:"tripleclick",4:"quadclick"};Array.isArray(e)||(e=[e]),e.forEach(function(e){t.addListener(e,"mousedown",c),i.isOldIE&&t.addListener(e,"dblclick",h)})};var u=!i.isMac||!i.isOpera||"KeyboardEvent"in window?function(e){return 0|(e.ctrlKey?1:0)|(e.altKey?2:0)|(e.shiftKey?4:0)|(e.metaKey?8:0)}:function(e){return 0|(e.metaKey?1:0)|(e.altKey?2:0)|(e.shiftKey?4:0)|(e.ctrlKey?8:0)};t.getModifierString=function(e){return r.KEY_MODS[u(e)]},t.addCommandKeyListener=function(e,n){var r=t.addListener;if(i.isOldGecko||i.isOpera&&!("KeyboardEvent"in window)){var o=null;r(e,"keydown",function(e){o=e.keyCode}),r(e,"keypress",function(e){return a(n,e,o)})}else{var u=null;r(e,"keydown",function(e){var t=e.keyCode;s[t]=(s[t]||0)+1,t==91||t==92?s.OSKey=!0:s.OSKey&&e.timeStamp-s.lastT>200&&s.count==1&&f(),s[t]==1&&s.count++,s.lastT=e.timeStamp;var r=a(n,e,t);return u=e.defaultPrevented,r}),r(e,"keypress",function(e){u&&(e.ctrlKey||e.altKey||e.shiftKey||e.metaKey)&&(t.stopEvent(e),u=null)}),r(e,"keyup",function(e){var t=e.keyCode;s[t]?s.count=Math.max(s.count-1,0):f();if(t==91||t==92)s.OSKey=!1;s[t]=null}),s||(f(),r(window,"focus",f))}};if(typeof window=="object"&&window.postMessage&&!i.isOldIE){var l=1;t.nextTick=function(e,n){n=n||window;var r="zero-timeout-message-"+l;t.addListener(n,"message",function i(s){s.data==r&&(t.stopPropagation(s),t.removeListener(n,"message",i),e())}),n.postMessage(r,"*")}}t.nextFrame=typeof window=="object"&&(window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame||window.oRequestAnimationFrame),t.nextFrame?t.nextFrame=t.nextFrame.bind(window):t.nextFrame=function(e){setTimeout(e,17)}}),ace.define("ace/lib/lang",["require","exports","module"],function(e,t,n){"use strict";t.last=function(e){return e[e.length-1]},t.stringReverse=function(e){return e.split("").reverse().join("")},t.stringRepeat=function(e,t){var n="";while(t>0){t&1&&(n+=e);if(t>>=1)e+=e}return n};var r=/^\s\s*/,i=/\s\s*$/;t.stringTrimLeft=function(e){return e.replace(r,"")},t.stringTrimRight=function(e){return e.replace(i,"")},t.copyObject=function(e){var t={};for(var n in e)t[n]=e[n];return t},t.copyArray=function(e){var t=[];for(var n=0,r=e.length;n<r;n++)e[n]&&typeof e[n]=="object"?t[n]=this.copyObject(e[n]):t[n]=e[n];return t},t.deepCopy=function s(e){if(typeof e!="object"||!e)return e;var t;if(Array.isArray(e)){t=[];for(var n=0;n<e.length;n++)t[n]=s(e[n]);return t}var r=e.constructor;if(r===RegExp)return e;t=r();for(var n in e)t[n]=s(e[n]);return t},t.arrayToMap=function(e){var t={};for(var n=0;n<e.length;n++)t[e[n]]=1;return t},t.createMap=function(e){var t=Object.create(null);for(var n in e)t[n]=e[n];return t},t.arrayRemove=function(e,t){for(var n=0;n<=e.length;n++)t===e[n]&&e.splice(n,1)},t.escapeRegExp=function(e){return e.replace(/([.*+?^${}()|[\]\/\\])/g,"\\$1")},t.escapeHTML=function(e){return e.replace(/&/g,"&#38;").replace(/"/g,"&#34;").replace(/'/g,"&#39;").replace(/</g,"&#60;")},t.getMatchOffsets=function(e,t){var n=[];return e.replace(t,function(e){n.push({offset:arguments[arguments.length-2],length:e.length})}),n},t.deferredCall=function(e){var t=null,n=function(){t=null,e()},r=function(e){return r.cancel(),t=setTimeout(n,e||0),r};return r.schedule=r,r.call=function(){return this.cancel(),e(),r},r.cancel=function(){return clearTimeout(t),t=null,r},r.isPending=function(){return t},r},t.delayedCall=function(e,t){var n=null,r=function(){n=null,e()},i=function(e){n==null&&(n=setTimeout(r,e||t))};return i.delay=function(e){n&&clearTimeout(n),n=setTimeout(r,e||t)},i.schedule=i,i.call=function(){this.cancel(),e()},i.cancel=function(){n&&clearTimeout(n),n=null},i.isPending=function(){return n},i}}),ace.define("ace/keyboard/textinput",["require","exports","module","ace/lib/event","ace/lib/useragent","ace/lib/dom","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../lib/event"),i=e("../lib/useragent"),s=e("../lib/dom"),o=e("../lib/lang"),u=i.isChrome<18,a=i.isIE,f=function(e,t){function b(e){if(h)return;h=!0;if(k)t=0,r=e?0:n.value.length-1;else var t=e?2:1,r=2;try{n.setSelectionRange(t,r)}catch(i){}h=!1}function w(){if(h)return;n.value=f,i.isWebKit&&y.schedule()}function R(){clearTimeout(q),q=setTimeout(function(){p&&(n.style.cssText=p,p=""),t.renderer.$keepTextAreaAtCursor==null&&(t.renderer.$keepTextAreaAtCursor=!0,t.renderer.$moveTextAreaToCursor())},i.isOldIE?200:0)}var n=s.createElement("textarea");n.className="ace_text-input",i.isTouchPad&&n.setAttribute("x-palm-disable-auto-cap",!0),n.setAttribute("wrap","off"),n.setAttribute("autocorrect","off"),n.setAttribute("autocapitalize","off"),n.setAttribute("spellcheck",!1),n.style.opacity="0",i.isOldIE&&(n.style.top="-1000px"),e.insertBefore(n,e.firstChild);var f="",l=!1,c=!1,h=!1,p="",d=!0;try{var v=document.activeElement===n}catch(m){}r.addListener(n,"blur",function(e){t.onBlur(e),v=!1}),r.addListener(n,"focus",function(e){v=!0,t.onFocus(e),b()}),this.focus=function(){if(p)return n.focus();var e=n.style.top;n.style.position="fixed",n.style.top="0px",n.focus(),setTimeout(function(){n.style.position="",n.style.top=="0px"&&(n.style.top=e)},0)},this.blur=function(){n.blur()},this.isFocused=function(){return v};var g=o.delayedCall(function(){v&&b(d)}),y=o.delayedCall(function(){h||(n.value=f,v&&b())});i.isWebKit||t.addEventListener("changeSelection",function(){t.selection.isEmpty()!=d&&(d=!d,g.schedule())}),w(),v&&t.onFocus();var E=function(e){return e.selectionStart===0&&e.selectionEnd===e.value.length};!n.setSelectionRange&&n.createTextRange&&(n.setSelectionRange=function(e,t){var n=this.createTextRange();n.collapse(!0),n.moveStart("character",e),n.moveEnd("character",t),n.select()},E=function(e){try{var t=e.ownerDocument.selection.createRange()}catch(n){}return!t||t.parentElement()!=e?!1:t.text==e.value});if(i.isOldIE){var S=!1,x=function(e){if(S)return;var t=n.value;if(h||!t||t==f)return;if(e&&t==f[0])return T.schedule();A(t),S=!0,w(),S=!1},T=o.delayedCall(x);r.addListener(n,"propertychange",x);var N={13:1,27:1};r.addListener(n,"keyup",function(e){h&&(!n.value||N[e.keyCode])&&setTimeout(F,0);if((n.value.charCodeAt(0)||0)<129)return T.call();h?j():B()}),r.addListener(n,"keydown",function(e){T.schedule(50)})}var C=function(e){l?l=!1:E(n)?(t.selectAll(),b()):k&&b(t.selection.isEmpty())},k=null;this.setInputHandler=function(e){k=e},this.getInputHandler=function(){return k};var L=!1,A=function(e){k&&(e=k(e),k=null),c?(b(),e&&t.onPaste(e),c=!1):e==f.charAt(0)?L?t.execCommand("del",{source:"ace"}):t.execCommand("backspace",{source:"ace"}):(e.substring(0,2)==f?e=e.substr(2):e.charAt(0)==f.charAt(0)?e=e.substr(1):e.charAt(e.length-1)==f.charAt(0)&&(e=e.slice(0,-1)),e.charAt(e.length-1)==f.charAt(0)&&(e=e.slice(0,-1)),e&&t.onTextInput(e)),L&&(L=!1)},O=function(e){if(h)return;var t=n.value;A(t),w()},M=function(e,t){var n=e.clipboardData||window.clipboardData;if(!n||u)return;var r=a?"Text":"text/plain";return t?n.setData(r,t)!==!1:n.getData(r)},_=function(e,i){var s=t.getCopyText();if(!s)return r.preventDefault(e);M(e,s)?(i?t.onCut():t.onCopy(),r.preventDefault(e)):(l=!0,n.value=s,n.select(),setTimeout(function(){l=!1,w(),b(),i?t.onCut():t.onCopy()}))},D=function(e){_(e,!0)},P=function(e){_(e,!1)},H=function(e){var s=M(e);typeof s=="string"?(s&&t.onPaste(s,e),i.isIE&&setTimeout(b),r.preventDefault(e)):(n.value="",c=!0)};r.addCommandKeyListener(n,t.onCommandKey.bind(t)),r.addListener(n,"select",C),r.addListener(n,"input",O),r.addListener(n,"cut",D),r.addListener(n,"copy",P),r.addListener(n,"paste",H),(!("oncut"in n)||!("oncopy"in n)||!("onpaste"in n))&&r.addListener(e,"keydown",function(e){if(i.isMac&&!e.metaKey||!e.ctrlKey)return;switch(e.keyCode){case 67:P(e);break;case 86:H(e);break;case 88:D(e)}});var B=function(e){if(h||!t.onCompositionStart||t.$readOnly)return;h={},t.onCompositionStart(),setTimeout(j,0),t.on("mousedown",F),t.selection.isEmpty()||(t.insert(""),t.session.markUndoGroup(),t.selection.clearSelection()),t.session.markUndoGroup()},j=function(){if(!h||!t.onCompositionUpdate||t.$readOnly)return;var e=n.value.replace(/\x01/g,"");if(h.lastValue===e)return;t.onCompositionUpdate(e),h.lastValue&&t.undo(),h.lastValue=e;if(h.lastValue){var r=t.selection.getRange();t.insert(h.lastValue),t.session.markUndoGroup(),h.range=t.selection.getRange(),t.selection.setRange(r),t.selection.clearSelection()}},F=function(e){if(!t.onCompositionEnd||t.$readOnly)return;var r=h;h=!1;var i=setTimeout(function(){i=null;var e=n.value.replace(/\x01/g,"");if(h)return;e==r.lastValue?w():!r.lastValue&&e&&(w(),A(e))});k=function(n){return i&&clearTimeout(i),n=n.replace(/\x01/g,""),n==r.lastValue?"":(r.lastValue&&i&&t.undo(),n)},t.onCompositionEnd(),t.removeListener("mousedown",F),e.type=="compositionend"&&r.range&&t.selection.setRange(r.range)},I=o.delayedCall(j,50);r.addListener(n,"compositionstart",B),i.isGecko?r.addListener(n,"text",function(){I.schedule()}):(r.addListener(n,"keyup",function(){I.schedule()}),r.addListener(n,"keydown",function(){I.schedule()})),r.addListener(n,"compositionend",F),this.getElement=function(){return n},this.setReadOnly=function(e){n.readOnly=e},this.onContextMenu=function(e){L=!0,b(t.selection.isEmpty()),t._emit("nativecontextmenu",{target:t,domEvent:e}),this.moveToMouse(e,!0)},this.moveToMouse=function(e,o){if(!o&&i.isOldIE)return;p||(p=n.style.cssText),n.style.cssText=(o?"z-index:100000;":"")+"height:"+n.style.height+";"+(i.isIE?"opacity:0.1;":"");var u=t.container.getBoundingClientRect(),a=s.computedStyle(t.container),f=u.top+(parseInt(a.borderTopWidth)||0),l=u.left+(parseInt(u.borderLeftWidth)||0),c=u.bottom-f-n.clientHeight-2,h=function(e){n.style.left=e.clientX-l-2+"px",n.style.top=Math.min(e.clientY-f-2,c)+"px"};h(e);if(e.type!="mousedown")return;t.renderer.$keepTextAreaAtCursor&&(t.renderer.$keepTextAreaAtCursor=null),clearTimeout(q),i.isWin&&!i.isOldIE&&r.capture(t.container,h,R)},this.onContextMenuClose=R;var q,U=function(e){t.textInput.onContextMenu(e),R()};r.addListener(n,"mouseup",U),r.addListener(n,"mousedown",function(e){e.preventDefault(),R()}),r.addListener(t.renderer.scroller,"contextmenu",U),r.addListener(n,"contextmenu",U)};t.TextInput=f}),ace.define("ace/mouse/default_handlers",["require","exports","module","ace/lib/dom","ace/lib/event","ace/lib/useragent"],function(e,t,n){"use strict";function u(e){e.$clickSelection=null;var t=e.editor;t.setDefaultHandler("mousedown",this.onMouseDown.bind(e)),t.setDefaultHandler("dblclick",this.onDoubleClick.bind(e)),t.setDefaultHandler("tripleclick",this.onTripleClick.bind(e)),t.setDefaultHandler("quadclick",this.onQuadClick.bind(e)),t.setDefaultHandler("mousewheel",this.onMouseWheel.bind(e)),t.setDefaultHandler("touchmove",this.onTouchMove.bind(e));var n=["select","startSelect","selectEnd","selectAllEnd","selectByWordsEnd","selectByLinesEnd","dragWait","dragWaitEnd","focusWait"];n.forEach(function(t){e[t]=this[t]},this),e.selectByLines=this.extendSelectionBy.bind(e,"getLineRange"),e.selectByWords=this.extendSelectionBy.bind(e,"getWordRange")}function a(e,t,n,r){return Math.sqrt(Math.pow(n-e,2)+Math.pow(r-t,2))}function f(e,t){if(e.start.row==e.end.row)var n=2*t.column-e.start.column-e.end.column;else if(e.start.row==e.end.row-1&&!e.start.column&&!e.end.column)var n=t.column-4;else var n=2*t.row-e.start.row-e.end.row;return n<0?{cursor:e.start,anchor:e.end}:{cursor:e.end,anchor:e.start}}var r=e("../lib/dom"),i=e("../lib/event"),s=e("../lib/useragent"),o=0;(function(){this.onMouseDown=function(e){var t=e.inSelection(),n=e.getDocumentPosition();this.mousedownEvent=e;var r=this.editor,i=e.getButton();if(i!==0){var s=r.getSelectionRange(),o=s.isEmpty();r.$blockScrolling++,(o||i==1)&&r.selection.moveToPosition(n),r.$blockScrolling--,i==2&&r.textInput.onContextMenu(e.domEvent);return}this.mousedownEvent.time=Date.now();if(t&&!r.isFocused()){r.focus();if(this.$focusTimout&&!this.$clickSelection&&!r.inMultiSelectMode){this.setState("focusWait"),this.captureMouse(e);return}}return this.captureMouse(e),this.startSelect(n,e.domEvent._clicks>1),e.preventDefault()},this.startSelect=function(e,t){e=e||this.editor.renderer.screenToTextCoordinates(this.x,this.y);var n=this.editor;n.$blockScrolling++,this.mousedownEvent.getShiftKey()?n.selection.selectToPosition(e):t||n.selection.moveToPosition(e),t||this.select(),n.renderer.scroller.setCapture&&n.renderer.scroller.setCapture(),n.setStyle("ace_selecting"),this.setState("select"),n.$blockScrolling--},this.select=function(){var e,t=this.editor,n=t.renderer.screenToTextCoordinates(this.x,this.y);t.$blockScrolling++;if(this.$clickSelection){var r=this.$clickSelection.comparePoint(n);if(r==-1)e=this.$clickSelection.end;else if(r==1)e=this.$clickSelection.start;else{var i=f(this.$clickSelection,n);n=i.cursor,e=i.anchor}t.selection.setSelectionAnchor(e.row,e.column)}t.selection.selectToPosition(n),t.$blockScrolling--,t.renderer.scrollCursorIntoView()},this.extendSelectionBy=function(e){var t,n=this.editor,r=n.renderer.screenToTextCoordinates(this.x,this.y),i=n.selection[e](r.row,r.column);n.$blockScrolling++;if(this.$clickSelection){var s=this.$clickSelection.comparePoint(i.start),o=this.$clickSelection.comparePoint(i.end);if(s==-1&&o<=0){t=this.$clickSelection.end;if(i.end.row!=r.row||i.end.column!=r.column)r=i.start}else if(o==1&&s>=0){t=this.$clickSelection.start;if(i.start.row!=r.row||i.start.column!=r.column)r=i.end}else if(s==-1&&o==1)r=i.end,t=i.start;else{var u=f(this.$clickSelection,r);r=u.cursor,t=u.anchor}n.selection.setSelectionAnchor(t.row,t.column)}n.selection.selectToPosition(r),n.$blockScrolling--,n.renderer.scrollCursorIntoView()},this.selectEnd=this.selectAllEnd=this.selectByWordsEnd=this.selectByLinesEnd=function(){this.$clickSelection=null,this.editor.unsetStyle("ace_selecting"),this.editor.renderer.scroller.releaseCapture&&this.editor.renderer.scroller.releaseCapture()},this.focusWait=function(){var e=a(this.mousedownEvent.x,this.mousedownEvent.y,this.x,this.y),t=Date.now();(e>o||t-this.mousedownEvent.time>this.$focusTimout)&&this.startSelect(this.mousedownEvent.getDocumentPosition())},this.onDoubleClick=function(e){var t=e.getDocumentPosition(),n=this.editor,r=n.session,i=r.getBracketRange(t);i?(i.isEmpty()&&(i.start.column--,i.end.column++),this.setState("select")):(i=n.selection.getWordRange(t.row,t.column),this.setState("selectByWords")),this.$clickSelection=i,this.select()},this.onTripleClick=function(e){var t=e.getDocumentPosition(),n=this.editor;this.setState("selectByLines");var r=n.getSelectionRange();r.isMultiLine()&&r.contains(t.row,t.column)?(this.$clickSelection=n.selection.getLineRange(r.start.row),this.$clickSelection.end=n.selection.getLineRange(r.end.row).end):this.$clickSelection=n.selection.getLineRange(t.row),this.select()},this.onQuadClick=function(e){var t=this.editor;t.selectAll(),this.$clickSelection=t.getSelectionRange(),this.setState("selectAll")},this.onMouseWheel=function(e){if(e.getAccelKey())return;e.getShiftKey()&&e.wheelY&&!e.wheelX&&(e.wheelX=e.wheelY,e.wheelY=0);var t=e.domEvent.timeStamp,n=t-(this.$lastScrollTime||0),r=this.editor,i=r.renderer.isScrollableBy(e.wheelX*e.speed,e.wheelY*e.speed);if(i||n<200)return this.$lastScrollTime=t,r.renderer.scrollBy(e.wheelX*e.speed,e.wheelY*e.speed),e.stop()},this.onTouchMove=function(e){var t=e.domEvent.timeStamp,n=t-(this.$lastScrollTime||0),r=this.editor,i=r.renderer.isScrollableBy(e.wheelX*e.speed,e.wheelY*e.speed);if(i||n<200)return this.$lastScrollTime=t,r.renderer.scrollBy(e.wheelX*e.speed,e.wheelY*e.speed),e.stop()}}).call(u.prototype),t.DefaultHandlers=u}),ace.define("ace/tooltip",["require","exports","module","ace/lib/oop","ace/lib/dom"],function(e,t,n){"use strict";function s(e){this.isOpen=!1,this.$element=null,this.$parentNode=e}var r=e("./lib/oop"),i=e("./lib/dom");(function(){this.$init=function(){return this.$element=i.createElement("div"),this.$element.className="ace_tooltip",this.$element.style.display="none",this.$parentNode.appendChild(this.$element),this.$element},this.getElement=function(){return this.$element||this.$init()},this.setText=function(e){i.setInnerText(this.getElement(),e)},this.setHtml=function(e){this.getElement().innerHTML=e},this.setPosition=function(e,t){this.getElement().style.left=e+"px",this.getElement().style.top=t+"px"},this.setClassName=function(e){i.addCssClass(this.getElement(),e)},this.show=function(e,t,n){e!=null&&this.setText(e),t!=null&&n!=null&&this.setPosition(t,n),this.isOpen||(this.getElement().style.display="block",this.isOpen=!0)},this.hide=function(){this.isOpen&&(this.getElement().style.display="none",this.isOpen=!1)},this.getHeight=function(){return this.getElement().offsetHeight},this.getWidth=function(){return this.getElement().offsetWidth}}).call(s.prototype),t.Tooltip=s}),ace.define("ace/mouse/default_gutter_handler",["require","exports","module","ace/lib/dom","ace/lib/oop","ace/lib/event","ace/tooltip"],function(e,t,n){"use strict";function u(e){function l(){var r=u.getDocumentPosition().row,s=n.$annotations[r];if(!s)return c();var o=t.session.getLength();if(r==o){var a=t.renderer.pixelToScreenCoordinates(0,u.y).row,l=u.$pos;if(a>t.session.documentToScreenRow(l.row,l.column))return c()}if(f==s)return;f=s.text.join("<br/>"),i.setHtml(f),i.show(),t.on("mousewheel",c);if(e.$tooltipFollowsMouse)h(u);else{var p=u.domEvent.target,d=p.getBoundingClientRect(),v=i.getElement().style;v.left=d.right+"px",v.top=d.bottom+"px"}}function c(){o&&(o=clearTimeout(o)),f&&(i.hide(),f=null,t.removeEventListener("mousewheel",c))}function h(e){i.setPosition(e.x,e.y)}var t=e.editor,n=t.renderer.$gutterLayer,i=new a(t.container);e.editor.setDefaultHandler("guttermousedown",function(r){if(!t.isFocused()||r.getButton()!=0)return;var i=n.getRegion(r);if(i=="foldWidgets")return;var s=r.getDocumentPosition().row,o=t.session.selection;if(r.getShiftKey())o.selectTo(s,0);else{if(r.domEvent.detail==2)return t.selectAll(),r.preventDefault();e.$clickSelection=t.selection.getLineRange(s)}return e.setState("selectByLines"),e.captureMouse(r),r.preventDefault()});var o,u,f;e.editor.setDefaultHandler("guttermousemove",function(t){var n=t.domEvent.target||t.domEvent.srcElement;if(r.hasCssClass(n,"ace_fold-widget"))return c();f&&e.$tooltipFollowsMouse&&h(t),u=t;if(o)return;o=setTimeout(function(){o=null,u&&!e.isMousePressed?l():c()},50)}),s.addListener(t.renderer.$gutter,"mouseout",function(e){u=null;if(!f||o)return;o=setTimeout(function(){o=null,c()},50)}),t.on("changeSession",c)}function a(e){o.call(this,e)}var r=e("../lib/dom"),i=e("../lib/oop"),s=e("../lib/event"),o=e("../tooltip").Tooltip;i.inherits(a,o),function(){this.setPosition=function(e,t){var n=window.innerWidth||document.documentElement.clientWidth,r=window.innerHeight||document.documentElement.clientHeight,i=this.getWidth(),s=this.getHeight();e+=15,t+=15,e+i>n&&(e-=e+i-n),t+s>r&&(t-=20+s),o.prototype.setPosition.call(this,e,t)}}.call(a.prototype),t.GutterHandler=u}),ace.define("ace/mouse/mouse_event",["require","exports","module","ace/lib/event","ace/lib/useragent"],function(e,t,n){"use strict";var r=e("../lib/event"),i=e("../lib/useragent"),s=t.MouseEvent=function(e,t){this.domEvent=e,this.editor=t,this.x=this.clientX=e.clientX,this.y=this.clientY=e.clientY,this.$pos=null,this.$inSelection=null,this.propagationStopped=!1,this.defaultPrevented=!1};(function(){this.stopPropagation=function(){r.stopPropagation(this.domEvent),this.propagationStopped=!0},this.preventDefault=function(){r.preventDefault(this.domEvent),this.defaultPrevented=!0},this.stop=function(){this.stopPropagation(),this.preventDefault()},this.getDocumentPosition=function(){return this.$pos?this.$pos:(this.$pos=this.editor.renderer.screenToTextCoordinates(this.clientX,this.clientY),this.$pos)},this.inSelection=function(){if(this.$inSelection!==null)return this.$inSelection;var e=this.editor,t=e.getSelectionRange();if(t.isEmpty())this.$inSelection=!1;else{var n=this.getDocumentPosition();this.$inSelection=t.contains(n.row,n.column)}return this.$inSelection},this.getButton=function(){return r.getButton(this.domEvent)},this.getShiftKey=function(){return this.domEvent.shiftKey},this.getAccelKey=i.isMac?function(){return this.domEvent.metaKey}:function(){return this.domEvent.ctrlKey}}).call(s.prototype)}),ace.define("ace/mouse/dragdrop_handler",["require","exports","module","ace/lib/dom","ace/lib/event","ace/lib/useragent"],function(e,t,n){"use strict";function f(e){function T(e,n){var r=Date.now(),i=!n||e.row!=n.row,s=!n||e.column!=n.column;if(!S||i||s)t.$blockScrolling+=1,t.moveCursorToPosition(e),t.$blockScrolling-=1,S=r,x={x:p,y:d};else{var o=l(x.x,x.y,p,d);o>a?S=null:r-S>=u&&(t.renderer.scrollCursorIntoView(),S=null)}}function N(e,n){var r=Date.now(),i=t.renderer.layerConfig.lineHeight,s=t.renderer.layerConfig.characterWidth,u=t.renderer.scroller.getBoundingClientRect(),a={x:{left:p-u.left,right:u.right-p},y:{top:d-u.top,bottom:u.bottom-d}},f=Math.min(a.x.left,a.x.right),l=Math.min(a.y.top,a.y.bottom),c={row:e.row,column:e.column};f/s<=2&&(c.column+=a.x.left<a.x.right?-3:2),l/i<=1&&(c.row+=a.y.top<a.y.bottom?-1:1);var h=e.row!=c.row,v=e.column!=c.column,m=!n||e.row!=n.row;h||v&&!m?E?r-E>=o&&t.renderer.scrollCursorIntoView(c):E=r:E=null}function C(){var e=g;g=t.renderer.screenToTextCoordinates(p,d),T(g,e),N(g,e)}function k(){m=t.selection.toOrientedRange(),h=t.session.addMarker(m,"ace_selection",t.getSelectionStyle()),t.clearSelection(),t.isFocused()&&t.renderer.$cursorLayer.setBlinking(!1),clearInterval(v),C(),v=setInterval(C,20),y=0,i.addListener(document,"mousemove",O)}function L(){clearInterval(v),t.session.removeMarker(h),h=null,t.$blockScrolling+=1,t.selection.fromOrientedRange(m),t.$blockScrolling-=1,t.isFocused()&&!w&&t.renderer.$cursorLayer.setBlinking(!t.getReadOnly()),m=null,g=null,y=0,E=null,S=null,i.removeListener(document,"mousemove",O)}function O(){A==null&&(A=setTimeout(function(){A!=null&&h&&L()},20))}function M(e){var t=e.types;return!t||Array.prototype.some.call(t,function(e){return e=="text/plain"||e=="Text"})}function _(e){var t=["copy","copymove","all","uninitialized"],n=["move","copymove","linkmove","all","uninitialized"],r=s.isMac?e.altKey:e.ctrlKey,i="uninitialized";try{i=e.dataTransfer.effectAllowed.toLowerCase()}catch(e){}var o="none";return r&&t.indexOf(i)>=0?o="copy":n.indexOf(i)>=0?o="move":t.indexOf(i)>=0&&(o="copy"),o}var t=e.editor,n=r.createElement("img");n.src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",s.isOpera&&(n.style.cssText="width:1px;height:1px;position:fixed;top:0;left:0;z-index:2147483647;opacity:0;");var f=["dragWait","dragWaitEnd","startDrag","dragReadyEnd","onMouseDrag"];f.forEach(function(t){e[t]=this[t]},this),t.addEventListener("mousedown",this.onMouseDown.bind(e));var c=t.container,h,p,d,v,m,g,y=0,b,w,E,S,x;this.onDragStart=function(e){if(this.cancelDrag||!c.draggable){var r=this;return setTimeout(function(){r.startSelect(),r.captureMouse(e)},0),e.preventDefault()}m=t.getSelectionRange();var i=e.dataTransfer;i.effectAllowed=t.getReadOnly()?"copy":"copyMove",s.isOpera&&(t.container.appendChild(n),n.scrollTop=0),i.setDragImage&&i.setDragImage(n,0,0),s.isOpera&&t.container.removeChild(n),i.clearData(),i.setData("Text",t.session.getTextRange()),w=!0,this.setState("drag")},this.onDragEnd=function(e){c.draggable=!1,w=!1,this.setState(null);if(!t.getReadOnly()){var n=e.dataTransfer.dropEffect;!b&&n=="move"&&t.session.remove(t.getSelectionRange()),t.renderer.$cursorLayer.setBlinking(!0)}this.editor.unsetStyle("ace_dragging"),this.editor.renderer.setCursorStyle("")},this.onDragEnter=function(e){if(t.getReadOnly()||!M(e.dataTransfer))return;return p=e.clientX,d=e.clientY,h||k(),y++,e.dataTransfer.dropEffect=b=_(e),i.preventDefault(e)},this.onDragOver=function(e){if(t.getReadOnly()||!M(e.dataTransfer))return;return p=e.clientX,d=e.clientY,h||(k(),y++),A!==null&&(A=null),e.dataTransfer.dropEffect=b=_(e),i.preventDefault(e)},this.onDragLeave=function(e){y--;if(y<=0&&h)return L(),b=null,i.preventDefault(e)},this.onDrop=function(e){if(!g)return;var n=e.dataTransfer;if(w)switch(b){case"move":m.contains(g.row,g.column)?m={start:g,end:g}:m=t.moveText(m,g);break;case"copy":m=t.moveText(m,g,!0)}else{var r=n.getData("Text");m={start:g,end:t.session.insert(g,r)},t.focus(),b=null}return L(),i.preventDefault(e)},i.addListener(c,"dragstart",this.onDragStart.bind(e)),i.addListener(c,"dragend",this.onDragEnd.bind(e)),i.addListener(c,"dragenter",this.onDragEnter.bind(e)),i.addListener(c,"dragover",this.onDragOver.bind(e)),i.addListener(c,"dragleave",this.onDragLeave.bind(e)),i.addListener(c,"drop",this.onDrop.bind(e));var A=null}function l(e,t,n,r){return Math.sqrt(Math.pow(n-e,2)+Math.pow(r-t,2))}var r=e("../lib/dom"),i=e("../lib/event"),s=e("../lib/useragent"),o=200,u=200,a=5;(function(){this.dragWait=function(){var e=Date.now()-this.mousedownEvent.time;e>this.editor.getDragDelay()&&this.startDrag()},this.dragWaitEnd=function(){var e=this.editor.container;e.draggable=!1,this.startSelect(this.mousedownEvent.getDocumentPosition()),this.selectEnd()},this.dragReadyEnd=function(e){this.editor.renderer.$cursorLayer.setBlinking(!this.editor.getReadOnly()),this.editor.unsetStyle("ace_dragging"),this.editor.renderer.setCursorStyle(""),this.dragWaitEnd()},this.startDrag=function(){this.cancelDrag=!1;var e=this.editor,t=e.container;t.draggable=!0,e.renderer.$cursorLayer.setBlinking(!1),e.setStyle("ace_dragging");var n=s.isWin?"default":"move";e.renderer.setCursorStyle(n),this.setState("dragReady")},this.onMouseDrag=function(e){var t=this.editor.container;if(s.isIE&&this.state=="dragReady"){var n=l(this.mousedownEvent.x,this.mousedownEvent.y,this.x,this.y);n>3&&t.dragDrop()}if(this.state==="dragWait"){var n=l(this.mousedownEvent.x,this.mousedownEvent.y,this.x,this.y);n>0&&(t.draggable=!1,this.startSelect(this.mousedownEvent.getDocumentPosition()))}},this.onMouseDown=function(e){if(!this.$dragEnabled)return;this.mousedownEvent=e;var t=this.editor,n=e.inSelection(),r=e.getButton(),i=e.domEvent.detail||1;if(i===1&&r===0&&n){if(e.editor.inMultiSelectMode&&(e.getAccelKey()||e.getShiftKey()))return;this.mousedownEvent.time=Date.now();var o=e.domEvent.target||e.domEvent.srcElement;"unselectable"in o&&(o.unselectable="on");if(t.getDragDelay()){if(s.isWebKit){this.cancelDrag=!0;var u=t.container;u.draggable=!0}this.setState("dragWait")}else this.startDrag();this.captureMouse(e,this.onMouseDrag.bind(this)),e.defaultPrevented=!0}}}).call(f.prototype),t.DragdropHandler=f}),ace.define("ace/lib/net",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";var r=e("./dom");t.get=function(e,t){var n=new XMLHttpRequest;n.open("GET",e,!0),n.onreadystatechange=function(){n.readyState===4&&t(n.responseText)},n.send(null)},t.loadScript=function(e,t){var n=r.getDocumentHead(),i=document.createElement("script");i.src=e,n.appendChild(i),i.onload=i.onreadystatechange=function(e,n){if(n||!i.readyState||i.readyState=="loaded"||i.readyState=="complete")i=i.onload=i.onreadystatechange=null,n||t()}},t.qualifyURL=function(e){var t=document.createElement("a");return t.href=e,t.href}}),ace.define("ace/lib/event_emitter",["require","exports","module"],function(e,t,n){"use strict";var r={},i=function(){this.propagationStopped=!0},s=function(){this.defaultPrevented=!0};r._emit=r._dispatchEvent=function(e,t){this._eventRegistry||(this._eventRegistry={}),this._defaultHandlers||(this._defaultHandlers={});var n=this._eventRegistry[e]||[],r=this._defaultHandlers[e];if(!n.length&&!r)return;if(typeof t!="object"||!t)t={};t.type||(t.type=e),t.stopPropagation||(t.stopPropagation=i),t.preventDefault||(t.preventDefault=s),n=n.slice();for(var o=0;o<n.length;o++){n[o](t,this);if(t.propagationStopped)break}if(r&&!t.defaultPrevented)return r(t,this)},r._signal=function(e,t){var n=(this._eventRegistry||{})[e];if(!n)return;n=n.slice();for(var r=0;r<n.length;r++)n[r](t,this)},r.once=function(e,t){var n=this;t&&this.addEventListener(e,function r(){n.removeEventListener(e,r),t.apply(null,arguments)})},r.setDefaultHandler=function(e,t){var n=this._defaultHandlers;n||(n=this._defaultHandlers={_disabled_:{}});if(n[e]){var r=n[e],i=n._disabled_[e];i||(n._disabled_[e]=i=[]),i.push(r);var s=i.indexOf(t);s!=-1&&i.splice(s,1)}n[e]=t},r.removeDefaultHandler=function(e,t){var n=this._defaultHandlers;if(!n)return;var r=n._disabled_[e];if(n[e]==t){var i=n[e];r&&this.setDefaultHandler(e,r.pop())}else if(r){var s=r.indexOf(t);s!=-1&&r.splice(s,1)}},r.on=r.addEventListener=function(e,t,n){this._eventRegistry=this._eventRegistry||{};var r=this._eventRegistry[e];return r||(r=this._eventRegistry[e]=[]),r.indexOf(t)==-1&&r[n?"unshift":"push"](t),t},r.off=r.removeListener=r.removeEventListener=function(e,t){this._eventRegistry=this._eventRegistry||{};var n=this._eventRegistry[e];if(!n)return;var r=n.indexOf(t);r!==-1&&n.splice(r,1)},r.removeAllListeners=function(e){this._eventRegistry&&(this._eventRegistry[e]=[])},t.EventEmitter=r}),ace.define("ace/lib/app_config",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"],function(e,t,n){"no use strict";function o(e){typeof console!="undefined"&&console.warn&&console.warn.apply(console,arguments)}function u(e,t){var n=new Error(e);n.data=t,typeof console=="object"&&console.error&&console.error(n),setTimeout(function(){throw n})}var r=e("./oop"),i=e("./event_emitter").EventEmitter,s={setOptions:function(e){Object.keys(e).forEach(function(t){this.setOption(t,e[t])},this)},getOptions:function(e){var t={};return e?Array.isArray(e)||(t=e,e=Object.keys(t)):e=Object.keys(this.$options),e.forEach(function(e){t[e]=this.getOption(e)},this),t},setOption:function(e,t){if(this["$"+e]===t)return;var n=this.$options[e];if(!n)return o('misspelled option "'+e+'"');if(n.forwardTo)return this[n.forwardTo]&&this[n.forwardTo].setOption(e,t);n.handlesSet||(this["$"+e]=t),n&&n.set&&n.set.call(this,t)},getOption:function(e){var t=this.$options[e];return t?t.forwardTo?this[t.forwardTo]&&this[t.forwardTo].getOption(e):t&&t.get?t.get.call(this):this["$"+e]:o('misspelled option "'+e+'"')}},a=function(){this.$defaultOptions={}};(function(){r.implement(this,i),this.defineOptions=function(e,t,n){return e.$options||(this.$defaultOptions[t]=e.$options={}),Object.keys(n).forEach(function(t){var r=n[t];typeof r=="string"&&(r={forwardTo:r}),r.name||(r.name=t),e.$options[r.name]=r,"initialValue"in r&&(e["$"+r.name]=r.initialValue)}),r.implement(e,s),this},this.resetOptions=function(e){Object.keys(e.$options).forEach(function(t){var n=e.$options[t];"value"in n&&e.setOption(t,n.value)})},this.setDefaultValue=function(e,t,n){var r=this.$defaultOptions[e]||(this.$defaultOptions[e]={});r[t]&&(r.forwardTo?this.setDefaultValue(r.forwardTo,t,n):r[t].value=n)},this.setDefaultValues=function(e,t){Object.keys(t).forEach(function(n){this.setDefaultValue(e,n,t[n])},this)},this.warn=o,this.reportError=u}).call(a.prototype),t.AppConfig=a}),ace.define("ace/config",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/lib/net","ace/lib/app_config"],function(e,t,n){"no use strict";function f(r){if(!u||!u.document)return;a.packaged=r||e.packaged||n.packaged||u.define&&define.packaged;var i={},s="",o=document.currentScript||document._currentScript,f=o&&o.ownerDocument||document,c=f.getElementsByTagName("script");for(var h=0;h<c.length;h++){var p=c[h],d=p.src||p.getAttribute("src");if(!d)continue;var v=p.attributes;for(var m=0,g=v.length;m<g;m++){var y=v[m];y.name.indexOf("data-ace-")===0&&(i[l(y.name.replace(/^data-ace-/,""))]=y.value)}var b=d.match(/^(.*)\/ace(\-\w+)?\.js(\?|$)/);b&&(s=b[1])}s&&(i.base=i.base||s,i.packaged=!0),i.basePath=i.base,i.workerPath=i.workerPath||i.base,i.modePath=i.modePath||i.base,i.themePath=i.themePath||i.base,delete i.base;for(var w in i)typeof i[w]!="undefined"&&t.set(w,i[w])}function l(e){return e.replace(/-(.)/g,function(e,t){return t.toUpperCase()})}var r=e("./lib/lang"),i=e("./lib/oop"),s=e("./lib/net"),o=e("./lib/app_config").AppConfig;n.exports=t=new o;var u=function(){return this||typeof window!="undefined"&&window}(),a={packaged:!1,workerPath:null,modePath:null,themePath:null,basePath:"",suffix:".js",$moduleUrls:{}};t.get=function(e){if(!a.hasOwnProperty(e))throw new Error("Unknown config key: "+e);return a[e]},t.set=function(e,t){if(!a.hasOwnProperty(e))throw new Error("Unknown config key: "+e);a[e]=t},t.all=function(){return r.copyObject(a)},t.moduleUrl=function(e,t){if(a.$moduleUrls[e])return a.$moduleUrls[e];var n=e.split("/");t=t||n[n.length-2]||"";var r=t=="snippets"?"/":"-",i=n[n.length-1];if(t=="worker"&&r=="-"){var s=new RegExp("^"+t+"[\\-_]|[\\-_]"+t+"$","g");i=i.replace(s,"")}(!i||i==t)&&n.length>1&&(i=n[n.length-2]);var o=a[t+"Path"];return o==null?o=a.basePath:r=="/"&&(t=r=""),o&&o.slice(-1)!="/"&&(o+="/"),o+t+r+i+this.get("suffix")},t.setModuleUrl=function(e,t){return a.$moduleUrls[e]=t},t.$loading={},t.loadModule=function(n,r){var i,o;Array.isArray(n)&&(o=n[0],n=n[1]);try{i=e(n)}catch(u){}if(i&&!t.$loading[n])return r&&r(i);t.$loading[n]||(t.$loading[n]=[]),t.$loading[n].push(r);if(t.$loading[n].length>1)return;var a=function(){e([n],function(e){t._emit("load.module",{name:n,module:e});var r=t.$loading[n];t.$loading[n]=null,r.forEach(function(t){t&&t(e)})})};if(!t.get("packaged"))return a();s.loadScript(t.moduleUrl(n,o),a)},t.init=f}),ace.define("ace/mouse/mouse_handler",["require","exports","module","ace/lib/event","ace/lib/useragent","ace/mouse/default_handlers","ace/mouse/default_gutter_handler","ace/mouse/mouse_event","ace/mouse/dragdrop_handler","ace/config"],function(e,t,n){"use strict";var r=e("../lib/event"),i=e("../lib/useragent"),s=e("./default_handlers").DefaultHandlers,o=e("./default_gutter_handler").GutterHandler,u=e("./mouse_event").MouseEvent,a=e("./dragdrop_handler").DragdropHandler,f=e("../config"),l=function(e){var t=this;this.editor=e,new s(this),new o(this),new a(this);var n=function(t){var n=!document.hasFocus||!document.hasFocus()||!e.isFocused()&&document.activeElement==(e.textInput&&e.textInput.getElement());n&&window.focus(),e.focus()},u=e.renderer.getMouseEventTarget();r.addListener(u,"click",this.onMouseEvent.bind(this,"click")),r.addListener(u,"mousemove",this.onMouseMove.bind(this,"mousemove")),r.addMultiMouseDownListener([u,e.renderer.scrollBarV&&e.renderer.scrollBarV.inner,e.renderer.scrollBarH&&e.renderer.scrollBarH.inner,e.textInput&&e.textInput.getElement()].filter(Boolean),[400,300,250],this,"onMouseEvent"),r.addMouseWheelListener(e.container,this.onMouseWheel.bind(this,"mousewheel")),r.addTouchMoveListener(e.container,this.onTouchMove.bind(this,"touchmove"));var f=e.renderer.$gutter;r.addListener(f,"mousedown",this.onMouseEvent.bind(this,"guttermousedown")),r.addListener(f,"click",this.onMouseEvent.bind(this,"gutterclick")),r.addListener(f,"dblclick",this.onMouseEvent.bind(this,"gutterdblclick")),r.addListener(f,"mousemove",this.onMouseEvent.bind(this,"guttermousemove")),r.addListener(u,"mousedown",n),r.addListener(f,"mousedown",n),i.isIE&&e.renderer.scrollBarV&&(r.addListener(e.renderer.scrollBarV.element,"mousedown",n),r.addListener(e.renderer.scrollBarH.element,"mousedown",n)),e.on("mousemove",function(n){if(t.state||t.$dragDelay||!t.$dragEnabled)return;var r=e.renderer.screenToTextCoordinates(n.x,n.y),i=e.session.selection.getRange(),s=e.renderer;!i.isEmpty()&&i.insideStart(r.row,r.column)?s.setCursorStyle("default"):s.setCursorStyle("")})};(function(){this.onMouseEvent=function(e,t){this.editor._emit(e,new u(t,this.editor))},this.onMouseMove=function(e,t){var n=this.editor._eventRegistry&&this.editor._eventRegistry.mousemove;if(!n||!n.length)return;this.editor._emit(e,new u(t,this.editor))},this.onMouseWheel=function(e,t){var n=new u(t,this.editor);n.speed=this.$scrollSpeed*2,n.wheelX=t.wheelX,n.wheelY=t.wheelY,this.editor._emit(e,n)},this.onTouchMove=function(e,t){var n=new u(t,this.editor);n.speed=1,n.wheelX=t.wheelX,n.wheelY=t.wheelY,this.editor._emit(e,n)},this.setState=function(e){this.state=e},this.captureMouse=function(e,t){this.x=e.x,this.y=e.y,this.isMousePressed=!0;var n=this.editor.renderer;n.$keepTextAreaAtCursor&&(n.$keepTextAreaAtCursor=null);var s=this,o=function(e){if(!e)return;if(i.isWebKit&&!e.which&&s.releaseMouse)return s.releaseMouse();s.x=e.clientX,s.y=e.clientY,t&&t(e),s.mouseEvent=new u(e,s.editor),s.$mouseMoved=!0},a=function(e){clearInterval(l),f(),s[s.state+"End"]&&s[s.state+"End"](e),s.state="",n.$keepTextAreaAtCursor==null&&(n.$keepTextAreaAtCursor=!0,n.$moveTextAreaToCursor()),s.isMousePressed=!1,s.$onCaptureMouseMove=s.releaseMouse=null,e&&s.onMouseEvent("mouseup",e)},f=function(){s[s.state]&&s[s.state](),s.$mouseMoved=!1};if(i.isOldIE&&e.domEvent.type=="dblclick")return setTimeout(function(){a(e)});s.$onCaptureMouseMove=o,s.releaseMouse=r.capture(this.editor.container,o,a);var l=setInterval(f,20)},this.releaseMouse=null,this.cancelContextMenu=function(){var e=function(t){if(t&&t.domEvent&&t.domEvent.type!="contextmenu")return;this.editor.off("nativecontextmenu",e),t&&t.domEvent&&r.stopEvent(t.domEvent)}.bind(this);setTimeout(e,10),this.editor.on("nativecontextmenu",e)}}).call(l.prototype),f.defineOptions(l.prototype,"mouseHandler",{scrollSpeed:{initialValue:2},dragDelay:{initialValue:i.isMac?150:0},dragEnabled:{initialValue:!0},focusTimout:{initialValue:0},tooltipFollowsMouse:{initialValue:!0}}),t.MouseHandler=l}),ace.define("ace/mouse/fold_handler",["require","exports","module"],function(e,t,n){"use strict";function r(e){e.on("click",function(t){var n=t.getDocumentPosition(),r=e.session,i=r.getFoldAt(n.row,n.column,1);i&&(t.getAccelKey()?r.removeFold(i):r.expandFold(i),t.stop())}),e.on("gutterclick",function(t){var n=e.renderer.$gutterLayer.getRegion(t);if(n=="foldWidgets"){var r=t.getDocumentPosition().row,i=e.session;i.foldWidgets&&i.foldWidgets[r]&&e.session.onFoldWidgetClick(r,t),e.isFocused()||e.focus(),t.stop()}}),e.on("gutterdblclick",function(t){var n=e.renderer.$gutterLayer.getRegion(t);if(n=="foldWidgets"){var r=t.getDocumentPosition().row,i=e.session,s=i.getParentFoldRangeData(r,!0),o=s.range||s.firstRange;if(o){r=o.start.row;var u=i.getFoldAt(r,i.getLine(r).length,1);u?i.removeFold(u):(i.addFold("...",o),e.renderer.scrollCursorIntoView({row:o.start.row,column:0}))}t.stop()}})}t.FoldHandler=r}),ace.define("ace/keyboard/keybinding",["require","exports","module","ace/lib/keys","ace/lib/event"],function(e,t,n){"use strict";var r=e("../lib/keys"),i=e("../lib/event"),s=function(e){this.$editor=e,this.$data={editor:e},this.$handlers=[],this.setDefaultHandler(e.commands)};(function(){this.setDefaultHandler=function(e){this.removeKeyboardHandler(this.$defaultHandler),this.$defaultHandler=e,this.addKeyboardHandler(e,0)},this.setKeyboardHandler=function(e){var t=this.$handlers;if(t[t.length-1]==e)return;while(t[t.length-1]&&t[t.length-1]!=this.$defaultHandler)this.removeKeyboardHandler(t[t.length-1]);this.addKeyboardHandler(e,1)},this.addKeyboardHandler=function(e,t){if(!e)return;typeof e=="function"&&!e.handleKeyboard&&(e.handleKeyboard=e);var n=this.$handlers.indexOf(e);n!=-1&&this.$handlers.splice(n,1),t==undefined?this.$handlers.push(e):this.$handlers.splice(t,0,e),n==-1&&e.attach&&e.attach(this.$editor)},this.removeKeyboardHandler=function(e){var t=this.$handlers.indexOf(e);return t==-1?!1:(this.$handlers.splice(t,1),e.detach&&e.detach(this.$editor),!0)},this.getKeyboardHandler=function(){return this.$handlers[this.$handlers.length-1]},this.getStatusText=function(){var e=this.$data,t=e.editor;return this.$handlers.map(function(n){return n.getStatusText&&n.getStatusText(t,e)||""}).filter(Boolean).join(" ")},this.$callKeyboardHandlers=function(e,t,n,r){var s,o=!1,u=this.$editor.commands;for(var a=this.$handlers.length;a--;){s=this.$handlers[a].handleKeyboard(this.$data,e,t,n,r);if(!s||!s.command)continue;s.command=="null"?o=!0:o=u.exec(s.command,this.$editor,s.args,r),o&&r&&e!=-1&&s.passEvent!=1&&s.command.passEvent!=1&&i.stopEvent(r);if(o)break}return!o&&e==-1&&(s={command:"insertstring"},o=u.exec("insertstring",this.$editor,t)),o&&this.$editor._signal("keyboardActivity",s),o},this.onCommandKey=function(e,t,n){var i=r.keyCodeToString(n);this.$callKeyboardHandlers(t,i,n,e)},this.onTextInput=function(e){this.$callKeyboardHandlers(-1,e)}}).call(s.prototype),t.KeyBinding=s}),ace.define("ace/range",["require","exports","module"],function(e,t,n){"use strict";var r=function(e,t){return e.row-t.row||e.column-t.column},i=function(e,t,n,r){this.start={row:e,column:t},this.end={row:n,column:r}};(function(){this.isEqual=function(e){return this.start.row===e.start.row&&this.end.row===e.end.row&&this.start.column===e.start.column&&this.end.column===e.end.column},this.toString=function(){return"Range: ["+this.start.row+"/"+this.start.column+"] -> ["+this.end.row+"/"+this.end.column+"]"},this.contains=function(e,t){return this.compare(e,t)==0},this.compareRange=function(e){var t,n=e.end,r=e.start;return t=this.compare(n.row,n.column),t==1?(t=this.compare(r.row,r.column),t==1?2:t==0?1:0):t==-1?-2:(t=this.compare(r.row,r.column),t==-1?-1:t==1?42:0)},this.comparePoint=function(e){return this.compare(e.row,e.column)},this.containsRange=function(e){return this.comparePoint(e.start)==0&&this.comparePoint(e.end)==0},this.intersects=function(e){var t=this.compareRange(e);return t==-1||t==0||t==1},this.isEnd=function(e,t){return this.end.row==e&&this.end.column==t},this.isStart=function(e,t){return this.start.row==e&&this.start.column==t},this.setStart=function(e,t){typeof e=="object"?(this.start.column=e.column,this.start.row=e.row):(this.start.row=e,this.start.column=t)},this.setEnd=function(e,t){typeof e=="object"?(this.end.column=e.column,this.end.row=e.row):(this.end.row=e,this.end.column=t)},this.inside=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)||this.isStart(e,t)?!1:!0:!1},this.insideStart=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)?!1:!0:!1},this.insideEnd=function(e,t){return this.compare(e,t)==0?this.isStart(e,t)?!1:!0:!1},this.compare=function(e,t){return!this.isMultiLine()&&e===this.start.row?t<this.start.column?-1:t>this.end.column?1:0:e<this.start.row?-1:e>this.end.row?1:this.start.row===e?t>=this.start.column?0:-1:this.end.row===e?t<=this.end.column?0:1:0},this.compareStart=function(e,t){return this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.compareEnd=function(e,t){return this.end.row==e&&this.end.column==t?1:this.compare(e,t)},this.compareInside=function(e,t){return this.end.row==e&&this.end.column==t?1:this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.clipRows=function(e,t){if(this.end.row>t)var n={row:t+1,column:0};else if(this.end.row<e)var n={row:e,column:0};if(this.start.row>t)var r={row:t+1,column:0};else if(this.start.row<e)var r={row:e,column:0};return i.fromPoints(r||this.start,n||this.end)},this.extend=function(e,t){var n=this.compare(e,t);if(n==0)return this;if(n==-1)var r={row:e,column:t};else var s={row:e,column:t};return i.fromPoints(r||this.start,s||this.end)},this.isEmpty=function(){return this.start.row===this.end.row&&this.start.column===this.end.column},this.isMultiLine=function(){return this.start.row!==this.end.row},this.clone=function(){return i.fromPoints(this.start,this.end)},this.collapseRows=function(){return this.end.column==0?new i(this.start.row,0,Math.max(this.start.row,this.end.row-1),0):new i(this.start.row,0,this.end.row,0)},this.toScreenRange=function(e){var t=e.documentToScreenPosition(this.start),n=e.documentToScreenPosition(this.end);return new i(t.row,t.column,n.row,n.column)},this.moveBy=function(e,t){this.start.row+=e,this.start.column+=t,this.end.row+=e,this.end.column+=t}}).call(i.prototype),i.fromPoints=function(e,t){return new i(e.row,e.column,t.row,t.column)},i.comparePoints=r,i.comparePoints=function(e,t){return e.row-t.row||e.column-t.column},t.Range=i}),ace.define("ace/selection",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter","ace/range"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/lang"),s=e("./lib/event_emitter").EventEmitter,o=e("./range").Range,u=function(e){this.session=e,this.doc=e.getDocument(),this.clearSelection(),this.lead=this.selectionLead=this.doc.createAnchor(0,0),this.anchor=this.selectionAnchor=this.doc.createAnchor(0,0);var t=this;this.lead.on("change",function(e){t._emit("changeCursor"),t.$isEmpty||t._emit("changeSelection"),!t.$keepDesiredColumnOnChange&&e.old.column!=e.value.column&&(t.$desiredColumn=null)}),this.selectionAnchor.on("change",function(){t.$isEmpty||t._emit("changeSelection")})};(function(){r.implement(this,s),this.isEmpty=function(){return this.$isEmpty||this.anchor.row==this.lead.row&&this.anchor.column==this.lead.column},this.isMultiLine=function(){return this.isEmpty()?!1:this.getRange().isMultiLine()},this.getCursor=function(){return this.lead.getPosition()},this.setSelectionAnchor=function(e,t){this.anchor.setPosition(e,t),this.$isEmpty&&(this.$isEmpty=!1,this._emit("changeSelection"))},this.getSelectionAnchor=function(){return this.$isEmpty?this.getSelectionLead():this.anchor.getPosition()},this.getSelectionLead=function(){return this.lead.getPosition()},this.shiftSelection=function(e){if(this.$isEmpty){this.moveCursorTo(this.lead.row,this.lead.column+e);return}var t=this.getSelectionAnchor(),n=this.getSelectionLead(),r=this.isBackwards();(!r||t.column!==0)&&this.setSelectionAnchor(t.row,t.column+e),(r||n.column!==0)&&this.$moveSelection(function(){this.moveCursorTo(n.row,n.column+e)})},this.isBackwards=function(){var e=this.anchor,t=this.lead;return e.row>t.row||e.row==t.row&&e.column>t.column},this.getRange=function(){var e=this.anchor,t=this.lead;return this.isEmpty()?o.fromPoints(t,t):this.isBackwards()?o.fromPoints(t,e):o.fromPoints(e,t)},this.clearSelection=function(){this.$isEmpty||(this.$isEmpty=!0,this._emit("changeSelection"))},this.selectAll=function(){var e=this.doc.getLength()-1;this.setSelectionAnchor(0,0),this.moveCursorTo(e,this.doc.getLine(e).length)},this.setRange=this.setSelectionRange=function(e,t){t?(this.setSelectionAnchor(e.end.row,e.end.column),this.selectTo(e.start.row,e.start.column)):(this.setSelectionAnchor(e.start.row,e.start.column),this.selectTo(e.end.row,e.end.column)),this.getRange().isEmpty()&&(this.$isEmpty=!0),this.$desiredColumn=null},this.$moveSelection=function(e){var t=this.lead;this.$isEmpty&&this.setSelectionAnchor(t.row,t.column),e.call(this)},this.selectTo=function(e,t){this.$moveSelection(function(){this.moveCursorTo(e,t)})},this.selectToPosition=function(e){this.$moveSelection(function(){this.moveCursorToPosition(e)})},this.moveTo=function(e,t){this.clearSelection(),this.moveCursorTo(e,t)},this.moveToPosition=function(e){this.clearSelection(),this.moveCursorToPosition(e)},this.selectUp=function(){this.$moveSelection(this.moveCursorUp)},this.selectDown=function(){this.$moveSelection(this.moveCursorDown)},this.selectRight=function(){this.$moveSelection(this.moveCursorRight)},this.selectLeft=function(){this.$moveSelection(this.moveCursorLeft)},this.selectLineStart=function(){this.$moveSelection(this.moveCursorLineStart)},this.selectLineEnd=function(){this.$moveSelection(this.moveCursorLineEnd)},this.selectFileEnd=function(){this.$moveSelection(this.moveCursorFileEnd)},this.selectFileStart=function(){this.$moveSelection(this.moveCursorFileStart)},this.selectWordRight=function(){this.$moveSelection(this.moveCursorWordRight)},this.selectWordLeft=function(){this.$moveSelection(this.moveCursorWordLeft)},this.getWordRange=function(e,t){if(typeof t=="undefined"){var n=e||this.lead;e=n.row,t=n.column}return this.session.getWordRange(e,t)},this.selectWord=function(){this.setSelectionRange(this.getWordRange())},this.selectAWord=function(){var e=this.getCursor(),t=this.session.getAWordRange(e.row,e.column);this.setSelectionRange(t)},this.getLineRange=function(e,t){var n=typeof e=="number"?e:this.lead.row,r,i=this.session.getFoldLine(n);return i?(n=i.start.row,r=i.end.row):r=n,t===!0?new o(n,0,r,this.session.getLine(r).length):new o(n,0,r+1,0)},this.selectLine=function(){this.setSelectionRange(this.getLineRange())},this.moveCursorUp=function(){this.moveCursorBy(-1,0)},this.moveCursorDown=function(){this.moveCursorBy(1,0)},this.moveCursorLeft=function(){var e=this.lead.getPosition(),t;if(t=this.session.getFoldAt(e.row,e.column,-1))this.moveCursorTo(t.start.row,t.start.column);else if(e.column===0)e.row>0&&this.moveCursorTo(e.row-1,this.doc.getLine(e.row-1).length);else{var n=this.session.getTabSize();this.session.isTabStop(e)&&this.doc.getLine(e.row).slice(e.column-n,e.column).split(" ").length-1==n?this.moveCursorBy(0,-n):this.moveCursorBy(0,-1)}},this.moveCursorRight=function(){var e=this.lead.getPosition(),t;if(t=this.session.getFoldAt(e.row,e.column,1))this.moveCursorTo(t.end.row,t.end.column);else if(this.lead.column==this.doc.getLine(this.lead.row).length)this.lead.row<this.doc.getLength()-1&&this.moveCursorTo(this.lead.row+1,0);else{var n=this.session.getTabSize(),e=this.lead;this.session.isTabStop(e)&&this.doc.getLine(e.row).slice(e.column,e.column+n).split(" ").length-1==n?this.moveCursorBy(0,n):this.moveCursorBy(0,1)}},this.moveCursorLineStart=function(){var e=this.lead.row,t=this.lead.column,n=this.session.documentToScreenRow(e,t),r=this.session.screenToDocumentPosition(n,0),i=this.session.getDisplayLine(e,null,r.row,r.column),s=i.match(/^\s*/);s[0].length!=t&&!this.session.$useEmacsStyleLineStart&&(r.column+=s[0].length),this.moveCursorToPosition(r)},this.moveCursorLineEnd=function(){var e=this.lead,t=this.session.getDocumentLastRowColumnPosition(e.row,e.column);if(this.lead.column==t.column){var n=this.session.getLine(t.row);if(t.column==n.length){var r=n.search(/\s+$/);r>0&&(t.column=r)}}this.moveCursorTo(t.row,t.column)},this.moveCursorFileEnd=function(){var e=this.doc.getLength()-1,t=this.doc.getLine(e).length;this.moveCursorTo(e,t)},this.moveCursorFileStart=function(){this.moveCursorTo(0,0)},this.moveCursorLongWordRight=function(){var e=this.lead.row,t=this.lead.column,n=this.doc.getLine(e),r=n.substring(t),i;this.session.nonTokenRe.lastIndex=0,this.session.tokenRe.lastIndex=0;var s=this.session.getFoldAt(e,t,1);if(s){this.moveCursorTo(s.end.row,s.end.column);return}if(i=this.session.nonTokenRe.exec(r))t+=this.session.nonTokenRe.lastIndex,this.session.nonTokenRe.lastIndex=0,r=n.substring(t);if(t>=n.length){this.moveCursorTo(e,n.length),this.moveCursorRight(),e<this.doc.getLength()-1&&this.moveCursorWordRight();return}if(i=this.session.tokenRe.exec(r))t+=this.session.tokenRe.lastIndex,this.session.tokenRe.lastIndex=0;this.moveCursorTo(e,t)},this.moveCursorLongWordLeft=function(){var e=this.lead.row,t=this.lead.column,n;if(n=this.session.getFoldAt(e,t,-1)){this.moveCursorTo(n.start.row,n.start.column);return}var r=this.session.getFoldStringAt(e,t,-1);r==null&&(r=this.doc.getLine(e).substring(0,t));var s=i.stringReverse(r),o;this.session.nonTokenRe.lastIndex=0,this.session.tokenRe.lastIndex=0;if(o=this.session.nonTokenRe.exec(s))t-=this.session.nonTokenRe.lastIndex,s=s.slice(this.session.nonTokenRe.lastIndex),this.session.nonTokenRe.lastIndex=0;if(t<=0){this.moveCursorTo(e,0),this.moveCursorLeft(),e>0&&this.moveCursorWordLeft();return}if(o=this.session.tokenRe.exec(s))t-=this.session.tokenRe.lastIndex,this.session.tokenRe.lastIndex=0;this.moveCursorTo(e,t)},this.$shortWordEndIndex=function(e){var t,n=0,r,i=/\s/,s=this.session.tokenRe;s.lastIndex=0;if(t=this.session.tokenRe.exec(e))n=this.session.tokenRe.lastIndex;else{while((r=e[n])&&i.test(r))n++;if(n<1){s.lastIndex=0;while((r=e[n])&&!s.test(r)){s.lastIndex=0,n++;if(i.test(r)){if(n>2){n--;break}while((r=e[n])&&i.test(r))n++;if(n>2)break}}}}return s.lastIndex=0,n},this.moveCursorShortWordRight=function(){var e=this.lead.row,t=this.lead.column,n=this.doc.getLine(e),r=n.substring(t),i=this.session.getFoldAt(e,t,1);if(i)return this.moveCursorTo(i.end.row,i.end.column);if(t==n.length){var s=this.doc.getLength();do e++,r=this.doc.getLine(e);while(e<s&&/^\s*$/.test(r));/^\s+/.test(r)||(r=""),t=0}var o=this.$shortWordEndIndex(r);this.moveCursorTo(e,t+o)},this.moveCursorShortWordLeft=function(){var e=this.lead.row,t=this.lead.column,n;if(n=this.session.getFoldAt(e,t,-1))return this.moveCursorTo(n.start.row,n.start.column);var r=this.session.getLine(e).substring(0,t);if(t===0){do e--,r=this.doc.getLine(e);while(e>0&&/^\s*$/.test(r));t=r.length,/\s+$/.test(r)||(r="")}var s=i.stringReverse(r),o=this.$shortWordEndIndex(s);return this.moveCursorTo(e,t-o)},this.moveCursorWordRight=function(){this.session.$selectLongWords?this.moveCursorLongWordRight():this.moveCursorShortWordRight()},this.moveCursorWordLeft=function(){this.session.$selectLongWords?this.moveCursorLongWordLeft():this.moveCursorShortWordLeft()},this.moveCursorBy=function(e,t){var n=this.session.documentToScreenPosition(this.lead.row,this.lead.column);t===0&&(this.$desiredColumn?n.column=this.$desiredColumn:this.$desiredColumn=n.column);var r=this.session.screenToDocumentPosition(n.row+e,n.column);e!==0&&t===0&&r.row===this.lead.row&&r.column===this.lead.column&&this.session.lineWidgets&&this.session.lineWidgets[r.row]&&(r.row>0||e>0)&&r.row++,this.moveCursorTo(r.row,r.column+t,t===0)},this.moveCursorToPosition=function(e){this.moveCursorTo(e.row,e.column)},this.moveCursorTo=function(e,t,n){var r=this.session.getFoldAt(e,t,1);r&&(e=r.start.row,t=r.start.column),this.$keepDesiredColumnOnChange=!0,this.lead.setPosition(e,t),this.$keepDesiredColumnOnChange=!1,n||(this.$desiredColumn=null)},this.moveCursorToScreen=function(e,t,n){var r=this.session.screenToDocumentPosition(e,t);this.moveCursorTo(r.row,r.column,n)},this.detach=function(){this.lead.detach(),this.anchor.detach(),this.session=this.doc=null},this.fromOrientedRange=function(e){this.setSelectionRange(e,e.cursor==e.start),this.$desiredColumn=e.desiredColumn||this.$desiredColumn},this.toOrientedRange=function(e){var t=this.getRange();return e?(e.start.column=t.start.column,e.start.row=t.start.row,e.end.column=t.end.column,e.end.row=t.end.row):e=t,e.cursor=this.isBackwards()?e.start:e.end,e.desiredColumn=this.$desiredColumn,e},this.getRangeOfMovements=function(e){var t=this.getCursor();try{e(this);var n=this.getCursor();return o.fromPoints(t,n)}catch(r){return o.fromPoints(t,t)}finally{this.moveCursorToPosition(t)}},this.toJSON=function(){if(this.rangeCount)var e=this.ranges.map(function(e){var t=e.clone();return t.isBackwards=e.cursor==e.start,t});else{var e=this.getRange();e.isBackwards=this.isBackwards()}return e},this.fromJSON=function(e){if(e.start==undefined){if(this.rangeList){this.toSingleRange(e[0]);for(var t=e.length;t--;){var n=o.fromPoints(e[t].start,e[t].end);e[t].isBackwards&&(n.cursor=n.start),this.addRange(n,!0)}return}e=e[0]}this.rangeList&&this.toSingleRange(e),this.setSelectionRange(e,e.isBackwards)},this.isEqual=function(e){if((e.length||this.rangeCount)&&e.length!=this.rangeCount)return!1;if(!e.length||!this.ranges)return this.getRange().isEqual(e);for(var t=this.ranges.length;t--;)if(!this.ranges[t].isEqual(e[t]))return!1;return!0}}).call(u.prototype),t.Selection=u}),ace.define("ace/tokenizer",["require","exports","module","ace/config"],function(e,t,n){"use strict";var r=e("./config"),i=2e3,s=function(e){this.states=e,this.regExps={},this.matchMappings={};for(var t in this.states){var n=this.states[t],r=[],i=0,s=this.matchMappings[t]={defaultToken:"text"},o="g",u=[];for(var a=0;a<n.length;a++){var f=n[a];f.defaultToken&&(s.defaultToken=f.defaultToken),f.caseInsensitive&&(o="gi");if(f.regex==null)continue;f.regex instanceof RegExp&&(f.regex=f.regex.toString().slice(1,-1));var l=f.regex,c=(new RegExp("(?:("+l+")|(.))")).exec("a").length-2;Array.isArray(f.token)?f.token.length==1||c==1?f.token=f.token[0]:c-1!=f.token.length?(this.reportError("number of classes and regexp groups doesn't match",{rule:f,groupCount:c-1}),f.token=f.token[0]):(f.tokenArray=f.token,f.token=null,f.onMatch=this.$arrayTokens):typeof f.token=="function"&&!f.onMatch&&(c>1?f.onMatch=this.$applyToken:f.onMatch=f.token),c>1&&(/\\\d/.test(f.regex)?l=f.regex.replace(/\\([0-9]+)/g,function(e,t){return"\\"+(parseInt(t,10)+i+1)}):(c=1,l=this.removeCapturingGroups(f.regex)),!f.splitRegex&&typeof f.token!="string"&&u.push(f)),s[i]=a,i+=c,r.push(l),f.onMatch||(f.onMatch=null)}r.length||(s[0]=0,r.push("$")),u.forEach(function(e){e.splitRegex=this.createSplitterRegexp(e.regex,o)},this),this.regExps[t]=new RegExp("("+r.join(")|(")+")|($)",o)}};(function(){this.$setMaxTokenCount=function(e){i=e|0},this.$applyToken=function(e){var t=this.splitRegex.exec(e).slice(1),n=this.token.apply(this,t);if(typeof n=="string")return[{type:n,value:e}];var r=[];for(var i=0,s=n.length;i<s;i++)t[i]&&(r[r.length]={type:n[i],value:t[i]});return r},this.$arrayTokens=function(e){if(!e)return[];var t=this.splitRegex.exec(e);if(!t)return"text";var n=[],r=this.tokenArray;for(var i=0,s=r.length;i<s;i++)t[i+1]&&(n[n.length]={type:r[i],value:t[i+1]});return n},this.removeCapturingGroups=function(e){var t=e.replace(/\[(?:\\.|[^\]])*?\]|\\.|\(\?[:=!]|(\()/g,function(e,t){return t?"(?:":e});return t},this.createSplitterRegexp=function(e,t){if(e.indexOf("(?=")!=-1){var n=0,r=!1,i={};e.replace(/(\\.)|(\((?:\?[=!])?)|(\))|([\[\]])/g,function(e,t,s,o,u,a){return r?r=u!="]":u?r=!0:o?(n==i.stack&&(i.end=a+1,i.stack=-1),n--):s&&(n++,s.length!=1&&(i.stack=n,i.start=a)),e}),i.end!=null&&/^\)*$/.test(e.substr(i.end))&&(e=e.substring(0,i.start)+e.substr(i.end))}return e.charAt(0)!="^"&&(e="^"+e),e.charAt(e.length-1)!="$"&&(e+="$"),new RegExp(e,(t||"").replace("g",""))},this.getLineTokens=function(e,t){if(t&&typeof t!="string"){var n=t.slice(0);t=n[0],t==="#tmp"&&(n.shift(),t=n.shift())}else var n=[];var r=t||"start",s=this.states[r];s||(r="start",s=this.states[r]);var o=this.matchMappings[r],u=this.regExps[r];u.lastIndex=0;var a,f=[],l=0,c=0,h={type:null,value:""};while(a=u.exec(e)){var p=o.defaultToken,d=null,v=a[0],m=u.lastIndex;if(m-v.length>l){var g=e.substring(l,m-v.length);h.type==p?h.value+=g:(h.type&&f.push(h),h={type:p,value:g})}for(var y=0;y<a.length-2;y++){if(a[y+1]===undefined)continue;d=s[o[y]],d.onMatch?p=d.onMatch(v,r,n):p=d.token,d.next&&(typeof d.next=="string"?r=d.next:r=d.next(r,n),s=this.states[r],s||(this.reportError("state doesn't exist",r),r="start",s=this.states[r]),o=this.matchMappings[r],l=m,u=this.regExps[r],u.lastIndex=m);break}if(v)if(typeof p=="string")!!d&&d.merge===!1||h.type!==p?(h.type&&f.push(h),h={type:p,value:v}):h.value+=v;else if(p){h.type&&f.push(h),h={type:null,value:""};for(var y=0;y<p.length;y++)f.push(p[y])}if(l==e.length)break;l=m;if(c++>i){c>2*e.length&&this.reportError("infinite loop with in ace tokenizer",{startState:t,line:e});while(l<e.length)h.type&&f.push(h),h={value:e.substring(l,l+=2e3),type:"overflow"};r="start",n=[];break}}return h.type&&f.push(h),n.length>1&&n[0]!==r&&n.unshift("#tmp",r),{tokens:f,state:n.length?n:r}},this.reportError=r.reportError}).call(s.prototype),t.Tokenizer=s}),ace.define("ace/mode/text_highlight_rules",["require","exports","module","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../lib/lang"),i=function(){this.$rules={start:[{token:"empty_line",regex:"^$"},{defaultToken:"text"}]}};(function(){this.addRules=function(e,t){if(!t){for(var n in e)this.$rules[n]=e[n];return}for(var n in e){var r=e[n];for(var i=0;i<r.length;i++){var s=r[i];if(s.next||s.onMatch)typeof s.next=="string"&&s.next.indexOf(t)!==0&&(s.next=t+s.next),s.nextState&&s.nextState.indexOf(t)!==0&&(s.nextState=t+s.nextState)}this.$rules[t+n]=r}},this.getRules=function(){return this.$rules},this.embedRules=function(e,t,n,i,s){var o=typeof e=="function"?(new e).getRules():e;if(i)for(var u=0;u<i.length;u++)i[u]=t+i[u];else{i=[];for(var a in o)i.push(t+a)}this.addRules(o,t);if(n){var f=Array.prototype[s?"push":"unshift"];for(var u=0;u<i.length;u++)f.apply(this.$rules[i[u]],r.deepCopy(n))}this.$embeds||(this.$embeds=[]),this.$embeds.push(t)},this.getEmbeds=function(){return this.$embeds};var e=function(e,t){return(e!="start"||t.length)&&t.unshift(this.nextState,e),this.nextState},t=function(e,t){return t.shift(),t.shift()||"start"};this.normalizeRules=function(){function i(s){var o=r[s];o.processed=!0;for(var u=0;u<o.length;u++){var a=o[u];!a.regex&&a.start&&(a.regex=a.start,a.next||(a.next=[]),a.next.push({defaultToken:a.token},{token:a.token+".end",regex:a.end||a.start,next:"pop"}),a.token=a.token+".start",a.push=!0);var f=a.next||a.push;if(f&&Array.isArray(f)){var l=a.stateName;l||(l=a.token,typeof l!="string"&&(l=l[0]||""),r[l]&&(l+=n++)),r[l]=f,a.next=l,i(l)}else f=="pop"&&(a.next=t);a.push&&(a.nextState=a.next||a.push,a.next=e,delete a.push);if(a.rules)for(var c in a.rules)r[c]?r[c].push&&r[c].push.apply(r[c],a.rules[c]):r[c]=a.rules[c];if(a.include||typeof a=="string")var h=a.include||a,p=r[h];else Array.isArray(a)&&(p=a);if(p){var d=[u,1].concat(p);a.noEscape&&(d=d.filter(function(e){return!e.next})),o.splice.apply(o,d),u--,p=null}a.keywordMap&&(a.token=this.createKeywordMapper(a.keywordMap,a.defaultToken||"text",a.caseInsensitive),delete a.defaultToken)}}var n=0,r=this.$rules;Object.keys(r).forEach(i,this)},this.createKeywordMapper=function(e,t,n,r){var i=Object.create(null);return Object.keys(e).forEach(function(t){var s=e[t];n&&(s=s.toLowerCase());var o=s.split(r||"|");for(var u=o.length;u--;)i[o[u]]=t}),Object.getPrototypeOf(i)&&(i.__proto__=null),this.$keywordList=Object.keys(i),e=null,n?function(e){return i[e.toLowerCase()]||t}:function(e){return i[e]||t}},this.getKeywords=function(){return this.$keywords}}).call(i.prototype),t.TextHighlightRules=i}),ace.define("ace/mode/behaviour",["require","exports","module"],function(e,t,n){"use strict";var r=function(){this.$behaviours={}};(function(){this.add=function(e,t,n){switch(undefined){case this.$behaviours:this.$behaviours={};case this.$behaviours[e]:this.$behaviours[e]={}}this.$behaviours[e][t]=n},this.addBehaviours=function(e){for(var t in e)for(var n in e[t])this.add(t,n,e[t][n])},this.remove=function(e){this.$behaviours&&this.$behaviours[e]&&delete this.$behaviours[e]},this.inherit=function(e,t){if(typeof e=="function")var n=(new e).getBehaviours(t);else var n=e.getBehaviours(t);this.addBehaviours(n)},this.getBehaviours=function(e){if(!e)return this.$behaviours;var t={};for(var n=0;n<e.length;n++)this.$behaviours[e[n]]&&(t[e[n]]=this.$behaviours[e[n]]);return t}}).call(r.prototype),t.Behaviour=r}),ace.define("ace/unicode",["require","exports","module"],function(e,t,n){"use strict";function r(e){var n=/\w{4}/g;for(var r in e)t.packages[r]=e[r].replace(n,"\\u$&")}t.packages={},r({L:"0041-005A0061-007A00AA00B500BA00C0-00D600D8-00F600F8-02C102C6-02D102E0-02E402EC02EE0370-037403760377037A-037D03860388-038A038C038E-03A103A3-03F503F7-0481048A-05250531-055605590561-058705D0-05EA05F0-05F20621-064A066E066F0671-06D306D506E506E606EE06EF06FA-06FC06FF07100712-072F074D-07A507B107CA-07EA07F407F507FA0800-0815081A082408280904-0939093D09500958-0961097109720979-097F0985-098C098F09900993-09A809AA-09B009B209B6-09B909BD09CE09DC09DD09DF-09E109F009F10A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A59-0A5C0A5E0A72-0A740A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD0AD00AE00AE10B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D0B5C0B5D0B5F-0B610B710B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BD00C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D0C580C590C600C610C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD0CDE0CE00CE10D05-0D0C0D0E-0D100D12-0D280D2A-0D390D3D0D600D610D7A-0D7F0D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60E01-0E300E320E330E40-0E460E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB00EB20EB30EBD0EC0-0EC40EC60EDC0EDD0F000F40-0F470F49-0F6C0F88-0F8B1000-102A103F1050-1055105A-105D106110651066106E-10701075-1081108E10A0-10C510D0-10FA10FC1100-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA1700-170C170E-17111720-17311740-17511760-176C176E-17701780-17B317D717DC1820-18771880-18A818AA18B0-18F51900-191C1950-196D1970-19741980-19AB19C1-19C71A00-1A161A20-1A541AA71B05-1B331B45-1B4B1B83-1BA01BAE1BAF1C00-1C231C4D-1C4F1C5A-1C7D1CE9-1CEC1CEE-1CF11D00-1DBF1E00-1F151F18-1F1D1F20-1F451F48-1F4D1F50-1F571F591F5B1F5D1F5F-1F7D1F80-1FB41FB6-1FBC1FBE1FC2-1FC41FC6-1FCC1FD0-1FD31FD6-1FDB1FE0-1FEC1FF2-1FF41FF6-1FFC2071207F2090-209421022107210A-211321152119-211D212421262128212A-212D212F-2139213C-213F2145-2149214E218321842C00-2C2E2C30-2C5E2C60-2CE42CEB-2CEE2D00-2D252D30-2D652D6F2D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE2E2F300530063031-3035303B303C3041-3096309D-309F30A1-30FA30FC-30FF3105-312D3131-318E31A0-31B731F0-31FF3400-4DB54E00-9FCBA000-A48CA4D0-A4FDA500-A60CA610-A61FA62AA62BA640-A65FA662-A66EA67F-A697A6A0-A6E5A717-A71FA722-A788A78BA78CA7FB-A801A803-A805A807-A80AA80C-A822A840-A873A882-A8B3A8F2-A8F7A8FBA90A-A925A930-A946A960-A97CA984-A9B2A9CFAA00-AA28AA40-AA42AA44-AA4BAA60-AA76AA7AAA80-AAAFAAB1AAB5AAB6AAB9-AABDAAC0AAC2AADB-AADDABC0-ABE2AC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA2DFA30-FA6DFA70-FAD9FB00-FB06FB13-FB17FB1DFB1F-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF21-FF3AFF41-FF5AFF66-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC",Ll:"0061-007A00AA00B500BA00DF-00F600F8-00FF01010103010501070109010B010D010F01110113011501170119011B011D011F01210123012501270129012B012D012F01310133013501370138013A013C013E014001420144014601480149014B014D014F01510153015501570159015B015D015F01610163016501670169016B016D016F0171017301750177017A017C017E-0180018301850188018C018D019201950199-019B019E01A101A301A501A801AA01AB01AD01B001B401B601B901BA01BD-01BF01C601C901CC01CE01D001D201D401D601D801DA01DC01DD01DF01E101E301E501E701E901EB01ED01EF01F001F301F501F901FB01FD01FF02010203020502070209020B020D020F02110213021502170219021B021D021F02210223022502270229022B022D022F02310233-0239023C023F0240024202470249024B024D024F-02930295-02AF037103730377037B-037D039003AC-03CE03D003D103D5-03D703D903DB03DD03DF03E103E303E503E703E903EB03ED03EF-03F303F503F803FB03FC0430-045F04610463046504670469046B046D046F04710473047504770479047B047D047F0481048B048D048F04910493049504970499049B049D049F04A104A304A504A704A904AB04AD04AF04B104B304B504B704B904BB04BD04BF04C204C404C604C804CA04CC04CE04CF04D104D304D504D704D904DB04DD04DF04E104E304E504E704E904EB04ED04EF04F104F304F504F704F904FB04FD04FF05010503050505070509050B050D050F05110513051505170519051B051D051F0521052305250561-05871D00-1D2B1D62-1D771D79-1D9A1E011E031E051E071E091E0B1E0D1E0F1E111E131E151E171E191E1B1E1D1E1F1E211E231E251E271E291E2B1E2D1E2F1E311E331E351E371E391E3B1E3D1E3F1E411E431E451E471E491E4B1E4D1E4F1E511E531E551E571E591E5B1E5D1E5F1E611E631E651E671E691E6B1E6D1E6F1E711E731E751E771E791E7B1E7D1E7F1E811E831E851E871E891E8B1E8D1E8F1E911E931E95-1E9D1E9F1EA11EA31EA51EA71EA91EAB1EAD1EAF1EB11EB31EB51EB71EB91EBB1EBD1EBF1EC11EC31EC51EC71EC91ECB1ECD1ECF1ED11ED31ED51ED71ED91EDB1EDD1EDF1EE11EE31EE51EE71EE91EEB1EED1EEF1EF11EF31EF51EF71EF91EFB1EFD1EFF-1F071F10-1F151F20-1F271F30-1F371F40-1F451F50-1F571F60-1F671F70-1F7D1F80-1F871F90-1F971FA0-1FA71FB0-1FB41FB61FB71FBE1FC2-1FC41FC61FC71FD0-1FD31FD61FD71FE0-1FE71FF2-1FF41FF61FF7210A210E210F2113212F21342139213C213D2146-2149214E21842C30-2C5E2C612C652C662C682C6A2C6C2C712C732C742C76-2C7C2C812C832C852C872C892C8B2C8D2C8F2C912C932C952C972C992C9B2C9D2C9F2CA12CA32CA52CA72CA92CAB2CAD2CAF2CB12CB32CB52CB72CB92CBB2CBD2CBF2CC12CC32CC52CC72CC92CCB2CCD2CCF2CD12CD32CD52CD72CD92CDB2CDD2CDF2CE12CE32CE42CEC2CEE2D00-2D25A641A643A645A647A649A64BA64DA64FA651A653A655A657A659A65BA65DA65FA663A665A667A669A66BA66DA681A683A685A687A689A68BA68DA68FA691A693A695A697A723A725A727A729A72BA72DA72F-A731A733A735A737A739A73BA73DA73FA741A743A745A747A749A74BA74DA74FA751A753A755A757A759A75BA75DA75FA761A763A765A767A769A76BA76DA76FA771-A778A77AA77CA77FA781A783A785A787A78CFB00-FB06FB13-FB17FF41-FF5A",Lu:"0041-005A00C0-00D600D8-00DE01000102010401060108010A010C010E01100112011401160118011A011C011E01200122012401260128012A012C012E01300132013401360139013B013D013F0141014301450147014A014C014E01500152015401560158015A015C015E01600162016401660168016A016C016E017001720174017601780179017B017D018101820184018601870189-018B018E-0191019301940196-0198019C019D019F01A001A201A401A601A701A901AC01AE01AF01B1-01B301B501B701B801BC01C401C701CA01CD01CF01D101D301D501D701D901DB01DE01E001E201E401E601E801EA01EC01EE01F101F401F6-01F801FA01FC01FE02000202020402060208020A020C020E02100212021402160218021A021C021E02200222022402260228022A022C022E02300232023A023B023D023E02410243-02460248024A024C024E03700372037603860388-038A038C038E038F0391-03A103A3-03AB03CF03D2-03D403D803DA03DC03DE03E003E203E403E603E803EA03EC03EE03F403F703F903FA03FD-042F04600462046404660468046A046C046E04700472047404760478047A047C047E0480048A048C048E04900492049404960498049A049C049E04A004A204A404A604A804AA04AC04AE04B004B204B404B604B804BA04BC04BE04C004C104C304C504C704C904CB04CD04D004D204D404D604D804DA04DC04DE04E004E204E404E604E804EA04EC04EE04F004F204F404F604F804FA04FC04FE05000502050405060508050A050C050E05100512051405160518051A051C051E0520052205240531-055610A0-10C51E001E021E041E061E081E0A1E0C1E0E1E101E121E141E161E181E1A1E1C1E1E1E201E221E241E261E281E2A1E2C1E2E1E301E321E341E361E381E3A1E3C1E3E1E401E421E441E461E481E4A1E4C1E4E1E501E521E541E561E581E5A1E5C1E5E1E601E621E641E661E681E6A1E6C1E6E1E701E721E741E761E781E7A1E7C1E7E1E801E821E841E861E881E8A1E8C1E8E1E901E921E941E9E1EA01EA21EA41EA61EA81EAA1EAC1EAE1EB01EB21EB41EB61EB81EBA1EBC1EBE1EC01EC21EC41EC61EC81ECA1ECC1ECE1ED01ED21ED41ED61ED81EDA1EDC1EDE1EE01EE21EE41EE61EE81EEA1EEC1EEE1EF01EF21EF41EF61EF81EFA1EFC1EFE1F08-1F0F1F18-1F1D1F28-1F2F1F38-1F3F1F48-1F4D1F591F5B1F5D1F5F1F68-1F6F1FB8-1FBB1FC8-1FCB1FD8-1FDB1FE8-1FEC1FF8-1FFB21022107210B-210D2110-211221152119-211D212421262128212A-212D2130-2133213E213F214521832C00-2C2E2C602C62-2C642C672C692C6B2C6D-2C702C722C752C7E-2C802C822C842C862C882C8A2C8C2C8E2C902C922C942C962C982C9A2C9C2C9E2CA02CA22CA42CA62CA82CAA2CAC2CAE2CB02CB22CB42CB62CB82CBA2CBC2CBE2CC02CC22CC42CC62CC82CCA2CCC2CCE2CD02CD22CD42CD62CD82CDA2CDC2CDE2CE02CE22CEB2CEDA640A642A644A646A648A64AA64CA64EA650A652A654A656A658A65AA65CA65EA662A664A666A668A66AA66CA680A682A684A686A688A68AA68CA68EA690A692A694A696A722A724A726A728A72AA72CA72EA732A734A736A738A73AA73CA73EA740A742A744A746A748A74AA74CA74EA750A752A754A756A758A75AA75CA75EA760A762A764A766A768A76AA76CA76EA779A77BA77DA77EA780A782A784A786A78BFF21-FF3A",Lt:"01C501C801CB01F21F88-1F8F1F98-1F9F1FA8-1FAF1FBC1FCC1FFC",Lm:"02B0-02C102C6-02D102E0-02E402EC02EE0374037A0559064006E506E607F407F507FA081A0824082809710E460EC610FC17D718431AA71C78-1C7D1D2C-1D611D781D9B-1DBF2071207F2090-20942C7D2D6F2E2F30053031-3035303B309D309E30FC-30FEA015A4F8-A4FDA60CA67FA717-A71FA770A788A9CFAA70AADDFF70FF9EFF9F",Lo:"01BB01C0-01C3029405D0-05EA05F0-05F20621-063F0641-064A066E066F0671-06D306D506EE06EF06FA-06FC06FF07100712-072F074D-07A507B107CA-07EA0800-08150904-0939093D09500958-096109720979-097F0985-098C098F09900993-09A809AA-09B009B209B6-09B909BD09CE09DC09DD09DF-09E109F009F10A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A59-0A5C0A5E0A72-0A740A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD0AD00AE00AE10B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D0B5C0B5D0B5F-0B610B710B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BD00C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D0C580C590C600C610C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD0CDE0CE00CE10D05-0D0C0D0E-0D100D12-0D280D2A-0D390D3D0D600D610D7A-0D7F0D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60E01-0E300E320E330E40-0E450E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB00EB20EB30EBD0EC0-0EC40EDC0EDD0F000F40-0F470F49-0F6C0F88-0F8B1000-102A103F1050-1055105A-105D106110651066106E-10701075-1081108E10D0-10FA1100-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA1700-170C170E-17111720-17311740-17511760-176C176E-17701780-17B317DC1820-18421844-18771880-18A818AA18B0-18F51900-191C1950-196D1970-19741980-19AB19C1-19C71A00-1A161A20-1A541B05-1B331B45-1B4B1B83-1BA01BAE1BAF1C00-1C231C4D-1C4F1C5A-1C771CE9-1CEC1CEE-1CF12135-21382D30-2D652D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE3006303C3041-3096309F30A1-30FA30FF3105-312D3131-318E31A0-31B731F0-31FF3400-4DB54E00-9FCBA000-A014A016-A48CA4D0-A4F7A500-A60BA610-A61FA62AA62BA66EA6A0-A6E5A7FB-A801A803-A805A807-A80AA80C-A822A840-A873A882-A8B3A8F2-A8F7A8FBA90A-A925A930-A946A960-A97CA984-A9B2AA00-AA28AA40-AA42AA44-AA4BAA60-AA6FAA71-AA76AA7AAA80-AAAFAAB1AAB5AAB6AAB9-AABDAAC0AAC2AADBAADCABC0-ABE2AC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA2DFA30-FA6DFA70-FAD9FB1DFB1F-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF66-FF6FFF71-FF9DFFA0-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC",M:"0300-036F0483-04890591-05BD05BF05C105C205C405C505C70610-061A064B-065E067006D6-06DC06DE-06E406E706E806EA-06ED07110730-074A07A6-07B007EB-07F30816-0819081B-08230825-08270829-082D0900-0903093C093E-094E0951-0955096209630981-098309BC09BE-09C409C709C809CB-09CD09D709E209E30A01-0A030A3C0A3E-0A420A470A480A4B-0A4D0A510A700A710A750A81-0A830ABC0ABE-0AC50AC7-0AC90ACB-0ACD0AE20AE30B01-0B030B3C0B3E-0B440B470B480B4B-0B4D0B560B570B620B630B820BBE-0BC20BC6-0BC80BCA-0BCD0BD70C01-0C030C3E-0C440C46-0C480C4A-0C4D0C550C560C620C630C820C830CBC0CBE-0CC40CC6-0CC80CCA-0CCD0CD50CD60CE20CE30D020D030D3E-0D440D46-0D480D4A-0D4D0D570D620D630D820D830DCA0DCF-0DD40DD60DD8-0DDF0DF20DF30E310E34-0E3A0E47-0E4E0EB10EB4-0EB90EBB0EBC0EC8-0ECD0F180F190F350F370F390F3E0F3F0F71-0F840F860F870F90-0F970F99-0FBC0FC6102B-103E1056-1059105E-10601062-10641067-106D1071-10741082-108D108F109A-109D135F1712-17141732-1734175217531772177317B6-17D317DD180B-180D18A91920-192B1930-193B19B0-19C019C819C91A17-1A1B1A55-1A5E1A60-1A7C1A7F1B00-1B041B34-1B441B6B-1B731B80-1B821BA1-1BAA1C24-1C371CD0-1CD21CD4-1CE81CED1CF21DC0-1DE61DFD-1DFF20D0-20F02CEF-2CF12DE0-2DFF302A-302F3099309AA66F-A672A67CA67DA6F0A6F1A802A806A80BA823-A827A880A881A8B4-A8C4A8E0-A8F1A926-A92DA947-A953A980-A983A9B3-A9C0AA29-AA36AA43AA4CAA4DAA7BAAB0AAB2-AAB4AAB7AAB8AABEAABFAAC1ABE3-ABEAABECABEDFB1EFE00-FE0FFE20-FE26",Mn:"0300-036F0483-04870591-05BD05BF05C105C205C405C505C70610-061A064B-065E067006D6-06DC06DF-06E406E706E806EA-06ED07110730-074A07A6-07B007EB-07F30816-0819081B-08230825-08270829-082D0900-0902093C0941-0948094D0951-095509620963098109BC09C1-09C409CD09E209E30A010A020A3C0A410A420A470A480A4B-0A4D0A510A700A710A750A810A820ABC0AC1-0AC50AC70AC80ACD0AE20AE30B010B3C0B3F0B41-0B440B4D0B560B620B630B820BC00BCD0C3E-0C400C46-0C480C4A-0C4D0C550C560C620C630CBC0CBF0CC60CCC0CCD0CE20CE30D41-0D440D4D0D620D630DCA0DD2-0DD40DD60E310E34-0E3A0E47-0E4E0EB10EB4-0EB90EBB0EBC0EC8-0ECD0F180F190F350F370F390F71-0F7E0F80-0F840F860F870F90-0F970F99-0FBC0FC6102D-10301032-10371039103A103D103E10581059105E-10601071-1074108210851086108D109D135F1712-17141732-1734175217531772177317B7-17BD17C617C9-17D317DD180B-180D18A91920-19221927192819321939-193B1A171A181A561A58-1A5E1A601A621A65-1A6C1A73-1A7C1A7F1B00-1B031B341B36-1B3A1B3C1B421B6B-1B731B801B811BA2-1BA51BA81BA91C2C-1C331C361C371CD0-1CD21CD4-1CE01CE2-1CE81CED1DC0-1DE61DFD-1DFF20D0-20DC20E120E5-20F02CEF-2CF12DE0-2DFF302A-302F3099309AA66FA67CA67DA6F0A6F1A802A806A80BA825A826A8C4A8E0-A8F1A926-A92DA947-A951A980-A982A9B3A9B6-A9B9A9BCAA29-AA2EAA31AA32AA35AA36AA43AA4CAAB0AAB2-AAB4AAB7AAB8AABEAABFAAC1ABE5ABE8ABEDFB1EFE00-FE0FFE20-FE26",Mc:"0903093E-09400949-094C094E0982098309BE-09C009C709C809CB09CC09D70A030A3E-0A400A830ABE-0AC00AC90ACB0ACC0B020B030B3E0B400B470B480B4B0B4C0B570BBE0BBF0BC10BC20BC6-0BC80BCA-0BCC0BD70C01-0C030C41-0C440C820C830CBE0CC0-0CC40CC70CC80CCA0CCB0CD50CD60D020D030D3E-0D400D46-0D480D4A-0D4C0D570D820D830DCF-0DD10DD8-0DDF0DF20DF30F3E0F3F0F7F102B102C10311038103B103C105610571062-10641067-106D108310841087-108C108F109A-109C17B617BE-17C517C717C81923-19261929-192B193019311933-193819B0-19C019C819C91A19-1A1B1A551A571A611A631A641A6D-1A721B041B351B3B1B3D-1B411B431B441B821BA11BA61BA71BAA1C24-1C2B1C341C351CE11CF2A823A824A827A880A881A8B4-A8C3A952A953A983A9B4A9B5A9BAA9BBA9BD-A9C0AA2FAA30AA33AA34AA4DAA7BABE3ABE4ABE6ABE7ABE9ABEAABEC",Me:"0488048906DE20DD-20E020E2-20E4A670-A672",N:"0030-003900B200B300B900BC-00BE0660-066906F0-06F907C0-07C90966-096F09E6-09EF09F4-09F90A66-0A6F0AE6-0AEF0B66-0B6F0BE6-0BF20C66-0C6F0C78-0C7E0CE6-0CEF0D66-0D750E50-0E590ED0-0ED90F20-0F331040-10491090-10991369-137C16EE-16F017E0-17E917F0-17F91810-18191946-194F19D0-19DA1A80-1A891A90-1A991B50-1B591BB0-1BB91C40-1C491C50-1C5920702074-20792080-20892150-21822185-21892460-249B24EA-24FF2776-27932CFD30073021-30293038-303A3192-31953220-32293251-325F3280-328932B1-32BFA620-A629A6E6-A6EFA830-A835A8D0-A8D9A900-A909A9D0-A9D9AA50-AA59ABF0-ABF9FF10-FF19",Nd:"0030-00390660-066906F0-06F907C0-07C90966-096F09E6-09EF0A66-0A6F0AE6-0AEF0B66-0B6F0BE6-0BEF0C66-0C6F0CE6-0CEF0D66-0D6F0E50-0E590ED0-0ED90F20-0F291040-10491090-109917E0-17E91810-18191946-194F19D0-19DA1A80-1A891A90-1A991B50-1B591BB0-1BB91C40-1C491C50-1C59A620-A629A8D0-A8D9A900-A909A9D0-A9D9AA50-AA59ABF0-ABF9FF10-FF19",Nl:"16EE-16F02160-21822185-218830073021-30293038-303AA6E6-A6EF",No:"00B200B300B900BC-00BE09F4-09F90BF0-0BF20C78-0C7E0D70-0D750F2A-0F331369-137C17F0-17F920702074-20792080-20892150-215F21892460-249B24EA-24FF2776-27932CFD3192-31953220-32293251-325F3280-328932B1-32BFA830-A835",P:"0021-00230025-002A002C-002F003A003B003F0040005B-005D005F007B007D00A100AB00B700BB00BF037E0387055A-055F0589058A05BE05C005C305C605F305F40609060A060C060D061B061E061F066A-066D06D40700-070D07F7-07F90830-083E0964096509700DF40E4F0E5A0E5B0F04-0F120F3A-0F3D0F850FD0-0FD4104A-104F10FB1361-13681400166D166E169B169C16EB-16ED1735173617D4-17D617D8-17DA1800-180A1944194519DE19DF1A1E1A1F1AA0-1AA61AA8-1AAD1B5A-1B601C3B-1C3F1C7E1C7F1CD32010-20272030-20432045-20512053-205E207D207E208D208E2329232A2768-277527C527C627E6-27EF2983-299829D8-29DB29FC29FD2CF9-2CFC2CFE2CFF2E00-2E2E2E302E313001-30033008-30113014-301F3030303D30A030FBA4FEA4FFA60D-A60FA673A67EA6F2-A6F7A874-A877A8CEA8CFA8F8-A8FAA92EA92FA95FA9C1-A9CDA9DEA9DFAA5C-AA5FAADEAADFABEBFD3EFD3FFE10-FE19FE30-FE52FE54-FE61FE63FE68FE6AFE6BFF01-FF03FF05-FF0AFF0C-FF0FFF1AFF1BFF1FFF20FF3B-FF3DFF3FFF5BFF5DFF5F-FF65",Pd:"002D058A05BE140018062010-20152E172E1A301C303030A0FE31FE32FE58FE63FF0D",Ps:"0028005B007B0F3A0F3C169B201A201E2045207D208D23292768276A276C276E27702772277427C527E627E827EA27EC27EE2983298529872989298B298D298F299129932995299729D829DA29FC2E222E242E262E283008300A300C300E3010301430163018301A301DFD3EFE17FE35FE37FE39FE3BFE3DFE3FFE41FE43FE47FE59FE5BFE5DFF08FF3BFF5BFF5FFF62",Pe:"0029005D007D0F3B0F3D169C2046207E208E232A2769276B276D276F27712773277527C627E727E927EB27ED27EF298429862988298A298C298E2990299229942996299829D929DB29FD2E232E252E272E293009300B300D300F3011301530173019301B301E301FFD3FFE18FE36FE38FE3AFE3CFE3EFE40FE42FE44FE48FE5AFE5CFE5EFF09FF3DFF5DFF60FF63",Pi:"00AB2018201B201C201F20392E022E042E092E0C2E1C2E20",Pf:"00BB2019201D203A2E032E052E0A2E0D2E1D2E21",Pc:"005F203F20402054FE33FE34FE4D-FE4FFF3F",Po:"0021-00230025-0027002A002C002E002F003A003B003F0040005C00A100B700BF037E0387055A-055F058905C005C305C605F305F40609060A060C060D061B061E061F066A-066D06D40700-070D07F7-07F90830-083E0964096509700DF40E4F0E5A0E5B0F04-0F120F850FD0-0FD4104A-104F10FB1361-1368166D166E16EB-16ED1735173617D4-17D617D8-17DA1800-18051807-180A1944194519DE19DF1A1E1A1F1AA0-1AA61AA8-1AAD1B5A-1B601C3B-1C3F1C7E1C7F1CD3201620172020-20272030-2038203B-203E2041-20432047-205120532055-205E2CF9-2CFC2CFE2CFF2E002E012E06-2E082E0B2E0E-2E162E182E192E1B2E1E2E1F2E2A-2E2E2E302E313001-3003303D30FBA4FEA4FFA60D-A60FA673A67EA6F2-A6F7A874-A877A8CEA8CFA8F8-A8FAA92EA92FA95FA9C1-A9CDA9DEA9DFAA5C-AA5FAADEAADFABEBFE10-FE16FE19FE30FE45FE46FE49-FE4CFE50-FE52FE54-FE57FE5F-FE61FE68FE6AFE6BFF01-FF03FF05-FF07FF0AFF0CFF0EFF0FFF1AFF1BFF1FFF20FF3CFF61FF64FF65",S:"0024002B003C-003E005E0060007C007E00A2-00A900AC00AE-00B100B400B600B800D700F702C2-02C502D2-02DF02E5-02EB02ED02EF-02FF03750384038503F604820606-0608060B060E060F06E906FD06FE07F609F209F309FA09FB0AF10B700BF3-0BFA0C7F0CF10CF20D790E3F0F01-0F030F13-0F170F1A-0F1F0F340F360F380FBE-0FC50FC7-0FCC0FCE0FCF0FD5-0FD8109E109F13601390-139917DB194019E0-19FF1B61-1B6A1B74-1B7C1FBD1FBF-1FC11FCD-1FCF1FDD-1FDF1FED-1FEF1FFD1FFE20442052207A-207C208A-208C20A0-20B8210021012103-21062108210921142116-2118211E-2123212521272129212E213A213B2140-2144214A-214D214F2190-2328232B-23E82400-24262440-244A249C-24E92500-26CD26CF-26E126E326E8-26FF2701-27042706-2709270C-27272729-274B274D274F-27522756-275E2761-276727942798-27AF27B1-27BE27C0-27C427C7-27CA27CC27D0-27E527F0-29822999-29D729DC-29FB29FE-2B4C2B50-2B592CE5-2CEA2E80-2E992E9B-2EF32F00-2FD52FF0-2FFB300430123013302030363037303E303F309B309C319031913196-319F31C0-31E33200-321E322A-32503260-327F328A-32B032C0-32FE3300-33FF4DC0-4DFFA490-A4C6A700-A716A720A721A789A78AA828-A82BA836-A839AA77-AA79FB29FDFCFDFDFE62FE64-FE66FE69FF04FF0BFF1C-FF1EFF3EFF40FF5CFF5EFFE0-FFE6FFE8-FFEEFFFCFFFD",Sm:"002B003C-003E007C007E00AC00B100D700F703F60606-060820442052207A-207C208A-208C2140-2144214B2190-2194219A219B21A021A321A621AE21CE21CF21D221D421F4-22FF2308-230B23202321237C239B-23B323DC-23E125B725C125F8-25FF266F27C0-27C427C7-27CA27CC27D0-27E527F0-27FF2900-29822999-29D729DC-29FB29FE-2AFF2B30-2B442B47-2B4CFB29FE62FE64-FE66FF0BFF1C-FF1EFF5CFF5EFFE2FFE9-FFEC",Sc:"002400A2-00A5060B09F209F309FB0AF10BF90E3F17DB20A0-20B8A838FDFCFE69FF04FFE0FFE1FFE5FFE6",Sk:"005E006000A800AF00B400B802C2-02C502D2-02DF02E5-02EB02ED02EF-02FF0375038403851FBD1FBF-1FC11FCD-1FCF1FDD-1FDF1FED-1FEF1FFD1FFE309B309CA700-A716A720A721A789A78AFF3EFF40FFE3",So:"00A600A700A900AE00B000B60482060E060F06E906FD06FE07F609FA0B700BF3-0BF80BFA0C7F0CF10CF20D790F01-0F030F13-0F170F1A-0F1F0F340F360F380FBE-0FC50FC7-0FCC0FCE0FCF0FD5-0FD8109E109F13601390-1399194019E0-19FF1B61-1B6A1B74-1B7C210021012103-21062108210921142116-2118211E-2123212521272129212E213A213B214A214C214D214F2195-2199219C-219F21A121A221A421A521A7-21AD21AF-21CD21D021D121D321D5-21F32300-2307230C-231F2322-2328232B-237B237D-239A23B4-23DB23E2-23E82400-24262440-244A249C-24E92500-25B625B8-25C025C2-25F72600-266E2670-26CD26CF-26E126E326E8-26FF2701-27042706-2709270C-27272729-274B274D274F-27522756-275E2761-276727942798-27AF27B1-27BE2800-28FF2B00-2B2F2B452B462B50-2B592CE5-2CEA2E80-2E992E9B-2EF32F00-2FD52FF0-2FFB300430123013302030363037303E303F319031913196-319F31C0-31E33200-321E322A-32503260-327F328A-32B032C0-32FE3300-33FF4DC0-4DFFA490-A4C6A828-A82BA836A837A839AA77-AA79FDFDFFE4FFE8FFEDFFEEFFFCFFFD",Z:"002000A01680180E2000-200A20282029202F205F3000",Zs:"002000A01680180E2000-200A202F205F3000",Zl:"2028",Zp:"2029",C:"0000-001F007F-009F00AD03780379037F-0383038B038D03A20526-05300557055805600588058B-059005C8-05CF05EB-05EF05F5-0605061C061D0620065F06DD070E070F074B074C07B2-07BF07FB-07FF082E082F083F-08FF093A093B094F095609570973-097809800984098D098E0991099209A909B109B3-09B509BA09BB09C509C609C909CA09CF-09D609D8-09DB09DE09E409E509FC-0A000A040A0B-0A0E0A110A120A290A310A340A370A3A0A3B0A3D0A43-0A460A490A4A0A4E-0A500A52-0A580A5D0A5F-0A650A76-0A800A840A8E0A920AA90AB10AB40ABA0ABB0AC60ACA0ACE0ACF0AD1-0ADF0AE40AE50AF00AF2-0B000B040B0D0B0E0B110B120B290B310B340B3A0B3B0B450B460B490B4A0B4E-0B550B58-0B5B0B5E0B640B650B72-0B810B840B8B-0B8D0B910B96-0B980B9B0B9D0BA0-0BA20BA5-0BA70BAB-0BAD0BBA-0BBD0BC3-0BC50BC90BCE0BCF0BD1-0BD60BD8-0BE50BFB-0C000C040C0D0C110C290C340C3A-0C3C0C450C490C4E-0C540C570C5A-0C5F0C640C650C70-0C770C800C810C840C8D0C910CA90CB40CBA0CBB0CC50CC90CCE-0CD40CD7-0CDD0CDF0CE40CE50CF00CF3-0D010D040D0D0D110D290D3A-0D3C0D450D490D4E-0D560D58-0D5F0D640D650D76-0D780D800D810D840D97-0D990DB20DBC0DBE0DBF0DC7-0DC90DCB-0DCE0DD50DD70DE0-0DF10DF5-0E000E3B-0E3E0E5C-0E800E830E850E860E890E8B0E8C0E8E-0E930E980EA00EA40EA60EA80EA90EAC0EBA0EBE0EBF0EC50EC70ECE0ECF0EDA0EDB0EDE-0EFF0F480F6D-0F700F8C-0F8F0F980FBD0FCD0FD9-0FFF10C6-10CF10FD-10FF1249124E124F12571259125E125F1289128E128F12B112B612B712BF12C112C612C712D7131113161317135B-135E137D-137F139A-139F13F5-13FF169D-169F16F1-16FF170D1715-171F1737-173F1754-175F176D17711774-177F17B417B517DE17DF17EA-17EF17FA-17FF180F181A-181F1878-187F18AB-18AF18F6-18FF191D-191F192C-192F193C-193F1941-1943196E196F1975-197F19AC-19AF19CA-19CF19DB-19DD1A1C1A1D1A5F1A7D1A7E1A8A-1A8F1A9A-1A9F1AAE-1AFF1B4C-1B4F1B7D-1B7F1BAB-1BAD1BBA-1BFF1C38-1C3A1C4A-1C4C1C80-1CCF1CF3-1CFF1DE7-1DFC1F161F171F1E1F1F1F461F471F4E1F4F1F581F5A1F5C1F5E1F7E1F7F1FB51FC51FD41FD51FDC1FF01FF11FF51FFF200B-200F202A-202E2060-206F20722073208F2095-209F20B9-20CF20F1-20FF218A-218F23E9-23FF2427-243F244B-245F26CE26E226E4-26E727002705270A270B2728274C274E2753-2755275F27602795-279727B027BF27CB27CD-27CF2B4D-2B4F2B5A-2BFF2C2F2C5F2CF2-2CF82D26-2D2F2D66-2D6E2D70-2D7F2D97-2D9F2DA72DAF2DB72DBF2DC72DCF2DD72DDF2E32-2E7F2E9A2EF4-2EFF2FD6-2FEF2FFC-2FFF3040309730983100-3104312E-3130318F31B8-31BF31E4-31EF321F32FF4DB6-4DBF9FCC-9FFFA48D-A48FA4C7-A4CFA62C-A63FA660A661A674-A67BA698-A69FA6F8-A6FFA78D-A7FAA82C-A82FA83A-A83FA878-A87FA8C5-A8CDA8DA-A8DFA8FC-A8FFA954-A95EA97D-A97FA9CEA9DA-A9DDA9E0-A9FFAA37-AA3FAA4EAA4FAA5AAA5BAA7C-AA7FAAC3-AADAAAE0-ABBFABEEABEFABFA-ABFFD7A4-D7AFD7C7-D7CAD7FC-F8FFFA2EFA2FFA6EFA6FFADA-FAFFFB07-FB12FB18-FB1CFB37FB3DFB3FFB42FB45FBB2-FBD2FD40-FD4FFD90FD91FDC8-FDEFFDFEFDFFFE1A-FE1FFE27-FE2FFE53FE67FE6C-FE6FFE75FEFD-FF00FFBF-FFC1FFC8FFC9FFD0FFD1FFD8FFD9FFDD-FFDFFFE7FFEF-FFFBFFFEFFFF",Cc:"0000-001F007F-009F",Cf:"00AD0600-060306DD070F17B417B5200B-200F202A-202E2060-2064206A-206FFEFFFFF9-FFFB",Co:"E000-F8FF",Cs:"D800-DFFF",Cn:"03780379037F-0383038B038D03A20526-05300557055805600588058B-059005C8-05CF05EB-05EF05F5-05FF06040605061C061D0620065F070E074B074C07B2-07BF07FB-07FF082E082F083F-08FF093A093B094F095609570973-097809800984098D098E0991099209A909B109B3-09B509BA09BB09C509C609C909CA09CF-09D609D8-09DB09DE09E409E509FC-0A000A040A0B-0A0E0A110A120A290A310A340A370A3A0A3B0A3D0A43-0A460A490A4A0A4E-0A500A52-0A580A5D0A5F-0A650A76-0A800A840A8E0A920AA90AB10AB40ABA0ABB0AC60ACA0ACE0ACF0AD1-0ADF0AE40AE50AF00AF2-0B000B040B0D0B0E0B110B120B290B310B340B3A0B3B0B450B460B490B4A0B4E-0B550B58-0B5B0B5E0B640B650B72-0B810B840B8B-0B8D0B910B96-0B980B9B0B9D0BA0-0BA20BA5-0BA70BAB-0BAD0BBA-0BBD0BC3-0BC50BC90BCE0BCF0BD1-0BD60BD8-0BE50BFB-0C000C040C0D0C110C290C340C3A-0C3C0C450C490C4E-0C540C570C5A-0C5F0C640C650C70-0C770C800C810C840C8D0C910CA90CB40CBA0CBB0CC50CC90CCE-0CD40CD7-0CDD0CDF0CE40CE50CF00CF3-0D010D040D0D0D110D290D3A-0D3C0D450D490D4E-0D560D58-0D5F0D640D650D76-0D780D800D810D840D97-0D990DB20DBC0DBE0DBF0DC7-0DC90DCB-0DCE0DD50DD70DE0-0DF10DF5-0E000E3B-0E3E0E5C-0E800E830E850E860E890E8B0E8C0E8E-0E930E980EA00EA40EA60EA80EA90EAC0EBA0EBE0EBF0EC50EC70ECE0ECF0EDA0EDB0EDE-0EFF0F480F6D-0F700F8C-0F8F0F980FBD0FCD0FD9-0FFF10C6-10CF10FD-10FF1249124E124F12571259125E125F1289128E128F12B112B612B712BF12C112C612C712D7131113161317135B-135E137D-137F139A-139F13F5-13FF169D-169F16F1-16FF170D1715-171F1737-173F1754-175F176D17711774-177F17DE17DF17EA-17EF17FA-17FF180F181A-181F1878-187F18AB-18AF18F6-18FF191D-191F192C-192F193C-193F1941-1943196E196F1975-197F19AC-19AF19CA-19CF19DB-19DD1A1C1A1D1A5F1A7D1A7E1A8A-1A8F1A9A-1A9F1AAE-1AFF1B4C-1B4F1B7D-1B7F1BAB-1BAD1BBA-1BFF1C38-1C3A1C4A-1C4C1C80-1CCF1CF3-1CFF1DE7-1DFC1F161F171F1E1F1F1F461F471F4E1F4F1F581F5A1F5C1F5E1F7E1F7F1FB51FC51FD41FD51FDC1FF01FF11FF51FFF2065-206920722073208F2095-209F20B9-20CF20F1-20FF218A-218F23E9-23FF2427-243F244B-245F26CE26E226E4-26E727002705270A270B2728274C274E2753-2755275F27602795-279727B027BF27CB27CD-27CF2B4D-2B4F2B5A-2BFF2C2F2C5F2CF2-2CF82D26-2D2F2D66-2D6E2D70-2D7F2D97-2D9F2DA72DAF2DB72DBF2DC72DCF2DD72DDF2E32-2E7F2E9A2EF4-2EFF2FD6-2FEF2FFC-2FFF3040309730983100-3104312E-3130318F31B8-31BF31E4-31EF321F32FF4DB6-4DBF9FCC-9FFFA48D-A48FA4C7-A4CFA62C-A63FA660A661A674-A67BA698-A69FA6F8-A6FFA78D-A7FAA82C-A82FA83A-A83FA878-A87FA8C5-A8CDA8DA-A8DFA8FC-A8FFA954-A95EA97D-A97FA9CEA9DA-A9DDA9E0-A9FFAA37-AA3FAA4EAA4FAA5AAA5BAA7C-AA7FAAC3-AADAAAE0-ABBFABEEABEFABFA-ABFFD7A4-D7AFD7C7-D7CAD7FC-D7FFFA2EFA2FFA6EFA6FFADA-FAFFFB07-FB12FB18-FB1CFB37FB3DFB3FFB42FB45FBB2-FBD2FD40-FD4FFD90FD91FDC8-FDEFFDFEFDFFFE1A-FE1FFE27-FE2FFE53FE67FE6C-FE6FFE75FEFDFEFEFF00FFBF-FFC1FFC8FFC9FFD0FFD1FFD8FFD9FFDD-FFDFFFE7FFEF-FFF8FFFEFFFF"})}),ace.define("ace/token_iterator",["require","exports","module"],function(e,t,n){"use strict";var r=function(e,t,n){this.$session=e,this.$row=t,this.$rowTokens=e.getTokens(t);var r=e.getTokenAt(t,n);this.$tokenIndex=r?r.index:-1};(function(){this.stepBackward=function(){this.$tokenIndex-=1;while(this.$tokenIndex<0){this.$row-=1;if(this.$row<0)return this.$row=0,null;this.$rowTokens=this.$session.getTokens(this.$row),this.$tokenIndex=this.$rowTokens.length-1}return this.$rowTokens[this.$tokenIndex]},this.stepForward=function(){this.$tokenIndex+=1;var e;while(this.$tokenIndex>=this.$rowTokens.length){this.$row+=1,e||(e=this.$session.getLength());if(this.$row>=e)return this.$row=e-1,null;this.$rowTokens=this.$session.getTokens(this.$row),this.$tokenIndex=0}return this.$rowTokens[this.$tokenIndex]},this.getCurrentToken=function(){return this.$rowTokens[this.$tokenIndex]},this.getCurrentTokenRow=function(){return this.$row},this.getCurrentTokenColumn=function(){var e=this.$rowTokens,t=this.$tokenIndex,n=e[t].start;if(n!==undefined)return n;n=0;while(t>0)t-=1,n+=e[t].value.length;return n},this.getCurrentTokenPosition=function(){return{row:this.$row,column:this.getCurrentTokenColumn()}}}).call(r.prototype),t.TokenIterator=r}),ace.define("ace/mode/text",["require","exports","module","ace/tokenizer","ace/mode/text_highlight_rules","ace/mode/behaviour","ace/unicode","ace/lib/lang","ace/token_iterator","ace/range"],function(e,t,n){"use strict";var r=e("../tokenizer").Tokenizer,i=e("./text_highlight_rules").TextHighlightRules,s=e("./behaviour").Behaviour,o=e("../unicode"),u=e("../lib/lang"),a=e("../token_iterator").TokenIterator,f=e("../range").Range,l=function(){this.HighlightRules=i,this.$behaviour=new s};(function(){this.tokenRe=new RegExp("^["+o.packages.L+o.packages.Mn+o.packages.Mc+o.packages.Nd+o.packages.Pc+"\\$_]+","g"),this.nonTokenRe=new RegExp("^(?:[^"+o.packages.L+o.packages.Mn+o.packages.Mc+o.packages.Nd+o.packages.Pc+"\\$_]|\\s])+","g"),this.getTokenizer=function(){return this.$tokenizer||(this.$highlightRules=this.$highlightRules||new this.HighlightRules,this.$tokenizer=new r(this.$highlightRules.getRules())),this.$tokenizer},this.lineCommentStart="",this.blockComment="",this.toggleCommentLines=function(e,t,n,r){function w(e){for(var t=n;t<=r;t++)e(i.getLine(t),t)}var i=t.doc,s=!0,o=!0,a=Infinity,f=t.getTabSize(),l=!1;if(!this.lineCommentStart){if(!this.blockComment)return!1;var c=this.blockComment.start,h=this.blockComment.end,p=new RegExp("^(\\s*)(?:"+u.escapeRegExp(c)+")"),d=new RegExp("(?:"+u.escapeRegExp(h)+")\\s*$"),v=function(e,t){if(g(e,t))return;if(!s||/\S/.test(e))i.insertInLine({row:t,column:e.length},h),i.insertInLine({row:t,column:a},c)},m=function(e,t){var n;(n=e.match(d))&&i.removeInLine(t,e.length-n[0].length,e.length),(n=e.match(p))&&i.removeInLine(t,n[1].length,n[0].length)},g=function(e,n){if(p.test(e))return!0;var r=t.getTokens(n);for(var i=0;i<r.length;i++)if(r[i].type==="comment")return!0}}else{if(Array.isArray(this.lineCommentStart))var p=this.lineCommentStart.map(u.escapeRegExp).join("|"),c=this.lineCommentStart[0];else var p=u.escapeRegExp(this.lineCommentStart),c=this.lineCommentStart;p=new RegExp("^(\\s*)(?:"+p+") ?"),l=t.getUseSoftTabs();var m=function(e,t){var n=e.match(p);if(!n)return;var r=n[1].length,s=n[0].length;!b(e,r,s)&&n[0][s-1]==" "&&s--,i.removeInLine(t,r,s)},y=c+" ",v=function(e,t){if(!s||/\S/.test(e))b(e,a,a)?i.insertInLine({row:t,column:a},y):i.insertInLine({row:t,column:a},c)},g=function(e,t){return p.test(e)},b=function(e,t,n){var r=0;while(t--&&e.charAt(t)==" ")r++;if(r%f!=0)return!1;var r=0;while(e.charAt(n++)==" ")r++;return f>2?r%f!=f-1:r%f==0}}var E=Infinity;w(function(e,t){var n=e.search(/\S/);n!==-1?(n<a&&(a=n),o&&!g(e,t)&&(o=!1)):E>e.length&&(E=e.length)}),a==Infinity&&(a=E,s=!1,o=!1),l&&a%f!=0&&(a=Math.floor(a/f)*f),w(o?m:v)},this.toggleBlockComment=function(e,t,n,r){var i=this.blockComment;if(!i)return;!i.start&&i[0]&&(i=i[0]);var s=new a(t,r.row,r.column),o=s.getCurrentToken(),u=t.selection,l=t.selection.toOrientedRange(),c,h;if(o&&/comment/.test(o.type)){var p,d;while(o&&/comment/.test(o.type)){var v=o.value.indexOf(i.start);if(v!=-1){var m=s.getCurrentTokenRow(),g=s.getCurrentTokenColumn()+v;p=new f(m,g,m,g+i.start.length);break}o=s.stepBackward()}var s=new a(t,r.row,r.column),o=s.getCurrentToken();while(o&&/comment/.test(o.type)){var v=o.value.indexOf(i.end);if(v!=-1){var m=s.getCurrentTokenRow(),g=s.getCurrentTokenColumn()+v;d=new f(m,g,m,g+i.end.length);break}o=s.stepForward()}d&&t.remove(d),p&&(t.remove(p),c=p.start.row,h=-i.start.length)}else h=i.start.length,c=n.start.row,t.insert(n.end,i.end),t.insert(n.start,i.start);l.start.row==c&&(l.start.column+=h),l.end.row==c&&(l.end.column+=h),t.selection.fromOrientedRange(l)},this.getNextLineIndent=function(e,t,n){return this.$getIndent(t)},this.checkOutdent=function(e,t,n){return!1},this.autoOutdent=function(e,t,n){},this.$getIndent=function(e){return e.match(/^\s*/)[0]},this.createWorker=function(e){return null},this.createModeDelegates=function(e){this.$embeds=[],this.$modes={};for(var t in e)e[t]&&(this.$embeds.push(t),this.$modes[t]=new e[t]);var n=["toggleBlockComment","toggleCommentLines","getNextLineIndent","checkOutdent","autoOutdent","transformAction","getCompletions"];for(var t=0;t<n.length;t++)(function(e){var r=n[t],i=e[r];e[n[t]]=function(){return this.$delegator(r,arguments,i)}})(this)},this.$delegator=function(e,t,n){var r=t[0];typeof r!="string"&&(r=r[0]);for(var i=0;i<this.$embeds.length;i++){if(!this.$modes[this.$embeds[i]])continue;var s=r.split(this.$embeds[i]);if(!s[0]&&s[1]){t[0]=s[1];var o=this.$modes[this.$embeds[i]];return o[e].apply(o,t)}}var u=n.apply(this,t);return n?u:undefined},this.transformAction=function(e,t,n,r,i){if(this.$behaviour){var s=this.$behaviour.getBehaviours();for(var o in s)if(s[o][t]){var u=s[o][t].apply(this,arguments);if(u)return u}}},this.getKeywords=function(e){if(!this.completionKeywords){var t=this.$tokenizer.rules,n=[];for(var r in t){var i=t[r];for(var s=0,o=i.length;s<o;s++)if(typeof i[s].token=="string")/keyword|support|storage/.test(i[s].token)&&n.push(i[s].regex);else if(typeof i[s].token=="object")for(var u=0,a=i[s].token.length;u<a;u++)if(/keyword|support|storage/.test(i[s].token[u])){var r=i[s].regex.match(/\(.+?\)/g)[u];n.push(r.substr(1,r.length-2))}}this.completionKeywords=n}return e?n.concat(this.$keywordList||[]):this.$keywordList},this.$createKeywordList=function(){return this.$highlightRules||this.getTokenizer(),this.$keywordList=this.$highlightRules.$keywordList||[]},this.getCompletions=function(e,t,n,r){var i=this.$keywordList||this.$createKeywordList();return i.map(function(e){return{name:e,value:e,score:0,meta:"keyword"}})},this.$id="ace/mode/text"}).call(l.prototype),t.Mode=l}),ace.define("ace/apply_delta",["require","exports","module"],function(e,t,n){"use strict";function r(e,t){throw console.log("Invalid Delta:",e),"Invalid Delta: "+t}function i(e,t){return t.row>=0&&t.row<e.length&&t.column>=0&&t.column<=e[t.row].length}function s(e,t){t.action!="insert"&&t.action!="remove"&&r(t,"delta.action must be 'insert' or 'remove'"),t.lines instanceof Array||r(t,"delta.lines must be an Array"),(!t.start||!t.end)&&r(t,"delta.start/end must be an present");var n=t.start;i(e,t.start)||r(t,"delta.start must be contained in document");var s=t.end;t.action=="remove"&&!i(e,s)&&r(t,"delta.end must contained in document for 'remove' actions");var o=s.row-n.row,u=s.column-(o==0?n.column:0);(o!=t.lines.length-1||t.lines[o].length!=u)&&r(t,"delta.range must match delta lines")}t.applyDelta=function(e,t,n){var r=t.start.row,i=t.start.column,s=e[r]||"";switch(t.action){case"insert":var o=t.lines;if(o.length===1)e[r]=s.substring(0,i)+t.lines[0]+s.substring(i);else{var u=[r,1].concat(t.lines);e.splice.apply(e,u),e[r]=s.substring(0,i)+e[r],e[r+t.lines.length-1]+=s.substring(i)}break;case"remove":var a=t.end.column,f=t.end.row;r===f?e[r]=s.substring(0,i)+s.substring(a):e.splice(r,f-r+1,s.substring(0,i)+e[f].substring(a))}}}),ace.define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=t.Anchor=function(e,t,n){this.$onChange=this.onChange.bind(this),this.attach(e),typeof n=="undefined"?this.setPosition(t.row,t.column):this.setPosition(t,n)};(function(){function e(e,t,n){var r=n?e.column<=t.column:e.column<t.column;return e.row<t.row||e.row==t.row&&r}function t(t,n,r){var i=t.action=="insert",s=(i?1:-1)*(t.end.row-t.start.row),o=(i?1:-1)*(t.end.column-t.start.column),u=t.start,a=i?u:t.end;return e(n,u,r)?{row:n.row,column:n.column}:e(a,n,!r)?{row:n.row+s,column:n.column+(n.row==a.row?o:0)}:{row:u.row,column:u.column}}r.implement(this,i),this.getPosition=function(){return this.$clipPositionToDocument(this.row,this.column)},this.getDocument=function(){return this.document},this.$insertRight=!1,this.onChange=function(e){if(e.start.row==e.end.row&&e.start.row!=this.row)return;if(e.start.row>this.row)return;var n=t(e,{row:this.row,column:this.column},this.$insertRight);this.setPosition(n.row,n.column,!0)},this.setPosition=function(e,t,n){var r;n?r={row:e,column:t}:r=this.$clipPositionToDocument(e,t);if(this.row==r.row&&this.column==r.column)return;var i={row:this.row,column:this.column};this.row=r.row,this.column=r.column,this._signal("change",{old:i,value:r})},this.detach=function(){this.document.removeEventListener("change",this.$onChange)},this.attach=function(e){this.document=e||this.document,this.document.on("change",this.$onChange)},this.$clipPositionToDocument=function(e,t){var n={};return e>=this.document.getLength()?(n.row=Math.max(0,this.document.getLength()-1),n.column=this.document.getLine(n.row).length):e<0?(n.row=0,n.column=0):(n.row=e,n.column=Math.min(this.document.getLine(n.row).length,Math.max(0,t))),t<0&&(n.column=0),n}}).call(s.prototype)}),ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./apply_delta").applyDelta,s=e("./lib/event_emitter").EventEmitter,o=e("./range").Range,u=e("./anchor").Anchor,a=function(e){this.$lines=[""],e.length===0?this.$lines=[""]:Array.isArray(e)?this.insertMergedLines({row:0,column:0},e):this.insert({row:0,column:0},e)};(function(){r.implement(this,s),this.setValue=function(e){var t=this.getLength()-1;this.remove(new o(0,0,t,this.getLine(t).length)),this.insert({row:0,column:0},e)},this.getValue=function(){return this.getAllLines().join(this.getNewLineCharacter())},this.createAnchor=function(e,t){return new u(this,e,t)},"aaa".split(/a/).length===0?this.$split=function(e){return e.replace(/\r\n|\r/g,"\n").split("\n")}:this.$split=function(e){return e.split(/\r\n|\r|\n/)},this.$detectNewLine=function(e){var t=e.match(/^.*?(\r\n|\r|\n)/m);this.$autoNewLine=t?t[1]:"\n",this._signal("changeNewLineMode")},this.getNewLineCharacter=function(){switch(this.$newLineMode){case"windows":return"\r\n";case"unix":return"\n";default:return this.$autoNewLine||"\n"}},this.$autoNewLine="",this.$newLineMode="auto",this.setNewLineMode=function(e){if(this.$newLineMode===e)return;this.$newLineMode=e,this._signal("changeNewLineMode")},this.getNewLineMode=function(){return this.$newLineMode},this.isNewLine=function(e){return e=="\r\n"||e=="\r"||e=="\n"},this.getLine=function(e){return this.$lines[e]||""},this.getLines=function(e,t){return this.$lines.slice(e,t+1)},this.getAllLines=function(){return this.getLines(0,this.getLength())},this.getLength=function(){return this.$lines.length},this.getTextRange=function(e){return this.getLinesForRange(e).join(this.getNewLineCharacter())},this.getLinesForRange=function(e){var t;if(e.start.row===e.end.row)t=[this.getLine(e.start.row).substring(e.start.column,e.end.column)];else{t=this.getLines(e.start.row,e.end.row),t[0]=(t[0]||"").substring(e.start.column);var n=t.length-1;e.end.row-e.start.row==n&&(t[n]=t[n].substring(0,e.end.column))}return t},this.insertLines=function(e,t){return console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."),this.insertFullLines(e,t)},this.removeLines=function(e,t){return console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."),this.removeFullLines(e,t)},this.insertNewLine=function(e){return console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead."),this.insertMergedLines(e,["",""])},this.insert=function(e,t){return this.getLength()<=1&&this.$detectNewLine(t),this.insertMergedLines(e,this.$split(t))},this.insertInLine=function(e,t){var n=this.clippedPos(e.row,e.column),r=this.pos(e.row,e.column+t.length);return this.applyDelta({start:n,end:r,action:"insert",lines:[t]},!0),this.clonePos(r)},this.clippedPos=function(e,t){var n=this.getLength();e===undefined?e=n:e<0?e=0:e>=n&&(e=n-1,t=undefined);var r=this.getLine(e);return t==undefined&&(t=r.length),t=Math.min(Math.max(t,0),r.length),{row:e,column:t}},this.clonePos=function(e){return{row:e.row,column:e.column}},this.pos=function(e,t){return{row:e,column:t}},this.$clipPosition=function(e){var t=this.getLength();return e.row>=t?(e.row=Math.max(0,t-1),e.column=this.getLine(t-1).length):(e.row=Math.max(0,e.row),e.column=Math.min(Math.max(e.column,0),this.getLine(e.row).length)),e},this.insertFullLines=function(e,t){e=Math.min(Math.max(e,0),this.getLength());var n=0;e<this.getLength()?(t=t.concat([""]),n=0):(t=[""].concat(t),e--,n=this.$lines[e].length),this.insertMergedLines({row:e,column:n},t)},this.insertMergedLines=function(e,t){var n=this.clippedPos(e.row,e.column),r={row:n.row+t.length-1,column:(t.length==1?n.column:0)+t[t.length-1].length};return this.applyDelta({start:n,end:r,action:"insert",lines:t}),this.clonePos(r)},this.remove=function(e){var t=this.clippedPos(e.start.row,e.start.column),n=this.clippedPos(e.end.row,e.end.column);return this.applyDelta({start:t,end:n,action:"remove",lines:this.getLinesForRange({start:t,end:n})}),this.clonePos(t)},this.removeInLine=function(e,t,n){var r=this.clippedPos(e,t),i=this.clippedPos(e,n);return this.applyDelta({start:r,end:i,action:"remove",lines:this.getLinesForRange({start:r,end:i})},!0),this.clonePos(r)},this.removeFullLines=function(e,t){e=Math.min(Math.max(0,e),this.getLength()-1),t=Math.min(Math.max(0,t),this.getLength()-1);var n=t==this.getLength()-1&&e>0,r=t<this.getLength()-1,i=n?e-1:e,s=n?this.getLine(i).length:0,u=r?t+1:t,a=r?0:this.getLine(u).length,f=new o(i,s,u,a),l=this.$lines.slice(e,t+1);return this.applyDelta({start:f.start,end:f.end,action:"remove",lines:this.getLinesForRange(f)}),l},this.removeNewLine=function(e){e<this.getLength()-1&&e>=0&&this.applyDelta({start:this.pos(e,this.getLine(e).length),end:this.pos(e+1,0),action:"remove",lines:["",""]})},this.replace=function(e,t){e instanceof o||(e=o.fromPoints(e.start,e.end));if(t.length===0&&e.isEmpty())return e.start;if(t==this.getTextRange(e))return e.end;this.remove(e);var n;return t?n=this.insert(e.start,t):n=e.start,n},this.applyDeltas=function(e){for(var t=0;t<e.length;t++)this.applyDelta(e[t])},this.revertDeltas=function(e){for(var t=e.length-1;t>=0;t--)this.revertDelta(e[t])},this.applyDelta=function(e,t){var n=e.action=="insert";if(n?e.lines.length<=1&&!e.lines[0]:!o.comparePoints(e.start,e.end))return;n&&e.lines.length>2e4&&this.$splitAndapplyLargeDelta(e,2e4),i(this.$lines,e,t),this._signal("change",e)},this.$splitAndapplyLargeDelta=function(e,t){var n=e.lines,r=n.length,i=e.start.row,s=e.start.column,o=0,u=0;do{o=u,u+=t-1;var a=n.slice(o,u);if(u>r){e.lines=a,e.start.row=i+o,e.start.column=s;break}a.push(""),this.applyDelta({start:this.pos(i+o,s),end:this.pos(i+u,s=0),action:e.action,lines:a},!0)}while(!0)},this.revertDelta=function(e){this.applyDelta({start:this.clonePos(e.start),end:this.clonePos(e.end),action:e.action=="insert"?"remove":"insert",lines:e.lines.slice()})},this.indexToPosition=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length;for(var i=t||0,s=n.length;i<s;i++){e-=n[i].length+r;if(e<0)return{row:i,column:e+n[i].length+r}}return{row:s-1,column:n[s-1].length}},this.positionToIndex=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length,i=0,s=Math.min(e.row,n.length);for(var o=t||0;o<s;++o)i+=n[o].length+r;return i+e.column}}).call(a.prototype),t.Document=a}),ace.define("ace/background_tokenizer",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=function(e,t){this.running=!1,this.lines=[],this.states=[],this.currentLine=0,this.tokenizer=e;var n=this;this.$worker=function(){if(!n.running)return;var e=new Date,t=n.currentLine,r=-1,i=n.doc,s=t;while(n.lines[t])t++;var o=i.getLength(),u=0;n.running=!1;while(t<o){n.$tokenizeRow(t),r=t;do t++;while(n.lines[t]);u++;if(u%5===0&&new Date-e>20){n.running=setTimeout(n.$worker,20);break}}n.currentLine=t,s<=r&&n.fireUpdateEvent(s,r)}};(function(){r.implement(this,i),this.setTokenizer=function(e){this.tokenizer=e,this.lines=[],this.states=[],this.start(0)},this.setDocument=function(e){this.doc=e,this.lines=[],this.states=[],this.stop()},this.fireUpdateEvent=function(e,t){var n={first:e,last:t};this._signal("update",{data:n})},this.start=function(e){this.currentLine=Math.min(e||0,this.currentLine,this.doc.getLength()),this.lines.splice(this.currentLine,this.lines.length),this.states.splice(this.currentLine,this.states.length),this.stop(),this.running=setTimeout(this.$worker,700)},this.scheduleStart=function(){this.running||(this.running=setTimeout(this.$worker,700))},this.$updateOnChange=function(e){var t=e.start.row,n=e.end.row-t;if(n===0)this.lines[t]=null;else if(e.action=="remove")this.lines.splice(t,n+1,null),this.states.splice(t,n+1,null);else{var r=Array(n+1);r.unshift(t,1),this.lines.splice.apply(this.lines,r),this.states.splice.apply(this.states,r)}this.currentLine=Math.min(t,this.currentLine,this.doc.getLength()),this.stop()},this.stop=function(){this.running&&clearTimeout(this.running),this.running=!1},this.getTokens=function(e){return this.lines[e]||this.$tokenizeRow(e)},this.getState=function(e){return this.currentLine==e&&this.$tokenizeRow(e),this.states[e]||"start"},this.$tokenizeRow=function(e){var t=this.doc.getLine(e),n=this.states[e-1],r=this.tokenizer.getLineTokens(t,n,e);return this.states[e]+""!=r.state+""?(this.states[e]=r.state,this.lines[e+1]=null,this.currentLine>e+1&&(this.currentLine=e+1)):this.currentLine==e&&(this.currentLine=e+1),this.lines[e]=r.tokens}}).call(s.prototype),t.BackgroundTokenizer=s}),ace.define("ace/search_highlight",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/range"],function(e,t,n){"use strict";var r=e("./lib/lang"),i=e("./lib/oop"),s=e("./range").Range,o=function(e,t,n){this.setRegexp(e),this.clazz=t,this.type=n||"text"};(function(){this.MAX_RANGES=500,this.setRegexp=function(e){if(this.regExp+""==e+"")return;this.regExp=e,this.cache=[]},this.update=function(e,t,n,i){if(!this.regExp)return;var o=i.firstRow,u=i.lastRow;for(var a=o;a<=u;a++){var f=this.cache[a];f==null&&(f=r.getMatchOffsets(n.getLine(a),this.regExp),f.length>this.MAX_RANGES&&(f=f.slice(0,this.MAX_RANGES)),f=f.map(function(e){return new s(a,e.offset,a,e.offset+e.length)}),this.cache[a]=f.length?f:"");for(var l=f.length;l--;)t.drawSingleLineMarker(e,f[l].toScreenRange(n),this.clazz,i)}}}).call(o.prototype),t.SearchHighlight=o}),ace.define("ace/edit_session/fold_line",["require","exports","module","ace/range"],function(e,t,n){"use strict";function i(e,t){this.foldData=e,Array.isArray(t)?this.folds=t:t=this.folds=[t];var n=t[t.length-1];this.range=new r(t[0].start.row,t[0].start.column,n.end.row,n.end.column),this.start=this.range.start,this.end=this.range.end,this.folds.forEach(function(e){e.setFoldLine(this)},this)}var r=e("../range").Range;(function(){this.shiftRow=function(e){this.start.row+=e,this.end.row+=e,this.folds.forEach(function(t){t.start.row+=e,t.end.row+=e})},this.addFold=function(e){if(e.sameRow){if(e.start.row<this.startRow||e.endRow>this.endRow)throw new Error("Can't add a fold to this FoldLine as it has no connection");this.folds.push(e),this.folds.sort(function(e,t){return-e.range.compareEnd(t.start.row,t.start.column)}),this.range.compareEnd(e.start.row,e.start.column)>0?(this.end.row=e.end.row,this.end.column=e.end.column):this.range.compareStart(e.end.row,e.end.column)<0&&(this.start.row=e.start.row,this.start.column=e.start.column)}else if(e.start.row==this.end.row)this.folds.push(e),this.end.row=e.end.row,this.end.column=e.end.column;else{if(e.end.row!=this.start.row)throw new Error("Trying to add fold to FoldRow that doesn't have a matching row");this.folds.unshift(e),this.start.row=e.start.row,this.start.column=e.start.column}e.foldLine=this},this.containsRow=function(e){return e>=this.start.row&&e<=this.end.row},this.walk=function(e,t,n){var r=0,i=this.folds,s,o,u,a=!0;t==null&&(t=this.end.row,n=this.end.column);for(var f=0;f<i.length;f++){s=i[f],o=s.range.compareStart(t,n);if(o==-1){e(null,t,n,r,a);return}u=e(null,s.start.row,s.start.column,r,a),u=!u&&e(s.placeholder,s.start.row,s.start.column,r);if(u||o===0)return;a=!s.sameRow,r=s.end.column}e(null,t,n,r,a)},this.getNextFoldTo=function(e,t){var n,r;for(var i=0;i<this.folds.length;i++){n=this.folds[i],r=n.range.compareEnd(e,t);if(r==-1)return{fold:n,kind:"after"};if(r===0)return{fold:n,kind:"inside"}}return null},this.addRemoveChars=function(e,t,n){var r=this.getNextFoldTo(e,t),i,s;if(r){i=r.fold;if(r.kind=="inside"&&i.start.column!=t&&i.start.row!=e)window.console&&window.console.log(e,t,i);else if(i.start.row==e){s=this.folds;var o=s.indexOf(i);o===0&&(this.start.column+=n);for(o;o<s.length;o++){i=s[o],i.start.column+=n;if(!i.sameRow)return;i.end.column+=n}this.end.column+=n}}},this.split=function(e,t){var n=this.getNextFoldTo(e,t);if(!n||n.kind=="inside")return null;var r=n.fold,s=this.folds,o=this.foldData,u=s.indexOf(r),a=s[u-1];this.end.row=a.end.row,this.end.column=a.end.column,s=s.splice(u,s.length-u);var f=new i(o,s);return o.splice(o.indexOf(this)+1,0,f),f},this.merge=function(e){var t=e.folds;for(var n=0;n<t.length;n++)this.addFold(t[n]);var r=this.foldData;r.splice(r.indexOf(e),1)},this.toString=function(){var e=[this.range.toString()+": ["];return this.folds.forEach(function(t){e.push("  "+t.toString())}),e.push("]"),e.join("\n")},this.idxToPosition=function(e){var t=0;for(var n=0;n<this.folds.length;n++){var r=this.folds[n];e-=r.start.column-t;if(e<0)return{row:r.start.row,column:r.start.column+e};e-=r.placeholder.length;if(e<0)return r.start;t=r.end.column}return{row:this.end.row,column:this.end.column+e}}}).call(i.prototype),t.FoldLine=i}),ace.define("ace/range_list",["require","exports","module","ace/range"],function(e,t,n){"use strict";var r=e("./range").Range,i=r.comparePoints,s=function(){this.ranges=[]};(function(){this.comparePoints=i,this.pointIndex=function(e,t,n){var r=this.ranges;for(var s=n||0;s<r.length;s++){var o=r[s],u=i(e,o.end);if(u>0)continue;var a=i(e,o.start);return u===0?t&&a!==0?-s-2:s:a>0||a===0&&!t?s:-s-1}return-s-1},this.add=function(e){var t=!e.isEmpty(),n=this.pointIndex(e.start,t);n<0&&(n=-n-1);var r=this.pointIndex(e.end,t,n);return r<0?r=-r-1:r++,this.ranges.splice(n,r-n,e)},this.addList=function(e){var t=[];for(var n=e.length;n--;)t.push.apply(t,this.add(e[n]));return t},this.substractPoint=function(e){var t=this.pointIndex(e);if(t>=0)return this.ranges.splice(t,1)},this.merge=function(){var e=[],t=this.ranges;t=t.sort(function(e,t){return i(e.start,t.start)});var n=t[0],r;for(var s=1;s<t.length;s++){r=n,n=t[s];var o=i(r.end,n.start);if(o<0)continue;if(o==0&&!r.isEmpty()&&!n.isEmpty())continue;i(r.end,n.end)<0&&(r.end.row=n.end.row,r.end.column=n.end.column),t.splice(s,1),e.push(n),n=r,s--}return this.ranges=t,e},this.contains=function(e,t){return this.pointIndex({row:e,column:t})>=0},this.containsPoint=function(e){return this.pointIndex(e)>=0},this.rangeAtPoint=function(e){var t=this.pointIndex(e);if(t>=0)return this.ranges[t]},this.clipRows=function(e,t){var n=this.ranges;if(n[0].start.row>t||n[n.length-1].start.row<e)return[];var r=this.pointIndex({row:e,column:0});r<0&&(r=-r-1);var i=this.pointIndex({row:t,column:0},r);i<0&&(i=-i-1);var s=[];for(var o=r;o<i;o++)s.push(n[o]);return s},this.removeAll=function(){return this.ranges.splice(0,this.ranges.length)},this.attach=function(e){this.session&&this.detach(),this.session=e,this.onChange=this.$onChange.bind(this),this.session.on("change",this.onChange)},this.detach=function(){if(!this.session)return;this.session.removeListener("change",this.onChange),this.session=null},this.$onChange=function(e){if(e.action=="insert")var t=e.start,n=e.end;else var n=e.start,t=e.end;var r=t.row,i=n.row,s=i-r,o=-t.column+n.column,u=this.ranges;for(var a=0,f=u.length;a<f;a++){var l=u[a];if(l.end.row<r)continue;if(l.start.row>r)break;l.start.row==r&&l.start.column>=t.column&&(l.start.column!=t.column||!this.$insertRight)&&(l.start.column+=o,l.start.row+=s);if(l.end.row==r&&l.end.column>=t.column){if(l.end.column==t.column&&this.$insertRight)continue;l.end.column==t.column&&o>0&&a<f-1&&l.end.column>l.start.column&&l.end.column==u[a+1].start.column&&(l.end.column-=o),l.end.column+=o,l.end.row+=s}}if(s!=0&&a<f)for(;a<f;a++){var l=u[a];l.start.row+=s,l.end.row+=s}}}).call(s.prototype),t.RangeList=s}),ace.define("ace/edit_session/fold",["require","exports","module","ace/range","ace/range_list","ace/lib/oop"],function(e,t,n){"use strict";function u(e,t){e.row-=t.row,e.row==0&&(e.column-=t.column)}function a(e,t){u(e.start,t),u(e.end,t)}function f(e,t){e.row==0&&(e.column+=t.column),e.row+=t.row}function l(e,t){f(e.start,t),f(e.end,t)}var r=e("../range").Range,i=e("../range_list").RangeList,s=e("../lib/oop"),o=t.Fold=function(e,t){this.foldLine=null,this.placeholder=t,this.range=e,this.start=e.start,this.end=e.end,this.sameRow=e.start.row==e.end.row,this.subFolds=this.ranges=[]};s.inherits(o,i),function(){this.toString=function(){return'"'+this.placeholder+'" '+this.range.toString()},this.setFoldLine=function(e){this.foldLine=e,this.subFolds.forEach(function(t){t.setFoldLine(e)})},this.clone=function(){var e=this.range.clone(),t=new o(e,this.placeholder);return this.subFolds.forEach(function(e){t.subFolds.push(e.clone())}),t.collapseChildren=this.collapseChildren,t},this.addSubFold=function(e){if(this.range.isEqual(e))return;if(!this.range.containsRange(e))throw new Error("A fold can't intersect already existing fold"+e.range+this.range);a(e,this.start);var t=e.start.row,n=e.start.column;for(var r=0,i=-1;r<this.subFolds.length;r++){i=this.subFolds[r].range.compare(t,n);if(i!=1)break}var s=this.subFolds[r];if(i==0)return s.addSubFold(e);var t=e.range.end.row,n=e.range.end.column;for(var o=r,i=-1;o<this.subFolds.length;o++){i=this.subFolds[o].range.compare(t,n);if(i!=1)break}var u=this.subFolds[o];if(i==0)throw new Error("A fold can't intersect already existing fold"+e.range+this.range);var f=this.subFolds.splice(r,o-r,e);return e.setFoldLine(this.foldLine),e},this.restoreRange=function(e){return l(e,this.start)}}.call(o.prototype)}),ace.define("ace/edit_session/folding",["require","exports","module","ace/range","ace/edit_session/fold_line","ace/edit_session/fold","ace/token_iterator"],function(e,t,n){"use strict";function u(){this.getFoldAt=function(e,t,n){var r=this.getFoldLine(e);if(!r)return null;var i=r.folds;for(var s=0;s<i.length;s++){var o=i[s];if(o.range.contains(e,t)){if(n==1&&o.range.isEnd(e,t))continue;if(n==-1&&o.range.isStart(e,t))continue;return o}}},this.getFoldsInRange=function(e){var t=e.start,n=e.end,r=this.$foldData,i=[];t.column+=1,n.column-=1;for(var s=0;s<r.length;s++){var o=r[s].range.compareRange(e);if(o==2)continue;if(o==-2)break;var u=r[s].folds;for(var a=0;a<u.length;a++){var f=u[a];o=f.range.compareRange(e);if(o==-2)break;if(o==2)continue;if(o==42)break;i.push(f)}}return t.column-=1,n.column+=1,i},this.getFoldsInRangeList=function(e){if(Array.isArray(e)){var t=[];e.forEach(function(e){t=t.concat(this.getFoldsInRange(e))},this)}else var t=this.getFoldsInRange(e);return t},this.getAllFolds=function(){var e=[],t=this.$foldData;for(var n=0;n<t.length;n++)for(var r=0;r<t[n].folds.length;r++)e.push(t[n].folds[r]);return e},this.getFoldStringAt=function(e,t,n,r){r=r||this.getFoldLine(e);if(!r)return null;var i={end:{column:0}},s,o;for(var u=0;u<r.folds.length;u++){o=r.folds[u];var a=o.range.compareEnd(e,t);if(a==-1){s=this.getLine(o.start.row).substring(i.end.column,o.start.column);break}if(a===0)return null;i=o}return s||(s=this.getLine(o.start.row).substring(i.end.column)),n==-1?s.substring(0,t-i.end.column):n==1?s.substring(t-i.end.column):s},this.getFoldLine=function(e,t){var n=this.$foldData,r=0;t&&(r=n.indexOf(t)),r==-1&&(r=0);for(r;r<n.length;r++){var i=n[r];if(i.start.row<=e&&i.end.row>=e)return i;if(i.end.row>e)return null}return null},this.getNextFoldLine=function(e,t){var n=this.$foldData,r=0;t&&(r=n.indexOf(t)),r==-1&&(r=0);for(r;r<n.length;r++){var i=n[r];if(i.end.row>=e)return i}return null},this.getFoldedRowCount=function(e,t){var n=this.$foldData,r=t-e+1;for(var i=0;i<n.length;i++){var s=n[i],o=s.end.row,u=s.start.row;if(o>=t){u<t&&(u>=e?r-=t-u:r=0);break}o>=e&&(u>=e?r-=o-u:r-=o-e+1)}return r},this.$addFoldLine=function(e){return this.$foldData.push(e),this.$foldData.sort(function(e,t){return e.start.row-t.start.row}),e},this.addFold=function(e,t){var n=this.$foldData,r=!1,o;e instanceof s?o=e:(o=new s(t,e),o.collapseChildren=t.collapseChildren),this.$clipRangeToDocument(o.range);var u=o.start.row,a=o.start.column,f=o.end.row,l=o.end.column;if(u<f||u==f&&a<=l-2){var c=this.getFoldAt(u,a,1),h=this.getFoldAt(f,l,-1);if(c&&h==c)return c.addSubFold(o);c&&!c.range.isStart(u,a)&&this.removeFold(c),h&&!h.range.isEnd(f,l)&&this.removeFold(h);var p=this.getFoldsInRange(o.range);p.length>0&&(this.removeFolds(p),p.forEach(function(e){o.addSubFold(e)}));for(var d=0;d<n.length;d++){var v=n[d];if(f==v.start.row){v.addFold(o),r=!0;break}if(u==v.end.row){v.addFold(o),r=!0;if(!o.sameRow){var m=n[d+1];if(m&&m.start.row==f){v.merge(m);break}}break}if(f<=v.start.row)break}return r||(v=this.$addFoldLine(new i(this.$foldData,o))),this.$useWrapMode?this.$updateWrapData(v.start.row,v.start.row):this.$updateRowLengthCache(v.start.row,v.start.row),this.$modified=!0,this._signal("changeFold",{data:o,action:"add"}),o}throw new Error("The range has to be at least 2 characters width")},this.addFolds=function(e){e.forEach(function(e){this.addFold(e)},this)},this.removeFold=function(e){var t=e.foldLine,n=t.start.row,r=t.end.row,i=this.$foldData,s=t.folds;if(s.length==1)i.splice(i.indexOf(t),1);else if(t.range.isEnd(e.end.row,e.end.column))s.pop(),t.end.row=s[s.length-1].end.row,t.end.column=s[s.length-1].end.column;else if(t.range.isStart(e.start.row,e.start.column))s.shift(),t.start.row=s[0].start.row,t.start.column=s[0].start.column;else if(e.sameRow)s.splice(s.indexOf(e),1);else{var o=t.split(e.start.row,e.start.column);s=o.folds,s.shift(),o.start.row=s[0].start.row,o.start.column=s[0].start.column}this.$updating||(this.$useWrapMode?this.$updateWrapData(n,r):this.$updateRowLengthCache(n,r)),this.$modified=!0,this._signal("changeFold",{data:e,action:"remove"})},this.removeFolds=function(e){var t=[];for(var n=0;n<e.length;n++)t.push(e[n]);t.forEach(function(e){this.removeFold(e)},this),this.$modified=!0},this.expandFold=function(e){this.removeFold(e),e.subFolds.forEach(function(t){e.restoreRange(t),this.addFold(t)},this),e.collapseChildren>0&&this.foldAll(e.start.row+1,e.end.row,e.collapseChildren-1),e.subFolds=[]},this.expandFolds=function(e){e.forEach(function(e){this.expandFold(e)},this)},this.unfold=function(e,t){var n,i;e==null?(n=new r(0,0,this.getLength(),0),t=!0):typeof e=="number"?n=new r(e,0,e,this.getLine(e).length):"row"in e?n=r.fromPoints(e,e):n=e,i=this.getFoldsInRangeList(n);if(t)this.removeFolds(i);else{var s=i;while(s.length)this.expandFolds(s),s=this.getFoldsInRangeList(n)}if(i.length)return i},this.isRowFolded=function(e,t){return!!this.getFoldLine(e,t)},this.getRowFoldEnd=function(e,t){var n=this.getFoldLine(e,t);return n?n.end.row:e},this.getRowFoldStart=function(e,t){var n=this.getFoldLine(e,t);return n?n.start.row:e},this.getFoldDisplayLine=function(e,t,n,r,i){r==null&&(r=e.start.row),i==null&&(i=0),t==null&&(t=e.end.row),n==null&&(n=this.getLine(t).length);var s=this.doc,o="";return e.walk(function(e,t,n,u){if(t<r)return;if(t==r){if(n<i)return;u=Math.max(i,u)}e!=null?o+=e:o+=s.getLine(t).substring(u,n)},t,n),o},this.getDisplayLine=function(e,t,n,r){var i=this.getFoldLine(e);if(!i){var s;return s=this.doc.getLine(e),s.substring(r||0,t||s.length)}return this.getFoldDisplayLine(i,e,t,n,r)},this.$cloneFoldData=function(){var e=[];return e=this.$foldData.map(function(t){var n=t.folds.map(function(e){return e.clone()});return new i(e,n)}),e},this.toggleFold=function(e){var t=this.selection,n=t.getRange(),r,i;if(n.isEmpty()){var s=n.start;r=this.getFoldAt(s.row,s.column);if(r){this.expandFold(r);return}(i=this.findMatchingBracket(s))?n.comparePoint(i)==1?n.end=i:(n.start=i,n.start.column++,n.end.column--):(i=this.findMatchingBracket({row:s.row,column:s.column+1}))?(n.comparePoint(i)==1?n.end=i:n.start=i,n.start.column++):n=this.getCommentFoldRange(s.row,s.column)||n}else{var o=this.getFoldsInRange(n);if(e&&o.length){this.expandFolds(o);return}o.length==1&&(r=o[0])}r||(r=this.getFoldAt(n.start.row,n.start.column));if(r&&r.range.toString()==n.toString()){this.expandFold(r);return}var u="...";if(!n.isMultiLine()){u=this.getTextRange(n);if(u.length<4)return;u=u.trim().substring(0,2)+".."}this.addFold(u,n)},this.getCommentFoldRange=function(e,t,n){var i=new o(this,e,t),s=i.getCurrentToken();if(s&&/^comment|string/.test(s.type)){var u=new r,a=new RegExp(s.type.replace(/\..*/,"\\."));if(n!=1){do s=i.stepBackward();while(s&&a.test(s.type));i.stepForward()}u.start.row=i.getCurrentTokenRow(),u.start.column=i.getCurrentTokenColumn()+2,i=new o(this,e,t);if(n!=-1){do s=i.stepForward();while(s&&a.test(s.type));s=i.stepBackward()}else s=i.getCurrentToken();return u.end.row=i.getCurrentTokenRow(),u.end.column=i.getCurrentTokenColumn()+s.value.length-2,u}},this.foldAll=function(e,t,n){n==undefined&&(n=1e5);var r=this.foldWidgets;if(!r)return;t=t||this.getLength(),e=e||0;for(var i=e;i<t;i++){r[i]==null&&(r[i]=this.getFoldWidget(i));if(r[i]!="start")continue;var s=this.getFoldWidgetRange(i);if(s&&s.isMultiLine()&&s.end.row<=t&&s.start.row>=e){i=s.end.row;try{var o=this.addFold("...",s);o&&(o.collapseChildren=n)}catch(u){}}}},this.$foldStyles={manual:1,markbegin:1,markbeginend:1},this.$foldStyle="markbegin",this.setFoldStyle=function(e){if(!this.$foldStyles[e])throw new Error("invalid fold style: "+e+"["+Object.keys(this.$foldStyles).join(", ")+"]");if(this.$foldStyle==e)return;this.$foldStyle=e,e=="manual"&&this.unfold();var t=this.$foldMode;this.$setFolding(null),this.$setFolding(t)},this.$setFolding=function(e){if(this.$foldMode==e)return;this.$foldMode=e,this.off("change",this.$updateFoldWidgets),this.off("tokenizerUpdate",this.$tokenizerUpdateFoldWidgets),this._signal("changeAnnotation");if(!e||this.$foldStyle=="manual"){this.foldWidgets=null;return}this.foldWidgets=[],this.getFoldWidget=e.getFoldWidget.bind(e,this,this.$foldStyle),this.getFoldWidgetRange=e.getFoldWidgetRange.bind(e,this,this.$foldStyle),this.$updateFoldWidgets=this.updateFoldWidgets.bind(this),this.$tokenizerUpdateFoldWidgets=this.tokenizerUpdateFoldWidgets.bind(this),this.on("change",this.$updateFoldWidgets),this.on("tokenizerUpdate",this.$tokenizerUpdateFoldWidgets)},this.getParentFoldRangeData=function(e,t){var n=this.foldWidgets;if(!n||t&&n[e])return{};var r=e-1,i;while(r>=0){var s=n[r];s==null&&(s=n[r]=this.getFoldWidget(r));if(s=="start"){var o=this.getFoldWidgetRange(r);i||(i=o);if(o&&o.end.row>=e)break}r--}return{range:r!==-1&&o,firstRange:i}},this.onFoldWidgetClick=function(e,t){t=t.domEvent;var n={children:t.shiftKey,all:t.ctrlKey||t.metaKey,siblings:t.altKey},r=this.$toggleFoldWidget(e,n);if(!r){var i=t.target||t.srcElement;i&&/ace_fold-widget/.test(i.className)&&(i.className+=" ace_invalid")}},this.$toggleFoldWidget=function(e,t){if(!this.getFoldWidget)return;var n=this.getFoldWidget(e),r=this.getLine(e),i=n==="end"?-1:1,s=this.getFoldAt(e,i===-1?0:r.length,i);if(s){t.children||t.all?this.removeFold(s):this.expandFold(s);return}var o=this.getFoldWidgetRange(e,!0);if(o&&!o.isMultiLine()){s=this.getFoldAt(o.start.row,o.start.column,1);if(s&&o.isEqual(s.range)){this.removeFold(s);return}}if(t.siblings){var u=this.getParentFoldRangeData(e);if(u.range)var a=u.range.start.row+1,f=u.range.end.row;this.foldAll(a,f,t.all?1e4:0)}else t.children?(f=o?o.end.row:this.getLength(),this.foldAll(e+1,f,t.all?1e4:0)):o&&(t.all&&(o.collapseChildren=1e4),this.addFold("...",o));return o},this.toggleFoldWidget=function(e){var t=this.selection.getCursor().row;t=this.getRowFoldStart(t);var n=this.$toggleFoldWidget(t,{});if(n)return;var r=this.getParentFoldRangeData(t,!0);n=r.range||r.firstRange;if(n){t=n.start.row;var i=this.getFoldAt(t,this.getLine(t).length,1);i?this.removeFold(i):this.addFold("...",n)}},this.updateFoldWidgets=function(e){var t=e.start.row,n=e.end.row-t;if(n===0)this.foldWidgets[t]=null;else if(e.action=="remove")this.foldWidgets.splice(t,n+1,null);else{var r=Array(n+1);r.unshift(t,1),this.foldWidgets.splice.apply(this.foldWidgets,r)}},this.tokenizerUpdateFoldWidgets=function(e){var t=e.data;t.first!=t.last&&this.foldWidgets.length>t.first&&this.foldWidgets.splice(t.first,this.foldWidgets.length)}}var r=e("../range").Range,i=e("./fold_line").FoldLine,s=e("./fold").Fold,o=e("../token_iterator").TokenIterator;t.Folding=u}),ace.define("ace/edit_session/bracket_match",["require","exports","module","ace/token_iterator","ace/range"],function(e,t,n){"use strict";function s(){this.findMatchingBracket=function(e,t){if(e.column==0)return null;var n=t||this.getLine(e.row).charAt(e.column-1);if(n=="")return null;var r=n.match(/([\(\[\{])|([\)\]\}])/);return r?r[1]?this.$findClosingBracket(r[1],e):this.$findOpeningBracket(r[2],e):null},this.getBracketRange=function(e){var t=this.getLine(e.row),n=!0,r,s=t.charAt(e.column-1),o=s&&s.match(/([\(\[\{])|([\)\]\}])/);o||(s=t.charAt(e.column),e={row:e.row,column:e.column+1},o=s&&s.match(/([\(\[\{])|([\)\]\}])/),n=!1);if(!o)return null;if(o[1]){var u=this.$findClosingBracket(o[1],e);if(!u)return null;r=i.fromPoints(e,u),n||(r.end.column++,r.start.column--),r.cursor=r.end}else{var u=this.$findOpeningBracket(o[2],e);if(!u)return null;r=i.fromPoints(u,e),n||(r.start.column++,r.end.column--),r.cursor=r.start}return r},this.$brackets={")":"(","(":")","]":"[","[":"]","{":"}","}":"{"},this.$findOpeningBracket=function(e,t,n){var i=this.$brackets[e],s=1,o=new r(this,t.row,t.column),u=o.getCurrentToken();u||(u=o.stepForward());if(!u)return;n||(n=new RegExp("(\\.?"+u.type.replace(".","\\.").replace("rparen",".paren").replace(/\b(?:end)\b/,"(?:start|begin|end)")+")+"));var a=t.column-o.getCurrentTokenColumn()-2,f=u.value;for(;;){while(a>=0){var l=f.charAt(a);if(l==i){s-=1;if(s==0)return{row:o.getCurrentTokenRow(),column:a+o.getCurrentTokenColumn()}}else l==e&&(s+=1);a-=1}do u=o.stepBackward();while(u&&!n.test(u.type));if(u==null)break;f=u.value,a=f.length-1}return null},this.$findClosingBracket=function(e,t,n){var i=this.$brackets[e],s=1,o=new r(this,t.row,t.column),u=o.getCurrentToken();u||(u=o.stepForward());if(!u)return;n||(n=new RegExp("(\\.?"+u.type.replace(".","\\.").replace("lparen",".paren").replace(/\b(?:start|begin)\b/,"(?:start|begin|end)")+")+"));var a=t.column-o.getCurrentTokenColumn();for(;;){var f=u.value,l=f.length;while(a<l){var c=f.charAt(a);if(c==i){s-=1;if(s==0)return{row:o.getCurrentTokenRow(),column:a+o.getCurrentTokenColumn()}}else c==e&&(s+=1);a+=1}do u=o.stepForward();while(u&&!n.test(u.type));if(u==null)break;a=0}return null}}var r=e("../token_iterator").TokenIterator,i=e("../range").Range;t.BracketMatch=s}),ace.define("ace/edit_session",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/config","ace/lib/event_emitter","ace/selection","ace/mode/text","ace/range","ace/document","ace/background_tokenizer","ace/search_highlight","ace/edit_session/folding","ace/edit_session/bracket_match"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/lang"),s=e("./config"),o=e("./lib/event_emitter").EventEmitter,u=e("./selection").Selection,a=e("./mode/text").Mode,f=e("./range").Range,l=e("./document").Document,c=e("./background_tokenizer").BackgroundTokenizer,h=e("./search_highlight").SearchHighlight,p=function(e,t){this.$breakpoints=[],this.$decorations=[],this.$frontMarkers={},this.$backMarkers={},this.$markerId=1,this.$undoSelect=!0,this.$foldData=[],this.$foldData.toString=function(){return this.join("\n")},this.on("changeFold",this.onChangeFold.bind(this)),this.$onChange=this.onChange.bind(this);if(typeof e!="object"||!e.getLine)e=new l(e);this.setDocument(e),this.selection=new u(this),s.resetOptions(this),this.setMode(t),s._signal("session",this)};(function(){function m(e){return e<4352?!1:e>=4352&&e<=4447||e>=4515&&e<=4519||e>=4602&&e<=4607||e>=9001&&e<=9002||e>=11904&&e<=11929||e>=11931&&e<=12019||e>=12032&&e<=12245||e>=12272&&e<=12283||e>=12288&&e<=12350||e>=12353&&e<=12438||e>=12441&&e<=12543||e>=12549&&e<=12589||e>=12593&&e<=12686||e>=12688&&e<=12730||e>=12736&&e<=12771||e>=12784&&e<=12830||e>=12832&&e<=12871||e>=12880&&e<=13054||e>=13056&&e<=19903||e>=19968&&e<=42124||e>=42128&&e<=42182||e>=43360&&e<=43388||e>=44032&&e<=55203||e>=55216&&e<=55238||e>=55243&&e<=55291||e>=63744&&e<=64255||e>=65040&&e<=65049||e>=65072&&e<=65106||e>=65108&&e<=65126||e>=65128&&e<=65131||e>=65281&&e<=65376||e>=65504&&e<=65510}r.implement(this,o),this.setDocument=function(e){this.doc&&this.doc.removeListener("change",this.$onChange),this.doc=e,e.on("change",this.$onChange),this.bgTokenizer&&this.bgTokenizer.setDocument(this.getDocument()),this.resetCaches()},this.getDocument=function(){return this.doc},this.$resetRowCache=function(e){if(!e){this.$docRowCache=[],this.$screenRowCache=[];return}var t=this.$docRowCache.length,n=this.$getRowCacheIndex(this.$docRowCache,e)+1;t>n&&(this.$docRowCache.splice(n,t),this.$screenRowCache.splice(n,t))},this.$getRowCacheIndex=function(e,t){var n=0,r=e.length-1;while(n<=r){var i=n+r>>1,s=e[i];if(t>s)n=i+1;else{if(!(t<s))return i;r=i-1}}return n-1},this.resetCaches=function(){this.$modified=!0,this.$wrapData=[],this.$rowLengthCache=[],this.$resetRowCache(0),this.bgTokenizer&&this.bgTokenizer.start(0)},this.onChangeFold=function(e){var t=e.data;this.$resetRowCache(t.start.row)},this.onChange=function(e){this.$modified=!0,this.$resetRowCache(e.start.row);var t=this.$updateInternalDataOnChange(e);!this.$fromUndo&&this.$undoManager&&!e.ignore&&(this.$deltasDoc.push(e),t&&t.length!=0&&this.$deltasFold.push({action:"removeFolds",folds:t}),this.$informUndoManager.schedule()),this.bgTokenizer&&this.bgTokenizer.$updateOnChange(e),this._signal("change",e)},this.setValue=function(e){this.doc.setValue(e),this.selection.moveTo(0,0),this.$resetRowCache(0),this.$deltas=[],this.$deltasDoc=[],this.$deltasFold=[],this.setUndoManager(this.$undoManager),this.getUndoManager().reset()},this.getValue=this.toString=function(){return this.doc.getValue()},this.getSelection=function(){return this.selection},this.getState=function(e){return this.bgTokenizer.getState(e)},this.getTokens=function(e){return this.bgTokenizer.getTokens(e)},this.getTokenAt=function(e,t){var n=this.bgTokenizer.getTokens(e),r,i=0;if(t==null)s=n.length-1,i=this.getLine(e).length;else for(var s=0;s<n.length;s++){i+=n[s].value.length;if(i>=t)break}return r=n[s],r?(r.index=s,r.start=i-r.value.length,r):null},this.setUndoManager=function(e){this.$undoManager=e,this.$deltas=[],this.$deltasDoc=[],this.$deltasFold=[],this.$informUndoManager&&this.$informUndoManager.cancel();if(e){var t=this;this.$syncInformUndoManager=function(){t.$informUndoManager.cancel(),t.$deltasFold.length&&(t.$deltas.push({group:"fold",deltas:t.$deltasFold}),t.$deltasFold=[]),t.$deltasDoc.length&&(t.$deltas.push({group:"doc",deltas:t.$deltasDoc}),t.$deltasDoc=[]),t.$deltas.length>0&&e.execute({action:"aceupdate",args:[t.$deltas,t],merge:t.mergeUndoDeltas}),t.mergeUndoDeltas=!1,t.$deltas=[]},this.$informUndoManager=i.delayedCall(this.$syncInformUndoManager)}},this.markUndoGroup=function(){this.$syncInformUndoManager&&this.$syncInformUndoManager()},this.$defaultUndoManager={undo:function(){},redo:function(){},reset:function(){}},this.getUndoManager=function(){return this.$undoManager||this.$defaultUndoManager},this.getTabString=function(){return this.getUseSoftTabs()?i.stringRepeat(" ",this.getTabSize()):"	"},this.setUseSoftTabs=function(e){this.setOption("useSoftTabs",e)},this.getUseSoftTabs=function(){return this.$useSoftTabs&&!this.$mode.$indentWithTabs},this.setTabSize=function(e){this.setOption("tabSize",e)},this.getTabSize=function(){return this.$tabSize},this.isTabStop=function(e){return this.$useSoftTabs&&e.column%this.$tabSize===0},this.$overwrite=!1,this.setOverwrite=function(e){this.setOption("overwrite",e)},this.getOverwrite=function(){return this.$overwrite},this.toggleOverwrite=function(){this.setOverwrite(!this.$overwrite)},this.addGutterDecoration=function(e,t){this.$decorations[e]||(this.$decorations[e]=""),this.$decorations[e]+=" "+t,this._signal("changeBreakpoint",{})},this.removeGutterDecoration=function(e,t){this.$decorations[e]=(this.$decorations[e]||"").replace(" "+t,""),this._signal("changeBreakpoint",{})},this.getBreakpoints=function(){return this.$breakpoints},this.setBreakpoints=function(e){this.$breakpoints=[];for(var t=0;t<e.length;t++)this.$breakpoints[e[t]]="ace_breakpoint";this._signal("changeBreakpoint",{})},this.clearBreakpoints=function(){this.$breakpoints=[],this._signal("changeBreakpoint",{})},this.setBreakpoint=function(e,t){t===undefined&&(t="ace_breakpoint"),t?this.$breakpoints[e]=t:delete this.$breakpoints[e],this._signal("changeBreakpoint",{})},this.clearBreakpoint=function(e){delete this.$breakpoints[e],this._signal("changeBreakpoint",{})},this.addMarker=function(e,t,n,r){var i=this.$markerId++,s={range:e,type:n||"line",renderer:typeof n=="function"?n:null,clazz:t,inFront:!!r,id:i};return r?(this.$frontMarkers[i]=s,this._signal("changeFrontMarker")):(this.$backMarkers[i]=s,this._signal("changeBackMarker")),i},this.addDynamicMarker=function(e,t){if(!e.update)return;var n=this.$markerId++;return e.id=n,e.inFront=!!t,t?(this.$frontMarkers[n]=e,this._signal("changeFrontMarker")):(this.$backMarkers[n]=e,this._signal("changeBackMarker")),e},this.removeMarker=function(e){var t=this.$frontMarkers[e]||this.$backMarkers[e];if(!t)return;var n=t.inFront?this.$frontMarkers:this.$backMarkers;t&&(delete n[e],this._signal(t.inFront?"changeFrontMarker":"changeBackMarker"))},this.getMarkers=function(e){return e?this.$frontMarkers:this.$backMarkers},this.highlight=function(e){if(!this.$searchHighlight){var t=new h(null,"ace_selected-word","text");this.$searchHighlight=this.addDynamicMarker(t)}this.$searchHighlight.setRegexp(e)},this.highlightLines=function(e,t,n,r){typeof t!="number"&&(n=t,t=e),n||(n="ace_step");var i=new f(e,0,t,Infinity);return i.id=this.addMarker(i,n,"fullLine",r),i},this.setAnnotations=function(e){this.$annotations=e,this._signal("changeAnnotation",{})},this.getAnnotations=function(){return this.$annotations||[]},this.clearAnnotations=function(){this.setAnnotations([])},this.$detectNewLine=function(e){var t=e.match(/^.*?(\r?\n)/m);t?this.$autoNewLine=t[1]:this.$autoNewLine="\n"},this.getWordRange=function(e,t){var n=this.getLine(e),r=!1;t>0&&(r=!!n.charAt(t-1).match(this.tokenRe)),r||(r=!!n.charAt(t).match(this.tokenRe));if(r)var i=this.tokenRe;else if(/^\s+$/.test(n.slice(t-1,t+1)))var i=/\s/;else var i=this.nonTokenRe;var s=t;if(s>0){do s--;while(s>=0&&n.charAt(s).match(i));s++}var o=t;while(o<n.length&&n.charAt(o).match(i))o++;return new f(e,s,e,o)},this.getAWordRange=function(e,t){var n=this.getWordRange(e,t),r=this.getLine(n.end.row);while(r.charAt(n.end.column).match(/[ \t]/))n.end.column+=1;return n},this.setNewLineMode=function(e){this.doc.setNewLineMode(e)},this.getNewLineMode=function(){return this.doc.getNewLineMode()},this.setUseWorker=function(e){this.setOption("useWorker",e)},this.getUseWorker=function(){return this.$useWorker},this.onReloadTokenizer=function(e){var t=e.data;this.bgTokenizer.start(t.first),this._signal("tokenizerUpdate",e)},this.$modes={},this.$mode=null,this.$modeId=null,this.setMode=function(e,t){if(e&&typeof e=="object"){if(e.getTokenizer)return this.$onChangeMode(e);var n=e,r=n.path}else r=e||"ace/mode/text";this.$modes["ace/mode/text"]||(this.$modes["ace/mode/text"]=new a);if(this.$modes[r]&&!n){this.$onChangeMode(this.$modes[r]),t&&t();return}this.$modeId=r,s.loadModule(["mode",r],function(e){if(this.$modeId!==r)return t&&t();this.$modes[r]&&!n?this.$onChangeMode(this.$modes[r]):e&&e.Mode&&(e=new e.Mode(n),n||(this.$modes[r]=e,e.$id=r),this.$onChangeMode(e)),t&&t()}.bind(this)),this.$mode||this.$onChangeMode(this.$modes["ace/mode/text"],!0)},this.$onChangeMode=function(e,t){t||(this.$modeId=e.$id);if(this.$mode===e)return;this.$mode=e,this.$stopWorker(),this.$useWorker&&this.$startWorker();var n=e.getTokenizer();if(n.addEventListener!==undefined){var r=this.onReloadTokenizer.bind(this);n.addEventListener("update",r)}if(!this.bgTokenizer){this.bgTokenizer=new c(n);var i=this;this.bgTokenizer.addEventListener("update",function(e){i._signal("tokenizerUpdate",e)})}else this.bgTokenizer.setTokenizer(n);this.bgTokenizer.setDocument(this.getDocument()),this.tokenRe=e.tokenRe,this.nonTokenRe=e.nonTokenRe,t||(e.attachToSession&&e.attachToSession(this),this.$options.wrapMethod.set.call(this,this.$wrapMethod),this.$setFolding(e.foldingRules),this.bgTokenizer.start(0),this._emit("changeMode"))},this.$stopWorker=function(){this.$worker&&(this.$worker.terminate(),this.$worker=null)},this.$startWorker=function(){try{this.$worker=this.$mode.createWorker(this)}catch(e){s.warn("Could not load worker",e),this.$worker=null}},this.getMode=function(){return this.$mode},this.$scrollTop=0,this.setScrollTop=function(e){if(this.$scrollTop===e||isNaN(e))return;this.$scrollTop=e,this._signal("changeScrollTop",e)},this.getScrollTop=function(){return this.$scrollTop},this.$scrollLeft=0,this.setScrollLeft=function(e){if(this.$scrollLeft===e||isNaN(e))return;this.$scrollLeft=e,this._signal("changeScrollLeft",e)},this.getScrollLeft=function(){return this.$scrollLeft},this.getScreenWidth=function(){return this.$computeWidth(),this.lineWidgets?Math.max(this.getLineWidgetMaxWidth(),this.screenWidth):this.screenWidth},this.getLineWidgetMaxWidth=function(){if(this.lineWidgetsWidth!=null)return this.lineWidgetsWidth;var e=0;return this.lineWidgets.forEach(function(t){t&&t.screenWidth>e&&(e=t.screenWidth)}),this.lineWidgetWidth=e},this.$computeWidth=function(e){if(this.$modified||e){this.$modified=!1;if(this.$useWrapMode)return this.screenWidth=this.$wrapLimit;var t=this.doc.getAllLines(),n=this.$rowLengthCache,r=0,i=0,s=this.$foldData[i],o=s?s.start.row:Infinity,u=t.length;for(var a=0;a<u;a++){if(a>o){a=s.end.row+1;if(a>=u)break;s=this.$foldData[i++],o=s?s.start.row:Infinity}n[a]==null&&(n[a]=this.$getStringScreenWidth(t[a])[0]),n[a]>r&&(r=n[a])}this.screenWidth=r}},this.getLine=function(e){return this.doc.getLine(e)},this.getLines=function(e,t){return this.doc.getLines(e,t)},this.getLength=function(){return this.doc.getLength()},this.getTextRange=function(e){return this.doc.getTextRange(e||this.selection.getRange())},this.insert=function(e,t){return this.doc.insert(e,t)},this.remove=function(e){return this.doc.remove(e)},this.removeFullLines=function(e,t){return this.doc.removeFullLines(e,t)},this.undoChanges=function(e,t){if(!e.length)return;this.$fromUndo=!0;var n=null;for(var r=e.length-1;r!=-1;r--){var i=e[r];i.group=="doc"?(this.doc.revertDeltas(i.deltas),n=this.$getUndoSelection(i.deltas,!0,n)):i.deltas.forEach(function(e){this.addFolds(e.folds)},this)}return this.$fromUndo=!1,n&&this.$undoSelect&&!t&&this.selection.setSelectionRange(n),n},this.redoChanges=function(e,t){if(!e.length)return;this.$fromUndo=!0;var n=null;for(var r=0;r<e.length;r++){var i=e[r];i.group=="doc"&&(this.doc.applyDeltas(i.deltas),n=this.$getUndoSelection(i.deltas,!1,n))}return this.$fromUndo=!1,n&&this.$undoSelect&&!t&&this.selection.setSelectionRange(n),n},this.setUndoSelect=function(e){this.$undoSelect=e},this.$getUndoSelection=function(e,t,n){function r(e){return t?e.action!=="insert":e.action==="insert"}var i=e[0],s,o,u=!1;r(i)?(s=f.fromPoints(i.start,i.end),u=!0):(s=f.fromPoints(i.start,i.start),u=!1);for(var a=1;a<e.length;a++)i=e[a],r(i)?(o=i.start,s.compare(o.row,o.column)==-1&&s.setStart(o),o=i.end,s.compare(o.row,o.column)==1&&s.setEnd(o),u=!0):(o=i.start,s.compare(o.row,o.column)==-1&&(s=f.fromPoints(i.start,i.start)),u=!1);if(n!=null){f.comparePoints(n.start,s.start)===0&&(n.start.column+=s.end.column-s.start.column,n.end.column+=s.end.column-s.start.column);var l=n.compareRange(s);l==1?s.setStart(n.start):l==-1&&s.setEnd(n.end)}return s},this.replace=function(e,t){return this.doc.replace(e,t)},this.moveText=function(e,t,n){var r=this.getTextRange(e),i=this.getFoldsInRange(e),s=f.fromPoints(t,t);if(!n){this.remove(e);var o=e.start.row-e.end.row,u=o?-e.end.column:e.start.column-e.end.column;u&&(s.start.row==e.end.row&&s.start.column>e.end.column&&(s.start.column+=u),s.end.row==e.end.row&&s.end.column>e.end.column&&(s.end.column+=u)),o&&s.start.row>=e.end.row&&(s.start.row+=o,s.end.row+=o)}s.end=this.insert(s.start,r);if(i.length){var a=e.start,l=s.start,o=l.row-a.row,u=l.column-a.column;this.addFolds(i.map(function(e){return e=e.clone(),e.start.row==a.row&&(e.start.column+=u),e.end.row==a.row&&(e.end.column+=u),e.start.row+=o,e.end.row+=o,e}))}return s},this.indentRows=function(e,t,n){n=n.replace(/\t/g,this.getTabString());for(var r=e;r<=t;r++)this.doc.insertInLine({row:r,column:0},n)},this.outdentRows=function(e){var t=e.collapseRows(),n=new f(0,0,0,0),r=this.getTabSize();for(var i=t.start.row;i<=t.end.row;++i){var s=this.getLine(i);n.start.row=i,n.end.row=i;for(var o=0;o<r;++o)if(s.charAt(o)!=" ")break;o<r&&s.charAt(o)=="	"?(n.start.column=o,n.end.column=o+1):(n.start.column=0,n.end.column=o),this.remove(n)}},this.$moveLines=function(e,t,n){e=this.getRowFoldStart(e),t=this.getRowFoldEnd(t);if(n<0){var r=this.getRowFoldStart(e+n);if(r<0)return 0;var i=r-e}else if(n>0){var r=this.getRowFoldEnd(t+n);if(r>this.doc.getLength()-1)return 0;var i=r-t}else{e=this.$clipRowToDocument(e),t=this.$clipRowToDocument(t);var i=t-e+1}var s=new f(e,0,t,Number.MAX_VALUE),o=this.getFoldsInRange(s).map(function(e){return e=e.clone(),e.start.row+=i,e.end.row+=i,e}),u=n==0?this.doc.getLines(e,t):this.doc.removeFullLines(e,t);return this.doc.insertFullLines(e+i,u),o.length&&this.addFolds(o),i},this.moveLinesUp=function(e,t){return this.$moveLines(e,t,-1)},this.moveLinesDown=function(e,t){return this.$moveLines(e,t,1)},this.duplicateLines=function(e,t){return this.$moveLines(e,t,0)},this.$clipRowToDocument=function(e){return Math.max(0,Math.min(e,this.doc.getLength()-1))},this.$clipColumnToRow=function(e,t){return t<0?0:Math.min(this.doc.getLine(e).length,t)},this.$clipPositionToDocument=function(e,t){t=Math.max(0,t);if(e<0)e=0,t=0;else{var n=this.doc.getLength();e>=n?(e=n-1,t=this.doc.getLine(n-1).length):t=Math.min(this.doc.getLine(e).length,t)}return{row:e,column:t}},this.$clipRangeToDocument=function(e){e.start.row<0?(e.start.row=0,e.start.column=0):e.start.column=this.$clipColumnToRow(e.start.row,e.start.column);var t=this.doc.getLength()-1;return e.end.row>t?(e.end.row=t,e.end.column=this.doc.getLine(t).length):e.end.column=this.$clipColumnToRow(e.end.row,e.end.column),e},this.$wrapLimit=80,this.$useWrapMode=!1,this.$wrapLimitRange={min:null,max:null},this.setUseWrapMode=function(e){if(e!=this.$useWrapMode){this.$useWrapMode=e,this.$modified=!0,this.$resetRowCache(0);if(e){var t=this.getLength();this.$wrapData=Array(t),this.$updateWrapData(0,t-1)}this._signal("changeWrapMode")}},this.getUseWrapMode=function(){return this.$useWrapMode},this.setWrapLimitRange=function(e,t){if(this.$wrapLimitRange.min!==e||this.$wrapLimitRange.max!==t)this.$wrapLimitRange={min:e,max:t},this.$modified=!0,this.$useWrapMode&&this._signal("changeWrapMode")},this.adjustWrapLimit=function(e,t){var n=this.$wrapLimitRange;n.max<0&&(n={min:t,max:t});var r=this.$constrainWrapLimit(e,n.min,n.max);return r!=this.$wrapLimit&&r>1?(this.$wrapLimit=r,this.$modified=!0,this.$useWrapMode&&(this.$updateWrapData(0,this.getLength()-1),this.$resetRowCache(0),this._signal("changeWrapLimit")),!0):!1},this.$constrainWrapLimit=function(e,t,n){return t&&(e=Math.max(t,e)),n&&(e=Math.min(n,e)),e},this.getWrapLimit=function(){return this.$wrapLimit},this.setWrapLimit=function(e){this.setWrapLimitRange(e,e)},this.getWrapLimitRange=function(){return{min:this.$wrapLimitRange.min,max:this.$wrapLimitRange.max}},this.$updateInternalDataOnChange=function(e){var t=this.$useWrapMode,n=e.action,r=e.start,i=e.end,s=r.row,o=i.row,u=o-s,a=null;this.$updating=!0;if(u!=0)if(n==="remove"){this[t?"$wrapData":"$rowLengthCache"].splice(s,u);var f=this.$foldData;a=this.getFoldsInRange(e),this.removeFolds(a);var l=this.getFoldLine(i.row),c=0;if(l){l.addRemoveChars(i.row,i.column,r.column-i.column),l.shiftRow(-u);var h=this.getFoldLine(s);h&&h!==l&&(h.merge(l),l=h),c=f.indexOf(l)+1}for(c;c<f.length;c++){var l=f[c];l.start.row>=i.row&&l.shiftRow(-u)}o=s}else{var p=Array(u);p.unshift(s,0);var d=t?this.$wrapData:this.$rowLengthCache;d.splice.apply(d,p);var f=this.$foldData,l=this.getFoldLine(s),c=0;if(l){var v=l.range.compareInside(r.row,r.column);v==0?(l=l.split(r.row,r.column),l&&(l.shiftRow(u),l.addRemoveChars(o,0,i.column-r.column))):v==-1&&(l.addRemoveChars(s,0,i.column-r.column),l.shiftRow(u)),c=f.indexOf(l)+1}for(c;c<f.length;c++){var l=f[c];l.start.row>=s&&l.shiftRow(u)}}else{u=Math.abs(e.start.column-e.end.column),n==="remove"&&(a=this.getFoldsInRange(e),this.removeFolds(a),u=-u);var l=this.getFoldLine(s);l&&l.addRemoveChars(s,r.column,u)}return t&&this.$wrapData.length!=this.doc.getLength()&&console.error("doc.getLength() and $wrapData.length have to be the same!"),this.$updating=!1,t?this.$updateWrapData(s,o):this.$updateRowLengthCache(s,o),a},this.$updateRowLengthCache=function(e,t,n){this.$rowLengthCache[e]=null,this.$rowLengthCache[t]=null},this.$updateWrapData=function(e,t){var r=this.doc.getAllLines(),i=this.getTabSize(),s=this.$wrapData,o=this.$wrapLimit,a,f,l=e;t=Math.min(t,r.length-1);while(l<=t)f=this.getFoldLine(l,f),f?(a=[],f.walk(function(e,t,i,s){var o;if(e!=null){o=this.$getDisplayTokens(e,a.length),o[0]=n;for(var f=1;f<o.length;f++)o[f]=u}else o=this.$getDisplayTokens(r[t].substring(s,i),a.length);a=a.concat(o)}.bind(this),f.end.row,r[f.end.row].length+1),s[f.start.row]=this.$computeWrapSplits(a,o,i),l=f.end.row+1):(a=this.$getDisplayTokens(r[l]),s[l]=this.$computeWrapSplits(a,o,i),l++)};var e=1,t=2,n=3,u=4,l=9,p=10,d=11,v=12;this.$computeWrapSplits=function(e,r,i){function g(){var t=0;if(m===0)return t;if(h)for(var n=0;n<e.length;n++){var r=e[n];if(r==p)t+=1;else{if(r!=d){if(r==v)continue;break}t+=i}}return c&&h!==!1&&(t+=i),Math.min(t,m)}function y(t){var n=e.slice(a,t),r=n.length;n.join("").replace(/12/g,function(){r-=1}).replace(/2/g,function(){r-=1}),s.length||(b=g(),s.indent=b),f+=r,s.push(f),a=t}if(e.length==0)return[];var s=[],o=e.length,a=0,f=0,c=this.$wrapAsCode,h=this.$indentedSoftWrap,m=r<=Math.max(2*i,8)||h===!1?0:Math.floor(r/2),b=0;while(o-a>r-b){var w=a+r-b;if(e[w-1]>=p&&e[w]>=p){y(w);continue}if(e[w]==n||e[w]==u){for(w;w!=a-1;w--)if(e[w]==n)break;if(w>a){y(w);continue}w=a+r;for(w;w<e.length;w++)if(e[w]!=u)break;if(w==e.length)break;y(w);continue}var E=Math.max(w-(r-(r>>2)),a-1);while(w>E&&e[w]<n)w--;if(c){while(w>E&&e[w]<n)w--;while(w>E&&e[w]==l)w--}else while(w>E&&e[w]<p)w--;if(w>E){y(++w);continue}w=a+r,e[w]==t&&w--,y(w-b)}return s},this.$getDisplayTokens=function(n,r){var i=[],s;r=r||0;for(var o=0;o<n.length;o++){var u=n.charCodeAt(o);if(u==9){s=this.getScreenTabSize(i.length+r),i.push(d);for(var a=1;a<s;a++)i.push(v)}else u==32?i.push(p):u>39&&u<48||u>57&&u<64?i.push(l):u>=4352&&m(u)?i.push(e,t):i.push(e)}return i},this.$getStringScreenWidth=function(e,t,n){if(t==0)return[0,0];t==null&&(t=Infinity),n=n||0;var r,i;for(i=0;i<e.length;i++){r=e.charCodeAt(i),r==9?n+=this.getScreenTabSize(n):r>=4352&&m(r)?n+=2:n+=1;if(n>t)break}return[n,i]},this.lineWidgets=null,this.getRowLength=function(e){if(this.lineWidgets)var t=this.lineWidgets[e]&&this.lineWidgets[e].rowCount||0;else t=0;return!this.$useWrapMode||!this.$wrapData[e]?1+t:this.$wrapData[e].length+1+t},this.getRowLineCount=function(e){return!this.$useWrapMode||!this.$wrapData[e]?1:this.$wrapData[e].length+1},this.getRowWrapIndent=function(e){if(this.$useWrapMode){var t=this.screenToDocumentPosition(e,Number.MAX_VALUE),n=this.$wrapData[t.row];return n.length&&n[0]<t.column?n.indent:0}return 0},this.getScreenLastRowColumn=function(e){var t=this.screenToDocumentPosition(e,Number.MAX_VALUE);return this.documentToScreenColumn(t.row,t.column)},this.getDocumentLastRowColumn=function(e,t){var n=this.documentToScreenRow(e,t);return this.getScreenLastRowColumn(n)},this.getDocumentLastRowColumnPosition=function(e,t){var n=this.documentToScreenRow(e,t);return this.screenToDocumentPosition(n,Number.MAX_VALUE/10)},this.getRowSplitData=function(e){return this.$useWrapMode?this.$wrapData[e]:undefined},this.getScreenTabSize=function(e){return this.$tabSize-e%this.$tabSize},this.screenToDocumentRow=function(e,t){return this.screenToDocumentPosition(e,t).row},this.screenToDocumentColumn=function(e,t){return this.screenToDocumentPosition(e,t).column},this.screenToDocumentPosition=function(e,t){if(e<0)return{row:0,column:0};var n,r=0,i=0,s,o=0,u=0,a=this.$screenRowCache,f=this.$getRowCacheIndex(a,e),l=a.length;if(l&&f>=0)var o=a[f],r=this.$docRowCache[f],c=e>a[l-1];else var c=!l;var h=this.getLength()-1,p=this.getNextFoldLine(r),d=p?p.start.row:Infinity;while(o<=e){u=this.getRowLength(r);if(o+u>e||r>=h)break;o+=u,r++,r>d&&(r=p.end.row+1,p=this.getNextFoldLine(r,p),d=p?p.start.row:Infinity),c&&(this.$docRowCache.push(r),this.$screenRowCache.push(o))}if(p&&p.start.row<=r)n=this.getFoldDisplayLine(p),r=p.start.row;else{if(o+u<=e||r>h)return{row:h,column:this.getLine(h).length};n=this.getLine(r),p=null}var v=0;if(this.$useWrapMode){var m=this.$wrapData[r];if(m){var g=Math.floor(e-o);s=m[g],g>0&&m.length&&(v=m.indent,i=m[g-1]||m[m.length-1],n=n.substring(i))}}return i+=this.$getStringScreenWidth(n,t-v)[1],this.$useWrapMode&&i>=s&&(i=s-1),p?p.idxToPosition(i):{row:r,column:i}},this.documentToScreenPosition=function(e,t){if(typeof t=="undefined")var n=this.$clipPositionToDocument(e.row,e.column);else n=this.$clipPositionToDocument(e,t);e=n.row,t=n.column;var r=0,i=null,s=null;s=this.getFoldAt(e,t,1),s&&(e=s.start.row,t=s.start.column);var o,u=0,a=this.$docRowCache,f=this.$getRowCacheIndex(a,e),l=a.length;if(l&&f>=0)var u=a[f],r=this.$screenRowCache[f],c=e>a[l-1];else var c=!l;var h=this.getNextFoldLine(u),p=h?h.start.row:Infinity;while(u<e){if(u>=p){o=h.end.row+1;if(o>e)break;h=this.getNextFoldLine(o,h),p=h?h.start.row:Infinity}else o=u+1;r+=this.getRowLength(u),u=o,c&&(this.$docRowCache.push(u),this.$screenRowCache.push(r))}var d="";h&&u>=p?(d=this.getFoldDisplayLine(h,e,t),i=h.start.row):(d=this.getLine(e).substring(0,t),i=e);var v=0;if(this.$useWrapMode){var m=this.$wrapData[i];if(m){var g=0;while(d.length>=m[g])r++,g++;d=d.substring(m[g-1]||0,d.length),v=g>0?m.indent:0}}return{row:r,column:v+this.$getStringScreenWidth(d)[0]}},this.documentToScreenColumn=function(e,t){return this.documentToScreenPosition(e,t).column},this.documentToScreenRow=function(e,t){return this.documentToScreenPosition(e,t).row},this.getScreenLength=function(){var e=0,t=null;if(!this.$useWrapMode){e=this.getLength();var n=this.$foldData;for(var r=0;r<n.length;r++)t=n[r],e-=t.end.row-t.start.row}else{var i=this.$wrapData.length,s=0,r=0,t=this.$foldData[r++],o=t?t.start.row:Infinity;while(s<i){var u=this.$wrapData[s];e+=u?u.length+1:1,s++,s>o&&(s=t.end.row+1,t=this.$foldData[r++],o=t?t.start.row:Infinity)}}return this.lineWidgets&&(e+=this.$getWidgetScreenLength()),e},this.$setFontMetrics=function(e){if(!this.$enableVarChar)return;this.$getStringScreenWidth=function(t,n,r){if(n===0)return[0,0];n||(n=Infinity),r=r||0;var i,s;for(s=0;s<t.length;s++){i=t.charAt(s),i==="	"?r+=this.getScreenTabSize(r):r+=e.getCharacterWidth(i);if(r>n)break}return[r,s]}},this.destroy=function(){this.bgTokenizer&&(this.bgTokenizer.setDocument(null),this.bgTokenizer=null),this.$stopWorker()}}).call(p.prototype),e("./edit_session/folding").Folding.call(p.prototype),e("./edit_session/bracket_match").BracketMatch.call(p.prototype),s.defineOptions(p.prototype,"session",{wrap:{set:function(e){!e||e=="off"?e=!1:e=="free"?e=!0:e=="printMargin"?e=-1:typeof e=="string"&&(e=parseInt(e,10)||!1);if(this.$wrap==e)return;this.$wrap=e;if(!e)this.setUseWrapMode(!1);else{var t=typeof e=="number"?e:null;this.setWrapLimitRange(t,t),this.setUseWrapMode(!0)}},get:function(){return this.getUseWrapMode()?this.$wrap==-1?"printMargin":this.getWrapLimitRange().min?this.$wrap:"free":"off"},handlesSet:!0},wrapMethod:{set:function(e){e=e=="auto"?this.$mode.type!="text":e!="text",e!=this.$wrapAsCode&&(this.$wrapAsCode=e,this.$useWrapMode&&(this.$modified=!0,this.$resetRowCache(0),this.$updateWrapData(0,this.getLength()-1)))},initialValue:"auto"},indentedSoftWrap:{initialValue:!0},firstLineNumber:{set:function(){this._signal("changeBreakpoint")},initialValue:1},useWorker:{set:function(e){this.$useWorker=e,this.$stopWorker(),e&&this.$startWorker()},initialValue:!0},useSoftTabs:{initialValue:!0},tabSize:{set:function(e){if(isNaN(e)||this.$tabSize===e)return;this.$modified=!0,this.$rowLengthCache=[],this.$tabSize=e,this._signal("changeTabSize")},initialValue:4,handlesSet:!0},overwrite:{set:function(e){this._signal("changeOverwrite")},initialValue:!1},newLineMode:{set:function(e){this.doc.setNewLineMode(e)},get:function(){return this.doc.getNewLineMode()},handlesSet:!0},mode:{set:function(e){this.setMode(e)},get:function(){return this.$modeId}}}),t.EditSession=p}),ace.define("ace/search",["require","exports","module","ace/lib/lang","ace/lib/oop","ace/range"],function(e,t,n){"use strict";var r=e("./lib/lang"),i=e("./lib/oop"),s=e("./range").Range,o=function(){this.$options={}};(function(){this.set=function(e){return i.mixin(this.$options,e),this},this.getOptions=function(){return r.copyObject(this.$options)},this.setOptions=function(e){this.$options=e},this.find=function(e){var t=this.$options,n=this.$matchIterator(e,t);if(!n)return!1;var r=null;return n.forEach(function(e,n,i){if(!e.start){var o=e.offset+(i||0);r=new s(n,o,n,o+e.length);if(!e.length&&t.start&&t.start.start&&t.skipCurrent!=0&&r.isEqual(t.start))return r=null,!1}else r=e;return!0}),r},this.findAll=function(e){var t=this.$options;if(!t.needle)return[];this.$assembleRegExp(t);var n=t.range,i=n?e.getLines(n.start.row,n.end.row):e.doc.getAllLines(),o=[],u=t.re;if(t.$isMultiLine){var a=u.length,f=i.length-a,l;e:for(var c=u.offset||0;c<=f;c++){for(var h=0;h<a;h++)if(i[c+h].search(u[h])==-1)continue e;var p=i[c],d=i[c+a-1],v=p.length-p.match(u[0])[0].length,m=d.match(u[a-1])[0].length;if(l&&l.end.row===c&&l.end.column>v)continue;o.push(l=new s(c,v,c+a-1,m)),a>2&&(c=c+a-2)}}else for(var g=0;g<i.length;g++){var y=r.getMatchOffsets(i[g],u);for(var h=0;h<y.length;h++){var b=y[h];o.push(new s(g,b.offset,g,b.offset+b.length))}}if(n){var w=n.start.column,E=n.start.column,g=0,h=o.length-1;while(g<h&&o[g].start.column<w&&o[g].start.row==n.start.row)g++;while(g<h&&o[h].end.column>E&&o[h].end.row==n.end.row)h--;o=o.slice(g,h+1);for(g=0,h=o.length;g<h;g++)o[g].start.row+=n.start.row,o[g].end.row+=n.start.row}return o},this.replace=function(e,t){var n=this.$options,r=this.$assembleRegExp(n);if(n.$isMultiLine)return t;if(!r)return;var i=r.exec(e);if(!i||i[0].length!=e.length)return null;t=e.replace(r,t);if(n.preserveCase){t=t.split("");for(var s=Math.min(e.length,e.length);s--;){var o=e[s];o&&o.toLowerCase()!=o?t[s]=t[s].toUpperCase():t[s]=t[s].toLowerCase()}t=t.join("")}return t},this.$matchIterator=function(e,t){var n=this.$assembleRegExp(t);if(!n)return!1;var i;if(t.$isMultiLine)var o=n.length,u=function(t,r,u){var a=t.search(n[0]);if(a==-1)return;for(var f=1;f<o;f++){t=e.getLine(r+f);if(t.search(n[f])==-1)return}var l=t.match(n[o-1])[0].length,c=new s(r,a,r+o-1,l);n.offset==1?(c.start.row--,c.start.column=Number.MAX_VALUE):u&&(c.start.column+=u);if(i(c))return!0};else if(t.backwards)var u=function(e,t,s){var o=r.getMatchOffsets(e,n);for(var u=o.length-1;u>=0;u--)if(i(o[u],t,s))return!0};else var u=function(e,t,s){var o=r.getMatchOffsets(e,n);for(var u=0;u<o.length;u++)if(i(o[u],t,s))return!0};var a=this.$lineIterator(e,t);return{forEach:function(e){i=e,a.forEach(u)}}},this.$assembleRegExp=function(e,t){if(e.needle instanceof RegExp)return e.re=e.needle;var n=e.needle;if(!e.needle)return e.re=!1;e.regExp||(n=r.escapeRegExp(n)),e.wholeWord&&(n="\\b"+n+"\\b");var i=e.caseSensitive?"gm":"gmi";e.$isMultiLine=!t&&/[\n\r]/.test(n);if(e.$isMultiLine)return e.re=this.$assembleMultilineRegExp(n,i);try{var s=new RegExp(n,i)}catch(o){s=!1}return e.re=s},this.$assembleMultilineRegExp=function(e,t){var n=e.replace(/\r\n|\r|\n/g,"$\n^").split("\n"),r=[];for(var i=0;i<n.length;i++)try{r.push(new RegExp(n[i],t))}catch(s){return!1}return n[0]==""?(r.shift(),r.offset=1):r.offset=0,r},this.$lineIterator=function(e,t){var n=t.backwards==1,r=t.skipCurrent!=0,i=t.range,s=t.start;s||(s=i?i[n?"end":"start"]:e.selection.getRange()),s.start&&(s=s[r!=n?"end":"start"]);var o=i?i.start.row:0,u=i?i.end.row:e.getLength()-1,a=n?function(n){var r=s.row,i=e.getLine(r).substring(0,s.column);if(n(i,r))return;for(r--;r>=o;r--)if(n(e.getLine(r),r))return;if(t.wrap==0)return;for(r=u,o=s.row;r>=o;r--)if(n(e.getLine(r),r))return}:function(n){var r=s.row,i=e.getLine(r).substr(s.column);if(n(i,r,s.column))return;for(r+=1;r<=u;r++)if(n(e.getLine(r),r))return;if(t.wrap==0)return;for(r=o,u=s.row;r<=u;r++)if(n(e.getLine(r),r))return};return{forEach:a}}}).call(o.prototype),t.Search=o}),ace.define("ace/keyboard/hash_handler",["require","exports","module","ace/lib/keys","ace/lib/useragent"],function(e,t,n){"use strict";function o(e,t){this.platform=t||(i.isMac?"mac":"win"),this.commands={},this.commandKeyBinding={},this.addCommands(e),this.$singleCommand=!0}function u(e,t){o.call(this,e,t),this.$singleCommand=!1}var r=e("../lib/keys"),i=e("../lib/useragent"),s=r.KEY_MODS;u.prototype=o.prototype,function(){function e(e){return typeof e=="object"&&e.bindKey&&e.bindKey.position||0}this.addCommand=function(e){this.commands[e.name]&&this.removeCommand(e),this.commands[e.name]=e,e.bindKey&&this._buildKeyHash(e)},this.removeCommand=function(e,t){var n=e&&(typeof e=="string"?e:e.name);e=this.commands[n],t||delete this.commands[n];var r=this.commandKeyBinding;for(var i in r){var s=r[i];if(s==e)delete r[i];else if(Array.isArray(s)){var o=s.indexOf(e);o!=-1&&(s.splice(o,1),s.length==1&&(r[i]=s[0]))}}},this.bindKey=function(e,t,n){typeof e=="object"&&e&&(n==undefined&&(n=e.position),e=e[this.platform]);if(!e)return;if(typeof t=="function")return this.addCommand({exec:t,bindKey:e,name:t.name||e});e.split("|").forEach(function(e){var r="";if(e.indexOf(" ")!=-1){var i=e.split(/\s+/);e=i.pop(),i.forEach(function(e){var t=this.parseKeys(e),n=s[t.hashId]+t.key;r+=(r?" ":"")+n,this._addCommandToBinding(r,"chainKeys")},this),r+=" "}var o=this.parseKeys(e),u=s[o.hashId]+o.key;this._addCommandToBinding(r+u,t,n)},this)},this._addCommandToBinding=function(t,n,r){var i=this.commandKeyBinding,s;if(!n)delete i[t];else if(!i[t]||this.$singleCommand)i[t]=n;else{Array.isArray(i[t])?(s=i[t].indexOf(n))!=-1&&i[t].splice(s,1):i[t]=[i[t]],typeof r!="number"&&(r||n.isDefault?r=-100:r=e(n));var o=i[t];for(s=0;s<o.length;s++){var u=o[s],a=e(u);if(a>r)break}o.splice(s,0,n)}},this.addCommands=function(e){e&&Object.keys(e).forEach(function(t){var n=e[t];if(!n)return;if(typeof n=="string")return this.bindKey(n,t);typeof n=="function"&&(n={exec:n});if(typeof n!="object")return;n.name||(n.name=t),this.addCommand(n)},this)},this.removeCommands=function(e){Object.keys(e).forEach(function(t){this.removeCommand(e[t])},this)},this.bindKeys=function(e){Object.keys(e).forEach(function(t){this.bindKey(t,e[t])},this)},this._buildKeyHash=function(e){this.bindKey(e.bindKey,e)},this.parseKeys=function(e){var t=e.toLowerCase().split(/[\-\+]([\-\+])?/).filter(function(e){return e}),n=t.pop(),i=r[n];if(r.FUNCTION_KEYS[i])n=r.FUNCTION_KEYS[i].toLowerCase();else{if(!t.length)return{key:n,hashId:-1};if(t.length==1&&t[0]=="shift")return{key:n.toUpperCase(),hashId:-1}}var s=0;for(var o=t.length;o--;){var u=r.KEY_MODS[t[o]];if(u==null)return typeof console!="undefined"&&console.error("invalid modifier "+t[o]+" in "+e),!1;s|=u}return{key:n,hashId:s}},this.findKeyCommand=function(t,n){var r=s[t]+n;return this.commandKeyBinding[r]},this.handleKeyboard=function(e,t,n,r){if(r<0)return;var i=s[t]+n,o=this.commandKeyBinding[i];e.$keyChain&&(e.$keyChain+=" "+i,o=this.commandKeyBinding[e.$keyChain]||o);if(o)if(o=="chainKeys"||o[o.length-1]=="chainKeys")return e.$keyChain=e.$keyChain||i,{command:"null"};if(e.$keyChain)if(!!t&&t!=4||n.length!=1){if(t==-1||r>0)e.$keyChain=""}else e.$keyChain=e.$keyChain.slice(0,-i.length-1);return{command:o}},this.getStatusText=function(e,t){return t.$keyChain||""}}.call(o.prototype),t.HashHandler=o,t.MultiHashHandler=u}),ace.define("ace/commands/command_manager",["require","exports","module","ace/lib/oop","ace/keyboard/hash_handler","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../keyboard/hash_handler").MultiHashHandler,s=e("../lib/event_emitter").EventEmitter,o=function(e,t){i.call(this,t,e),this.byName=this.commands,this.setDefaultHandler("exec",function(e){return e.command.exec(e.editor,e.args||{})})};r.inherits(o,i),function(){r.implement(this,s),this.exec=function(e,t,n){if(Array.isArray(e)){for(var r=e.length;r--;)if(this.exec(e[r],t,n))return!0;return!1}typeof e=="string"&&(e=this.commands[e]);if(!e)return!1;if(t&&t.$readOnly&&!e.readOnly)return!1;var i={editor:t,command:e,args:n};return i.returnValue=this._emit("exec",i),this._signal("afterExec",i),i.returnValue===!1?!1:!0},this.toggleRecording=function(e){if(this.$inReplay)return;return e&&e._emit("changeStatus"),this.recording?(this.macro.pop(),this.removeEventListener("exec",this.$addCommandToMacro),this.macro.length||(this.macro=this.oldMacro),this.recording=!1):(this.$addCommandToMacro||(this.$addCommandToMacro=function(e){this.macro.push([e.command,e.args])}.bind(this)),this.oldMacro=this.macro,this.macro=[],this.on("exec",this.$addCommandToMacro),this.recording=!0)},this.replay=function(e){if(this.$inReplay||!this.macro)return;if(this.recording)return this.toggleRecording(e);try{this.$inReplay=!0,this.macro.forEach(function(t){typeof t=="string"?this.exec(t,e):this.exec(t[0],e,t[1])},this)}finally{this.$inReplay=!1}},this.trimMacro=function(e){return e.map(function(e){return typeof e[0]!="string"&&(e[0]=e[0].name),e[1]||(e=e[0]),e})}}.call(o.prototype),t.CommandManager=o}),ace.define("ace/commands/default_commands",["require","exports","module","ace/lib/lang","ace/config","ace/range"],function(e,t,n){"use strict";function o(e,t){return{win:e,mac:t}}var r=e("../lib/lang"),i=e("../config"),s=e("../range").Range;t.commands=[{name:"showSettingsMenu",bindKey:o("Ctrl-,","Command-,"),exec:function(e){i.loadModule("ace/ext/settings_menu",function(t){t.init(e),e.showSettingsMenu()})},readOnly:!0},{name:"goToNextError",bindKey:o("Alt-E","Ctrl-E"),exec:function(e){i.loadModule("ace/ext/error_marker",function(t){t.showErrorMarker(e,1)})},scrollIntoView:"animate",readOnly:!0},{name:"goToPreviousError",bindKey:o("Alt-Shift-E","Ctrl-Shift-E"),exec:function(e){i.loadModule("ace/ext/error_marker",function(t){t.showErrorMarker(e,-1)})},scrollIntoView:"animate",readOnly:!0},{name:"selectall",bindKey:o("Ctrl-A","Command-A"),exec:function(e){e.selectAll()},readOnly:!0},{name:"centerselection",bindKey:o(null,"Ctrl-L"),exec:function(e){e.centerSelection()},readOnly:!0},{name:"gotoline",bindKey:o("Ctrl-L","Command-L"),exec:function(e){var t=parseInt(prompt("Enter line number:"),10);isNaN(t)||e.gotoLine(t)},readOnly:!0},{name:"fold",bindKey:o("Alt-L|Ctrl-F1","Command-Alt-L|Command-F1"),exec:function(e){e.session.toggleFold(!1)},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"unfold",bindKey:o("Alt-Shift-L|Ctrl-Shift-F1","Command-Alt-Shift-L|Command-Shift-F1"),exec:function(e){e.session.toggleFold(!0)},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"toggleFoldWidget",bindKey:o("F2","F2"),exec:function(e){e.session.toggleFoldWidget()},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"toggleParentFoldWidget",bindKey:o("Alt-F2","Alt-F2"),exec:function(e){e.session.toggleFoldWidget(!0)},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"foldall",bindKey:o(null,"Ctrl-Command-Option-0"),exec:function(e){e.session.foldAll()},scrollIntoView:"center",readOnly:!0},{name:"foldOther",bindKey:o("Alt-0","Command-Option-0"),exec:function(e){e.session.foldAll(),e.session.unfold(e.selection.getAllRanges())},scrollIntoView:"center",readOnly:!0},{name:"unfoldall",bindKey:o("Alt-Shift-0","Command-Option-Shift-0"),exec:function(e){e.session.unfold()},scrollIntoView:"center",readOnly:!0},{name:"findnext",bindKey:o("Ctrl-K","Command-G"),exec:function(e){e.findNext()},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"findprevious",bindKey:o("Ctrl-Shift-K","Command-Shift-G"),exec:function(e){e.findPrevious()},multiSelectAction:"forEach",scrollIntoView:"center",readOnly:!0},{name:"selectOrFindNext",bindKey:o("Alt-K","Ctrl-G"),exec:function(e){e.selection.isEmpty()?e.selection.selectWord():e.findNext()},readOnly:!0},{name:"selectOrFindPrevious",bindKey:o("Alt-Shift-K","Ctrl-Shift-G"),exec:function(e){e.selection.isEmpty()?e.selection.selectWord():e.findPrevious()},readOnly:!0},{name:"find",bindKey:o("Ctrl-F","Command-F"),exec:function(e){i.loadModule("ace/ext/searchbox",function(t){t.Search(e)})},readOnly:!0},{name:"overwrite",bindKey:"Insert",exec:function(e){e.toggleOverwrite()},readOnly:!0},{name:"selecttostart",bindKey:o("Ctrl-Shift-Home","Command-Shift-Up"),exec:function(e){e.getSelection().selectFileStart()},multiSelectAction:"forEach",readOnly:!0,scrollIntoView:"animate",aceCommandGroup:"fileJump"},{name:"gotostart",bindKey:o("Ctrl-Home","Command-Home|Command-Up"),exec:function(e){e.navigateFileStart()},multiSelectAction:"forEach",readOnly:!0,scrollIntoView:"animate",aceCommandGroup:"fileJump"},{name:"selectup",bindKey:o("Shift-Up","Shift-Up"),exec:function(e){e.getSelection().selectUp()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"golineup",bindKey:o("Up","Up|Ctrl-P"),exec:function(e,t){e.navigateUp(t.times)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selecttoend",bindKey:o("Ctrl-Shift-End","Command-Shift-Down"),exec:function(e){e.getSelection().selectFileEnd()},multiSelectAction:"forEach",readOnly:!0,scrollIntoView:"animate",aceCommandGroup:"fileJump"},{name:"gotoend",bindKey:o("Ctrl-End","Command-End|Command-Down"),exec:function(e){e.navigateFileEnd()},multiSelectAction:"forEach",readOnly:!0,scrollIntoView:"animate",aceCommandGroup:"fileJump"},{name:"selectdown",bindKey:o("Shift-Down","Shift-Down"),exec:function(e){e.getSelection().selectDown()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"golinedown",bindKey:o("Down","Down|Ctrl-N"),exec:function(e,t){e.navigateDown(t.times)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectwordleft",bindKey:o("Ctrl-Shift-Left","Option-Shift-Left"),exec:function(e){e.getSelection().selectWordLeft()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotowordleft",bindKey:o("Ctrl-Left","Option-Left"),exec:function(e){e.navigateWordLeft()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selecttolinestart",bindKey:o("Alt-Shift-Left","Command-Shift-Left"),exec:function(e){e.getSelection().selectLineStart()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotolinestart",bindKey:o("Alt-Left|Home","Command-Left|Home|Ctrl-A"),exec:function(e){e.navigateLineStart()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectleft",bindKey:o("Shift-Left","Shift-Left"),exec:function(e){e.getSelection().selectLeft()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotoleft",bindKey:o("Left","Left|Ctrl-B"),exec:function(e,t){e.navigateLeft(t.times)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectwordright",bindKey:o("Ctrl-Shift-Right","Option-Shift-Right"),exec:function(e){e.getSelection().selectWordRight()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotowordright",bindKey:o("Ctrl-Right","Option-Right"),exec:function(e){e.navigateWordRight()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selecttolineend",bindKey:o("Alt-Shift-Right","Command-Shift-Right"),exec:function(e){e.getSelection().selectLineEnd()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotolineend",bindKey:o("Alt-Right|End","Command-Right|End|Ctrl-E"),exec:function(e){e.navigateLineEnd()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectright",bindKey:o("Shift-Right","Shift-Right"),exec:function(e){e.getSelection().selectRight()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"gotoright",bindKey:o("Right","Right|Ctrl-F"),exec:function(e,t){e.navigateRight(t.times)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectpagedown",bindKey:"Shift-PageDown",exec:function(e){e.selectPageDown()},readOnly:!0},{name:"pagedown",bindKey:o(null,"Option-PageDown"),exec:function(e){e.scrollPageDown()},readOnly:!0},{name:"gotopagedown",bindKey:o("PageDown","PageDown|Ctrl-V"),exec:function(e){e.gotoPageDown()},readOnly:!0},{name:"selectpageup",bindKey:"Shift-PageUp",exec:function(e){e.selectPageUp()},readOnly:!0},{name:"pageup",bindKey:o(null,"Option-PageUp"),exec:function(e){e.scrollPageUp()},readOnly:!0},{name:"gotopageup",bindKey:"PageUp",exec:function(e){e.gotoPageUp()},readOnly:!0},{name:"scrollup",bindKey:o("Ctrl-Up",null),exec:function(e){e.renderer.scrollBy(0,-2*e.renderer.layerConfig.lineHeight)},readOnly:!0},{name:"scrolldown",bindKey:o("Ctrl-Down",null),exec:function(e){e.renderer.scrollBy(0,2*e.renderer.layerConfig.lineHeight)},readOnly:!0},{name:"selectlinestart",bindKey:"Shift-Home",exec:function(e){e.getSelection().selectLineStart()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"selectlineend",bindKey:"Shift-End",exec:function(e){e.getSelection().selectLineEnd()},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"togglerecording",bindKey:o("Ctrl-Alt-E","Command-Option-E"),exec:function(e){e.commands.toggleRecording(e)},readOnly:!0},{name:"replaymacro",bindKey:o("Ctrl-Shift-E","Command-Shift-E"),exec:function(e){e.commands.replay(e)},readOnly:!0},{name:"jumptomatching",bindKey:o("Ctrl-P","Ctrl-P"),exec:function(e){e.jumpToMatching()},multiSelectAction:"forEach",scrollIntoView:"animate",readOnly:!0},{name:"selecttomatching",bindKey:o("Ctrl-Shift-P","Ctrl-Shift-P"),exec:function(e){e.jumpToMatching(!0)},multiSelectAction:"forEach",scrollIntoView:"animate",readOnly:!0},{name:"expandToMatching",bindKey:o("Ctrl-Shift-M","Ctrl-Shift-M"),exec:function(e){e.jumpToMatching(!0,!0)},multiSelectAction:"forEach",scrollIntoView:"animate",readOnly:!0},{name:"passKeysToBrowser",bindKey:o(null,null),exec:function(){},passEvent:!0,readOnly:!0},{name:"copy",exec:function(e){},readOnly:!0},{name:"cut",exec:function(e){var t=e.getSelectionRange();e._emit("cut",t),e.selection.isEmpty()||(e.session.remove(t),e.clearSelection())},scrollIntoView:"cursor",multiSelectAction:"forEach"},{name:"paste",exec:function(e,t){e.$handlePaste(t)},scrollIntoView:"cursor"},{name:"removeline",bindKey:o("Ctrl-D","Command-D"),exec:function(e){e.removeLines()},scrollIntoView:"cursor",multiSelectAction:"forEachLine"},{name:"duplicateSelection",bindKey:o("Ctrl-Shift-D","Command-Shift-D"),exec:function(e){e.duplicateSelection()},scrollIntoView:"cursor",multiSelectAction:"forEach"},{name:"sortlines",bindKey:o("Ctrl-Alt-S","Command-Alt-S"),exec:function(e){e.sortLines()},scrollIntoView:"selection",multiSelectAction:"forEachLine"},{name:"togglecomment",bindKey:o("Ctrl-/","Command-/"),exec:function(e){e.toggleCommentLines()},multiSelectAction:"forEachLine",scrollIntoView:"selectionPart"},{name:"toggleBlockComment",bindKey:o("Ctrl-Shift-/","Command-Shift-/"),exec:function(e){e.toggleBlockComment()},multiSelectAction:"forEach",scrollIntoView:"selectionPart"},{name:"modifyNumberUp",bindKey:o("Ctrl-Shift-Up","Alt-Shift-Up"),exec:function(e){e.modifyNumber(1)},scrollIntoView:"cursor",multiSelectAction:"forEach"},{name:"modifyNumberDown",bindKey:o("Ctrl-Shift-Down","Alt-Shift-Down"),exec:function(e){e.modifyNumber(-1)},scrollIntoView:"cursor",multiSelectAction:"forEach"},{name:"replace",bindKey:o("Ctrl-H","Command-Option-F"),exec:function(e){i.loadModule("ace/ext/searchbox",function(t){t.Search(e,!0)})}},{name:"undo",bindKey:o("Ctrl-Z","Command-Z"),exec:function(e){e.undo()}},{name:"redo",bindKey:o("Ctrl-Shift-Z|Ctrl-Y","Command-Shift-Z|Command-Y"),exec:function(e){e.redo()}},{name:"copylinesup",bindKey:o("Alt-Shift-Up","Command-Option-Up"),exec:function(e){e.copyLinesUp()},scrollIntoView:"cursor"},{name:"movelinesup",bindKey:o("Alt-Up","Option-Up"),exec:function(e){e.moveLinesUp()},scrollIntoView:"cursor"},{name:"copylinesdown",bindKey:o("Alt-Shift-Down","Command-Option-Down"),exec:function(e){e.copyLinesDown()},scrollIntoView:"cursor"},{name:"movelinesdown",bindKey:o("Alt-Down","Option-Down"),exec:function(e){e.moveLinesDown()},scrollIntoView:"cursor"},{name:"del",bindKey:o("Delete","Delete|Ctrl-D|Shift-Delete"),exec:function(e){e.remove("right")},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"backspace",bindKey:o("Shift-Backspace|Backspace","Ctrl-Backspace|Shift-Backspace|Backspace|Ctrl-H"),exec:function(e){e.remove("left")},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"cut_or_delete",bindKey:o("Shift-Delete",null),exec:function(e){if(!e.selection.isEmpty())return!1;e.remove("left")},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removetolinestart",bindKey:o("Alt-Backspace","Command-Backspace"),exec:function(e){e.removeToLineStart()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removetolineend",bindKey:o("Alt-Delete","Ctrl-K"),exec:function(e){e.removeToLineEnd()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removewordleft",bindKey:o("Ctrl-Backspace","Alt-Backspace|Ctrl-Alt-Backspace"),exec:function(e){e.removeWordLeft()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"removewordright",bindKey:o("Ctrl-Delete","Alt-Delete"),exec:function(e){e.removeWordRight()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"outdent",bindKey:o("Shift-Tab","Shift-Tab"),exec:function(e){e.blockOutdent()},multiSelectAction:"forEach",scrollIntoView:"selectionPart"},{name:"indent",bindKey:o("Tab","Tab"),exec:function(e){e.indent()},multiSelectAction:"forEach",scrollIntoView:"selectionPart"},{name:"blockoutdent",bindKey:o("Ctrl-[","Ctrl-["),exec:function(e){e.blockOutdent()},multiSelectAction:"forEachLine",scrollIntoView:"selectionPart"},{name:"blockindent",bindKey:o("Ctrl-]","Ctrl-]"),exec:function(e){e.blockIndent()},multiSelectAction:"forEachLine",scrollIntoView:"selectionPart"},{name:"insertstring",exec:function(e,t){e.insert(t)},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"inserttext",exec:function(e,t){e.insert(r.stringRepeat(t.text||"",t.times||1))},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"splitline",bindKey:o(null,"Ctrl-O"),exec:function(e){e.splitLine()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"transposeletters",bindKey:o("Ctrl-T","Ctrl-T"),exec:function(e){e.transposeLetters()},multiSelectAction:function(e){e.transposeSelections(1)},scrollIntoView:"cursor"},{name:"touppercase",bindKey:o("Ctrl-U","Ctrl-U"),exec:function(e){e.toUpperCase()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"tolowercase",bindKey:o("Ctrl-Shift-U","Ctrl-Shift-U"),exec:function(e){e.toLowerCase()},multiSelectAction:"forEach",scrollIntoView:"cursor"},{name:"expandtoline",bindKey:o("Ctrl-Shift-L","Command-Shift-L"),exec:function(e){var t=e.selection.getRange();t.start.column=t.end.column=0,t.end.row++,e.selection.setRange(t,!1)},multiSelectAction:"forEach",scrollIntoView:"cursor",readOnly:!0},{name:"joinlines",bindKey:o(null,null),exec:function(e){var t=e.selection.isBackwards(),n=t?e.selection.getSelectionLead():e.selection.getSelectionAnchor(),i=t?e.selection.getSelectionAnchor():e.selection.getSelectionLead(),o=e.session.doc.getLine(n.row).length,u=e.session.doc.getTextRange(e.selection.getRange()),a=u.replace(/\n\s*/," ").length,f=e.session.doc.getLine(n.row);for(var l=n.row+1;l<=i.row+1;l++){var c=r.stringTrimLeft(r.stringTrimRight(e.session.doc.getLine(l)));c.length!==0&&(c=" "+c),f+=c}i.row+1<e.session.doc.getLength()-1&&(f+=e.session.doc.getNewLineCharacter()),e.clearSelection(),e.session.doc.replace(new s(n.row,0,i.row+2,0),f),a>0?(e.selection.moveCursorTo(n.row,n.column),e.selection.selectTo(n.row,n.column+a)):(o=e.session.doc.getLine(n.row).length>o?o+1:o,e.selection.moveCursorTo(n.row,o))},multiSelectAction:"forEach",readOnly:!0},{name:"invertSelection",bindKey:o(null,null),exec:function(e){var t=e.session.doc.getLength()-1,n=e.session.doc.getLine(t).length,r=e.selection.rangeList.ranges,i=[];r.length<1&&(r=[e.selection.getRange()]);for(var o=0;o<r.length;o++)o==r.length-1&&(r[o].end.row!==t||r[o].end.column!==n)&&i.push(new s(r[o].end.row,r[o].end.column,t,n)),o===0?(r[o].start.row!==0||r[o].start.column!==0)&&i.push(new s(0,0,r[o].start.row,r[o].start.column)):i.push(new s(r[o-1].end.row,r[o-1].end.column,r[o].start.row,r[o].start.column));e.exitMultiSelectMode(),e.clearSelection();for(var o=0;o<i.length;o++)e.selection.addRange(i[o],!1)},readOnly:!0,scrollIntoView:"none"}]}),ace.define("ace/editor",["require","exports","module","ace/lib/fixoldbrowsers","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/lib/useragent","ace/keyboard/textinput","ace/mouse/mouse_handler","ace/mouse/fold_handler","ace/keyboard/keybinding","ace/edit_session","ace/search","ace/range","ace/lib/event_emitter","ace/commands/command_manager","ace/commands/default_commands","ace/config","ace/token_iterator"],function(e,t,n){"use strict";e("./lib/fixoldbrowsers");var r=e("./lib/oop"),i=e("./lib/dom"),s=e("./lib/lang"),o=e("./lib/useragent"),u=e("./keyboard/textinput").TextInput,a=e("./mouse/mouse_handler").MouseHandler,f=e("./mouse/fold_handler").FoldHandler,l=e("./keyboard/keybinding").KeyBinding,c=e("./edit_session").EditSession,h=e("./search").Search,p=e("./range").Range,d=e("./lib/event_emitter").EventEmitter,v=e("./commands/command_manager").CommandManager,m=e("./commands/default_commands").commands,g=e("./config"),y=e("./token_iterator").TokenIterator,b=function(e,t){var n=e.getContainerElement();this.container=n,this.renderer=e,this.commands=new v(o.isMac?"mac":"win",m),this.textInput=new u(e.getTextAreaContainer(),this),this.renderer.textarea=this.textInput.getElement(),this.keyBinding=new l(this),this.$mouseHandler=new a(this),new f(this),this.$blockScrolling=0,this.$search=(new h).set({wrap:!0}),this.$historyTracker=this.$historyTracker.bind(this),this.commands.on("exec",this.$historyTracker),this.$initOperationListeners(),this._$emitInputEvent=s.delayedCall(function(){this._signal("input",{}),this.session&&this.session.bgTokenizer&&this.session.bgTokenizer.scheduleStart()}.bind(this)),this.on("change",function(e,t){t._$emitInputEvent.schedule(31)}),this.setSession(t||new c("")),g.resetOptions(this),g._signal("editor",this)};(function(){r.implement(this,d),this.$initOperationListeners=function(){function e(e){return e[e.length-1]}this.selections=[],this.commands.on("exec",this.startOperation.bind(this),!0),this.commands.on("afterExec",this.endOperation.bind(this),!0),this.$opResetTimer=s.delayedCall(this.endOperation.bind(this)),this.on("change",function(){this.curOp||this.startOperation(),this.curOp.docChanged=!0}.bind(this),!0),this.on("changeSelection",function(){this.curOp||this.startOperation(),this.curOp.selectionChanged=!0}.bind(this),!0)},this.curOp=null,this.prevOp={},this.startOperation=function(e){if(this.curOp){if(!e||this.curOp.command)return;this.prevOp=this.curOp}e||(this.previousCommand=null,e={}),this.$opResetTimer.schedule(),this.curOp={command:e.command||{},args:e.args,scrollTop:this.renderer.scrollTop},this.curOp.command.name&&this.curOp.command.scrollIntoView!==undefined&&this.$blockScrolling++},this.endOperation=function(e){if(this.curOp){if(e&&e.returnValue===!1)return this.curOp=null;this._signal("beforeEndOperation");var t=this.curOp.command;t.name&&this.$blockScrolling>0&&this.$blockScrolling--;var n=t&&t.scrollIntoView;if(n){switch(n){case"center-animate":n="animate";case"center":this.renderer.scrollCursorIntoView(null,.5);break;case"animate":case"cursor":this.renderer.scrollCursorIntoView();break;case"selectionPart":var r=this.selection.getRange(),i=this.renderer.layerConfig;(r.start.row>=i.lastRow||r.end.row<=i.firstRow)&&this.renderer.scrollSelectionIntoView(this.selection.anchor,this.selection.lead);break;default:}n=="animate"&&this.renderer.animateScrolling(this.curOp.scrollTop)}this.prevOp=this.curOp,this.curOp=null}},this.$mergeableCommands=["backspace","del","insertstring"],this.$historyTracker=function(e){if(!this.$mergeUndoDeltas)return;var t=this.prevOp,n=this.$mergeableCommands,r=t.command&&e.command.name==t.command.name;if(e.command.name=="insertstring"){var i=e.args;this.mergeNextCommand===undefined&&(this.mergeNextCommand=!0),r=r&&this.mergeNextCommand&&(!/\s/.test(i)||/\s/.test(t.args)),this.mergeNextCommand=!0}else r=r&&n.indexOf(e.command.name)!==-1;this.$mergeUndoDeltas!="always"&&Date.now()-this.sequenceStartTime>2e3&&(r=!1),r?this.session.mergeUndoDeltas=!0:n.indexOf(e.command.name)!==-1&&(this.sequenceStartTime=Date.now())},this.setKeyboardHandler=function(e,t){if(e&&typeof e=="string"){this.$keybindingId=e;var n=this;g.loadModule(["keybinding",e],function(r){n.$keybindingId==e&&n.keyBinding.setKeyboardHandler(r&&r.handler),t&&t()})}else this.$keybindingId=null,this.keyBinding.setKeyboardHandler(e),t&&t()},this.getKeyboardHandler=function(){return this.keyBinding.getKeyboardHandler()},this.setSession=function(e){if(this.session==e)return;this.curOp&&this.endOperation(),this.curOp={};var t=this.session;if(t){this.session.off("change",this.$onDocumentChange),this.session.off("changeMode",this.$onChangeMode),this.session.off("tokenizerUpdate",this.$onTokenizerUpdate),this.session.off("changeTabSize",this.$onChangeTabSize),this.session.off("changeWrapLimit",this.$onChangeWrapLimit),this.session.off("changeWrapMode",this.$onChangeWrapMode),this.session.off("changeFold",this.$onChangeFold),this.session.off("changeFrontMarker",this.$onChangeFrontMarker),this.session.off("changeBackMarker",this.$onChangeBackMarker),this.session.off("changeBreakpoint",this.$onChangeBreakpoint),this.session.off("changeAnnotation",this.$onChangeAnnotation),this.session.off("changeOverwrite",this.$onCursorChange),this.session.off("changeScrollTop",this.$onScrollTopChange),this.session.off("changeScrollLeft",this.$onScrollLeftChange);var n=this.session.getSelection();n.off("changeCursor",this.$onCursorChange),n.off("changeSelection",this.$onSelectionChange)}this.session=e,e?(this.$onDocumentChange=this.onDocumentChange.bind(this),e.on("change",this.$onDocumentChange),this.renderer.setSession(e),this.$onChangeMode=this.onChangeMode.bind(this),e.on("changeMode",this.$onChangeMode),this.$onTokenizerUpdate=this.onTokenizerUpdate.bind(this),e.on("tokenizerUpdate",this.$onTokenizerUpdate),this.$onChangeTabSize=this.renderer.onChangeTabSize.bind(this.renderer),e.on("changeTabSize",this.$onChangeTabSize),this.$onChangeWrapLimit=this.onChangeWrapLimit.bind(this),e.on("changeWrapLimit",this.$onChangeWrapLimit),this.$onChangeWrapMode=this.onChangeWrapMode.bind(this),e.on("changeWrapMode",this.$onChangeWrapMode),this.$onChangeFold=this.onChangeFold.bind(this),e.on("changeFold",this.$onChangeFold),this.$onChangeFrontMarker=this.onChangeFrontMarker.bind(this),this.session.on("changeFrontMarker",this.$onChangeFrontMarker),this.$onChangeBackMarker=this.onChangeBackMarker.bind(this),this.session.on("changeBackMarker",this.$onChangeBackMarker),this.$onChangeBreakpoint=this.onChangeBreakpoint.bind(this),this.session.on("changeBreakpoint",this.$onChangeBreakpoint),this.$onChangeAnnotation=this.onChangeAnnotation.bind(this),this.session.on("changeAnnotation",this.$onChangeAnnotation),this.$onCursorChange=this.onCursorChange.bind(this),this.session.on("changeOverwrite",this.$onCursorChange),this.$onScrollTopChange=this.onScrollTopChange.bind(this),this.session.on("changeScrollTop",this.$onScrollTopChange),this.$onScrollLeftChange=this.onScrollLeftChange.bind(this),this.session.on("changeScrollLeft",this.$onScrollLeftChange),this.selection=e.getSelection(),this.selection.on("changeCursor",this.$onCursorChange),this.$onSelectionChange=this.onSelectionChange.bind(this),this.selection.on("changeSelection",this.$onSelectionChange),this.onChangeMode(),this.$blockScrolling+=1,this.onCursorChange(),this.$blockScrolling-=1,this.onScrollTopChange(),this.onScrollLeftChange(),this.onSelectionChange(),this.onChangeFrontMarker(),this.onChangeBackMarker(),this.onChangeBreakpoint(),this.onChangeAnnotation(),this.session.getUseWrapMode()&&this.renderer.adjustWrapLimit(),this.renderer.updateFull()):(this.selection=null,this.renderer.setSession(e)),this._signal("changeSession",{session:e,oldSession:t}),this.curOp=null,t&&t._signal("changeEditor",{oldEditor:this}),e&&e._signal("changeEditor",{editor:this})},this.getSession=function(){return this.session},this.setValue=function(e,t){return this.session.doc.setValue(e),t?t==1?this.navigateFileEnd():t==-1&&this.navigateFileStart():this.selectAll(),e},this.getValue=function(){return this.session.getValue()},this.getSelection=function(){return this.selection},this.resize=function(e){this.renderer.onResize(e)},this.setTheme=function(e,t){this.renderer.setTheme(e,t)},this.getTheme=function(){return this.renderer.getTheme()},this.setStyle=function(e){this.renderer.setStyle(e)},this.unsetStyle=function(e){this.renderer.unsetStyle(e)},this.getFontSize=function(){return this.getOption("fontSize")||i.computedStyle(this.container,"fontSize")},this.setFontSize=function(e){this.setOption("fontSize",e)},this.$highlightBrackets=function(){this.session.$bracketHighlight&&(this.session.removeMarker(this.session.$bracketHighlight),this.session.$bracketHighlight=null);if(this.$highlightPending)return;var e=this;this.$highlightPending=!0,setTimeout(function(){e.$highlightPending=!1;var t=e.session;if(!t||!t.bgTokenizer)return;var n=t.findMatchingBracket(e.getCursorPosition());if(n)var r=new p(n.row,n.column,n.row,n.column+1);else if(t.$mode.getMatching)var r=t.$mode.getMatching(e.session);r&&(t.$bracketHighlight=t.addMarker(r,"ace_bracket","text"))},50)},this.$highlightTags=function(){if(this.$highlightTagPending)return;var e=this;this.$highlightTagPending=!0,setTimeout(function(){e.$highlightTagPending=!1;var t=e.session;if(!t||!t.bgTokenizer)return;var n=e.getCursorPosition(),r=new y(e.session,n.row,n.column),i=r.getCurrentToken();if(!i||!/\b(?:tag-open|tag-name)/.test(i.type)){t.removeMarker(t.$tagHighlight),t.$tagHighlight=null;return}if(i.type.indexOf("tag-open")!=-1){i=r.stepForward();if(!i)return}var s=i.value,o=0,u=r.stepBackward();if(u.value=="<"){do u=i,i=r.stepForward(),i&&i.value===s&&i.type.indexOf("tag-name")!==-1&&(u.value==="<"?o++:u.value==="</"&&o--);while(i&&o>=0)}else{do i=u,u=r.stepBackward(),i&&i.value===s&&i.type.indexOf("tag-name")!==-1&&(u.value==="<"?o++:u.value==="</"&&o--);while(u&&o<=0);r.stepForward()}if(!i){t.removeMarker(t.$tagHighlight),t.$tagHighlight=null;return}var a=r.getCurrentTokenRow(),f=r.getCurrentTokenColumn(),l=new p(a,f,a,f+i.value.length);t.$tagHighlight&&l.compareRange(t.$backMarkers[t.$tagHighlight].range)!==0&&(t.removeMarker(t.$tagHighlight),t.$tagHighlight=null),l&&!t.$tagHighlight&&(t.$tagHighlight=t.addMarker(l,"ace_bracket","text"))},50)},this.focus=function(){var e=this;setTimeout(function(){e.textInput.focus()}),this.textInput.focus()},this.isFocused=function(){return this.textInput.isFocused()},this.blur=function(){this.textInput.blur()},this.onFocus=function(e){if(this.$isFocused)return;this.$isFocused=!0,this.renderer.showCursor(),this.renderer.visualizeFocus(),this._emit("focus",e)},this.onBlur=function(e){if(!this.$isFocused)return;this.$isFocused=!1,this.renderer.hideCursor(),this.renderer.visualizeBlur(),this._emit("blur",e)},this.$cursorChange=function(){this.renderer.updateCursor()},this.onDocumentChange=function(e){var t=this.session.$useWrapMode,n=e.start.row==e.end.row?e.end.row:Infinity;this.renderer.updateLines(e.start.row,n,t),this._signal("change",e),this.$cursorChange(),this.$updateHighlightActiveLine()},this.onTokenizerUpdate=function(e){var t=e.data;this.renderer.updateLines(t.first,t.last)},this.onScrollTopChange=function(){this.renderer.scrollToY(this.session.getScrollTop())},this.onScrollLeftChange=function(){this.renderer.scrollToX(this.session.getScrollLeft())},this.onCursorChange=function(){this.$cursorChange(),this.$blockScrolling||(g.warn("Automatically scrolling cursor into view after selection change","this will be disabled in the next version","set editor.$blockScrolling = Infinity to disable this message"),this.renderer.scrollCursorIntoView()),this.$highlightBrackets(),this.$highlightTags(),this.$updateHighlightActiveLine(),this._signal("changeSelection")},this.$updateHighlightActiveLine=function(){var e=this.getSession(),t;if(this.$highlightActiveLine){if(this.$selectionStyle!="line"||!this.selection.isMultiLine())t=this.getCursorPosition();this.renderer.$maxLines&&this.session.getLength()===1&&!(this.renderer.$minLines>1)&&(t=!1)}if(e.$highlightLineMarker&&!t)e.removeMarker(e.$highlightLineMarker.id),e.$highlightLineMarker=null;else if(!e.$highlightLineMarker&&t){var n=new p(t.row,t.column,t.row,Infinity);n.id=e.addMarker(n,"ace_active-line","screenLine"),e.$highlightLineMarker=n}else t&&(e.$highlightLineMarker.start.row=t.row,e.$highlightLineMarker.end.row=t.row,e.$highlightLineMarker.start.column=t.column,e._signal("changeBackMarker"))},this.onSelectionChange=function(e){var t=this.session;t.$selectionMarker&&t.removeMarker(t.$selectionMarker),t.$selectionMarker=null;if(!this.selection.isEmpty()){var n=this.selection.getRange(),r=this.getSelectionStyle();t.$selectionMarker=t.addMarker(n,"ace_selection",r)}else this.$updateHighlightActiveLine();var i=this.$highlightSelectedWord&&this.$getSelectionHighLightRegexp();this.session.highlight(i),this._signal("changeSelection")},this.$getSelectionHighLightRegexp=function(){var e=this.session,t=this.getSelectionRange();if(t.isEmpty()||t.isMultiLine())return;var n=t.start.column-1,r=t.end.column+1,i=e.getLine(t.start.row),s=i.length,o=i.substring(Math.max(n,0),Math.min(r,s));if(n>=0&&/^[\w\d]/.test(o)||r<=s&&/[\w\d]$/.test(o))return;o=i.substring(t.start.column,t.end.column);if(!/^[\w\d]+$/.test(o))return;var u=this.$search.$assembleRegExp({wholeWord:!0,caseSensitive:!0,needle:o});return u},this.onChangeFrontMarker=function(){this.renderer.updateFrontMarkers()},this.onChangeBackMarker=function(){this.renderer.updateBackMarkers()},this.onChangeBreakpoint=function(){this.renderer.updateBreakpoints()},this.onChangeAnnotation=function(){this.renderer.setAnnotations(this.session.getAnnotations())},this.onChangeMode=function(e){this.renderer.updateText(),this._emit("changeMode",e)},this.onChangeWrapLimit=function(){this.renderer.updateFull()},this.onChangeWrapMode=function(){this.renderer.onResize(!0)},this.onChangeFold=function(){this.$updateHighlightActiveLine(),this.renderer.updateFull()},this.getSelectedText=function(){return this.session.getTextRange(this.getSelectionRange())},this.getCopyText=function(){var e=this.getSelectedText();return this._signal("copy",e),e},this.onCopy=function(){this.commands.exec("copy",this)},this.onCut=function(){this.commands.exec("cut",this)},this.onPaste=function(e,t){var n={text:e,event:t};this.commands.exec("paste",this,n)},this.$handlePaste=function(e){typeof e=="string"&&(e={text:e}),this._signal("paste",e);var t=e.text;if(!this.inMultiSelectMode||this.inVirtualSelectionMode)this.insert(t);else{var n=t.split(/\r\n|\r|\n/),r=this.selection.rangeList.ranges;if(n.length>r.length||n.length<2||!n[1])return this.commands.exec("insertstring",this,t);for(var i=r.length;i--;){var s=r[i];s.isEmpty()||this.session.remove(s),this.session.insert(s.start,n[i])}}},this.execCommand=function(e,t){return this.commands.exec(e,this,t)},this.insert=function(e,t){var n=this.session,r=n.getMode(),i=this.getCursorPosition();if(this.getBehavioursEnabled()&&!t){var s=r.transformAction(n.getState(i.row),"insertion",this,n,e);s&&(e!==s.text&&(this.session.mergeUndoDeltas=!1,this.$mergeNextCommand=!1),e=s.text)}e=="	"&&(e=this.session.getTabString());if(!this.selection.isEmpty()){var o=this.getSelectionRange();i=this.session.remove(o),this.clearSelection()}else if(this.session.getOverwrite()){var o=new p.fromPoints(i,i);o.end.column+=e.length,this.session.remove(o)}if(e=="\n"||e=="\r\n"){var u=n.getLine(i.row);if(i.column>u.search(/\S|$/)){var a=u.substr(i.column).search(/\S|$/);n.doc.removeInLine(i.row,i.column,i.column+a)}}this.clearSelection();var f=i.column,l=n.getState(i.row),u=n.getLine(i.row),c=r.checkOutdent(l,u,e),h=n.insert(i,e);s&&s.selection&&(s.selection.length==2?this.selection.setSelectionRange(new p(i.row,f+s.selection[0],i.row,f+s.selection[1])):this.selection.setSelectionRange(new p(i.row+s.selection[0],s.selection[1],i.row+s.selection[2],s.selection[3])));if(n.getDocument().isNewLine(e)){var d=r.getNextLineIndent(l,u.slice(0,i.column),n.getTabString());n.insert({row:i.row+1,column:0},d)}c&&r.autoOutdent(l,n,i.row)},this.onTextInput=function(e){this.keyBinding.onTextInput(e)},this.onCommandKey=function(e,t,n){this.keyBinding.onCommandKey(e,t,n)},this.setOverwrite=function(e){this.session.setOverwrite(e)},this.getOverwrite=function(){return this.session.getOverwrite()},this.toggleOverwrite=function(){this.session.toggleOverwrite()},this.setScrollSpeed=function(e){this.setOption("scrollSpeed",e)},this.getScrollSpeed=function(){return this.getOption("scrollSpeed")},this.setDragDelay=function(e){this.setOption("dragDelay",e)},this.getDragDelay=function(){return this.getOption("dragDelay")},this.setSelectionStyle=function(e){this.setOption("selectionStyle",e)},this.getSelectionStyle=function(){return this.getOption("selectionStyle")},this.setHighlightActiveLine=function(e){this.setOption("highlightActiveLine",e)},this.getHighlightActiveLine=function(){return this.getOption("highlightActiveLine")},this.setHighlightGutterLine=function(e){this.setOption("highlightGutterLine",e)},this.getHighlightGutterLine=function(){return this.getOption("highlightGutterLine")},this.setHighlightSelectedWord=function(e){this.setOption("highlightSelectedWord",e)},this.getHighlightSelectedWord=function(){return this.$highlightSelectedWord},this.setAnimatedScroll=function(e){this.renderer.setAnimatedScroll(e)},this.getAnimatedScroll=function(){return this.renderer.getAnimatedScroll()},this.setShowInvisibles=function(e){this.renderer.setShowInvisibles(e)},this.getShowInvisibles=function(){return this.renderer.getShowInvisibles()},this.setDisplayIndentGuides=function(e){this.renderer.setDisplayIndentGuides(e)},this.getDisplayIndentGuides=function(){return this.renderer.getDisplayIndentGuides()},this.setShowPrintMargin=function(e){this.renderer.setShowPrintMargin(e)},this.getShowPrintMargin=function(){return this.renderer.getShowPrintMargin()},this.setPrintMarginColumn=function(e){this.renderer.setPrintMarginColumn(e)},this.getPrintMarginColumn=function(){return this.renderer.getPrintMarginColumn()},this.setReadOnly=function(e){this.setOption("readOnly",e)},this.getReadOnly=function(){return this.getOption("readOnly")},this.setBehavioursEnabled=function(e){this.setOption("behavioursEnabled",e)},this.getBehavioursEnabled=function(){return this.getOption("behavioursEnabled")},this.setWrapBehavioursEnabled=function(e){this.setOption("wrapBehavioursEnabled",e)},this.getWrapBehavioursEnabled=function(){return this.getOption("wrapBehavioursEnabled")},this.setShowFoldWidgets=function(e){this.setOption("showFoldWidgets",e)},this.getShowFoldWidgets=function(){return this.getOption("showFoldWidgets")},this.setFadeFoldWidgets=function(e){this.setOption("fadeFoldWidgets",e)},this.getFadeFoldWidgets=function(){return this.getOption("fadeFoldWidgets")},this.remove=function(e){this.selection.isEmpty()&&(e=="left"?this.selection.selectLeft():this.selection.selectRight());var t=this.getSelectionRange();if(this.getBehavioursEnabled()){var n=this.session,r=n.getState(t.start.row),i=n.getMode().transformAction(r,"deletion",this,n,t);if(t.end.column===0){var s=n.getTextRange(t);if(s[s.length-1]=="\n"){var o=n.getLine(t.end.row);/^\s+$/.test(o)&&(t.end.column=o.length)}}i&&(t=i)}this.session.remove(t),this.clearSelection()},this.removeWordRight=function(){this.selection.isEmpty()&&this.selection.selectWordRight(),this.session.remove(this.getSelectionRange()),this.clearSelection()},this.removeWordLeft=function(){this.selection.isEmpty()&&this.selection.selectWordLeft(),this.session.remove(this.getSelectionRange()),this.clearSelection()},this.removeToLineStart=function(){this.selection.isEmpty()&&this.selection.selectLineStart(),this.session.remove(this.getSelectionRange()),this.clearSelection()},this.removeToLineEnd=function(){this.selection.isEmpty()&&this.selection.selectLineEnd();var e=this.getSelectionRange();e.start.column==e.end.column&&e.start.row==e.end.row&&(e.end.column=0,e.end.row++),this.session.remove(e),this.clearSelection()},this.splitLine=function(){this.selection.isEmpty()||(this.session.remove(this.getSelectionRange()),this.clearSelection());var e=this.getCursorPosition();this.insert("\n"),this.moveCursorToPosition(e)},this.transposeLetters=function(){if(!this.selection.isEmpty())return;var e=this.getCursorPosition(),t=e.column;if(t===0)return;var n=this.session.getLine(e.row),r,i;t<n.length?(r=n.charAt(t)+n.charAt(t-1),i=new p(e.row,t-1,e.row,t+1)):(r=n.charAt(t-1)+n.charAt(t-2),i=new p(e.row,t-2,e.row,t)),this.session.replace(i,r)},this.toLowerCase=function(){var e=this.getSelectionRange();this.selection.isEmpty()&&this.selection.selectWord();var t=this.getSelectionRange(),n=this.session.getTextRange(t);this.session.replace(t,n.toLowerCase()),this.selection.setSelectionRange(e)},this.toUpperCase=function(){var e=this.getSelectionRange();this.selection.isEmpty()&&this.selection.selectWord();var t=this.getSelectionRange(),n=this.session.getTextRange(t);this.session.replace(t,n.toUpperCase()),this.selection.setSelectionRange(e)},this.indent=function(){var e=this.session,t=this.getSelectionRange();if(t.start.row<t.end.row){var n=this.$getSelectedRows();e.indentRows(n.first,n.last,"	");return}if(t.start.column<t.end.column){var r=e.getTextRange(t);if(!/^\s+$/.test(r)){var n=this.$getSelectedRows();e.indentRows(n.first,n.last,"	");return}}var i=e.getLine(t.start.row),o=t.start,u=e.getTabSize(),a=e.documentToScreenColumn(o.row,o.column);if(this.session.getUseSoftTabs())var f=u-a%u,l=s.stringRepeat(" ",f);else{var f=a%u;while(i[t.start.column]==" "&&f)t.start.column--,f--;this.selection.setSelectionRange(t),l="	"}return this.insert(l)},this.blockIndent=function(){var e=this.$getSelectedRows();this.session.indentRows(e.first,e.last,"	")},this.blockOutdent=function(){var e=this.session.getSelection();this.session.outdentRows(e.getRange())},this.sortLines=function(){var e=this.$getSelectedRows(),t=this.session,n=[];for(i=e.first;i<=e.last;i++)n.push(t.getLine(i));n.sort(function(e,t){return e.toLowerCase()<t.toLowerCase()?-1:e.toLowerCase()>t.toLowerCase()?1:0});var r=new p(0,0,0,0);for(var i=e.first;i<=e.last;i++){var s=t.getLine(i);r.start.row=i,r.end.row=i,r.end.column=s.length,t.replace(r,n[i-e.first])}},this.toggleCommentLines=function(){var e=this.session.getState(this.getCursorPosition().row),t=this.$getSelectedRows();this.session.getMode().toggleCommentLines(e,this.session,t.first,t.last)},this.toggleBlockComment=function(){var e=this.getCursorPosition(),t=this.session.getState(e.row),n=this.getSelectionRange();this.session.getMode().toggleBlockComment(t,this.session,n,e)},this.getNumberAt=function(e,t){var n=/[\-]?[0-9]+(?:\.[0-9]+)?/g;n.lastIndex=0;var r=this.session.getLine(e);while(n.lastIndex<t){var i=n.exec(r);if(i.index<=t&&i.index+i[0].length>=t){var s={value:i[0],start:i.index,end:i.index+i[0].length};return s}}return null},this.modifyNumber=function(e){var t=this.selection.getCursor().row,n=this.selection.getCursor().column,r=new p(t,n-1,t,n),i=this.session.getTextRange(r);if(!isNaN(parseFloat(i))&&isFinite(i)){var s=this.getNumberAt(t,n);if(s){var o=s.value.indexOf(".")>=0?s.start+s.value.indexOf(".")+1:s.end,u=s.start+s.value.length-o,a=parseFloat(s.value);a*=Math.pow(10,u),o!==s.end&&n<o?e*=Math.pow(10,s.end-n-1):e*=Math.pow(10,s.end-n),a+=e,a/=Math.pow(10,u);var f=a.toFixed(u),l=new p(t,s.start,t,s.end);this.session.replace(l,f),this.moveCursorTo(t,Math.max(s.start+1,n+f.length-s.value.length))}}},this.removeLines=function(){var e=this.$getSelectedRows();this.session.removeFullLines(e.first,e.last),this.clearSelection()},this.duplicateSelection=function(){var e=this.selection,t=this.session,n=e.getRange(),r=e.isBackwards();if(n.isEmpty()){var i=n.start.row;t.duplicateLines(i,i)}else{var s=r?n.start:n.end,o=t.insert(s,t.getTextRange(n),!1);n.start=s,n.end=o,e.setSelectionRange(n,r)}},this.moveLinesDown=function(){this.$moveLines(1,!1)},this.moveLinesUp=function(){this.$moveLines(-1,!1)},this.moveText=function(e,t,n){return this.session.moveText(e,t,n)},this.copyLinesUp=function(){this.$moveLines(-1,!0)},this.copyLinesDown=function(){this.$moveLines(1,!0)},this.$moveLines=function(e,t){var n,r,i=this.selection;if(!i.inMultiSelectMode||this.inVirtualSelectionMode){var s=i.toOrientedRange();n=this.$getSelectedRows(s),r=this.session.$moveLines(n.first,n.last,t?0:e),t&&e==-1&&(r=0),s.moveBy(r,0),i.fromOrientedRange(s)}else{var o=i.rangeList.ranges;i.rangeList.detach(this.session),this.inVirtualSelectionMode=!0;var u=0,a=0,f=o.length;for(var l=0;l<f;l++){var c=l;o[l].moveBy(u,0),n=this.$getSelectedRows(o[l]);var h=n.first,p=n.last;while(++l<f){a&&o[l].moveBy(a,0);var d=this.$getSelectedRows(o[l]);if(t&&d.first!=p)break;if(!t&&d.first>p+1)break;p=d.last}l--,u=this.session.$moveLines(h,p,t?0:e),t&&e==-1&&(c=l+1);while(c<=l)o[c].moveBy(u,0),c++;t||(u=0),a+=u}i.fromOrientedRange(i.ranges[0]),i.rangeList.attach(this.session),this.inVirtualSelectionMode=!1}},this.$getSelectedRows=function(e){return e=(e||this.getSelectionRange()).collapseRows(),{first:this.session.getRowFoldStart(e.start.row),last:this.session.getRowFoldEnd(e.end.row)}},this.onCompositionStart=function(e){this.renderer.showComposition(this.getCursorPosition())},this.onCompositionUpdate=function(e){this.renderer.setCompositionText(e)},this.onCompositionEnd=function(){this.renderer.hideComposition()},this.getFirstVisibleRow=function(){return this.renderer.getFirstVisibleRow()},this.getLastVisibleRow=function(){return this.renderer.getLastVisibleRow()},this.isRowVisible=function(e){return e>=this.getFirstVisibleRow()&&e<=this.getLastVisibleRow()},this.isRowFullyVisible=function(e){return e>=this.renderer.getFirstFullyVisibleRow()&&e<=this.renderer.getLastFullyVisibleRow()},this.$getVisibleRowCount=function(){return this.renderer.getScrollBottomRow()-this.renderer.getScrollTopRow()+1},this.$moveByPage=function(e,t){var n=this.renderer,r=this.renderer.layerConfig,i=e*Math.floor(r.height/r.lineHeight);this.$blockScrolling++,t===!0?this.selection.$moveSelection(function(){this.moveCursorBy(i,0)}):t===!1&&(this.selection.moveCursorBy(i,0),this.selection.clearSelection()),this.$blockScrolling--;var s=n.scrollTop;n.scrollBy(0,i*r.lineHeight),t!=null&&n.scrollCursorIntoView(null,.5),n.animateScrolling(s)},this.selectPageDown=function(){this.$moveByPage(1,!0)},this.selectPageUp=function(){this.$moveByPage(-1,!0)},this.gotoPageDown=function(){this.$moveByPage(1,!1)},this.gotoPageUp=function(){this.$moveByPage(-1,!1)},this.scrollPageDown=function(){this.$moveByPage(1)},this.scrollPageUp=function(){this.$moveByPage(-1)},this.scrollToRow=function(e){this.renderer.scrollToRow(e)},this.scrollToLine=function(e,t,n,r){this.renderer.scrollToLine(e,t,n,r)},this.centerSelection=function(){var e=this.getSelectionRange(),t={row:Math.floor(e.start.row+(e.end.row-e.start.row)/2),column:Math.floor(e.start.column+(e.end.column-e.start.column)/2)};this.renderer.alignCursor(t,.5)},this.getCursorPosition=function(){return this.selection.getCursor()},this.getCursorPositionScreen=function(){return this.session.documentToScreenPosition(this.getCursorPosition())},this.getSelectionRange=function(){return this.selection.getRange()},this.selectAll=function(){this.$blockScrolling+=1,this.selection.selectAll(),this.$blockScrolling-=1},this.clearSelection=function(){this.selection.clearSelection()},this.moveCursorTo=function(e,t){this.selection.moveCursorTo(e,t)},this.moveCursorToPosition=function(e){this.selection.moveCursorToPosition(e)},this.jumpToMatching=function(e,t){var n=this.getCursorPosition(),r=new y(this.session,n.row,n.column),i=r.getCurrentToken(),s=i||r.stepForward();if(!s)return;var o,u=!1,a={},f=n.column-s.start,l,c={")":"(","(":"(","]":"[","[":"[","{":"{","}":"{"};do{if(s.value.match(/[{}()\[\]]/g))for(;f<s.value.length&&!u;f++){if(!c[s.value[f]])continue;l=c[s.value[f]]+"."+s.type.replace("rparen","lparen"),isNaN(a[l])&&(a[l]=0);switch(s.value[f]){case"(":case"[":case"{":a[l]++;break;case")":case"]":case"}":a[l]--,a[l]===-1&&(o="bracket",u=!0)}}else s&&s.type.indexOf("tag-name")!==-1&&(isNaN(a[s.value])&&(a[s.value]=0),i.value==="<"?a[s.value]++:i.value==="</"&&a[s.value]--,a[s.value]===-1&&(o="tag",u=!0));u||(i=s,s=r.stepForward(),f=0)}while(s&&!u);if(!o)return;var h,d;if(o==="bracket"){h=this.session.getBracketRange(n);if(!h){h=new p(r.getCurrentTokenRow(),r.getCurrentTokenColumn()+f-1,r.getCurrentTokenRow(),r.getCurrentTokenColumn()+f-1),d=h.start;if(t||d.row===n.row&&Math.abs(d.column-n.column)<2)h=this.session.getBracketRange(d)}}else if(o==="tag"){if(!s||s.type.indexOf("tag-name")===-1)return;var v=s.value;h=new p(r.getCurrentTokenRow(),r.getCurrentTokenColumn()-2,r.getCurrentTokenRow(),r.getCurrentTokenColumn()-2);if(h.compare(n.row,n.column)===0){u=!1;do s=i,i=r.stepBackward(),i&&(i.type.indexOf("tag-close")!==-1&&h.setEnd(r.getCurrentTokenRow(),r.getCurrentTokenColumn()+1),s.value===v&&s.type.indexOf("tag-name")!==-1&&(i.value==="<"?a[v]++:i.value==="</"&&a[v]--,a[v]===0&&(u=!0)));while(i&&!u)}s&&s.type.indexOf("tag-name")&&(d=h.start,d.row==n.row&&Math.abs(d.column-n.column)<2&&(d=h.end))}d=h&&h.cursor||d,d&&(e?h&&t?this.selection.setRange(h):h&&h.isEqual(this.getSelectionRange())?this.clearSelection():this.selection.selectTo(d.row,d.column):this.selection.moveTo(d.row,d.column))},this.gotoLine=function(e,t,n){this.selection.clearSelection(),this.session.unfold({row:e-1,column:t||0}),this.$blockScrolling+=1,this.exitMultiSelectMode&&this.exitMultiSelectMode(),this.moveCursorTo(e-1,t||0),this.$blockScrolling-=1,this.isRowFullyVisible(e-1)||this.scrollToLine(e-1,!0,n)},this.navigateTo=function(e,t){this.selection.moveTo(e,t)},this.navigateUp=function(e){if(this.selection.isMultiLine()&&!this.selection.isBackwards()){var t=this.selection.anchor.getPosition();return this.moveCursorToPosition(t)}this.selection.clearSelection(),this.selection.moveCursorBy(-e||-1,0)},this.navigateDown=function(e){if(this.selection.isMultiLine()&&this.selection.isBackwards()){var t=this.selection.anchor.getPosition();return this.moveCursorToPosition(t)}this.selection.clearSelection(),this.selection.moveCursorBy(e||1,0)},this.navigateLeft=function(e){if(!this.selection.isEmpty()){var t=this.getSelectionRange().start;this.moveCursorToPosition(t)}else{e=e||1;while(e--)this.selection.moveCursorLeft()}this.clearSelection()},this.navigateRight=function(e){if(!this.selection.isEmpty()){var t=this.getSelectionRange().end;this.moveCursorToPosition(t)}else{e=e||1;while(e--)this.selection.moveCursorRight()}this.clearSelection()},this.navigateLineStart=function(){this.selection.moveCursorLineStart(),this.clearSelection()},this.navigateLineEnd=function(){this.selection.moveCursorLineEnd(),this.clearSelection()},this.navigateFileEnd=function(){this.selection.moveCursorFileEnd(),this.clearSelection()},this.navigateFileStart=function(){this.selection.moveCursorFileStart(),this.clearSelection()},this.navigateWordRight=function(){this.selection.moveCursorWordRight(),this.clearSelection()},this.navigateWordLeft=function(){this.selection.moveCursorWordLeft(),this.clearSelection()},this.replace=function(e,t){t&&this.$search.set(t);var n=this.$search.find(this.session),r=0;return n?(this.$tryReplace(n,e)&&(r=1),n!==null&&(this.selection.setSelectionRange(n),this.renderer.scrollSelectionIntoView(n.start,n.end)),r):r},this.replaceAll=function(e,t){t&&this.$search.set(t);var n=this.$search.findAll(this.session),r=0;if(!n.length)return r;this.$blockScrolling+=1;var i=this.getSelectionRange();this.selection.moveTo(0,0);for(var s=n.length-1;s>=0;--s)this.$tryReplace(n[s],e)&&r++;return this.selection.setSelectionRange(i),this.$blockScrolling-=1,r},this.$tryReplace=function(e,t){var n=this.session.getTextRange(e);return t=this.$search.replace(n,t),t!==null?(e.end=this.session.replace(e,t),e):null},this.getLastSearchOptions=function(){return this.$search.getOptions()},this.find=function(e,t,n){t||(t={}),typeof e=="string"||e instanceof RegExp?t.needle=e:typeof e=="object"&&r.mixin(t,e);var i=this.selection.getRange();t.needle==null&&(e=this.session.getTextRange(i)||this.$search.$options.needle,e||(i=this.session.getWordRange(i.start.row,i.start.column),e=this.session.getTextRange(i)),this.$search.set({needle:e})),this.$search.set(t),t.start||this.$search.set({start:i});var s=this.$search.find(this.session);if(t.preventScroll)return s;if(s)return this.revealRange(s,n),s;t.backwards?i.start=i.end:i.end=i.start,this.selection.setRange(i)},this.findNext=function(e,t){this.find({skipCurrent:!0,backwards:!1},e,t)},this.findPrevious=function(e,t){this.find(e,{skipCurrent:!0,backwards:!0},t)},this.revealRange=function(e,t){this.$blockScrolling+=1,this.session.unfold(e),this.selection.setSelectionRange(e),this.$blockScrolling-=1;var n=this.renderer.scrollTop;this.renderer.scrollSelectionIntoView(e.start,e.end,.5),t!==!1&&this.renderer.animateScrolling(n)},this.undo=function(){this.$blockScrolling++,this.session.getUndoManager().undo(),this.$blockScrolling--,this.renderer.scrollCursorIntoView(null,.5)},this.redo=function(){this.$blockScrolling++,this.session.getUndoManager().redo(),this.$blockScrolling--,this.renderer.scrollCursorIntoView(null,.5)},this.destroy=function(){this.renderer.destroy(),this._signal("destroy",this),this.session&&this.session.destroy()},this.setAutoScrollEditorIntoView=function(e){if(!e)return;var t,n=this,r=!1;this.$scrollAnchor||(this.$scrollAnchor=document.createElement("div"));var i=this.$scrollAnchor;i.style.cssText="position:absolute",this.container.insertBefore(i,this.container.firstChild);var s=this.on("changeSelection",function(){r=!0}),o=this.renderer.on("beforeRender",function(){r&&(t=n.renderer.container.getBoundingClientRect())}),u=this.renderer.on("afterRender",function(){if(r&&t&&(n.isFocused()||n.searchBox&&n.searchBox.isFocused())){var e=n.renderer,s=e.$cursorLayer.$pixelPos,o=e.layerConfig,u=s.top-o.offset;s.top>=0&&u+t.top<0?r=!0:s.top<o.height&&s.top+t.top+o.lineHeight>window.innerHeight?r=!1:r=null,r!=null&&(i.style.top=u+"px",i.style.left=s.left+"px",i.style.height=o.lineHeight+"px",i.scrollIntoView(r)),r=t=null}});this.setAutoScrollEditorIntoView=function(e){if(e)return;delete this.setAutoScrollEditorIntoView,this.off("changeSelection",s),this.renderer.off("afterRender",u),this.renderer.off("beforeRender",o)}},this.$resetCursorStyle=function(){var e=this.$cursorStyle||"ace",t=this.renderer.$cursorLayer;if(!t)return;t.setSmoothBlinking(/smooth/.test(e)),t.isBlinking=!this.$readOnly&&e!="wide",i.setCssClass(t.element,"ace_slim-cursors",/slim/.test(e))}}).call(b.prototype),g.defineOptions(b.prototype,"editor",{selectionStyle:{set:function(e){this.onSelectionChange(),this._signal("changeSelectionStyle",{data:e})},initialValue:"line"},highlightActiveLine:{set:function(){this.$updateHighlightActiveLine()},initialValue:!0},highlightSelectedWord:{set:function(e){this.$onSelectionChange()},initialValue:!0},readOnly:{set:function(e){this.$resetCursorStyle()},initialValue:!1},cursorStyle:{set:function(e){this.$resetCursorStyle()},values:["ace","slim","smooth","wide"],initialValue:"ace"},mergeUndoDeltas:{values:[!1,!0,"always"],initialValue:!0},behavioursEnabled:{initialValue:!0},wrapBehavioursEnabled:{initialValue:!0},autoScrollEditorIntoView:{set:function(e){this.setAutoScrollEditorIntoView(e)}},keyboardHandler:{set:function(e){this.setKeyboardHandler(e)},get:function(){return this.keybindingId},handlesSet:!0},hScrollBarAlwaysVisible:"renderer",vScrollBarAlwaysVisible:"renderer",highlightGutterLine:"renderer",animatedScroll:"renderer",showInvisibles:"renderer",showPrintMargin:"renderer",printMarginColumn:"renderer",printMargin:"renderer",fadeFoldWidgets:"renderer",showFoldWidgets:"renderer",showLineNumbers:"renderer",showGutter:"renderer",displayIndentGuides:"renderer",fontSize:"renderer",fontFamily:"renderer",maxLines:"renderer",minLines:"renderer",scrollPastEnd:"renderer",fixedWidthGutter:"renderer",theme:"renderer",scrollSpeed:"$mouseHandler",dragDelay:"$mouseHandler",dragEnabled:"$mouseHandler",focusTimout:"$mouseHandler",tooltipFollowsMouse:"$mouseHandler",firstLineNumber:"session",overwrite:"session",newLineMode:"session",useWorker:"session",useSoftTabs:"session",tabSize:"session",wrap:"session",indentedSoftWrap:"session",foldStyle:"session",mode:"session"}),t.Editor=b}),ace.define("ace/undomanager",["require","exports","module"],function(e,t,n){"use strict";var r=function(){this.reset()};(function(){function e(e){return{action:e.action,start:e.start,end:e.end,lines:e.lines.length==1?null:e.lines,text:e.lines.length==1?e.lines[0]:null}}function t(e){return{action:e.action,start:e.start,end:e.end,lines:e.lines||[e.text]}}function n(e,t){var n=new Array(e.length);for(var r=0;r<e.length;r++){var i=e[r],s={group:i.group,deltas:new Array(i.length)};for(var o=0;o<i.deltas.length;o++){var u=i.deltas[o];s.deltas[o]=t(u)}n[r]=s}return n}this.execute=function(e){var t=e.args[0];this.$doc=e.args[1],e.merge&&this.hasUndo()&&(this.dirtyCounter--,t=this.$undoStack.pop().concat(t)),this.$undoStack.push(t),this.$redoStack=[],this.dirtyCounter<0&&(this.dirtyCounter=NaN),this.dirtyCounter++},this.undo=function(e){var t=this.$undoStack.pop(),n=null;return t&&(n=this.$doc.undoChanges(t,e),this.$redoStack.push(t),this.dirtyCounter--),n},this.redo=function(e){var t=this.$redoStack.pop(),n=null;return t&&(n=this.$doc.redoChanges(this.$deserializeDeltas(t),e),this.$undoStack.push(t),this.dirtyCounter++),n},this.reset=function(){this.$undoStack=[],this.$redoStack=[],this.dirtyCounter=0},this.hasUndo=function(){return this.$undoStack.length>0},this.hasRedo=function(){return this.$redoStack.length>0},this.markClean=function(){this.dirtyCounter=0},this.isClean=function(){return this.dirtyCounter===0},this.$serializeDeltas=function(t){return n(t,e)},this.$deserializeDeltas=function(e){return n(e,t)}}).call(r.prototype),t.UndoManager=r}),ace.define("ace/layer/gutter",["require","exports","module","ace/lib/dom","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("../lib/dom"),i=e("../lib/oop"),s=e("../lib/lang"),o=e("../lib/event_emitter").EventEmitter,u=function(e){this.element=r.createElement("div"),this.element.className="ace_layer ace_gutter-layer",e.appendChild(this.element),this.setShowFoldWidgets(this.$showFoldWidgets),this.gutterWidth=0,this.$annotations=[],this.$updateAnnotations=this.$updateAnnotations.bind(this),this.$cells=[]};(function(){i.implement(this,o),this.setSession=function(e){this.session&&this.session.removeEventListener("change",this.$updateAnnotations),this.session=e,e&&e.on("change",this.$updateAnnotations)},this.addGutterDecoration=function(e,t){window.console&&console.warn&&console.warn("deprecated use session.addGutterDecoration"),this.session.addGutterDecoration(e,t)},this.removeGutterDecoration=function(e,t){window.console&&console.warn&&console.warn("deprecated use session.removeGutterDecoration"),this.session.removeGutterDecoration(e,t)},this.setAnnotations=function(e){this.$annotations=[];for(var t=0;t<e.length;t++){var n=e[t],r=n.row,i=this.$annotations[r];i||(i=this.$annotations[r]={text:[]});var o=n.text;o=o?s.escapeHTML(o):n.html||"",i.text.indexOf(o)===-1&&i.text.push(o);var u=n.type;u=="error"?i.className=" ace_error":u=="warning"&&i.className!=" ace_error"?i.className=" ace_warning":u=="info"&&!i.className&&(i.className=" ace_info")}},this.$updateAnnotations=function(e){if(!this.$annotations.length)return;var t=e.start.row,n=e.end.row-t;if(n!==0)if(e.action=="remove")this.$annotations.splice(t,n+1,null);else{var r=new Array(n+1);r.unshift(t,1),this.$annotations.splice.apply(this.$annotations,r)}},this.update=function(e){var t=this.session,n=e.firstRow,i=Math.min(e.lastRow+e.gutterOffset,t.getLength()-1),s=t.getNextFoldLine(n),o=s?s.start.row:Infinity,u=this.$showFoldWidgets&&t.foldWidgets,a=t.$breakpoints,f=t.$decorations,l=t.$firstLineNumber,c=0,h=t.gutterRenderer||this.$renderer,p=null,d=-1,v=n;for(;;){v>o&&(v=s.end.row+1,s=t.getNextFoldLine(v,s),o=s?s.start.row:Infinity);if(v>i){while(this.$cells.length>d+1)p=this.$cells.pop(),this.element.removeChild(p.element);break}p=this.$cells[++d],p||(p={element:null,textNode:null,foldWidget:null},p.element=r.createElement("div"),p.textNode=document.createTextNode(""),p.element.appendChild(p.textNode),this.element.appendChild(p.element),this.$cells[d]=p);var m="ace_gutter-cell ";a[v]&&(m+=a[v]),f[v]&&(m+=f[v]),this.$annotations[v]&&(m+=this.$annotations[v].className),p.element.className!=m&&(p.element.className=m);var g=t.getRowLength(v)*e.lineHeight+"px";g!=p.element.style.height&&(p.element.style.height=g);if(u){var y=u[v];y==null&&(y=u[v]=t.getFoldWidget(v))}if(y){p.foldWidget||(p.foldWidget=r.createElement("span"),p.element.appendChild(p.foldWidget));var m="ace_fold-widget ace_"+y;y=="start"&&v==o&&v<s.end.row?m+=" ace_closed":m+=" ace_open",p.foldWidget.className!=m&&(p.foldWidget.className=m);var g=e.lineHeight+"px";p.foldWidget.style.height!=g&&(p.foldWidget.style.height=g)}else p.foldWidget&&(p.element.removeChild(p.foldWidget),p.foldWidget=null);var b=c=h?h.getText(t,v):v+l;b!=p.textNode.data&&(p.textNode.data=b),v++}this.element.style.height=e.minHeight+"px";if(this.$fixedWidth||t.$useWrapMode)c=t.getLength()+l;var w=h?h.getWidth(t,c,e):c.toString().length*e.characterWidth,E=this.$padding||this.$computePadding();w+=E.left+E.right,w!==this.gutterWidth&&!isNaN(w)&&(this.gutterWidth=w,this.element.style.width=Math.ceil(this.gutterWidth)+"px",this._emit("changeGutterWidth",w))},this.$fixedWidth=!1,this.$showLineNumbers=!0,this.$renderer="",this.setShowLineNumbers=function(e){this.$renderer=!e&&{getWidth:function(){return""},getText:function(){return""}}},this.getShowLineNumbers=function(){return this.$showLineNumbers},this.$showFoldWidgets=!0,this.setShowFoldWidgets=function(e){e?r.addCssClass(this.element,"ace_folding-enabled"):r.removeCssClass(this.element,"ace_folding-enabled"),this.$showFoldWidgets=e,this.$padding=null},this.getShowFoldWidgets=function(){return this.$showFoldWidgets},this.$computePadding=function(){if(!this.element.firstChild)return{left:0,right:0};var e=r.computedStyle(this.element.firstChild);return this.$padding={},this.$padding.left=parseInt(e.paddingLeft)+1||0,this.$padding.right=parseInt(e.paddingRight)||0,this.$padding},this.getRegion=function(e){var t=this.$padding||this.$computePadding(),n=this.element.getBoundingClientRect();if(e.x<t.left+n.left)return"markers";if(this.$showFoldWidgets&&e.x>n.right-t.right)return"foldWidgets"}}).call(u.prototype),t.Gutter=u}),ace.define("ace/layer/marker",["require","exports","module","ace/range","ace/lib/dom"],function(e,t,n){"use strict";var r=e("../range").Range,i=e("../lib/dom"),s=function(e){this.element=i.createElement("div"),this.element.className="ace_layer ace_marker-layer",e.appendChild(this.element)};(function(){function e(e,t,n,r){return(e?1:0)|(t?2:0)|(n?4:0)|(r?8:0)}this.$padding=0,this.setPadding=function(e){this.$padding=e},this.setSession=function(e){this.session=e},this.setMarkers=function(e){this.markers=e},this.update=function(e){var e=e||this.config;if(!e)return;this.config=e;var t=[];for(var n in this.markers){var r=this.markers[n];if(!r.range){r.update(t,this,this.session,e);continue}var i=r.range.clipRows(e.firstRow,e.lastRow);if(i.isEmpty())continue;i=i.toScreenRange(this.session);if(r.renderer){var s=this.$getTop(i.start.row,e),o=this.$padding+i.start.column*e.characterWidth;r.renderer(t,i,o,s,e)}else r.type=="fullLine"?this.drawFullLineMarker(t,i,r.clazz,e):r.type=="screenLine"?this.drawScreenLineMarker(t,i,r.clazz,e):i.isMultiLine()?r.type=="text"?this.drawTextMarker(t,i,r.clazz,e):this.drawMultiLineMarker(t,i,r.clazz,e):this.drawSingleLineMarker(t,i,r.clazz+" ace_start"+" ace_br15",e)}this.element.innerHTML=t.join("")},this.$getTop=function(e,t){return(e-t.firstRowScreen)*t.lineHeight},this.drawTextMarker=function(t,n,i,s,o){var u=this.session,a=n.start.row,f=n.end.row,l=a,c=0,h=0,p=u.getScreenLastRowColumn(l),d=new r(l,n.start.column,l,h);for(;l<=f;l++)d.start.row=d.end.row=l,d.start.column=l==a?n.start.column:u.getRowWrapIndent(l),d.end.column=p,c=h,h=p,p=l+1<f?u.getScreenLastRowColumn(l+1):l==f?0:n.end.column,this.drawSingleLineMarker(t,d,i+(l==a?" ace_start":"")+" ace_br"+e(l==a||l==a+1&&n.start.column,c<h,h>p,l==f),s,l==f?0:1,o)},this.drawMultiLineMarker=function(e,t,n,r,i){var s=this.$padding,o=r.lineHeight,u=this.$getTop(t.start.row,r),a=s+t.start.column*r.characterWidth;i=i||"",e.push("<div class='",n," ace_br1 ace_start' style='","height:",o,"px;","right:0;","top:",u,"px;","left:",a,"px;",i,"'></div>"),u=this.$getTop(t.end.row,r);var f=t.end.column*r.characterWidth;e.push("<div class='",n," ace_br12' style='","height:",o,"px;","width:",f,"px;","top:",u,"px;","left:",s,"px;",i,"'></div>"),o=(t.end.row-t.start.row-1)*r.lineHeight;if(o<=0)return;u=this.$getTop(t.start.row+1,r);var l=(t.start.column?1:0)|(t.end.column?0:8);e.push("<div class='",n,l?" ace_br"+l:"","' style='","height:",o,"px;","right:0;","top:",u,"px;","left:",s,"px;",i,"'></div>")},this.drawSingleLineMarker=function(e,t,n,r,i,s){var o=r.lineHeight,u=(t.end.column+(i||0)-t.start.column)*r.characterWidth,a=this.$getTop(t.start.row,r),f=this.$padding+t.start.column*r.characterWidth;e.push("<div class='",n,"' style='","height:",o,"px;","width:",u,"px;","top:",a,"px;","left:",f,"px;",s||"","'></div>")},this.drawFullLineMarker=function(e,t,n,r,i){var s=this.$getTop(t.start.row,r),o=r.lineHeight;t.start.row!=t.end.row&&(o+=this.$getTop(t.end.row,r)-s),e.push("<div class='",n,"' style='","height:",o,"px;","top:",s,"px;","left:0;right:0;",i||"","'></div>")},this.drawScreenLineMarker=function(e,t,n,r,i){var s=this.$getTop(t.start.row,r),o=r.lineHeight;e.push("<div class='",n,"' style='","height:",o,"px;","top:",s,"px;","left:0;right:0;",i||"","'></div>")}}).call(s.prototype),t.Marker=s}),ace.define("ace/layer/text",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/lib/useragent","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../lib/dom"),s=e("../lib/lang"),o=e("../lib/useragent"),u=e("../lib/event_emitter").EventEmitter,a=function(e){this.element=i.createElement("div"),this.element.className="ace_layer ace_text-layer",e.appendChild(this.element),this.$updateEolChar=this.$updateEolChar.bind(this)};(function(){r.implement(this,u),this.EOF_CHAR="\u00b6",this.EOL_CHAR_LF="\u00ac",this.EOL_CHAR_CRLF="\u00a4",this.EOL_CHAR=this.EOL_CHAR_LF,this.TAB_CHAR="\u2014",this.SPACE_CHAR="\u00b7",this.$padding=0,this.$updateEolChar=function(){var e=this.session.doc.getNewLineCharacter()=="\n"?this.EOL_CHAR_LF:this.EOL_CHAR_CRLF;if(this.EOL_CHAR!=e)return this.EOL_CHAR=e,!0},this.setPadding=function(e){this.$padding=e,this.element.style.padding="0 "+e+"px"},this.getLineHeight=function(){return this.$fontMetrics.$characterSize.height||0},this.getCharacterWidth=function(){return this.$fontMetrics.$characterSize.width||0},this.$setFontMetrics=function(e){this.$fontMetrics=e,this.$fontMetrics.on("changeCharacterSize",function(e){this._signal("changeCharacterSize",e)}.bind(this)),this.$pollSizeChanges()},this.checkForSizeChanges=function(){this.$fontMetrics.checkForSizeChanges()},this.$pollSizeChanges=function(){return this.$pollSizeChangesTimer=this.$fontMetrics.$pollSizeChanges()},this.setSession=function(e){this.session=e,e&&this.$computeTabString()},this.showInvisibles=!1,this.setShowInvisibles=function(e){return this.showInvisibles==e?!1:(this.showInvisibles=e,this.$computeTabString(),!0)},this.displayIndentGuides=!0,this.setDisplayIndentGuides=function(e){return this.displayIndentGuides==e?!1:(this.displayIndentGuides=e,this.$computeTabString(),!0)},this.$tabStrings=[],this.onChangeTabSize=this.$computeTabString=function(){var e=this.session.getTabSize();this.tabSize=e;var t=this.$tabStrings=[0];for(var n=1;n<e+1;n++)this.showInvisibles?t.push("<span class='ace_invisible ace_invisible_tab'>"+s.stringRepeat(this.TAB_CHAR,n)+"</span>"):t.push(s.stringRepeat(" ",n));if(this.displayIndentGuides){this.$indentGuideRe=/\s\S| \t|\t |\s$/;var r="ace_indent-guide",i="",o="";if(this.showInvisibles){r+=" ace_invisible",i=" ace_invisible_space",o=" ace_invisible_tab";var u=s.stringRepeat(this.SPACE_CHAR,this.tabSize),a=s.stringRepeat(this.TAB_CHAR,this.tabSize)}else var u=s.stringRepeat(" ",this.tabSize),a=u;this.$tabStrings[" "]="<span class='"+r+i+"'>"+u+"</span>",this.$tabStrings["	"]="<span class='"+r+o+"'>"+a+"</span>"}},this.updateLines=function(e,t,n){(this.config.lastRow!=e.lastRow||this.config.firstRow!=e.firstRow)&&this.scrollLines(e),this.config=e;var r=Math.max(t,e.firstRow),i=Math.min(n,e.lastRow),s=this.element.childNodes,o=0;for(var u=e.firstRow;u<r;u++){var a=this.session.getFoldLine(u);if(a){if(a.containsRow(r)){r=a.start.row;break}u=a.end.row}o++}var u=r,a=this.session.getNextFoldLine(u),f=a?a.start.row:Infinity;for(;;){u>f&&(u=a.end.row+1,a=this.session.getNextFoldLine(u,a),f=a?a.start.row:Infinity);if(u>i)break;var l=s[o++];if(l){var c=[];this.$renderLine(c,u,!this.$useLineGroups(),u==f?a:!1),l.style.height=e.lineHeight*this.session.getRowLength(u)+"px",l.innerHTML=c.join("")}u++}},this.scrollLines=function(e){var t=this.config;this.config=e;if(!t||t.lastRow<e.firstRow)return this.update(e);if(e.lastRow<t.firstRow)return this.update(e);var n=this.element;if(t.firstRow<e.firstRow)for(var r=this.session.getFoldedRowCount(t.firstRow,e.firstRow-1);r>0;r--)n.removeChild(n.firstChild);if(t.lastRow>e.lastRow)for(var r=this.session.getFoldedRowCount(e.lastRow+1,t.lastRow);r>0;r--)n.removeChild(n.lastChild);if(e.firstRow<t.firstRow){var i=this.$renderLinesFragment(e,e.firstRow,t.firstRow-1);n.firstChild?n.insertBefore(i,n.firstChild):n.appendChild(i)}if(e.lastRow>t.lastRow){var i=this.$renderLinesFragment(e,t.lastRow+1,e.lastRow);n.appendChild(i)}},this.$renderLinesFragment=function(e,t,n){var r=this.element.ownerDocument.createDocumentFragment(),s=t,o=this.session.getNextFoldLine(s),u=o?o.start.row:Infinity;for(;;){s>u&&(s=o.end.row+1,o=this.session.getNextFoldLine(s,o),u=o?o.start.row:Infinity);if(s>n)break;var a=i.createElement("div"),f=[];this.$renderLine(f,s,!1,s==u?o:!1),a.innerHTML=f.join("");if(this.$useLineGroups())a.className="ace_line_group",r.appendChild(a),a.style.height=e.lineHeight*this.session.getRowLength(s)+"px";else while(a.firstChild)r.appendChild(a.firstChild);s++}return r},this.update=function(e){this.config=e;var t=[],n=e.firstRow,r=e.lastRow,i=n,s=this.session.getNextFoldLine(i),o=s?s.start.row:Infinity;for(;;){i>o&&(i=s.end.row+1,s=this.session.getNextFoldLine(i,s),o=s?s.start.row:Infinity);if(i>r)break;this.$useLineGroups()&&t.push("<div class='ace_line_group' style='height:",e.lineHeight*this.session.getRowLength(i),"px'>"),this.$renderLine(t,i,!1,i==o?s:!1),this.$useLineGroups()&&t.push("</div>"),i++}this.element.innerHTML=t.join("")},this.$textToken={text:!0,rparen:!0,lparen:!0},this.$renderToken=function(e,t,n,r){var i=this,o=/\t|&|<|>|( +)|([\x00-\x1f\x80-\xa0\xad\u1680\u180E\u2000-\u200f\u2028\u2029\u202F\u205F\u3000\uFEFF\uFFF9-\uFFFC])|[\u1100-\u115F\u11A3-\u11A7\u11FA-\u11FF\u2329-\u232A\u2E80-\u2E99\u2E9B-\u2EF3\u2F00-\u2FD5\u2FF0-\u2FFB\u3000-\u303E\u3041-\u3096\u3099-\u30FF\u3105-\u312D\u3131-\u318E\u3190-\u31BA\u31C0-\u31E3\u31F0-\u321E\u3220-\u3247\u3250-\u32FE\u3300-\u4DBF\u4E00-\uA48C\uA490-\uA4C6\uA960-\uA97C\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFAFF\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE66\uFE68-\uFE6B\uFF01-\uFF60\uFFE0-\uFFE6]/g,u=function(e,n,r,o,u){if(n)return i.showInvisibles?"<span class='ace_invisible ace_invisible_space'>"+s.stringRepeat(i.SPACE_CHAR,e.length)+"</span>":e;if(e=="&")return"&#38;";if(e=="<")return"&#60;";if(e==">")return"&#62;";if(e=="	"){var a=i.session.getScreenTabSize(t+o);return t+=a-1,i.$tabStrings[a]}if(e=="\u3000"){var f=i.showInvisibles?"ace_cjk ace_invisible ace_invisible_space":"ace_cjk",l=i.showInvisibles?i.SPACE_CHAR:"";return t+=1,"<span class='"+f+"' style='width:"+i.config.characterWidth*2+"px'>"+l+"</span>"}return r?"<span class='ace_invisible ace_invisible_space ace_invalid'>"+i.SPACE_CHAR+"</span>":(t+=1,"<span class='ace_cjk' style='width:"+i.config.characterWidth*2+"px'>"+e+"</span>")},a=r.replace(o,u);if(!this.$textToken[n.type]){var f="ace_"+n.type.replace(/\./g," ace_"),l="";n.type=="fold"&&(l=" style='width:"+n.value.length*this.config.characterWidth+"px;' "),e.push("<span class='",f,"'",l,">",a,"</span>")}else e.push(a);return t+r.length},this.renderIndentGuide=function(e,t,n){var r=t.search(this.$indentGuideRe);return r<=0||r>=n?t:t[0]==" "?(r-=r%this.tabSize,e.push(s.stringRepeat(this.$tabStrings[" "],r/this.tabSize)),t.substr(r)):t[0]=="	"?(e.push(s.stringRepeat(this.$tabStrings["	"],r)),t.substr(r)):t},this.$renderWrappedLine=function(e,t,n,r){var i=0,o=0,u=n[0],a=0;for(var f=0;f<t.length;f++){var l=t[f],c=l.value;if(f==0&&this.displayIndentGuides){i=c.length,c=this.renderIndentGuide(e,c,u);if(!c)continue;i-=c.length}if(i+c.length<u)a=this.$renderToken(e,a,l,c),i+=c.length;else{while(i+c.length>=u)a=this.$renderToken(e,a,l,c.substring(0,u-i)),c=c.substring(u-i),i=u,r||e.push("</div>","<div class='ace_line' style='height:",this.config.lineHeight,"px'>"),e.push(s.stringRepeat("\u00a0",n.indent)),o++,a=0,u=n[o]||Number.MAX_VALUE;c.length!=0&&(i+=c.length,a=this.$renderToken(e,a,l,c))}}},this.$renderSimpleLine=function(e,t){var n=0,r=t[0],i=r.value;this.displayIndentGuides&&(i=this.renderIndentGuide(e,i)),i&&(n=this.$renderToken(e,n,r,i));for(var s=1;s<t.length;s++)r=t[s],i=r.value,n=this.$renderToken(e,n,r,i)},this.$renderLine=function(e,t,n,r){!r&&r!=0&&(r=this.session.getFoldLine(t));if(r)var i=this.$getFoldLineTokens(t,r);else var i=this.session.getTokens(t);n||e.push("<div class='ace_line' style='height:",this.config.lineHeight*(this.$useLineGroups()?1:this.session.getRowLength(t)),"px'>");if(i.length){var s=this.session.getRowSplitData(t);s&&s.length?this.$renderWrappedLine(e,i,s,n):this.$renderSimpleLine(e,i)}this.showInvisibles&&(r&&(t=r.end.row),e.push("<span class='ace_invisible ace_invisible_eol'>",t==this.session.getLength()-1?this.EOF_CHAR:this.EOL_CHAR,"</span>")),n||e.push("</div>")},this.$getFoldLineTokens=function(e,t){function i(e,t,n){var i=0,s=0;while(s+e[i].value.length<t){s+=e[i].value.length,i++;if(i==e.length)return}if(s!=t){var o=e[i].value.substring(t-s);o.length>n-t&&(o=o.substring(0,n-t)),r.push({type:e[i].type,value:o}),s=t+o.length,i+=1}while(s<n&&i<e.length){var o=e[i].value;o.length+s>n?r.push({type:e[i].type,value:o.substring(0,n-s)}):r.push(e[i]),s+=o.length,i+=1}}var n=this.session,r=[],s=n.getTokens(e);return t.walk(function(e,t,o,u,a){e!=null?r.push({type:"fold",value:e}):(a&&(s=n.getTokens(t)),s.length&&i(s,u,o))},t.end.row,this.session.getLine(t.end.row).length),r},this.$useLineGroups=function(){return this.session.getUseWrapMode()},this.destroy=function(){clearInterval(this.$pollSizeChangesTimer),this.$measureNode&&this.$measureNode.parentNode.removeChild(this.$measureNode),delete this.$measureNode}}).call(a.prototype),t.Text=a}),ace.define("ace/layer/cursor",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";var r=e("../lib/dom"),i,s=function(e){this.element=r.createElement("div"),this.element.className="ace_layer ace_cursor-layer",e.appendChild(this.element),i===undefined&&(i=!("opacity"in this.element.style)),this.isVisible=!1,this.isBlinking=!0,this.blinkInterval=1e3,this.smoothBlinking=!1,this.cursors=[],this.cursor=this.addCursor(),r.addCssClass(this.element,"ace_hidden-cursors"),this.$updateCursors=(i?this.$updateVisibility:this.$updateOpacity).bind(this)};(function(){this.$updateVisibility=function(e){var t=this.cursors;for(var n=t.length;n--;)t[n].style.visibility=e?"":"hidden"},this.$updateOpacity=function(e){var t=this.cursors;for(var n=t.length;n--;)t[n].style.opacity=e?"":"0"},this.$padding=0,this.setPadding=function(e){this.$padding=e},this.setSession=function(e){this.session=e},this.setBlinking=function(e){e!=this.isBlinking&&(this.isBlinking=e,this.restartTimer())},this.setBlinkInterval=function(e){e!=this.blinkInterval&&(this.blinkInterval=e,this.restartTimer())},this.setSmoothBlinking=function(e){e!=this.smoothBlinking&&!i&&(this.smoothBlinking=e,r.setCssClass(this.element,"ace_smooth-blinking",e),this.$updateCursors(!0),this.$updateCursors=this.$updateOpacity.bind(this),this.restartTimer())},this.addCursor=function(){var e=r.createElement("div");return e.className="ace_cursor",this.element.appendChild(e),this.cursors.push(e),e},this.removeCursor=function(){if(this.cursors.length>1){var e=this.cursors.pop();return e.parentNode.removeChild(e),e}},this.hideCursor=function(){this.isVisible=!1,r.addCssClass(this.element,"ace_hidden-cursors"),this.restartTimer()},this.showCursor=function(){this.isVisible=!0,r.removeCssClass(this.element,"ace_hidden-cursors"),this.restartTimer()},this.restartTimer=function(){var e=this.$updateCursors;clearInterval(this.intervalId),clearTimeout(this.timeoutId),this.smoothBlinking&&r.removeCssClass(this.element,"ace_smooth-blinking"),e(!0);if(!this.isBlinking||!this.blinkInterval||!this.isVisible)return;this.smoothBlinking&&setTimeout(function(){r.addCssClass(this.element,"ace_smooth-blinking")}.bind(this));var t=function(){this.timeoutId=setTimeout(function(){e(!1)},.6*this.blinkInterval)}.bind(this);this.intervalId=setInterval(function(){e(!0),t()},this.blinkInterval),t()},this.getPixelPosition=function(e,t){if(!this.config||!this.session)return{left:0,top:0};e||(e=this.session.selection.getCursor());var n=this.session.documentToScreenPosition(e),r=this.$padding+n.column*this.config.characterWidth,i=(n.row-(t?this.config.firstRowScreen:0))*this.config.lineHeight;return{left:r,top:i}},this.update=function(e){this.config=e;var t=this.session.$selectionMarkers,n=0,r=0;if(t===undefined||t.length===0)t=[{cursor:null}];for(var n=0,i=t.length;n<i;n++){var s=this.getPixelPosition(t[n].cursor,!0);if((s.top>e.height+e.offset||s.top<0)&&n>1)continue;var o=(this.cursors[r++]||this.addCursor()).style;this.drawCursor?this.drawCursor(o,s,e,t[n],this.session):(o.left=s.left+"px",o.top=s.top+"px",o.width=e.characterWidth+"px",o.height=e.lineHeight+"px")}while(this.cursors.length>r)this.removeCursor();var u=this.session.getOverwrite();this.$setOverwrite(u),this.$pixelPos=s,this.restartTimer()},this.drawCursor=null,this.$setOverwrite=function(e){e!=this.overwrite&&(this.overwrite=e,e?r.addCssClass(this.element,"ace_overwrite-cursors"):r.removeCssClass(this.element,"ace_overwrite-cursors"))},this.destroy=function(){clearInterval(this.intervalId),clearTimeout(this.timeoutId)}}).call(s.prototype),t.Cursor=s}),ace.define("ace/scrollbar",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/event","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/dom"),s=e("./lib/event"),o=e("./lib/event_emitter").EventEmitter,u=function(e){this.element=i.createElement("div"),this.element.className="ace_scrollbar ace_scrollbar"+this.classSuffix,this.inner=i.createElement("div"),this.inner.className="ace_scrollbar-inner",this.element.appendChild(this.inner),e.appendChild(this.element),this.setVisible(!1),this.skipEvent=!1,s.addListener(this.element,"scroll",this.onScroll.bind(this)),s.addListener(this.element,"mousedown",s.preventDefault)};(function(){r.implement(this,o),this.setVisible=function(e){this.element.style.display=e?"":"none",this.isVisible=e}}).call(u.prototype);var a=function(e,t){u.call(this,e),this.scrollTop=0,t.$scrollbarWidth=this.width=i.scrollbarWidth(e.ownerDocument),this.inner.style.width=this.element.style.width=(this.width||15)+5+"px"};r.inherits(a,u),function(){this.classSuffix="-v",this.onScroll=function(){this.skipEvent||(this.scrollTop=this.element.scrollTop,this._emit("scroll",{data:this.scrollTop})),this.skipEvent=!1},this.getWidth=function(){return this.isVisible?this.width:0},this.setHeight=function(e){this.element.style.height=e+"px"},this.setInnerHeight=function(e){this.inner.style.height=e+"px"},this.setScrollHeight=function(e){this.inner.style.height=e+"px"},this.setScrollTop=function(e){this.scrollTop!=e&&(this.skipEvent=!0,this.scrollTop=this.element.scrollTop=e)}}.call(a.prototype);var f=function(e,t){u.call(this,e),this.scrollLeft=0,this.height=t.$scrollbarWidth,this.inner.style.height=this.element.style.height=(this.height||15)+5+"px"};r.inherits(f,u),function(){this.classSuffix="-h",this.onScroll=function(){this.skipEvent||(this.scrollLeft=this.element.scrollLeft,this._emit("scroll",{data:this.scrollLeft})),this.skipEvent=!1},this.getHeight=function(){return this.isVisible?this.height:0},this.setWidth=function(e){this.element.style.width=e+"px"},this.setInnerWidth=function(e){this.inner.style.width=e+"px"},this.setScrollWidth=function(e){this.inner.style.width=e+"px"},this.setScrollLeft=function(e){this.scrollLeft!=e&&(this.skipEvent=!0,this.scrollLeft=this.element.scrollLeft=e)}}.call(f.prototype),t.ScrollBar=a,t.ScrollBarV=a,t.ScrollBarH=f,t.VScrollBar=a,t.HScrollBar=f}),ace.define("ace/renderloop",["require","exports","module","ace/lib/event"],function(e,t,n){"use strict";var r=e("./lib/event"),i=function(e,t){this.onRender=e,this.pending=!1,this.changes=0,this.window=t||window};(function(){this.schedule=function(e){this.changes=this.changes|e;if(!this.pending&&this.changes){this.pending=!0;var t=this;r.nextFrame(function(){t.pending=!1;var e;while(e=t.changes)t.changes=0,t.onRender(e)},this.window)}}}).call(i.prototype),t.RenderLoop=i}),ace.define("ace/layer/font_metrics",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/lib/lang","ace/lib/useragent","ace/lib/event_emitter"],function(e,t,n){var r=e("../lib/oop"),i=e("../lib/dom"),s=e("../lib/lang"),o=e("../lib/useragent"),u=e("../lib/event_emitter").EventEmitter,a=0,f=t.FontMetrics=function(e){this.el=i.createElement("div"),this.$setMeasureNodeStyles(this.el.style,!0),this.$main=i.createElement("div"),this.$setMeasureNodeStyles(this.$main.style),this.$measureNode=i.createElement("div"),this.$setMeasureNodeStyles(this.$measureNode.style),this.el.appendChild(this.$main),this.el.appendChild(this.$measureNode),e.appendChild(this.el),a||this.$testFractionalRect(),this.$measureNode.innerHTML=s.stringRepeat("X",a),this.$characterSize={width:0,height:0},this.checkForSizeChanges()};(function(){r.implement(this,u),this.$characterSize={width:0,height:0},this.$testFractionalRect=function(){var e=i.createElement("div");this.$setMeasureNodeStyles(e.style),e.style.width="0.2px",document.documentElement.appendChild(e);var t=e.getBoundingClientRect().width;t>0&&t<1?a=50:a=100,e.parentNode.removeChild(e)},this.$setMeasureNodeStyles=function(e,t){e.width=e.height="auto",e.left=e.top="0px",e.visibility="hidden",e.position="absolute",e.whiteSpace="pre",o.isIE<8?e["font-family"]="inherit":e.font="inherit",e.overflow=t?"hidden":"visible"},this.checkForSizeChanges=function(){var e=this.$measureSizes();if(e&&(this.$characterSize.width!==e.width||this.$characterSize.height!==e.height)){this.$measureNode.style.fontWeight="bold";var t=this.$measureSizes();this.$measureNode.style.fontWeight="",this.$characterSize=e,this.charSizes=Object.create(null),this.allowBoldFonts=t&&t.width===e.width&&t.height===e.height,this._emit("changeCharacterSize",{data:e})}},this.$pollSizeChanges=function(){if(this.$pollSizeChangesTimer)return this.$pollSizeChangesTimer;var e=this;return this.$pollSizeChangesTimer=setInterval(function(){e.checkForSizeChanges()},500)},this.setPolling=function(e){e?this.$pollSizeChanges():this.$pollSizeChangesTimer&&(clearInterval(this.$pollSizeChangesTimer),this.$pollSizeChangesTimer=0)},this.$measureSizes=function(){if(a===50){var e=null;try{e=this.$measureNode.getBoundingClientRect()}catch(t){e={width:0,height:0}}var n={height:e.height,width:e.width/a}}else var n={height:this.$measureNode.clientHeight,width:this.$measureNode.clientWidth/a};return n.width===0||n.height===0?null:n},this.$measureCharWidth=function(e){this.$main.innerHTML=s.stringRepeat(e,a);var t=this.$main.getBoundingClientRect();return t.width/a},this.getCharacterWidth=function(e){var t=this.charSizes[e];return t===undefined&&(t=this.charSizes[e]=this.$measureCharWidth(e)/this.$characterSize.width),t},this.destroy=function(){clearInterval(this.$pollSizeChangesTimer),this.el&&this.el.parentNode&&this.el.parentNode.removeChild(this.el)}}).call(f.prototype)}),ace.define("ace/virtual_renderer",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/config","ace/lib/useragent","ace/layer/gutter","ace/layer/marker","ace/layer/text","ace/layer/cursor","ace/scrollbar","ace/scrollbar","ace/renderloop","ace/layer/font_metrics","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/dom"),s=e("./config"),o=e("./lib/useragent"),u=e("./layer/gutter").Gutter,a=e("./layer/marker").Marker,f=e("./layer/text").Text,l=e("./layer/cursor").Cursor,c=e("./scrollbar").HScrollBar,h=e("./scrollbar").VScrollBar,p=e("./renderloop").RenderLoop,d=e("./layer/font_metrics").FontMetrics,v=e("./lib/event_emitter").EventEmitter,m='.ace_editor {position: relative;overflow: hidden;font: 12px/normal \'Monaco\', \'Menlo\', \'Ubuntu Mono\', \'Consolas\', \'source-code-pro\', monospace;direction: ltr;}.ace_scroller {position: absolute;overflow: hidden;top: 0;bottom: 0;background-color: inherit;-ms-user-select: none;-moz-user-select: none;-webkit-user-select: none;user-select: none;cursor: text;}.ace_content {position: absolute;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;min-width: 100%;}.ace_dragging .ace_scroller:before{position: absolute;top: 0;left: 0;right: 0;bottom: 0;content: \'\';background: rgba(250, 250, 250, 0.01);z-index: 1000;}.ace_dragging.ace_dark .ace_scroller:before{background: rgba(0, 0, 0, 0.01);}.ace_selecting, .ace_selecting * {cursor: text !important;}.ace_gutter {position: absolute;overflow : hidden;width: auto;top: 0;bottom: 0;left: 0;cursor: default;z-index: 4;-ms-user-select: none;-moz-user-select: none;-webkit-user-select: none;user-select: none;}.ace_gutter-active-line {position: absolute;left: 0;right: 0;}.ace_scroller.ace_scroll-left {box-shadow: 17px 0 16px -16px rgba(0, 0, 0, 0.4) inset;}.ace_gutter-cell {padding-left: 19px;padding-right: 6px;background-repeat: no-repeat;}.ace_gutter-cell.ace_error {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAABOFBMVEX/////////QRswFAb/Ui4wFAYwFAYwFAaWGAfDRymzOSH/PxswFAb/SiUwFAYwFAbUPRvjQiDllog5HhHdRybsTi3/Tyv9Tir+Syj/UC3////XurebMBIwFAb/RSHbPx/gUzfdwL3kzMivKBAwFAbbvbnhPx66NhowFAYwFAaZJg8wFAaxKBDZurf/RB6mMxb/SCMwFAYwFAbxQB3+RB4wFAb/Qhy4Oh+4QifbNRcwFAYwFAYwFAb/QRzdNhgwFAYwFAbav7v/Uy7oaE68MBK5LxLewr/r2NXewLswFAaxJw4wFAbkPRy2PyYwFAaxKhLm1tMwFAazPiQwFAaUGAb/QBrfOx3bvrv/VC/maE4wFAbRPBq6MRO8Qynew8Dp2tjfwb0wFAbx6eju5+by6uns4uH9/f36+vr/GkHjAAAAYnRSTlMAGt+64rnWu/bo8eAA4InH3+DwoN7j4eLi4xP99Nfg4+b+/u9B/eDs1MD1mO7+4PHg2MXa347g7vDizMLN4eG+Pv7i5evs/v79yu7S3/DV7/498Yv24eH+4ufQ3Ozu/v7+y13sRqwAAADLSURBVHjaZc/XDsFgGIBhtDrshlitmk2IrbHFqL2pvXf/+78DPokj7+Fz9qpU/9UXJIlhmPaTaQ6QPaz0mm+5gwkgovcV6GZzd5JtCQwgsxoHOvJO15kleRLAnMgHFIESUEPmawB9ngmelTtipwwfASilxOLyiV5UVUyVAfbG0cCPHig+GBkzAENHS0AstVF6bacZIOzgLmxsHbt2OecNgJC83JERmePUYq8ARGkJx6XtFsdddBQgZE2nPR6CICZhawjA4Fb/chv+399kfR+MMMDGOQAAAABJRU5ErkJggg==");background-repeat: no-repeat;background-position: 2px center;}.ace_gutter-cell.ace_warning {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAmVBMVEX///8AAAD///8AAAAAAABPSzb/5sAAAAB/blH/73z/ulkAAAAAAAD85pkAAAAAAAACAgP/vGz/rkDerGbGrV7/pkQICAf////e0IsAAAD/oED/qTvhrnUAAAD/yHD/njcAAADuv2r/nz//oTj/p064oGf/zHAAAAA9Nir/tFIAAAD/tlTiuWf/tkIAAACynXEAAAAAAAAtIRW7zBpBAAAAM3RSTlMAABR1m7RXO8Ln31Z36zT+neXe5OzooRDfn+TZ4p3h2hTf4t3k3ucyrN1K5+Xaks52Sfs9CXgrAAAAjklEQVR42o3PbQ+CIBQFYEwboPhSYgoYunIqqLn6/z8uYdH8Vmdnu9vz4WwXgN/xTPRD2+sgOcZjsge/whXZgUaYYvT8QnuJaUrjrHUQreGczuEafQCO/SJTufTbroWsPgsllVhq3wJEk2jUSzX3CUEDJC84707djRc5MTAQxoLgupWRwW6UB5fS++NV8AbOZgnsC7BpEAAAAABJRU5ErkJggg==");background-position: 2px center;}.ace_gutter-cell.ace_info {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAJ0Uk5TAAB2k804AAAAPklEQVQY02NgIB68QuO3tiLznjAwpKTgNyDbMegwisCHZUETUZV0ZqOquBpXj2rtnpSJT1AEnnRmL2OgGgAAIKkRQap2htgAAAAASUVORK5CYII=");background-position: 2px center;}.ace_dark .ace_gutter-cell.ace_info {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAJFBMVEUAAAChoaGAgIAqKiq+vr6tra1ZWVmUlJSbm5s8PDxubm56enrdgzg3AAAAAXRSTlMAQObYZgAAAClJREFUeNpjYMAPdsMYHegyJZFQBlsUlMFVCWUYKkAZMxZAGdxlDMQBAG+TBP4B6RyJAAAAAElFTkSuQmCC");}.ace_scrollbar {position: absolute;right: 0;bottom: 0;z-index: 6;}.ace_scrollbar-inner {position: absolute;cursor: text;left: 0;top: 0;}.ace_scrollbar-v{overflow-x: hidden;overflow-y: scroll;top: 0;}.ace_scrollbar-h {overflow-x: scroll;overflow-y: hidden;left: 0;}.ace_print-margin {position: absolute;height: 100%;}.ace_text-input {position: absolute;z-index: 0;width: 0.5em;height: 1em;opacity: 0;background: transparent;-moz-appearance: none;appearance: none;border: none;resize: none;outline: none;overflow: hidden;font: inherit;padding: 0 1px;margin: 0 -1px;text-indent: -1em;-ms-user-select: text;-moz-user-select: text;-webkit-user-select: text;user-select: text;white-space: pre!important;}.ace_text-input.ace_composition {background: inherit;color: inherit;z-index: 1000;opacity: 1;text-indent: 0;}.ace_layer {z-index: 1;position: absolute;overflow: hidden;word-wrap: normal;white-space: pre;height: 100%;width: 100%;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;pointer-events: none;}.ace_gutter-layer {position: relative;width: auto;text-align: right;pointer-events: auto;}.ace_text-layer {font: inherit !important;}.ace_cjk {display: inline-block;text-align: center;}.ace_cursor-layer {z-index: 4;}.ace_cursor {z-index: 4;position: absolute;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;border-left: 2px solid;transform: translatez(0);}.ace_slim-cursors .ace_cursor {border-left-width: 1px;}.ace_overwrite-cursors .ace_cursor {border-left-width: 0;border-bottom: 1px solid;}.ace_hidden-cursors .ace_cursor {opacity: 0.2;}.ace_smooth-blinking .ace_cursor {-webkit-transition: opacity 0.18s;transition: opacity 0.18s;}.ace_editor.ace_multiselect .ace_cursor {border-left-width: 1px;}.ace_marker-layer .ace_step, .ace_marker-layer .ace_stack {position: absolute;z-index: 3;}.ace_marker-layer .ace_selection {position: absolute;z-index: 5;}.ace_marker-layer .ace_bracket {position: absolute;z-index: 6;}.ace_marker-layer .ace_active-line {position: absolute;z-index: 2;}.ace_marker-layer .ace_selected-word {position: absolute;z-index: 4;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;}.ace_line .ace_fold {-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;display: inline-block;height: 11px;margin-top: -2px;vertical-align: middle;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII="),url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACJJREFUeNpi+P//fxgTAwPDBxDxD078RSX+YeEyDFMCIMAAI3INmXiwf2YAAAAASUVORK5CYII=");background-repeat: no-repeat, repeat-x;background-position: center center, top left;color: transparent;border: 1px solid black;border-radius: 2px;cursor: pointer;pointer-events: auto;}.ace_dark .ace_fold {}.ace_fold:hover{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAJCAYAAADU6McMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAJpJREFUeNpi/P//PwOlgAXGYGRklAVSokD8GmjwY1wasKljQpYACtpCFeADcHVQfQyMQAwzwAZI3wJKvCLkfKBaMSClBlR7BOQikCFGQEErIH0VqkabiGCAqwUadAzZJRxQr/0gwiXIal8zQQPnNVTgJ1TdawL0T5gBIP1MUJNhBv2HKoQHHjqNrA4WO4zY0glyNKLT2KIfIMAAQsdgGiXvgnYAAAAASUVORK5CYII="),url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAA3CAYAAADNNiA5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAACBJREFUeNpi+P//fz4TAwPDZxDxD5X4i5fLMEwJgAADAEPVDbjNw87ZAAAAAElFTkSuQmCC");}.ace_tooltip {background-color: #FFF;background-image: -webkit-linear-gradient(top, transparent, rgba(0, 0, 0, 0.1));background-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.1));border: 1px solid gray;border-radius: 1px;box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);color: black;max-width: 100%;padding: 3px 4px;position: fixed;z-index: 999999;-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;cursor: default;white-space: pre;word-wrap: break-word;line-height: normal;font-style: normal;font-weight: normal;letter-spacing: normal;pointer-events: none;}.ace_folding-enabled > .ace_gutter-cell {padding-right: 13px;}.ace_fold-widget {-moz-box-sizing: border-box;-webkit-box-sizing: border-box;box-sizing: border-box;margin: 0 -12px 0 1px;display: none;width: 11px;vertical-align: top;background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42mWKsQ0AMAzC8ixLlrzQjzmBiEjp0A6WwBCSPgKAXoLkqSot7nN3yMwR7pZ32NzpKkVoDBUxKAAAAABJRU5ErkJggg==");background-repeat: no-repeat;background-position: center;border-radius: 3px;border: 1px solid transparent;cursor: pointer;}.ace_folding-enabled .ace_fold-widget {display: inline-block;   }.ace_fold-widget.ace_end {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAANElEQVR42m3HwQkAMAhD0YzsRchFKI7sAikeWkrxwScEB0nh5e7KTPWimZki4tYfVbX+MNl4pyZXejUO1QAAAABJRU5ErkJggg==");}.ace_fold-widget.ace_closed {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAGCAYAAAAG5SQMAAAAOUlEQVR42jXKwQkAMAgDwKwqKD4EwQ26sSOkVWjgIIHAzPiCgaqiqnJHZnKICBERHN194O5b9vbLuAVRL+l0YWnZAAAAAElFTkSuQmCCXA==");}.ace_fold-widget:hover {border: 1px solid rgba(0, 0, 0, 0.3);background-color: rgba(255, 255, 255, 0.2);box-shadow: 0 1px 1px rgba(255, 255, 255, 0.7);}.ace_fold-widget:active {border: 1px solid rgba(0, 0, 0, 0.4);background-color: rgba(0, 0, 0, 0.05);box-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);}.ace_dark .ace_fold-widget {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHklEQVQIW2P4//8/AzoGEQ7oGCaLLAhWiSwB146BAQCSTPYocqT0AAAAAElFTkSuQmCC");}.ace_dark .ace_fold-widget.ace_end {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH0lEQVQIW2P4//8/AxQ7wNjIAjDMgC4AxjCVKBirIAAF0kz2rlhxpAAAAABJRU5ErkJggg==");}.ace_dark .ace_fold-widget.ace_closed {background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAHElEQVQIW2P4//+/AxAzgDADlOOAznHAKgPWAwARji8UIDTfQQAAAABJRU5ErkJggg==");}.ace_dark .ace_fold-widget:hover {box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);background-color: rgba(255, 255, 255, 0.1);}.ace_dark .ace_fold-widget:active {box-shadow: 0 1px 1px rgba(255, 255, 255, 0.2);}.ace_fold-widget.ace_invalid {background-color: #FFB4B4;border-color: #DE5555;}.ace_fade-fold-widgets .ace_fold-widget {-webkit-transition: opacity 0.4s ease 0.05s;transition: opacity 0.4s ease 0.05s;opacity: 0;}.ace_fade-fold-widgets:hover .ace_fold-widget {-webkit-transition: opacity 0.05s ease 0.05s;transition: opacity 0.05s ease 0.05s;opacity:1;}.ace_underline {text-decoration: underline;}.ace_bold {font-weight: bold;}.ace_nobold .ace_bold {font-weight: normal;}.ace_italic {font-style: italic;}.ace_error-marker {background-color: rgba(255, 0, 0,0.2);position: absolute;z-index: 9;}.ace_highlight-marker {background-color: rgba(255, 255, 0,0.2);position: absolute;z-index: 8;}.ace_br1 {border-top-left-radius    : 3px;}.ace_br2 {border-top-right-radius   : 3px;}.ace_br3 {border-top-left-radius    : 3px; border-top-right-radius:    3px;}.ace_br4 {border-bottom-right-radius: 3px;}.ace_br5 {border-top-left-radius    : 3px; border-bottom-right-radius: 3px;}.ace_br6 {border-top-right-radius   : 3px; border-bottom-right-radius: 3px;}.ace_br7 {border-top-left-radius    : 3px; border-top-right-radius:    3px; border-bottom-right-radius: 3px;}.ace_br8 {border-bottom-left-radius : 3px;}.ace_br9 {border-top-left-radius    : 3px; border-bottom-left-radius:  3px;}.ace_br10{border-top-right-radius   : 3px; border-bottom-left-radius:  3px;}.ace_br11{border-top-left-radius    : 3px; border-top-right-radius:    3px; border-bottom-left-radius:  3px;}.ace_br12{border-bottom-right-radius: 3px; border-bottom-left-radius:  3px;}.ace_br13{border-top-left-radius    : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius:  3px;}.ace_br14{border-top-right-radius   : 3px; border-bottom-right-radius: 3px; border-bottom-left-radius:  3px;}.ace_br15{border-top-left-radius    : 3px; border-top-right-radius:    3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;}';i.importCssString(m,"ace_editor.css");var g=function(e,t){var n=this;this.container=e||i.createElement("div"),this.$keepTextAreaAtCursor=!o.isOldIE,i.addCssClass(this.container,"ace_editor"),this.setTheme(t),this.$gutter=i.createElement("div"),this.$gutter.className="ace_gutter",this.container.appendChild(this.$gutter),this.scroller=i.createElement("div"),this.scroller.className="ace_scroller",this.container.appendChild(this.scroller),this.content=i.createElement("div"),this.content.className="ace_content",this.scroller.appendChild(this.content),this.$gutterLayer=new u(this.$gutter),this.$gutterLayer.on("changeGutterWidth",this.onGutterResize.bind(this)),this.$markerBack=new a(this.content);var r=this.$textLayer=new f(this.content);this.canvas=r.element,this.$markerFront=new a(this.content),this.$cursorLayer=new l(this.content),this.$horizScroll=!1,this.$vScroll=!1,this.scrollBar=this.scrollBarV=new h(this.container,this),this.scrollBarH=new c(this.container,this),this.scrollBarV.addEventListener("scroll",function(e){n.$scrollAnimation||n.session.setScrollTop(e.data-n.scrollMargin.top)}),this.scrollBarH.addEventListener("scroll",function(e){n.$scrollAnimation||n.session.setScrollLeft(e.data-n.scrollMargin.left)}),this.scrollTop=0,this.scrollLeft=0,this.cursorPos={row:0,column:0},this.$fontMetrics=new d(this.container),this.$textLayer.$setFontMetrics(this.$fontMetrics),this.$textLayer.addEventListener("changeCharacterSize",function(e){n.updateCharacterSize(),n.onResize(!0,n.gutterWidth,n.$size.width,n.$size.height),n._signal("changeCharacterSize",e)}),this.$size={width:0,height:0,scrollerHeight:0,scrollerWidth:0,$dirty:!0},this.layerConfig={width:1,padding:0,firstRow:0,firstRowScreen:0,lastRow:0,lineHeight:0,characterWidth:0,minHeight:1,maxHeight:1,offset:0,height:1,gutterOffset:1},this.scrollMargin={left:0,right:0,top:0,bottom:0,v:0,h:0},this.$loop=new p(this.$renderChanges.bind(this),this.container.ownerDocument.defaultView),this.$loop.schedule(this.CHANGE_FULL),this.updateCharacterSize(),this.setPadding(4),s.resetOptions(this),s._emit("renderer",this)};(function(){this.CHANGE_CURSOR=1,this.CHANGE_MARKER=2,this.CHANGE_GUTTER=4,this.CHANGE_SCROLL=8,this.CHANGE_LINES=16,this.CHANGE_TEXT=32,this.CHANGE_SIZE=64,this.CHANGE_MARKER_BACK=128,this.CHANGE_MARKER_FRONT=256,this.CHANGE_FULL=512,this.CHANGE_H_SCROLL=1024,r.implement(this,v),this.updateCharacterSize=function(){this.$textLayer.allowBoldFonts!=this.$allowBoldFonts&&(this.$allowBoldFonts=this.$textLayer.allowBoldFonts,this.setStyle("ace_nobold",!this.$allowBoldFonts)),this.layerConfig.characterWidth=this.characterWidth=this.$textLayer.getCharacterWidth(),this.layerConfig.lineHeight=this.lineHeight=this.$textLayer.getLineHeight(),this.$updatePrintMargin()},this.setSession=function(e){this.session&&this.session.doc.off("changeNewLineMode",this.onChangeNewLineMode),this.session=e,e&&this.scrollMargin.top&&e.getScrollTop()<=0&&e.setScrollTop(-this.scrollMargin.top),this.$cursorLayer.setSession(e),this.$markerBack.setSession(e),this.$markerFront.setSession(e),this.$gutterLayer.setSession(e),this.$textLayer.setSession(e);if(!e)return;this.$loop.schedule(this.CHANGE_FULL),this.session.$setFontMetrics(this.$fontMetrics),this.onChangeNewLineMode=this.onChangeNewLineMode.bind(this),this.onChangeNewLineMode(),this.session.doc.on("changeNewLineMode",this.onChangeNewLineMode)},this.updateLines=function(e,t,n){t===undefined&&(t=Infinity),this.$changedLines?(this.$changedLines.firstRow>e&&(this.$changedLines.firstRow=e),this.$changedLines.lastRow<t&&(this.$changedLines.lastRow=t)):this.$changedLines={firstRow:e,lastRow:t};if(this.$changedLines.lastRow<this.layerConfig.firstRow){if(!n)return;this.$changedLines.lastRow=this.layerConfig.lastRow}if(this.$changedLines.firstRow>this.layerConfig.lastRow)return;this.$loop.schedule(this.CHANGE_LINES)},this.onChangeNewLineMode=function(){this.$loop.schedule(this.CHANGE_TEXT),this.$textLayer.$updateEolChar()},this.onChangeTabSize=function(){this.$loop.schedule(this.CHANGE_TEXT|this.CHANGE_MARKER),this.$textLayer.onChangeTabSize()},this.updateText=function(){this.$loop.schedule(this.CHANGE_TEXT)},this.updateFull=function(e){e?this.$renderChanges(this.CHANGE_FULL,!0):this.$loop.schedule(this.CHANGE_FULL)},this.updateFontSize=function(){this.$textLayer.checkForSizeChanges()},this.$changes=0,this.$updateSizeAsync=function(){this.$loop.pending?this.$size.$dirty=!0:this.onResize()},this.onResize=function(e,t,n,r){if(this.resizing>2)return;this.resizing>0?this.resizing++:this.resizing=e?1:0;var i=this.container;r||(r=i.clientHeight||i.scrollHeight),n||(n=i.clientWidth||i.scrollWidth);var s=this.$updateCachedSize(e,t,n,r);if(!this.$size.scrollerHeight||!n&&!r)return this.resizing=0;e&&(this.$gutterLayer.$padding=null),e?this.$renderChanges(s|this.$changes,!0):this.$loop.schedule(s|this.$changes),this.resizing&&(this.resizing=0),this.scrollBarV.scrollLeft=this.scrollBarV.scrollTop=null},this.$updateCachedSize=function(e,t,n,r){r-=this.$extraHeight||0;var i=0,s=this.$size,o={width:s.width,height:s.height,scrollerHeight:s.scrollerHeight,scrollerWidth:s.scrollerWidth};r&&(e||s.height!=r)&&(s.height=r,i|=this.CHANGE_SIZE,s.scrollerHeight=s.height,this.$horizScroll&&(s.scrollerHeight-=this.scrollBarH.getHeight()),this.scrollBarV.element.style.bottom=this.scrollBarH.getHeight()+"px",i|=this.CHANGE_SCROLL);if(n&&(e||s.width!=n)){i|=this.CHANGE_SIZE,s.width=n,t==null&&(t=this.$showGutter?this.$gutter.offsetWidth:0),this.gutterWidth=t,this.scrollBarH.element.style.left=this.scroller.style.left=t+"px",s.scrollerWidth=Math.max(0,n-t-this.scrollBarV.getWidth()),this.scrollBarH.element.style.right=this.scroller.style.right=this.scrollBarV.getWidth()+"px",this.scroller.style.bottom=this.scrollBarH.getHeight()+"px";if(this.session&&this.session.getUseWrapMode()&&this.adjustWrapLimit()||e)i|=this.CHANGE_FULL}return s.$dirty=!n||!r,i&&this._signal("resize",o),i},this.onGutterResize=function(){var e=this.$showGutter?this.$gutter.offsetWidth:0;e!=this.gutterWidth&&(this.$changes|=this.$updateCachedSize(!0,e,this.$size.width,this.$size.height)),this.session.getUseWrapMode()&&this.adjustWrapLimit()?this.$loop.schedule(this.CHANGE_FULL):this.$size.$dirty?this.$loop.schedule(this.CHANGE_FULL):(this.$computeLayerConfig(),this.$loop.schedule(this.CHANGE_MARKER))},this.adjustWrapLimit=function(){var e=this.$size.scrollerWidth-this.$padding*2,t=Math.floor(e/this.characterWidth);return this.session.adjustWrapLimit(t,this.$showPrintMargin&&this.$printMarginColumn)},this.setAnimatedScroll=function(e){this.setOption("animatedScroll",e)},this.getAnimatedScroll=function(){return this.$animatedScroll},this.setShowInvisibles=function(e){this.setOption("showInvisibles",e)},this.getShowInvisibles=function(){return this.getOption("showInvisibles")},this.getDisplayIndentGuides=function(){return this.getOption("displayIndentGuides")},this.setDisplayIndentGuides=function(e){this.setOption("displayIndentGuides",e)},this.setShowPrintMargin=function(e){this.setOption("showPrintMargin",e)},this.getShowPrintMargin=function(){return this.getOption("showPrintMargin")},this.setPrintMarginColumn=function(e){this.setOption("printMarginColumn",e)},this.getPrintMarginColumn=function(){return this.getOption("printMarginColumn")},this.getShowGutter=function(){return this.getOption("showGutter")},this.setShowGutter=function(e){return this.setOption("showGutter",e)},this.getFadeFoldWidgets=function(){return this.getOption("fadeFoldWidgets")},this.setFadeFoldWidgets=function(e){this.setOption("fadeFoldWidgets",e)},this.setHighlightGutterLine=function(e){this.setOption("highlightGutterLine",e)},this.getHighlightGutterLine=function(){return this.getOption("highlightGutterLine")},this.$updateGutterLineHighlight=function(){var e=this.$cursorLayer.$pixelPos,t=this.layerConfig.lineHeight;if(this.session.getUseWrapMode()){var n=this.session.selection.getCursor();n.column=0,e=this.$cursorLayer.getPixelPosition(n,!0),t*=this.session.getRowLength(n.row)}this.$gutterLineHighlight.style.top=e.top-this.layerConfig.offset+"px",this.$gutterLineHighlight.style.height=t+"px"},this.$updatePrintMargin=function(){if(!this.$showPrintMargin&&!this.$printMarginEl)return;if(!this.$printMarginEl){var e=i.createElement("div");e.className="ace_layer ace_print-margin-layer",this.$printMarginEl=i.createElement("div"),this.$printMarginEl.className="ace_print-margin",e.appendChild(this.$printMarginEl),this.content.insertBefore(e,this.content.firstChild)}var t=this.$printMarginEl.style;t.left=this.characterWidth*this.$printMarginColumn+this.$padding+"px",t.visibility=this.$showPrintMargin?"visible":"hidden",this.session&&this.session.$wrap==-1&&this.adjustWrapLimit()},this.getContainerElement=function(){return this.container},this.getMouseEventTarget=function(){return this.scroller},this.getTextAreaContainer=function(){return this.container},this.$moveTextAreaToCursor=function(){if(!this.$keepTextAreaAtCursor)return;var e=this.layerConfig,t=this.$cursorLayer.$pixelPos.top,n=this.$cursorLayer.$pixelPos.left;t-=e.offset;var r=this.textarea.style,i=this.lineHeight;if(t<0||t>e.height-i){r.top=r.left="0";return}var s=this.characterWidth;if(this.$composition){var o=this.textarea.value.replace(/^\x01+/,"");s*=this.session.$getStringScreenWidth(o)[0]+2,i+=2}n-=this.scrollLeft,n>this.$size.scrollerWidth-s&&(n=this.$size.scrollerWidth-s),n+=this.gutterWidth,r.height=i+"px",r.width=s+"px",r.left=Math.min(n,this.$size.scrollerWidth-s)+"px",r.top=Math.min(t,this.$size.height-i)+"px"},this.getFirstVisibleRow=function(){return this.layerConfig.firstRow},this.getFirstFullyVisibleRow=function(){return this.layerConfig.firstRow+(this.layerConfig.offset===0?0:1)},this.getLastFullyVisibleRow=function(){var e=this.layerConfig,t=e.lastRow,n=this.session.documentToScreenRow(t,0)*e.lineHeight;return n-this.session.getScrollTop()>e.height-e.lineHeight?t-1:t},this.getLastVisibleRow=function(){return this.layerConfig.lastRow},this.$padding=null,this.setPadding=function(e){this.$padding=e,this.$textLayer.setPadding(e),this.$cursorLayer.setPadding(e),this.$markerFront.setPadding(e),this.$markerBack.setPadding(e),this.$loop.schedule(this.CHANGE_FULL),this.$updatePrintMargin()},this.setScrollMargin=function(e,t,n,r){var i=this.scrollMargin;i.top=e|0,i.bottom=t|0,i.right=r|0,i.left=n|0,i.v=i.top+i.bottom,i.h=i.left+i.right,i.top&&this.scrollTop<=0&&this.session&&this.session.setScrollTop(-i.top),this.updateFull()},this.getHScrollBarAlwaysVisible=function(){return this.$hScrollBarAlwaysVisible},this.setHScrollBarAlwaysVisible=function(e){this.setOption("hScrollBarAlwaysVisible",e)},this.getVScrollBarAlwaysVisible=function(){return this.$vScrollBarAlwaysVisible},this.setVScrollBarAlwaysVisible=function(e){this.setOption("vScrollBarAlwaysVisible",e)},this.$updateScrollBarV=function(){var e=this.layerConfig.maxHeight,t=this.$size.scrollerHeight;!this.$maxLines&&this.$scrollPastEnd&&(e-=(t-this.lineHeight)*this.$scrollPastEnd,this.scrollTop>e-t&&(e=this.scrollTop+t,this.scrollBarV.scrollTop=null)),this.scrollBarV.setScrollHeight(e+this.scrollMargin.v),this.scrollBarV.setScrollTop(this.scrollTop+this.scrollMargin.top)},this.$updateScrollBarH=function(){this.scrollBarH.setScrollWidth(this.layerConfig.width+2*this.$padding+this.scrollMargin.h),this.scrollBarH.setScrollLeft(this.scrollLeft+this.scrollMargin.left)},this.$frozen=!1,this.freeze=function(){this.$frozen=!0},this.unfreeze=function(){this.$frozen=!1},this.$renderChanges=function(e,t){this.$changes&&(e|=this.$changes,this.$changes=0);if(!this.session||!this.container.offsetWidth||this.$frozen||!e&&!t){this.$changes|=e;return}if(this.$size.$dirty)return this.$changes|=e,this.onResize(!0);this.lineHeight||this.$textLayer.checkForSizeChanges(),this._signal("beforeRender");var n=this.layerConfig;if(e&this.CHANGE_FULL||e&this.CHANGE_SIZE||e&this.CHANGE_TEXT||e&this.CHANGE_LINES||e&this.CHANGE_SCROLL||e&this.CHANGE_H_SCROLL){e|=this.$computeLayerConfig();if(n.firstRow!=this.layerConfig.firstRow&&n.firstRowScreen==this.layerConfig.firstRowScreen){var r=this.scrollTop+(n.firstRow-this.layerConfig.firstRow)*this.lineHeight;r>0&&(this.scrollTop=r,e|=this.CHANGE_SCROLL,e|=this.$computeLayerConfig())}n=this.layerConfig,this.$updateScrollBarV(),e&this.CHANGE_H_SCROLL&&this.$updateScrollBarH(),this.$gutterLayer.element.style.marginTop=-n.offset+"px",this.content.style.marginTop=-n.offset+"px",this.content.style.width=n.width+2*this.$padding+"px",this.content.style.height=n.minHeight+"px"}e&this.CHANGE_H_SCROLL&&(this.content.style.marginLeft=-this.scrollLeft+"px",this.scroller.className=this.scrollLeft<=0?"ace_scroller":"ace_scroller ace_scroll-left");if(e&this.CHANGE_FULL){this.$textLayer.update(n),this.$showGutter&&this.$gutterLayer.update(n),this.$markerBack.update(n),this.$markerFront.update(n),this.$cursorLayer.update(n),this.$moveTextAreaToCursor(),this.$highlightGutterLine&&this.$updateGutterLineHighlight(),this._signal("afterRender");return}if(e&this.CHANGE_SCROLL){e&this.CHANGE_TEXT||e&this.CHANGE_LINES?this.$textLayer.update(n):this.$textLayer.scrollLines(n),this.$showGutter&&this.$gutterLayer.update(n),this.$markerBack.update(n),this.$markerFront.update(n),this.$cursorLayer.update(n),this.$highlightGutterLine&&this.$updateGutterLineHighlight(),this.$moveTextAreaToCursor(),this._signal("afterRender");return}e&this.CHANGE_TEXT?(this.$textLayer.update(n),this.$showGutter&&this.$gutterLayer.update(n)):e&this.CHANGE_LINES?(this.$updateLines()||e&this.CHANGE_GUTTER&&this.$showGutter)&&this.$gutterLayer.update(n):(e&this.CHANGE_TEXT||e&this.CHANGE_GUTTER)&&this.$showGutter&&this.$gutterLayer.update(n),e&this.CHANGE_CURSOR&&(this.$cursorLayer.update(n),this.$moveTextAreaToCursor(),this.$highlightGutterLine&&this.$updateGutterLineHighlight()),e&(this.CHANGE_MARKER|this.CHANGE_MARKER_FRONT)&&this.$markerFront.update(n),e&(this.CHANGE_MARKER|this.CHANGE_MARKER_BACK)&&this.$markerBack.update(n),this._signal("afterRender")},this.$autosize=function(){var e=this.session.getScreenLength()*this.lineHeight,t=this.$maxLines*this.lineHeight,n=Math.max((this.$minLines||1)*this.lineHeight,Math.min(t,e))+this.scrollMargin.v+(this.$extraHeight||0);this.$horizScroll&&(n+=this.scrollBarH.getHeight());var r=e>t;if(n!=this.desiredHeight||this.$size.height!=this.desiredHeight||r!=this.$vScroll){r!=this.$vScroll&&(this.$vScroll=r,this.scrollBarV.setVisible(r));var i=this.container.clientWidth;this.container.style.height=n+"px",this.$updateCachedSize(!0,this.$gutterWidth,i,n),this.desiredHeight=n,this._signal("autosize")}},this.$computeLayerConfig=function(){var e=this.session,t=this.$size,n=t.height<=2*this.lineHeight,r=this.session.getScreenLength(),i=r*this.lineHeight,s=this.$getLongestLine(),o=!n&&(this.$hScrollBarAlwaysVisible||t.scrollerWidth-s-2*this.$padding<0),u=this.$horizScroll!==o;u&&(this.$horizScroll=o,this.scrollBarH.setVisible(o));var a=this.$vScroll;this.$maxLines&&this.lineHeight>1&&this.$autosize();var f=this.scrollTop%this.lineHeight,l=t.scrollerHeight+this.lineHeight,c=!this.$maxLines&&this.$scrollPastEnd?(t.scrollerHeight-this.lineHeight)*this.$scrollPastEnd:0;i+=c;var h=this.scrollMargin;this.session.setScrollTop(Math.max(-h.top,Math.min(this.scrollTop,i-t.scrollerHeight+h.bottom))),this.session.setScrollLeft(Math.max(-h.left,Math.min(this.scrollLeft,s+2*this.$padding-t.scrollerWidth+h.right)));var p=!n&&(this.$vScrollBarAlwaysVisible||t.scrollerHeight-i+c<0||this.scrollTop>h.top),d=a!==p;d&&(this.$vScroll=p,this.scrollBarV.setVisible(p));var v=Math.ceil(l/this.lineHeight)-1,m=Math.max(0,Math.round((this.scrollTop-f)/this.lineHeight)),g=m+v,y,b,w=this.lineHeight;m=e.screenToDocumentRow(m,0);var E=e.getFoldLine(m);E&&(m=E.start.row),y=e.documentToScreenRow(m,0),b=e.getRowLength(m)*w,g=Math.min(e.screenToDocumentRow(g,0),e.getLength()-1),l=t.scrollerHeight+e.getRowLength(g)*w+b,f=this.scrollTop-y*w;var S=0;this.layerConfig.width!=s&&(S=this.CHANGE_H_SCROLL);if(u||d)S=this.$updateCachedSize(!0,this.gutterWidth,t.width,t.height),this._signal("scrollbarVisibilityChanged"),d&&(s=this.$getLongestLine());return this.layerConfig={width:s,padding:this.$padding,firstRow:m,firstRowScreen:y,lastRow:g,lineHeight:w,characterWidth:this.characterWidth,minHeight:l,maxHeight:i,offset:f,gutterOffset:Math.max(0,Math.ceil((f+t.height-t.scrollerHeight)/w)),height:this.$size.scrollerHeight},S},this.$updateLines=function(){var e=this.$changedLines.firstRow,t=this.$changedLines.lastRow;this.$changedLines=null;var n=this.layerConfig;if(e>n.lastRow+1)return;if(t<n.firstRow)return;if(t===Infinity){this.$showGutter&&this.$gutterLayer.update(n),this.$textLayer.update(n);return}return this.$textLayer.updateLines(n,e,t),!0},this.$getLongestLine=function(){var e=this.session.getScreenWidth();return this.showInvisibles&&!this.session.$useWrapMode&&(e+=1),Math.max(this.$size.scrollerWidth-2*this.$padding,Math.round(e*this.characterWidth))},this.updateFrontMarkers=function(){this.$markerFront.setMarkers(this.session.getMarkers(!0)),this.$loop.schedule(this.CHANGE_MARKER_FRONT)},this.updateBackMarkers=function(){this.$markerBack.setMarkers(this.session.getMarkers()),this.$loop.schedule(this.CHANGE_MARKER_BACK)},this.addGutterDecoration=function(e,t){this.$gutterLayer.addGutterDecoration(e,t)},this.removeGutterDecoration=function(e,t){this.$gutterLayer.removeGutterDecoration(e,t)},this.updateBreakpoints=function(e){this.$loop.schedule(this.CHANGE_GUTTER)},this.setAnnotations=function(e){this.$gutterLayer.setAnnotations(e),this.$loop.schedule(this.CHANGE_GUTTER)},this.updateCursor=function(){this.$loop.schedule(this.CHANGE_CURSOR)},this.hideCursor=function(){this.$cursorLayer.hideCursor()},this.showCursor=function(){this.$cursorLayer.showCursor()},this.scrollSelectionIntoView=function(e,t,n){this.scrollCursorIntoView(e,n),this.scrollCursorIntoView(t,n)},this.scrollCursorIntoView=function(e,t,n){if(this.$size.scrollerHeight===0)return;var r=this.$cursorLayer.getPixelPosition(e),i=r.left,s=r.top,o=n&&n.top||0,u=n&&n.bottom||0,a=this.$scrollAnimation?this.session.getScrollTop():this.scrollTop;a+o>s?(t&&a+o>s+this.lineHeight&&(s-=t*this.$size.scrollerHeight),s===0&&(s=-this.scrollMargin.top),this.session.setScrollTop(s)):a+this.$size.scrollerHeight-u<s+this.lineHeight&&(t&&a+this.$size.scrollerHeight-u<s-this.lineHeight&&(s+=t*this.$size.scrollerHeight),this.session.setScrollTop(s+this.lineHeight-this.$size.scrollerHeight));var f=this.scrollLeft;f>i?(i<this.$padding+2*this.layerConfig.characterWidth&&(i=-this.scrollMargin.left),this.session.setScrollLeft(i)):f+this.$size.scrollerWidth<i+this.characterWidth?this.session.setScrollLeft(Math.round(i+this.characterWidth-this.$size.scrollerWidth)):f<=this.$padding&&i-f<this.characterWidth&&this.session.setScrollLeft(0)},this.getScrollTop=function(){return this.session.getScrollTop()},this.getScrollLeft=function(){return this.session.getScrollLeft()},this.getScrollTopRow=function(){return this.scrollTop/this.lineHeight},this.getScrollBottomRow=function(){return Math.max(0,Math.floor((this.scrollTop+this.$size.scrollerHeight)/this.lineHeight)-1)},this.scrollToRow=function(e){this.session.setScrollTop(e*this.lineHeight)},this.alignCursor=function(e,t){typeof e=="number"&&(e={row:e,column:0});var n=this.$cursorLayer.getPixelPosition(e),r=this.$size.scrollerHeight-this.lineHeight,i=n.top-r*(t||0);return this.session.setScrollTop(i),i},this.STEPS=8,this.$calcSteps=function(e,t){var n=0,r=this.STEPS,i=[],s=function(e,t,n){return n*(Math.pow(e-1,3)+1)+t};for(n=0;n<r;++n)i.push(s(n/this.STEPS,e,t-e));return i},this.scrollToLine=function(e,t,n,r){var i=this.$cursorLayer.getPixelPosition({row:e,column:0}),s=i.top;t&&(s-=this.$size.scrollerHeight/2);var o=this.scrollTop;this.session.setScrollTop(s),n!==!1&&this.animateScrolling(o,r)},this.animateScrolling=function(e,t){var n=this.scrollTop;if(!this.$animatedScroll)return;var r=this;if(e==n)return;if(this.$scrollAnimation){var i=this.$scrollAnimation.steps;if(i.length){e=i[0];if(e==n)return}}var s=r.$calcSteps(e,n);this.$scrollAnimation={from:e,to:n,steps:s},clearInterval(this.$timer),r.session.setScrollTop(s.shift()),r.session.$scrollTop=n,this.$timer=setInterval(function(){s.length?(r.session.setScrollTop(s.shift()),r.session.$scrollTop=n):n!=null?(r.session.$scrollTop=-1,r.session.setScrollTop(n),n=null):(r.$timer=clearInterval(r.$timer),r.$scrollAnimation=null,t&&t())},10)},this.scrollToY=function(e){this.scrollTop!==e&&(this.$loop.schedule(this.CHANGE_SCROLL),this.scrollTop=e)},this.scrollToX=function(e){this.scrollLeft!==e&&(this.scrollLeft=e),this.$loop.schedule(this.CHANGE_H_SCROLL)},this.scrollTo=function(e,t){this.session.setScrollTop(t),this.session.setScrollLeft(t)},this.scrollBy=function(e,t){t&&this.session.setScrollTop(this.session.getScrollTop()+t),e&&this.session.setScrollLeft(this.session.getScrollLeft()+e)},this.isScrollableBy=function(e,t){if(t<0&&this.session.getScrollTop()>=1-this.scrollMargin.top)return!0;if(t>0&&this.session.getScrollTop()+this.$size.scrollerHeight-this.layerConfig.maxHeight<-1+this.scrollMargin.bottom)return!0;if(e<0&&this.session.getScrollLeft()>=1-this.scrollMargin.left)return!0;if(e>0&&this.session.getScrollLeft()+this.$size.scrollerWidth-this.layerConfig.width<-1+this.scrollMargin.right)return!0},this.pixelToScreenCoordinates=function(e,t){var n=this.scroller.getBoundingClientRect(),r=(e+this.scrollLeft-n.left-this.$padding)/this.characterWidth,i=Math.floor((t+this.scrollTop-n.top)/this.lineHeight),s=Math.round(r);return{row:i,column:s,side:r-s>0?1:-1}},this.screenToTextCoordinates=function(e,t){var n=this.scroller.getBoundingClientRect(),r=Math.round((e+this.scrollLeft-n.left-this.$padding)/this.characterWidth),i=(t+this.scrollTop-n.top)/this.lineHeight;return this.session.screenToDocumentPosition(i,Math.max(r,0))},this.textToScreenCoordinates=function(e,t){var n=this.scroller.getBoundingClientRect(),r=this.session.documentToScreenPosition(e,t),i=this.$padding+Math.round(r.column*this.characterWidth),s=r.row*this.lineHeight;return{pageX:n.left+i-this.scrollLeft,pageY:n.top+s-this.scrollTop}},this.visualizeFocus=function(){i.addCssClass(this.container,"ace_focus")},this.visualizeBlur=function(){i.removeCssClass(this.container,"ace_focus")},this.showComposition=function(e){this.$composition||(this.$composition={keepTextAreaAtCursor:this.$keepTextAreaAtCursor,cssText:this.textarea.style.cssText}),this.$keepTextAreaAtCursor=!0,i.addCssClass(this.textarea,"ace_composition"),this.textarea.style.cssText="",this.$moveTextAreaToCursor()},this.setCompositionText=function(e){this.$moveTextAreaToCursor()},this.hideComposition=function(){if(!this.$composition)return;i.removeCssClass(this.textarea,"ace_composition"),this.$keepTextAreaAtCursor=this.$composition.keepTextAreaAtCursor,this.textarea.style.cssText=this.$composition.cssText,this.$composition=null},this.setTheme=function(e,t){function o(r){if(n.$themeId!=e)return t&&t();if(!r.cssClass)return;i.importCssString(r.cssText,r.cssClass,n.container.ownerDocument),n.theme&&i.removeCssClass(n.container,n.theme.cssClass);var s="padding"in r?r.padding:"padding"in(n.theme||{})?4:n.$padding;n.$padding&&s!=n.$padding&&n.setPadding(s),n.$theme=r.cssClass,n.theme=r,i.addCssClass(n.container,r.cssClass),i.setCssClass(n.container,"ace_dark",r.isDark),n.$size&&(n.$size.width=0,n.$updateSizeAsync()),n._dispatchEvent("themeLoaded",{theme:r}),t&&t()}var n=this;this.$themeId=e,n._dispatchEvent("themeChange",{theme:e});if(!e||typeof e=="string"){var r=e||this.$options.theme.initialValue;s.loadModule(["theme",r],o)}else o(e)},this.getTheme=function(){return this.$themeId},this.setStyle=function(e,t){i.setCssClass(this.container,e,t!==!1)},this.unsetStyle=function(e){i.removeCssClass(this.container,e)},this.setCursorStyle=function(e){this.scroller.style.cursor!=e&&(this.scroller.style.cursor=e)},this.setMouseCursor=function(e){this.scroller.style.cursor=e},this.destroy=function(){this.$textLayer.destroy(),this.$cursorLayer.destroy()}}).call(g.prototype),s.defineOptions(g.prototype,"renderer",{animatedScroll:{initialValue:!1},showInvisibles:{set:function(e){this.$textLayer.setShowInvisibles(e)&&this.$loop.schedule(this.CHANGE_TEXT)},initialValue:!1},showPrintMargin:{set:function(){this.$updatePrintMargin()},initialValue:!0},printMarginColumn:{set:function(){this.$updatePrintMargin()},initialValue:80},printMargin:{set:function(e){typeof e=="number"&&(this.$printMarginColumn=e),this.$showPrintMargin=!!e,this.$updatePrintMargin()},get:function(){return this.$showPrintMargin&&this.$printMarginColumn}},showGutter:{set:function(e){this.$gutter.style.display=e?"block":"none",this.$loop.schedule(this.CHANGE_FULL),this.onGutterResize()},initialValue:!0},fadeFoldWidgets:{set:function(e){i.setCssClass(this.$gutter,"ace_fade-fold-widgets",e)},initialValue:!1},showFoldWidgets:{set:function(e){this.$gutterLayer.setShowFoldWidgets(e)},initialValue:!0},showLineNumbers:{set:function(e){this.$gutterLayer.setShowLineNumbers(e),this.$loop.schedule(this.CHANGE_GUTTER)},initialValue:!0},displayIndentGuides:{set:function(e){this.$textLayer.setDisplayIndentGuides(e)&&this.$loop.schedule(this.CHANGE_TEXT)},initialValue:!0},highlightGutterLine:{set:function(e){if(!this.$gutterLineHighlight){this.$gutterLineHighlight=i.createElement("div"),this.$gutterLineHighlight.className="ace_gutter-active-line",this.$gutter.appendChild(this.$gutterLineHighlight);return}this.$gutterLineHighlight.style.display=e?"":"none",this.$cursorLayer.$pixelPos&&this.$updateGutterLineHighlight()},initialValue:!1,value:!0},hScrollBarAlwaysVisible:{set:function(e){(!this.$hScrollBarAlwaysVisible||!this.$horizScroll)&&this.$loop.schedule(this.CHANGE_SCROLL)},initialValue:!1},vScrollBarAlwaysVisible:{set:function(e){(!this.$vScrollBarAlwaysVisible||!this.$vScroll)&&this.$loop.schedule(this.CHANGE_SCROLL)},initialValue:!1},fontSize:{set:function(e){typeof e=="number"&&(e+="px"),this.container.style.fontSize=e,this.updateFontSize()},initialValue:12},fontFamily:{set:function(e){this.container.style.fontFamily=e,this.updateFontSize()}},maxLines:{set:function(e){this.updateFull()}},minLines:{set:function(e){this.updateFull()}},scrollPastEnd:{set:function(e){e=+e||0;if(this.$scrollPastEnd==e)return;this.$scrollPastEnd=e,this.$loop.schedule(this.CHANGE_SCROLL)},initialValue:0,handlesSet:!0},fixedWidthGutter:{set:function(e){this.$gutterLayer.$fixedWidth=!!e,this.$loop.schedule(this.CHANGE_GUTTER)}},theme:{set:function(e){this.setTheme(e)},get:function(){return this.$themeId||this.theme},initialValue:"./theme/textmate",handlesSet:!0}}),t.VirtualRenderer=g}),ace.define("ace/worker/worker_client",["require","exports","module","ace/lib/oop","ace/lib/net","ace/lib/event_emitter","ace/config"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../lib/net"),s=e("../lib/event_emitter").EventEmitter,o=e("../config"),u=function(t,n,r,i){this.$sendDeltaQueue=this.$sendDeltaQueue.bind(this),this.changeListener=this.changeListener.bind(this),this.onMessage=this.onMessage.bind(this),e.nameToUrl&&!e.toUrl&&(e.toUrl=e.nameToUrl);if(o.get("packaged")||!e.toUrl)i=i||o.moduleUrl(n,"worker");else{var s=this.$normalizePath;i=i||s(e.toUrl("ace/worker/worker.js",null,"_"));var u={};t.forEach(function(t){u[t]=s(e.toUrl(t,null,"_").replace(/(\.js)?(\?.*)?$/,""))})}try{this.$worker=new Worker(i)}catch(a){if(!(a instanceof window.DOMException))throw a;var f=this.$workerBlob(i),l=window.URL||window.webkitURL,c=l.createObjectURL(f);this.$worker=new Worker(c),l.revokeObjectURL(c)}this.$worker.postMessage({init:!0,tlns:u,module:n,classname:r}),this.callbackId=1,this.callbacks={},this.$worker.onmessage=this.onMessage};(function(){r.implement(this,s),this.onMessage=function(e){var t=e.data;switch(t.type){case"event":this._signal(t.name,{data:t.data});break;case"call":var n=this.callbacks[t.id];n&&(n(t.data),delete this.callbacks[t.id]);break;case"error":this.reportError(t.data);break;case"log":window.console&&console.log&&console.log.apply(console,t.data)}},this.reportError=function(e){window.console&&console.error&&console.error(e)},this.$normalizePath=function(e){return i.qualifyURL(e)},this.terminate=function(){this._signal("terminate",{}),this.deltaQueue=null,this.$worker.terminate(),this.$worker=null,this.$doc&&this.$doc.off("change",this.changeListener),this.$doc=null},this.send=function(e,t){this.$worker.postMessage({command:e,args:t})},this.call=function(e,t,n){if(n){var r=this.callbackId++;this.callbacks[r]=n,t.push(r)}this.send(e,t)},this.emit=function(e,t){try{this.$worker.postMessage({event:e,data:{data:t.data}})}catch(n){console.error(n.stack)}},this.attachToDocument=function(e){this.$doc&&this.terminate(),this.$doc=e,this.call("setValue",[e.getValue()]),e.on("change",this.changeListener)},this.changeListener=function(e){this.deltaQueue||(this.deltaQueue=[],setTimeout(this.$sendDeltaQueue,0)),e.action=="insert"?this.deltaQueue.push(e.start,e.lines):this.deltaQueue.push(e.start,e.end)},this.$sendDeltaQueue=function(){var e=this.deltaQueue;if(!e)return;this.deltaQueue=null,e.length>50&&e.length>this.$doc.getLength()>>1?this.call("setValue",[this.$doc.getValue()]):this.emit("change",{data:e})},this.$workerBlob=function(e){var t="importScripts('"+i.qualifyURL(e)+"');";try{return new Blob([t],{type:"application/javascript"})}catch(n){var r=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder,s=new r;return s.append(t),s.getBlob("application/javascript")}}}).call(u.prototype);var a=function(e,t,n){this.$sendDeltaQueue=this.$sendDeltaQueue.bind(this),this.changeListener=this.changeListener.bind(this),this.callbackId=1,this.callbacks={},this.messageBuffer=[];var r=null,i=!1,u=Object.create(s),a=this;this.$worker={},this.$worker.terminate=function(){},this.$worker.postMessage=function(e){a.messageBuffer.push(e),r&&(i?setTimeout(f):f())},this.setEmitSync=function(e){i=e};var f=function(){var e=a.messageBuffer.shift();e.command?r[e.command].apply(r,e.args):e.event&&u._signal(e.event,e.data)};u.postMessage=function(e){a.onMessage({data:e})},u.callback=function(e,t){this.postMessage({type:"call",id:t,data:e})},u.emit=function(e,t){this.postMessage({type:"event",name:e,data:t})},o.loadModule(["worker",t],function(e){r=new e[n](u);while(a.messageBuffer.length)f()})};a.prototype=u.prototype,t.UIWorkerClient=a,t.WorkerClient=u}),ace.define("ace/placeholder",["require","exports","module","ace/range","ace/lib/event_emitter","ace/lib/oop"],function(e,t,n){"use strict";var r=e("./range").Range,i=e("./lib/event_emitter").EventEmitter,s=e("./lib/oop"),o=function(e,t,n,r,i,s){var o=this;this.length=t,this.session=e,this.doc=e.getDocument(),this.mainClass=i,this.othersClass=s,this.$onUpdate=this.onUpdate.bind(this),this.doc.on("change",this.$onUpdate),this.$others=r,this.$onCursorChange=function(){setTimeout(function(){o.onCursorChange()})},this.$pos=n;var u=e.getUndoManager().$undoStack||e.getUndoManager().$undostack||{length:-1};this.$undoStackDepth=u.length,this.setup(),e.selection.on("changeCursor",this.$onCursorChange)};(function(){s.implement(this,i),this.setup=function(){var e=this,t=this.doc,n=this.session;this.selectionBefore=n.selection.toJSON(),n.selection.inMultiSelectMode&&n.selection.toSingleRange(),this.pos=t.createAnchor(this.$pos.row,this.$pos.column);var i=this.pos;i.$insertRight=!0,i.detach(),i.markerId=n.addMarker(new r(i.row,i.column,i.row,i.column+this.length),this.mainClass,null,!1),this.others=[],this.$others.forEach(function(n){var r=t.createAnchor(n.row,n.column);r.$insertRight=!0,r.detach(),e.others.push(r)}),n.setUndoSelect(!1)},this.showOtherMarkers=function(){if(this.othersActive)return;var e=this.session,t=this;this.othersActive=!0,this.others.forEach(function(n){n.markerId=e.addMarker(new r(n.row,n.column,n.row,n.column+t.length),t.othersClass,null,!1)})},this.hideOtherMarkers=function(){if(!this.othersActive)return;this.othersActive=!1;for(var e=0;e<this.others.length;e++)this.session.removeMarker(this.others[e].markerId)},this.onUpdate=function(e){if(this.$updating)return this.updateAnchors(e);var t=e;if(t.start.row!==t.end.row)return;if(t.start.row!==this.pos.row)return;this.$updating=!0;var n=e.action==="insert"?t.end.column-t.start.column:t.start.column-t.end.column,i=t.start.column>=this.pos.column&&t.start.column<=this.pos.column+this.length+1,s=t.start.column-this.pos.column;this.updateAnchors(e),i&&(this.length+=n);if(i&&!this.session.$fromUndo)if(e.action==="insert")for(var o=this.others.length-1;o>=0;o--){var u=this.others[o],a={row:u.row,column:u.column+s};this.doc.insertMergedLines(a,e.lines)}else if(e.action==="remove")for(var o=this.others.length-1;o>=0;o--){var u=this.others[o],a={row:u.row,column:u.column+s};this.doc.remove(new r(a.row,a.column,a.row,a.column-n))}this.$updating=!1,this.updateMarkers()},this.updateAnchors=function(e){this.pos.onChange(e);for(var t=this.others.length;t--;)this.others[t].onChange(e);this.updateMarkers()},this.updateMarkers=function(){if(this.$updating)return;var e=this,t=this.session,n=function(n,i){t.removeMarker(n.markerId),n.markerId=t.addMarker(new r(n.row,n.column,n.row,n.column+e.length),i,null,!1)};n(this.pos,this.mainClass);for(var i=this.others.length;i--;)n(this.others[i],this.othersClass)},this.onCursorChange=function(e){if(this.$updating||!this.session)return;var t=this.session.selection.getCursor();t.row===this.pos.row&&t.column>=this.pos.column&&t.column<=this.pos.column+this.length?(this.showOtherMarkers(),this._emit("cursorEnter",e)):(this.hideOtherMarkers(),this._emit("cursorLeave",e))},this.detach=function(){this.session.removeMarker(this.pos&&this.pos.markerId),this.hideOtherMarkers(),this.doc.removeEventListener("change",this.$onUpdate),this.session.selection.removeEventListener("changeCursor",this.$onCursorChange),this.session.setUndoSelect(!0),this.session=null},this.cancel=function(){if(this.$undoStackDepth===-1)return;var e=this.session.getUndoManager(),t=(e.$undoStack||e.$undostack).length-this.$undoStackDepth;for(var n=0;n<t;n++)e.undo(!0);this.selectionBefore&&this.session.selection.fromJSON(this.selectionBefore)}}).call(o.prototype),t.PlaceHolder=o}),ace.define("ace/mouse/multi_select_handler",["require","exports","module","ace/lib/event","ace/lib/useragent"],function(e,t,n){function s(e,t){return e.row==t.row&&e.column==t.column}function o(e){var t=e.domEvent,n=t.altKey,o=t.shiftKey,u=t.ctrlKey,a=e.getAccelKey(),f=e.getButton();u&&i.isMac&&(f=t.button);if(e.editor.inMultiSelectMode&&f==2){e.editor.textInput.onContextMenu(e.domEvent);return}if(!u&&!n&&!a){f===0&&e.editor.inMultiSelectMode&&e.editor.exitMultiSelectMode();return}if(f!==0)return;var l=e.editor,c=l.selection,h=l.inMultiSelectMode,p=e.getDocumentPosition(),d=c.getCursor(),v=e.inSelection()||c.isEmpty()&&s(p,d),m=e.x,g=e.y,y=function(e){m=e.clientX,g=e.clientY},b=l.session,w=l.renderer.pixelToScreenCoordinates(m,g),E=w,S;if(l.$mouseHandler.$enableJumpToDef)u&&n||a&&n?S=o?"block":"add":n&&l.$blockSelectEnabled&&(S="block");else if(a&&!n){S="add";if(!h&&o)return}else n&&l.$blockSelectEnabled&&(S="block");S&&i.isMac&&t.ctrlKey&&l.$mouseHandler.cancelContextMenu();if(S=="add"){if(!h&&v)return;if(!h){var x=c.toOrientedRange();l.addSelectionMarker(x)}var T=c.rangeList.rangeAtPoint(p);l.$blockScrolling++,l.inVirtualSelectionMode=!0,o&&(T=null,x=c.ranges[0]||x,l.removeSelectionMarker(x)),l.once("mouseup",function(){var e=c.toOrientedRange();T&&e.isEmpty()&&s(T.cursor,e.cursor)?c.substractPoint(e.cursor):(o?c.substractPoint(x.cursor):x&&(l.removeSelectionMarker(x),c.addRange(x)),c.addRange(e)),l.$blockScrolling--,l.inVirtualSelectionMode=!1})}else if(S=="block"){e.stop(),l.inVirtualSelectionMode=!0;var N,C=[],k=function(){var e=l.renderer.pixelToScreenCoordinates(m,g),t=b.screenToDocumentPosition(e.row,e.column);if(s(E,e)&&s(t,c.lead))return;E=e,l.$blockScrolling++,l.selection.moveToPosition(t),l.renderer.scrollCursorIntoView(),l.removeSelectionMarkers(C),C=c.rectangularRangeBlock(E,w),l.$mouseHandler.$clickSelection&&C.length==1&&C[0].isEmpty()&&(C[0]=l.$mouseHandler.$clickSelection.clone()),C.forEach(l.addSelectionMarker,l),l.updateSelectionMarkers(),l.$blockScrolling--};l.$blockScrolling++,h&&!a?c.toSingleRange():!h&&a&&(N=c.toOrientedRange(),l.addSelectionMarker(N)),o?w=b.documentToScreenPosition(c.lead):c.moveToPosition(p),l.$blockScrolling--,E={row:-1,column:-1};var L=function(e){clearInterval(O),l.removeSelectionMarkers(C),C.length||(C=[c.toOrientedRange()]),l.$blockScrolling++,N&&(l.removeSelectionMarker(N),c.toSingleRange(N));for(var t=0;t<C.length;t++)c.addRange(C[t]);l.inVirtualSelectionMode=!1,l.$mouseHandler.$clickSelection=null,l.$blockScrolling--},A=k;r.capture(l.container,y,L);var O=setInterval(function(){A()},20);return e.preventDefault()}}var r=e("../lib/event"),i=e("../lib/useragent");t.onMouseDown=o}),ace.define("ace/commands/multi_select_commands",["require","exports","module","ace/keyboard/hash_handler"],function(e,t,n){t.defaultCommands=[{name:"addCursorAbove",exec:function(e){e.selectMoreLines(-1)},bindKey:{win:"Ctrl-Alt-Up",mac:"Ctrl-Alt-Up"},scrollIntoView:"cursor",readOnly:!0},{name:"addCursorBelow",exec:function(e){e.selectMoreLines(1)},bindKey:{win:"Ctrl-Alt-Down",mac:"Ctrl-Alt-Down"},scrollIntoView:"cursor",readOnly:!0},{name:"addCursorAboveSkipCurrent",exec:function(e){e.selectMoreLines(-1,!0)},bindKey:{win:"Ctrl-Alt-Shift-Up",mac:"Ctrl-Alt-Shift-Up"},scrollIntoView:"cursor",readOnly:!0},{name:"addCursorBelowSkipCurrent",exec:function(e){e.selectMoreLines(1,!0)},bindKey:{win:"Ctrl-Alt-Shift-Down",mac:"Ctrl-Alt-Shift-Down"},scrollIntoView:"cursor",readOnly:!0},{name:"selectMoreBefore",exec:function(e){e.selectMore(-1)},bindKey:{win:"Ctrl-Alt-Left",mac:"Ctrl-Alt-Left"},scrollIntoView:"cursor",readOnly:!0},{name:"selectMoreAfter",exec:function(e){e.selectMore(1)},bindKey:{win:"Ctrl-Alt-Right",mac:"Ctrl-Alt-Right"},scrollIntoView:"cursor",readOnly:!0},{name:"selectNextBefore",exec:function(e){e.selectMore(-1,!0)},bindKey:{win:"Ctrl-Alt-Shift-Left",mac:"Ctrl-Alt-Shift-Left"},scrollIntoView:"cursor",readOnly:!0},{name:"selectNextAfter",exec:function(e){e.selectMore(1,!0)},bindKey:{win:"Ctrl-Alt-Shift-Right",mac:"Ctrl-Alt-Shift-Right"},scrollIntoView:"cursor",readOnly:!0},{name:"splitIntoLines",exec:function(e){e.multiSelect.splitIntoLines()},bindKey:{win:"Ctrl-Alt-L",mac:"Ctrl-Alt-L"},readOnly:!0},{name:"alignCursors",exec:function(e){e.alignCursors()},bindKey:{win:"Ctrl-Alt-A",mac:"Ctrl-Alt-A"},scrollIntoView:"cursor"},{name:"findAll",exec:function(e){e.findAll()},bindKey:{win:"Ctrl-Alt-K",mac:"Ctrl-Alt-G"},scrollIntoView:"cursor",readOnly:!0}],t.multiSelectCommands=[{name:"singleSelection",bindKey:"esc",exec:function(e){e.exitMultiSelectMode()},scrollIntoView:"cursor",readOnly:!0,isAvailable:function(e){return e&&e.inMultiSelectMode}}];var r=e("../keyboard/hash_handler").HashHandler;t.keyboardHandler=new r(t.multiSelectCommands)}),ace.define("ace/multi_select",["require","exports","module","ace/range_list","ace/range","ace/selection","ace/mouse/multi_select_handler","ace/lib/event","ace/lib/lang","ace/commands/multi_select_commands","ace/search","ace/edit_session","ace/editor","ace/config"],function(e,t,n){function h(e,t,n){return c.$options.wrap=!0,c.$options.needle=t,c.$options.backwards=n==-1,c.find(e)}function v(e,t){return e.row==t.row&&e.column==t.column}function m(e){if(e.$multiselectOnSessionChange)return;e.$onAddRange=e.$onAddRange.bind(e),e.$onRemoveRange=e.$onRemoveRange.bind(e),e.$onMultiSelect=e.$onMultiSelect.bind(e),e.$onSingleSelect=e.$onSingleSelect.bind(e),e.$multiselectOnSessionChange=t.onSessionChange.bind(e),e.$checkMultiselectChange=e.$checkMultiselectChange.bind(e),e.$multiselectOnSessionChange(e),e.on("changeSession",e.$multiselectOnSessionChange),e.on("mousedown",o),e.commands.addCommands(f.defaultCommands),g(e)}function g(e){function r(t){n&&(e.renderer.setMouseCursor(""),n=!1)}var t=e.textInput.getElement(),n=!1;u.addListener(t,"keydown",function(t){var i=t.keyCode==18&&!(t.ctrlKey||t.shiftKey||t.metaKey);e.$blockSelectEnabled&&i?n||(e.renderer.setMouseCursor("crosshair"),n=!0):n&&r()}),u.addListener(t,"keyup",r),u.addListener(t,"blur",r)}var r=e("./range_list").RangeList,i=e("./range").Range,s=e("./selection").Selection,o=e("./mouse/multi_select_handler").onMouseDown,u=e("./lib/event"),a=e("./lib/lang"),f=e("./commands/multi_select_commands");t.commands=f.defaultCommands.concat(f.multiSelectCommands);var l=e("./search").Search,c=new l,p=e("./edit_session").EditSession;(function(){this.getSelectionMarkers=function(){return this.$selectionMarkers}}).call(p.prototype),function(){this.ranges=null,this.rangeList=null,this.addRange=function(e,t){if(!e)return;if(!this.inMultiSelectMode&&this.rangeCount===0){var n=this.toOrientedRange();this.rangeList.add(n),this.rangeList.add(e);if(this.rangeList.ranges.length!=2)return this.rangeList.removeAll(),t||this.fromOrientedRange(e);this.rangeList.removeAll(),this.rangeList.add(n),this.$onAddRange(n)}e.cursor||(e.cursor=e.end);var r=this.rangeList.add(e);return this.$onAddRange(e),r.length&&this.$onRemoveRange(r),this.rangeCount>1&&!this.inMultiSelectMode&&(this._signal("multiSelect"),this.inMultiSelectMode=!0,this.session.$undoSelect=!1,this.rangeList.attach(this.session)),t||this.fromOrientedRange(e)},this.toSingleRange=function(e){e=e||this.ranges[0];var t=this.rangeList.removeAll();t.length&&this.$onRemoveRange(t),e&&this.fromOrientedRange(e)},this.substractPoint=function(e){var t=this.rangeList.substractPoint(e);if(t)return this.$onRemoveRange(t),t[0]},this.mergeOverlappingRanges=function(){var e=this.rangeList.merge();e.length?this.$onRemoveRange(e):this.ranges[0]&&this.fromOrientedRange(this.ranges[0])},this.$onAddRange=function(e){this.rangeCount=this.rangeList.ranges.length,this.ranges.unshift(e),this._signal("addRange",{range:e})},this.$onRemoveRange=function(e){this.rangeCount=this.rangeList.ranges.length;if(this.rangeCount==1&&this.inMultiSelectMode){var t=this.rangeList.ranges.pop();e.push(t),this.rangeCount=0}for(var n=e.length;n--;){var r=this.ranges.indexOf(e[n]);this.ranges.splice(r,1)}this._signal("removeRange",{ranges:e}),this.rangeCount===0&&this.inMultiSelectMode&&(this.inMultiSelectMode=!1,this._signal("singleSelect"),this.session.$undoSelect=!0,this.rangeList.detach(this.session)),t=t||this.ranges[0],t&&!t.isEqual(this.getRange())&&this.fromOrientedRange(t)},this.$initRangeList=function(){if(this.rangeList)return;this.rangeList=new r,this.ranges=[],this.rangeCount=0},this.getAllRanges=function(){return this.rangeCount?this.rangeList.ranges.concat():[this.getRange()]},this.splitIntoLines=function(){if(this.rangeCount>1){var e=this.rangeList.ranges,t=e[e.length-1],n=i.fromPoints(e[0].start,t.end);this.toSingleRange(),this.setSelectionRange(n,t.cursor==t.start)}else{var n=this.getRange(),r=this.isBackwards(),s=n.start.row,o=n.end.row;if(s==o){if(r)var u=n.end,a=n.start;else var u=n.start,a=n.end;this.addRange(i.fromPoints(a,a)),this.addRange(i.fromPoints(u,u));return}var f=[],l=this.getLineRange(s,!0);l.start.column=n.start.column,f.push(l);for(var c=s+1;c<o;c++)f.push(this.getLineRange(c,!0));l=this.getLineRange(o,!0),l.end.column=n.end.column,f.push(l),f.forEach(this.addRange,this)}},this.toggleBlockSelection=function(){if(this.rangeCount>1){var e=this.rangeList.ranges,t=e[e.length-1],n=i.fromPoints(e[0].start,t.end);this.toSingleRange(),this.setSelectionRange(n,t.cursor==t.start)}else{var r=this.session.documentToScreenPosition(this.selectionLead),s=this.session.documentToScreenPosition(this.selectionAnchor),o=this.rectangularRangeBlock(r,s);o.forEach(this.addRange,this)}},this.rectangularRangeBlock=function(e,t,n){var r=[],s=e.column<t.column;if(s)var o=e.column,u=t.column;else var o=t.column,u=e.column;var a=e.row<t.row;if(a)var f=e.row,l=t.row;else var f=t.row,l=e.row;o<0&&(o=0),f<0&&(f=0),f==l&&(n=!0);for(var c=f;c<=l;c++){var h=i.fromPoints(this.session.screenToDocumentPosition(c,o),this.session.screenToDocumentPosition(c,u));if(h.isEmpty()){if(p&&v(h.end,p))break;var p=h.end}h.cursor=s?h.start:h.end,r.push(h)}a&&r.reverse();if(!n){var d=r.length-1;while(r[d].isEmpty()&&d>0)d--;if(d>0){var m=0;while(r[m].isEmpty())m++}for(var g=d;g>=m;g--)r[g].isEmpty()&&r.splice(g,1)}return r}}.call(s.prototype);var d=e("./editor").Editor;(function(){this.updateSelectionMarkers=function(){this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.addSelectionMarker=function(e){e.cursor||(e.cursor=e.end);var t=this.getSelectionStyle();return e.marker=this.session.addMarker(e,"ace_selection",t),this.session.$selectionMarkers.push(e),this.session.selectionMarkerCount=this.session.$selectionMarkers.length,e},this.removeSelectionMarker=function(e){if(!e.marker)return;this.session.removeMarker(e.marker);var t=this.session.$selectionMarkers.indexOf(e);t!=-1&&this.session.$selectionMarkers.splice(t,1),this.session.selectionMarkerCount=this.session.$selectionMarkers.length},this.removeSelectionMarkers=function(e){var t=this.session.$selectionMarkers;for(var n=e.length;n--;){var r=e[n];if(!r.marker)continue;this.session.removeMarker(r.marker);var i=t.indexOf(r);i!=-1&&t.splice(i,1)}this.session.selectionMarkerCount=t.length},this.$onAddRange=function(e){this.addSelectionMarker(e.range),this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.$onRemoveRange=function(e){this.removeSelectionMarkers(e.ranges),this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.$onMultiSelect=function(e){if(this.inMultiSelectMode)return;this.inMultiSelectMode=!0,this.setStyle("ace_multiselect"),this.keyBinding.addKeyboardHandler(f.keyboardHandler),this.commands.setDefaultHandler("exec",this.$onMultiSelectExec),this.renderer.updateCursor(),this.renderer.updateBackMarkers()},this.$onSingleSelect=function(e){if(this.session.multiSelect.inVirtualMode)return;this.inMultiSelectMode=!1,this.unsetStyle("ace_multiselect"),this.keyBinding.removeKeyboardHandler(f.keyboardHandler),this.commands.removeDefaultHandler("exec",this.$onMultiSelectExec),this.renderer.updateCursor(),this.renderer.updateBackMarkers(),this._emit("changeSelection")},this.$onMultiSelectExec=function(e){var t=e.command,n=e.editor;if(!n.multiSelect)return;if(!t.multiSelectAction){var r=t.exec(n,e.args||{});n.multiSelect.addRange(n.multiSelect.toOrientedRange()),n.multiSelect.mergeOverlappingRanges()}else t.multiSelectAction=="forEach"?r=n.forEachSelection(t,e.args):t.multiSelectAction=="forEachLine"?r=n.forEachSelection(t,e.args,!0):t.multiSelectAction=="single"?(n.exitMultiSelectMode(),r=t.exec(n,e.args||{})):r=t.multiSelectAction(n,e.args||{});return r},this.forEachSelection=function(e,t,n){if(this.inVirtualSelectionMode)return;var r=n&&n.keepOrder,i=n==1||n&&n.$byLines,o=this.session,u=this.selection,a=u.rangeList,f=(r?u:a).ranges,l;if(!f.length)return e.exec?e.exec(this,t||{}):e(this,t||{});var c=u._eventRegistry;u._eventRegistry={};var h=new s(o);this.inVirtualSelectionMode=!0;for(var p=f.length;p--;){if(i)while(p>0&&f[p].start.row==f[p-1].end.row)p--;h.fromOrientedRange(f[p]),h.index=p,this.selection=o.selection=h;var d=e.exec?e.exec(this,t||{}):e(this,t||{});!l&&d!==undefined&&(l=d),h.toOrientedRange(f[p])}h.detach(),this.selection=o.selection=u,this.inVirtualSelectionMode=!1,u._eventRegistry=c,u.mergeOverlappingRanges();var v=this.renderer.$scrollAnimation;return this.onCursorChange(),this.onSelectionChange(),v&&v.from==v.to&&this.renderer.animateScrolling(v.from),l},this.exitMultiSelectMode=function(){if(!this.inMultiSelectMode||this.inVirtualSelectionMode)return;this.multiSelect.toSingleRange()},this.getSelectedText=function(){var e="";if(this.inMultiSelectMode&&!this.inVirtualSelectionMode){var t=this.multiSelect.rangeList.ranges,n=[];for(var r=0;r<t.length;r++)n.push(this.session.getTextRange(t[r]));var i=this.session.getDocument().getNewLineCharacter();e=n.join(i),e.length==(n.length-1)*i.length&&(e="")}else this.selection.isEmpty()||(e=this.session.getTextRange(this.getSelectionRange()));return e},this.$checkMultiselectChange=function(e,t){if(this.inMultiSelectMode&&!this.inVirtualSelectionMode){var n=this.multiSelect.ranges[0];if(this.multiSelect.isEmpty()&&t==this.multiSelect.anchor)return;var r=t==this.multiSelect.anchor?n.cursor==n.start?n.end:n.start:n.cursor;(r.row!=t.row||this.session.$clipPositionToDocument(r.row,r.column).column!=t.column)&&this.multiSelect.toSingleRange(this.multiSelect.toOrientedRange())}},this.findAll=function(e,t,n){t=t||{},t.needle=e||t.needle;if(t.needle==undefined){var r=this.selection.isEmpty()?this.selection.getWordRange():this.selection.getRange();t.needle=this.session.getTextRange(r)}this.$search.set(t);var i=this.$search.findAll(this.session);if(!i.length)return 0;this.$blockScrolling+=1;var s=this.multiSelect;n||s.toSingleRange(i[0]);for(var o=i.length;o--;)s.addRange(i[o],!0);return r&&s.rangeList.rangeAtPoint(r.start)&&s.addRange(r,!0),this.$blockScrolling-=1,i.length},this.selectMoreLines=function(e,t){var n=this.selection.toOrientedRange(),r=n.cursor==n.end,s=this.session.documentToScreenPosition(n.cursor);this.selection.$desiredColumn&&(s.column=this.selection.$desiredColumn);var o=this.session.screenToDocumentPosition(s.row+e,s.column);if(!n.isEmpty())var u=this.session.documentToScreenPosition(r?n.end:n.start),a=this.session.screenToDocumentPosition(u.row+e,u.column);else var a=o;if(r){var f=i.fromPoints(o,a);f.cursor=f.start}else{var f=i.fromPoints(a,o);f.cursor=f.end}f.desiredColumn=s.column;if(!this.selection.inMultiSelectMode)this.selection.addRange(n);else if(t)var l=n.cursor;this.selection.addRange(f),l&&this.selection.substractPoint(l)},this.transposeSelections=function(e){var t=this.session,n=t.multiSelect,r=n.ranges;for(var i=r.length;i--;){var s=r[i];if(s.isEmpty()){var o=t.getWordRange(s.start.row,s.start.column);s.start.row=o.start.row,s.start.column=o.start.column,s.end.row=o.end.row,s.end.column=o.end.column}}n.mergeOverlappingRanges();var u=[];for(var i=r.length;i--;){var s=r[i];u.unshift(t.getTextRange(s))}e<0?u.unshift(u.pop()):u.push(u.shift());for(var i=r.length;i--;){var s=r[i],o=s.clone();t.replace(s,u[i]),s.start.row=o.start.row,s.start.column=o.start.column}},this.selectMore=function(e,t,n){var r=this.session,i=r.multiSelect,s=i.toOrientedRange();if(s.isEmpty()){s=r.getWordRange(s.start.row,s.start.column),s.cursor=e==-1?s.start:s.end,this.multiSelect.addRange(s);if(n)return}var o=r.getTextRange(s),u=h(r,o,e);u&&(u.cursor=e==-1?u.start:u.end,this.$blockScrolling+=1,this.session.unfold(u),this.multiSelect.addRange(u),this.$blockScrolling-=1,this.renderer.scrollCursorIntoView(null,.5)),t&&this.multiSelect.substractPoint(s.cursor)},this.alignCursors=function(){var e=this.session,t=e.multiSelect,n=t.ranges,r=-1,s=n.filter(function(e){if(e.cursor.row==r)return!0;r=e.cursor.row});if(!n.length||s.length==n.length-1){var o=this.selection.getRange(),u=o.start.row,f=o.end.row,l=u==f;if(l){var c=this.session.getLength(),h;do h=this.session.getLine(f);while(/[=:]/.test(h)&&++f<c);do h=this.session.getLine(u);while(/[=:]/.test(h)&&--u>0);u<0&&(u=0),f>=c&&(f=c-1)}var p=this.session.removeFullLines(u,f);p=this.$reAlignText(p,l),this.session.insert({row:u,column:0},p.join("\n")+"\n"),l||(o.start.column=0,o.end.column=p[p.length-1].length),this.selection.setRange(o)}else{s.forEach(function(e){t.substractPoint(e.cursor)});var d=0,v=Infinity,m=n.map(function(t){var n=t.cursor,r=e.getLine(n.row),i=r.substr(n.column).search(/\S/g);return i==-1&&(i=0),n.column>d&&(d=n.column),i<v&&(v=i),i});n.forEach(function(t,n){var r=t.cursor,s=d-r.column,o=m[n]-v;s>o?e.insert(r,a.stringRepeat(" ",s-o)):e.remove(new i(r.row,r.column,r.row,r.column-s+o)),t.start.column=t.end.column=d,t.start.row=t.end.row=r.row,t.cursor=t.end}),t.fromOrientedRange(n[0]),this.renderer.updateCursor(),this.renderer.updateBackMarkers()}},this.$reAlignText=function(e,t){function u(e){return a.stringRepeat(" ",e)}function f(e){return e[2]?u(i)+e[2]+u(s-e[2].length+o)+e[4].replace(/^([=:])\s+/,"$1 "):e[0]}function l(e){return e[2]?u(i+s-e[2].length)+e[2]+u(o," ")+e[4].replace(/^([=:])\s+/,"$1 "):e[0]}function c(e){return e[2]?u(i)+e[2]+u(o)+e[4].replace(/^([=:])\s+/,"$1 "):e[0]}var n=!0,r=!0,i,s,o;return e.map(function(e){var t=e.match(/(\s*)(.*?)(\s*)([=:].*)/);return t?i==null?(i=t[1].length,s=t[2].length,o=t[3].length,t):(i+s+o!=t[1].length+t[2].length+t[3].length&&(r=!1),i!=t[1].length&&(n=!1),i>t[1].length&&(i=t[1].length),s<t[2].length&&(s=t[2].length),o>t[3].length&&(o=t[3].length),t):[e]}).map(t?f:n?r?l:f:c)}}).call(d.prototype),t.onSessionChange=function(e){var t=e.session;t&&!t.multiSelect&&(t.$selectionMarkers=[],t.selection.$initRangeList(),t.multiSelect=t.selection),this.multiSelect=t&&t.multiSelect;var n=e.oldSession;n&&(n.multiSelect.off("addRange",this.$onAddRange),n.multiSelect.off("removeRange",this.$onRemoveRange),n.multiSelect.off("multiSelect",this.$onMultiSelect),n.multiSelect.off("singleSelect",this.$onSingleSelect),n.multiSelect.lead.off("change",this.$checkMultiselectChange),n.multiSelect.anchor.off("change",this.$checkMultiselectChange)),t&&(t.multiSelect.on("addRange",this.$onAddRange),t.multiSelect.on("removeRange",this.$onRemoveRange),t.multiSelect.on("multiSelect",this.$onMultiSelect),t.multiSelect.on("singleSelect",this.$onSingleSelect),t.multiSelect.lead.on("change",this.$checkMultiselectChange),t.multiSelect.anchor.on("change",this.$checkMultiselectChange)),t&&this.inMultiSelectMode!=t.selection.inMultiSelectMode&&(t.selection.inMultiSelectMode?this.$onMultiSelect():this.$onSingleSelect())},t.MultiSelect=m,e("./config").defineOptions(d.prototype,"editor",{enableMultiselect:{set:function(e){m(this),e?(this.on("changeSession",this.$multiselectOnSessionChange),this.on("mousedown",o)):(this.off("changeSession",this.$multiselectOnSessionChange),this.off("mousedown",o))},value:!0},enableBlockSelect:{set:function(e){this.$blockSelectEnabled=e},value:!0}})}),ace.define("ace/mode/folding/fold_mode",["require","exports","module","ace/range"],function(e,t,n){"use strict";var r=e("../../range").Range,i=t.FoldMode=function(){};(function(){this.foldingStartMarker=null,this.foldingStopMarker=null,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);return this.foldingStartMarker.test(r)?"start":t=="markbeginend"&&this.foldingStopMarker&&this.foldingStopMarker.test(r)?"end":""},this.getFoldWidgetRange=function(e,t,n){return null},this.indentationBlock=function(e,t,n){var i=/\S/,s=e.getLine(t),o=s.search(i);if(o==-1)return;var u=n||s.length,a=e.getLength(),f=t,l=t;while(++t<a){var c=e.getLine(t).search(i);if(c==-1)continue;if(c<=o)break;l=t}if(l>f){var h=e.getLine(l).length;return new r(f,u,l,h)}},this.openingBracketBlock=function(e,t,n,i,s){var o={row:n,column:i+1},u=e.$findClosingBracket(t,o,s);if(!u)return;var a=e.foldWidgets[u.row];return a==null&&(a=e.getFoldWidget(u.row)),a=="start"&&u.row>o.row&&(u.row--,u.column=e.getLine(u.row).length),r.fromPoints(o,u)},this.closingBracketBlock=function(e,t,n,i,s){var o={row:n,column:i},u=e.$findOpeningBracket(t,o);if(!u)return;return u.column++,o.column--,r.fromPoints(u,o)}}).call(i.prototype)}),ace.define("ace/theme/textmate",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";t.isDark=!1,t.cssClass="ace-tm",t.cssText='.ace-tm .ace_gutter {background: #f0f0f0;color: #333;}.ace-tm .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-tm .ace_fold {background-color: #6B72E6;}.ace-tm {background-color: #FFFFFF;color: black;}.ace-tm .ace_cursor {color: black;}.ace-tm .ace_invisible {color: rgb(191, 191, 191);}.ace-tm .ace_storage,.ace-tm .ace_keyword {color: blue;}.ace-tm .ace_constant {color: rgb(197, 6, 11);}.ace-tm .ace_constant.ace_buildin {color: rgb(88, 72, 246);}.ace-tm .ace_constant.ace_language {color: rgb(88, 92, 246);}.ace-tm .ace_constant.ace_library {color: rgb(6, 150, 14);}.ace-tm .ace_invalid {background-color: rgba(255, 0, 0, 0.1);color: red;}.ace-tm .ace_support.ace_function {color: rgb(60, 76, 114);}.ace-tm .ace_support.ace_constant {color: rgb(6, 150, 14);}.ace-tm .ace_support.ace_type,.ace-tm .ace_support.ace_class {color: rgb(109, 121, 222);}.ace-tm .ace_keyword.ace_operator {color: rgb(104, 118, 135);}.ace-tm .ace_string {color: rgb(3, 106, 7);}.ace-tm .ace_comment {color: rgb(76, 136, 107);}.ace-tm .ace_comment.ace_doc {color: rgb(0, 102, 255);}.ace-tm .ace_comment.ace_doc.ace_tag {color: rgb(128, 159, 191);}.ace-tm .ace_constant.ace_numeric {color: rgb(0, 0, 205);}.ace-tm .ace_variable {color: rgb(49, 132, 149);}.ace-tm .ace_xml-pe {color: rgb(104, 104, 91);}.ace-tm .ace_entity.ace_name.ace_function {color: #0000A2;}.ace-tm .ace_heading {color: rgb(12, 7, 255);}.ace-tm .ace_list {color:rgb(185, 6, 144);}.ace-tm .ace_meta.ace_tag {color:rgb(0, 22, 142);}.ace-tm .ace_string.ace_regex {color: rgb(255, 0, 0)}.ace-tm .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-tm.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px white;}.ace-tm .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-tm .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-tm .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-tm .ace_marker-layer .ace_active-line {background: rgba(0, 0, 0, 0.07);}.ace-tm .ace_gutter-active-line {background-color : #dcdcdc;}.ace-tm .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-tm .ace_indent-guide {background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y;}';var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)}),ace.define("ace/line_widgets",["require","exports","module","ace/lib/oop","ace/lib/dom","ace/range"],function(e,t,n){"use strict";function o(e){this.session=e,this.session.widgetManager=this,this.session.getRowLength=this.getRowLength,this.session.$getWidgetScreenLength=this.$getWidgetScreenLength,this.updateOnChange=this.updateOnChange.bind(this),this.renderWidgets=this.renderWidgets.bind(this),this.measureWidgets=this.measureWidgets.bind(this),this.session._changedWidgets=[],this.$onChangeEditor=this.$onChangeEditor.bind(this),this.session.on("change",this.updateOnChange),this.session.on("changeFold",this.updateOnFold),this.session.on("changeEditor",this.$onChangeEditor)}var r=e("./lib/oop"),i=e("./lib/dom"),s=e("./range").Range;(function(){this.getRowLength=function(e){var t;return this.lineWidgets?t=this.lineWidgets[e]&&this.lineWidgets[e].rowCount||0:t=0,!this.$useWrapMode||!this.$wrapData[e]?1+t:this.$wrapData[e].length+1+t},this.$getWidgetScreenLength=function(){var e=0;return this.lineWidgets.forEach(function(t){t&&t.rowCount&&!t.hidden&&(e+=t.rowCount)}),e},this.$onChangeEditor=function(e){this.attach(e.editor)},this.attach=function(e){e&&e.widgetManager&&e.widgetManager!=this&&e.widgetManager.detach();if(this.editor==e)return;this.detach(),this.editor=e,e&&(e.widgetManager=this,e.renderer.on("beforeRender",this.measureWidgets),e.renderer.on("afterRender",this.renderWidgets))},this.detach=function(e){var t=this.editor;if(!t)return;this.editor=null,t.widgetManager=null,t.renderer.off("beforeRender",this.measureWidgets),t.renderer.off("afterRender",this.renderWidgets);var n=this.session.lineWidgets;n&&n.forEach(function(e){e&&e.el&&e.el.parentNode&&(e._inDocument=!1,e.el.parentNode.removeChild(e.el))})},this.updateOnFold=function(e,t){var n=t.lineWidgets;if(!n||!e.action)return;var r=e.data,i=r.start.row,s=r.end.row,o=e.action=="add";for(var u=i+1;u<s;u++)n[u]&&(n[u].hidden=o);n[s]&&(o?n[i]?n[s].hidden=o:n[i]=n[s]:(n[i]==n[s]&&(n[i]=undefined),n[s].hidden=o))},this.updateOnChange=function(e){var t=this.session.lineWidgets;if(!t)return;var n=e.start.row,r=e.end.row-n;if(r!==0)if(e.action=="remove"){var i=t.splice(n+1,r);i.forEach(function(e){e&&this.removeLineWidget(e)},this),this.$updateRows()}else{var s=new Array(r);s.unshift(n,0),t.splice.apply(t,s),this.$updateRows()}},this.$updateRows=function(){var e=this.session.lineWidgets;if(!e)return;var t=!0;e.forEach(function(e,n){if(e){t=!1,e.row=n;while(e.$oldWidget)e.$oldWidget.row=n,e=e.$oldWidget}}),t&&(this.session.lineWidgets=null)},this.addLineWidget=function(e){this.session.lineWidgets||(this.session.lineWidgets=new Array(this.session.getLength()));var t=this.session.lineWidgets[e.row];t&&(e.$oldWidget=t,t.el&&t.el.parentNode&&(t.el.parentNode.removeChild(t.el),t._inDocument=!1)),this.session.lineWidgets[e.row]=e,e.session=this.session;var n=this.editor.renderer;e.html&&!e.el&&(e.el=i.createElement("div"),e.el.innerHTML=e.html),e.el&&(i.addCssClass(e.el,"ace_lineWidgetContainer"),e.el.style.position="absolute",e.el.style.zIndex=5,n.container.appendChild(e.el),e._inDocument=!0),e.coverGutter||(e.el.style.zIndex=3),e.pixelHeight||(e.pixelHeight=e.el.offsetHeight),e.rowCount==null&&(e.rowCount=e.pixelHeight/n.layerConfig.lineHeight);var r=this.session.getFoldAt(e.row,0);e.$fold=r;if(r){var s=this.session.lineWidgets;e.row==r.end.row&&!s[r.start.row]?s[r.start.row]=e:e.hidden=!0}return this.session._emit("changeFold",{data:{start:{row:e.row}}}),this.$updateRows(),this.renderWidgets(null,n),this.onWidgetChanged(e),e},this.removeLineWidget=function(e){e._inDocument=!1,e.session=null,e.el&&e.el.parentNode&&e.el.parentNode.removeChild(e.el);if(e.editor&&e.editor.destroy)try{e.editor.destroy()}catch(t){}if(this.session.lineWidgets){var n=this.session.lineWidgets[e.row];if(n==e)this.session.lineWidgets[e.row]=e.$oldWidget,e.$oldWidget&&this.onWidgetChanged(e.$oldWidget);else while(n){if(n.$oldWidget==e){n.$oldWidget=e.$oldWidget;break}n=n.$oldWidget}}this.session._emit("changeFold",{data:{start:{row:e.row}}}),this.$updateRows()},this.getWidgetsAtRow=function(e){var t=this.session.lineWidgets,n=t&&t[e],r=[];while(n)r.push(n),n=n.$oldWidget;return r},this.onWidgetChanged=function(e){this.session._changedWidgets.push(e),this.editor&&this.editor.renderer.updateFull()},this.measureWidgets=function(e,t){var n=this.session._changedWidgets,r=t.layerConfig;if(!n||!n.length)return;var i=Infinity;for(var s=0;s<n.length;s++){var o=n[s];if(!o||!o.el)continue;if(o.session!=this.session)continue;if(!o._inDocument){if(this.session.lineWidgets[o.row]!=o)continue;o._inDocument=!0,t.container.appendChild(o.el)}o.h=o.el.offsetHeight,o.fixedWidth||(o.w=o.el.offsetWidth,o.screenWidth=Math.ceil(o.w/r.characterWidth));var u=o.h/r.lineHeight;o.coverLine&&(u-=this.session.getRowLineCount(o.row),u<0&&(u=0)),o.rowCount!=u&&(o.rowCount=u,o.row<i&&(i=o.row))}i!=Infinity&&(this.session._emit("changeFold",{data:{start:{row:i}}}),this.session.lineWidgetWidth=null),this.session._changedWidgets=[]},this.renderWidgets=function(e,t){var n=t.layerConfig,r=this.session.lineWidgets;if(!r)return;var i=Math.min(this.firstRow,n.firstRow),s=Math.max(this.lastRow,n.lastRow,r.length);while(i>0&&!r[i])i--;this.firstRow=n.firstRow,this.lastRow=n.lastRow,t.$cursorLayer.config=n;for(var o=i;o<=s;o++){var u=r[o];if(!u||!u.el)continue;if(u.hidden){u.el.style.top=-100-(u.pixelHeight||0)+"px";continue}u._inDocument||(u._inDocument=!0,t.container.appendChild(u.el));var a=t.$cursorLayer.getPixelPosition({row:o,column:0},!0).top;u.coverLine||(a+=n.lineHeight*this.session.getRowLineCount(u.row)),u.el.style.top=a-n.offset+"px";var f=u.coverGutter?0:t.gutterWidth;u.fixedWidth||(f-=t.scrollLeft),u.el.style.left=f+"px",u.fullWidth&&u.screenWidth&&(u.el.style.minWidth=n.width+2*n.padding+"px"),u.fixedWidth?u.el.style.right=t.scrollBar.getWidth()+"px":u.el.style.right=""}}}).call(o.prototype),t.LineWidgets=o}),ace.define("ace/ext/error_marker",["require","exports","module","ace/line_widgets","ace/lib/dom","ace/range"],function(e,t,n){"use strict";function o(e,t,n){var r=0,i=e.length-1;while(r<=i){var s=r+i>>1,o=n(t,e[s]);if(o>0)r=s+1;else{if(!(o<0))return s;i=s-1}}return-(r+1)}function u(e,t,n){var r=e.getAnnotations().sort(s.comparePoints);if(!r.length)return;var i=o(r,{row:t,column:-1},s.comparePoints);i<0&&(i=-i-1),i>=r.length?i=n>0?0:r.length-1:i===0&&n<0&&(i=r.length-1);var u=r[i];if(!u||!n)return;if(u.row===t){do u=r[i+=n];while(u&&u.row===t);if(!u)return r.slice()}var a=[];t=u.row;do a[n<0?"unshift":"push"](u),u=r[i+=n];while(u&&u.row==t);return a.length&&a}var r=e("../line_widgets").LineWidgets,i=e("../lib/dom"),s=e("../range").Range;t.showErrorMarker=function(e,t){var n=e.session;n.widgetManager||(n.widgetManager=new r(n),n.widgetManager.attach(e));var s=e.getCursorPosition(),o=s.row,a=n.widgetManager.getWidgetsAtRow(o).filter(function(e){return e.type=="errorMarker"})[0];a?a.destroy():o-=t;var f=u(n,o,t),l;if(f){var c=f[0];s.column=(c.pos&&typeof c.column!="number"?c.pos.sc:c.column)||0,s.row=c.row,l=e.renderer.$gutterLayer.$annotations[s.row]}else{if(a)return;l={text:["Looks good!"],className:"ace_ok"}}e.session.unfold(s.row),e.selection.moveToPosition(s);var h={row:s.row,fixedWidth:!0,coverGutter:!0,el:i.createElement("div"),type:"errorMarker"},p=h.el.appendChild(i.createElement("div")),d=h.el.appendChild(i.createElement("div"));d.className="error_widget_arrow "+l.className;var v=e.renderer.$cursorLayer.getPixelPosition(s).left;d.style.left=v+e.renderer.gutterWidth-5+"px",h.el.className="error_widget_wrapper",p.className="error_widget "+l.className,p.innerHTML=l.text.join("<br>"),p.appendChild(i.createElement("div"));var m=function(e,t,n){if(t===0&&(n==="esc"||n==="return"))return h.destroy(),{command:"null"}};h.destroy=function(){if(e.$mouseHandler.isMousePressed)return;e.keyBinding.removeKeyboardHandler(m),n.widgetManager.removeLineWidget(h),e.off("changeSelection",h.destroy),e.off("changeSession",h.destroy),e.off("mouseup",h.destroy),e.off("change",h.destroy)},e.keyBinding.addKeyboardHandler(m),e.on("changeSelection",h.destroy),e.on("changeSession",h.destroy),e.on("mouseup",h.destroy),e.on("change",h.destroy),e.session.widgetManager.addLineWidget(h),h.el.onmousedown=e.focus.bind(e),e.renderer.scrollCursorIntoView(null,.5,{bottom:h.el.offsetHeight})},i.importCssString("    .error_widget_wrapper {        background: inherit;        color: inherit;        border:none    }    .error_widget {        border-top: solid 2px;        border-bottom: solid 2px;        margin: 5px 0;        padding: 10px 40px;        white-space: pre-wrap;    }    .error_widget.ace_error, .error_widget_arrow.ace_error{        border-color: #ff5a5a    }    .error_widget.ace_warning, .error_widget_arrow.ace_warning{        border-color: #F1D817    }    .error_widget.ace_info, .error_widget_arrow.ace_info{        border-color: #5a5a5a    }    .error_widget.ace_ok, .error_widget_arrow.ace_ok{        border-color: #5aaa5a    }    .error_widget_arrow {        position: absolute;        border: solid 5px;        border-top-color: transparent!important;        border-right-color: transparent!important;        border-left-color: transparent!important;        top: -5px;    }","")}),ace.define("ace/ace",["require","exports","module","ace/lib/fixoldbrowsers","ace/lib/dom","ace/lib/event","ace/editor","ace/edit_session","ace/undomanager","ace/virtual_renderer","ace/worker/worker_client","ace/keyboard/hash_handler","ace/placeholder","ace/multi_select","ace/mode/folding/fold_mode","ace/theme/textmate","ace/ext/error_marker","ace/config"],function(e,t,n){"use strict";e("./lib/fixoldbrowsers");var r=e("./lib/dom"),i=e("./lib/event"),s=e("./editor").Editor,o=e("./edit_session").EditSession,u=e("./undomanager").UndoManager,a=e("./virtual_renderer").VirtualRenderer;e("./worker/worker_client"),e("./keyboard/hash_handler"),e("./placeholder"),e("./multi_select"),e("./mode/folding/fold_mode"),e("./theme/textmate"),e("./ext/error_marker"),t.config=e("./config"),t.require=e,t.edit=function(e){if(typeof e=="string"){var n=e;e=document.getElementById(n);if(!e)throw new Error("ace.edit can't find div #"+n)}if(e&&e.env&&e.env.editor instanceof s)return e.env.editor;var o="";if(e&&/input|textarea/i.test(e.tagName)){var u=e;o=u.value,e=r.createElement("pre"),u.parentNode.replaceChild(e,u)}else e&&(o=r.getInnerText(e),e.innerHTML="");var f=t.createEditSession(o),l=new s(new a(e));l.setSession(f);var c={document:f,editor:l,onResize:l.resize.bind(l,null)};return u&&(c.textarea=u),i.addListener(window,"resize",c.onResize),l.on("destroy",function(){i.removeListener(window,"resize",c.onResize),c.editor.container.env=null}),l.container.env=l.env=c,l},t.createEditSession=function(e,t){var n=new o(e,t);return n.setUndoManager(new u),n},t.EditSession=o,t.UndoManager=u,t.version="1.2.3"});
+            (function() {
+                ace.require(["ace/ace"], function(a) {
+                    a && a.config.init(true);
+                    if (!window.ace)
+                        window.ace = a;
+                    for (var key in a) if (a.hasOwnProperty(key))
+                        window.ace[key] = a[key];
+                });
+            })();
+        
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-beautify.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-beautify.js
new file mode 100644
index 0000000..659262c
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-beautify.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/beautify/php_rules",["require","exports","module","ace/token_iterator"],function(e,t,n){"use strict";var r=e("ace/token_iterator").TokenIterator;t.newLines=[{type:"support.php_tag",value:"<?php"},{type:"support.php_tag",value:"<?"},{type:"support.php_tag",value:"?>"},{type:"paren.lparen",value:"{",indent:!0},{type:"paren.rparen",breakBefore:!0,value:"}",indent:!1},{type:"paren.rparen",breakBefore:!0,value:"})",indent:!1,dontBreak:!0},{type:"comment"},{type:"text",value:";"},{type:"text",value:":",context:"php"},{type:"keyword",value:"case",indent:!0,dontBreak:!0},{type:"keyword",value:"default",indent:!0,dontBreak:!0},{type:"keyword",value:"break",indent:!1,dontBreak:!0},{type:"punctuation.doctype.end",value:">"},{type:"meta.tag.punctuation.end",value:">"},{type:"meta.tag.punctuation.begin",value:"<",blockTag:!0,indent:!0,dontBreak:!0},{type:"meta.tag.punctuation.begin",value:"</",indent:!1,breakBefore:!0,dontBreak:!0},{type:"punctuation.operator",value:";"}],t.spaces=[{type:"xml-pe",prepend:!0},{type:"entity.other.attribute-name",prepend:!0},{type:"storage.type",value:"var",append:!0},{type:"storage.type",value:"function",append:!0},{type:"keyword.operator",value:"="},{type:"keyword",value:"as",prepend:!0,append:!0},{type:"keyword",value:"function",append:!0},{type:"support.function",next:/[^\(]/,append:!0},{type:"keyword",value:"or",append:!0,prepend:!0},{type:"keyword",value:"and",append:!0,prepend:!0},{type:"keyword",value:"case",append:!0},{type:"keyword.operator",value:"||",append:!0,prepend:!0},{type:"keyword.operator",value:"&&",append:!0,prepend:!0}],t.singleTags=["!doctype","area","base","br","hr","input","img","link","meta"],t.transform=function(e,n,r){var i=e.getCurrentToken(),s=t.newLines,o=t.spaces,u=t.singleTags,a="",f=0,l=!1,c,h,p={},d,v={},m=!1,g="";while(i!==null){console.log(i);if(!i){i=e.stepForward();continue}i.type=="support.php_tag"&&i.value!="?>"?r="php":i.type=="support.php_tag"&&i.value=="?>"?r="html":i.type=="meta.tag.name.style"&&r!="css"?r="css":i.type=="meta.tag.name.style"&&r=="css"?r="html":i.type=="meta.tag.name.script"&&r!="js"?r="js":i.type=="meta.tag.name.script"&&r=="js"&&(r="html"),v=e.stepForward(),v&&v.type.indexOf("meta.tag.name")==0&&(d=v.value),p.type=="support.php_tag"&&p.value=="<?="&&(l=!0),i.type=="meta.tag.name"&&(i.value=i.value.toLowerCase()),i.type=="text"&&(i.value=i.value.trim());if(!i.value){i=v;continue}g=i.value;for(var y in o)i.type==o[y].type&&(!o[y].value||i.value==o[y].value)&&v&&(!o[y].next||o[y].next.test(v.value))&&(o[y].prepend&&(g=" "+i.value),o[y].append&&(g+=" "));i.type.indexOf("meta.tag.name")==0&&(c=i.value),m=!1;for(y in s)if(i.type==s[y].type&&(!s[y].value||i.value==s[y].value)&&(!s[y].blockTag||u.indexOf(d)===-1)&&(!s[y].context||s[y].context===r)){s[y].indent===!1&&f--;if(s[y].breakBefore&&(!s[y].prev||s[y].prev.test(p.value))){a+="\n",m=!0;for(y=0;y<f;y++)a+="	"}break}if(l===!1)for(y in s)if(p.type==s[y].type&&(!s[y].value||p.value==s[y].value)&&(!s[y].blockTag||u.indexOf(c)===-1)&&(!s[y].context||s[y].context===r)){s[y].indent===!0&&f++;if(!s[y].dontBreak&&!m){a+="\n";for(y=0;y<f;y++)a+="	"}break}a+=g,p.type=="support.php_tag"&&p.value=="?>"&&(l=!1),h=c,p=i,i=v;if(i===null)break}return a}}),ace.define("ace/ext/beautify",["require","exports","module","ace/token_iterator","ace/ext/beautify/php_rules"],function(e,t,n){"use strict";var r=e("ace/token_iterator").TokenIterator,i=e("./beautify/php_rules").transform;t.beautify=function(e){var t=new r(e,0,0),n=t.getCurrentToken(),s=e.$modeId.split("/").pop(),o=i(t,s);e.doc.setValue(o)},t.commands=[{name:"beautify",exec:function(e){t.beautify(e.session)},bindKey:"Ctrl-Shift-B"}]});
+                (function() {
+                    ace.require(["ace/ext/beautify"], function() {});
+                })();
+            
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-chromevox.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-chromevox.js
new file mode 100644
index 0000000..afaad86
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-chromevox.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/chromevox",["require","exports","module","ace/editor","ace/config"],function(e,t,n){function gt(){return typeof cvox!="undefined"&&cvox&&cvox.Api}function wt(e){if(gt())mt(e);else{yt++;if(yt>=bt)return;window.setTimeout(wt,500,e)}}var r={};r.SpeechProperty,r.Cursor,r.Token,r.Annotation;var i={rate:.8,pitch:.4,volume:.9},s={rate:1,pitch:.5,volume:.9},o={rate:.8,pitch:.8,volume:.9},u={rate:.8,pitch:.3,volume:.9},a={rate:.8,pitch:.7,volume:.9},f={rate:.8,pitch:.8,volume:.9},l={punctuationEcho:"none",relativePitch:-0.6},c="ALERT_NONMODAL",h="ALERT_MODAL",p="INVALID_KEYPRESS",d="insertMode",v="start",m=[{substr:";",newSubstr:" semicolon "},{substr:":",newSubstr:" colon "}],g={SPEAK_ANNOT:"annots",SPEAK_ALL_ANNOTS:"all_annots",TOGGLE_LOCATION:"toggle_location",SPEAK_MODE:"mode",SPEAK_ROW_COL:"row_col",TOGGLE_DISPLACEMENT:"toggle_displacement",FOCUS_TEXT:"focus_text"},y="CONTROL + SHIFT ";r.editor=null;var b=null,w={},E=!1,S=!1,x=!1,T=null,N={},C={},k=function(e){return y+String.fromCharCode(e)},L=function(){var e=r.editor.keyBinding.getKeyboardHandler();return e.$id==="ace/keyboard/vim"},A=function(e){return r.editor.getSession().getTokenAt(e.row,e.column+1)},O=function(e){return r.editor.getSession().getLine(e.row)},M=function(e){w[e.row]&&cvox.Api.playEarcon(c),E?(cvox.Api.stop(),W(e),R(A(e)),I(e.row,1)):I(e.row,0)},_=function(e){var t=O(e),n=t.substr(e.column-1);e.column===0&&(n=" "+t);var r=/^\W(\w+)/,i=r.exec(n);return i!==null},D={constant:{prop:i},entity:{prop:o},keyword:{prop:u},storage:{prop:a},variable:{prop:f},meta:{prop:s,replace:[{substr:"</",newSubstr:" closing tag "},{substr:"/>",newSubstr:" close tag "},{substr:"<",newSubstr:" tag start "},{substr:">",newSubstr:" tag end "}]}},P={prop:P},H=function(e,t){var n=e;for(var r=0;r<t.length;r++){var i=t[r],s=new RegExp(i.substr,"g");n=n.replace(s,i.newSubstr)}return n},B=function(e,t,n){var r={};r.value="",r.type=e[t].type;for(var i=t;i<n;i++)r.value+=e[i].value;return r},j=function(e){if(e.length<=1)return e;var t=[],n=0;for(var r=1;r<e.length;r++){var i=e[n],s=e[r];U(i)!==U(s)&&(t.push(B(e,n,r)),n=r)}return t.push(B(e,n,e.length)),t},F=function(e){var t=r.editor.getSession().getLine(e),n=/^\s*$/;return n.exec(t)!==null},I=function(e,t){var n=r.editor.getSession().getTokens(e);if(n.length===0||F(e)){cvox.Api.playEarcon("EDITABLE_TEXT");return}n=j(n);var i=n[0];n=n.filter(function(e){return e!==i}),z(i,t),n.forEach(R)},q=function(e){z(e,0)},R=function(e){z(e,1)},U=function(e){if(!e||!e.type)return;var t=e.type.split(".");if(t.length===0)return;var n=t[0],r=D[n];return r?r:P},z=function(e,t){var n=U(e),r=H(e.value,m);n.replace&&(r=H(r,n.replace)),cvox.Api.speak(r,t,n.prop)},W=function(e){var t=O(e);cvox.Api.speak(t[e.column],1)},X=function(e,t){var n=O(t),r=n.substring(e.column,t.column);r=r.replace(/ /g," space "),cvox.Api.speak(r)},V=function(e,t){if(Math.abs(e.column-t.column)!==1){var n=O(t).length;if(t.column===0||t.column===n){I(t.row,0);return}if(_(t)){cvox.Api.stop(),R(A(t));return}}W(t)},$=function(e,t){r.editor.selection.isEmpty()?S?X(e,t):V(e,t):(X(e,t),cvox.Api.speak("selected",1))},J=function(e){if(x){x=!1;return}var t=r.editor.selection.getCursor();t.row!==b.row?M(t):$(b,t),b=t},K=function(e){r.editor.selection.isEmpty()&&cvox.Api.speak("unselected")},Q=function(e){switch(e.action){case"remove":cvox.Api.speak(e.text,0,l),x=!0;break;case"insert":cvox.Api.speak(e.text,0),x=!0}},G=function(e){var t=e.row,n=e.column;return!w[t]||!w[t][n]},Y=function(e){w={};for(var t=0;t<e.length;t++){var n=e[t],r=n.row,i=n.column;w[r]||(w[r]={}),w[r][i]=n}},Z=function(e){var t=r.editor.getSession().getAnnotations(),n=t.filter(G);n.length>0&&cvox.Api.playEarcon(c),Y(t)},et=function(e){var t=e.type+" "+e.text+" on "+nt(e.row,e.column);t=t.replace(";","semicolon"),cvox.Api.speak(t,1)},tt=function(e){var t=w[e];for(var n in t)et(t[n])},nt=function(e,t){return"row "+(e+1)+" column "+(t+1)},rt=function(){cvox.Api.speak(nt(b.row,b.column))},it=function(){for(var e in w)tt(e)},st=function(){if(!L())return;switch(r.editor.keyBinding.$data.state){case d:cvox.Api.speak("Insert mode");break;case v:cvox.Api.speak("Command mode")}},ot=function(){E=!E,E?cvox.Api.speak("Speak location on row change enabled."):cvox.Api.speak("Speak location on row change disabled.")},ut=function(){S=!S,S?cvox.Api.speak("Speak displacement on column changes."):cvox.Api.speak("Speak current character or word on column changes.")},at=function(e){if(e.ctrlKey&&e.shiftKey){var t=N[e.keyCode];t&&t.func()}},ft=function(e,t){if(!L())return;var n=t.keyBinding.$data.state;if(n===T)return;switch(n){case d:cvox.Api.playEarcon(h),cvox.Api.setKeyEcho(!0);break;case v:cvox.Api.playEarcon(h),cvox.Api.setKeyEcho(!1)}T=n},lt=function(e){var t=e.detail.customCommand,n=C[t];n&&(n.func(),r.editor.focus())},ct=function(){var e=dt.map(function(e){return{desc:e.desc+k(e.keyCode),cmd:e.cmd}}),t=document.querySelector("body");t.setAttribute("contextMenuActions",JSON.stringify(e)),t.addEventListener("ATCustomEvent",lt,!0)},ht=function(e){e.match?I(b.row,0):cvox.Api.playEarcon(p)},pt=function(){r.editor.focus()},dt=[{keyCode:49,func:function(){tt(b.row)},cmd:g.SPEAK_ANNOT,desc:"Speak annotations on line"},{keyCode:50,func:it,cmd:g.SPEAK_ALL_ANNOTS,desc:"Speak all annotations"},{keyCode:51,func:st,cmd:g.SPEAK_MODE,desc:"Speak Vim mode"},{keyCode:52,func:ot,cmd:g.TOGGLE_LOCATION,desc:"Toggle speak row location"},{keyCode:53,func:rt,cmd:g.SPEAK_ROW_COL,desc:"Speak row and column"},{keyCode:54,func:ut,cmd:g.TOGGLE_DISPLACEMENT,desc:"Toggle speak displacement"},{keyCode:55,func:pt,cmd:g.FOCUS_TEXT,desc:"Focus text"}],vt=function(e,t){r.editor=t,t.getSession().selection.on("changeCursor",J),t.getSession().selection.on("changeSelection",K),t.getSession().on("change",Q),t.getSession().on("changeAnnotation",Z),t.on("changeStatus",ft),t.on("findSearchBox",ht),t.container.addEventListener("keydown",at),b=t.selection.getCursor()},mt=function(e){vt(null,e),dt.forEach(function(e){N[e.keyCode]=e,C[e.cmd]=e}),e.on("focus",vt),L()&&cvox.Api.setKeyEcho(!1),ct()},yt=0,bt=15,Et=e("../editor").Editor;e("../config").defineOptions(Et.prototype,"editor",{enableChromevoxEnhancements:{set:function(e){e&&wt(this)},value:!0}})});
+                (function() {
+                    ace.require(["ace/ext/chromevox"], function() {});
+                })();
+            
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-elastic_tabstops_lite.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-elastic_tabstops_lite.js
new file mode 100644
index 0000000..bae2275
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-elastic_tabstops_lite.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/elastic_tabstops_lite",["require","exports","module","ace/editor","ace/config"],function(e,t,n){"use strict";var r=function(e){this.$editor=e;var t=this,n=[],r=!1;this.onAfterExec=function(){r=!1,t.processRows(n),n=[]},this.onExec=function(){r=!0},this.onChange=function(e){r&&(n.indexOf(e.start.row)==-1&&n.push(e.start.row),e.end.row!=e.start.row&&n.push(e.end.row))}};(function(){this.processRows=function(e){this.$inChange=!0;var t=[];for(var n=0,r=e.length;n<r;n++){var i=e[n];if(t.indexOf(i)>-1)continue;var s=this.$findCellWidthsForBlock(i),o=this.$setBlockCellWidthsToMax(s.cellWidths),u=s.firstRow;for(var a=0,f=o.length;a<f;a++){var l=o[a];t.push(u),this.$adjustRow(u,l),u++}}this.$inChange=!1},this.$findCellWidthsForBlock=function(e){var t=[],n,r=e;while(r>=0){n=this.$cellWidthsForRow(r);if(n.length==0)break;t.unshift(n),r--}var i=r+1;r=e;var s=this.$editor.session.getLength();while(r<s-1){r++,n=this.$cellWidthsForRow(r);if(n.length==0)break;t.push(n)}return{cellWidths:t,firstRow:i}},this.$cellWidthsForRow=function(e){var t=this.$selectionColumnsForRow(e),n=[-1].concat(this.$tabsForRow(e)),r=n.map(function(e){return 0}).slice(1),i=this.$editor.session.getLine(e);for(var s=0,o=n.length-1;s<o;s++){var u=n[s]+1,a=n[s+1],f=this.$rightmostSelectionInCell(t,a),l=i.substring(u,a);r[s]=Math.max(l.replace(/\s+$/g,"").length,f-u)}return r},this.$selectionColumnsForRow=function(e){var t=[],n=this.$editor.getCursorPosition();return this.$editor.session.getSelection().isEmpty()&&e==n.row&&t.push(n.column),t},this.$setBlockCellWidthsToMax=function(e){var t=!0,n,r,i,s=this.$izip_longest(e);for(var o=0,u=s.length;o<u;o++){var a=s[o];if(!a.push){console.error(a);continue}a.push(NaN);for(var f=0,l=a.length;f<l;f++){var c=a[f];t&&(n=f,i=0,t=!1);if(isNaN(c)){r=f;for(var h=n;h<r;h++)e[h][o]=i;t=!0}i=Math.max(i,c)}}return e},this.$rightmostSelectionInCell=function(e,t){var n=0;if(e.length){var r=[];for(var i=0,s=e.length;i<s;i++)e[i]<=t?r.push(i):r.push(0);n=Math.max.apply(Math,r)}return n},this.$tabsForRow=function(e){var t=[],n=this.$editor.session.getLine(e),r=/\t/g,i;while((i=r.exec(n))!=null)t.push(i.index);return t},this.$adjustRow=function(e,t){var n=this.$tabsForRow(e);if(n.length==0)return;var r=0,i=-1,s=this.$izip(t,n);for(var o=0,u=s.length;o<u;o++){var a=s[o][0],f=s[o][1];i+=1+a,f+=r;var l=i-f;if(l==0)continue;var c=this.$editor.session.getLine(e).substr(0,f),h=c.replace(/\s*$/g,""),p=c.length-h.length;l>0&&(this.$editor.session.getDocument().insertInLine({row:e,column:f+1},Array(l+1).join(" ")+"	"),this.$editor.session.getDocument().removeInLine(e,f,f+1),r+=l),l<0&&p>=-l&&(this.$editor.session.getDocument().removeInLine(e,f+l,f),r+=l)}},this.$izip_longest=function(e){if(!e[0])return[];var t=e[0].length,n=e.length;for(var r=1;r<n;r++){var i=e[r].length;i>t&&(t=i)}var s=[];for(var o=0;o<t;o++){var u=[];for(var r=0;r<n;r++)e[r][o]===""?u.push(NaN):u.push(e[r][o]);s.push(u)}return s},this.$izip=function(e,t){var n=e.length>=t.length?t.length:e.length,r=[];for(var i=0;i<n;i++){var s=[e[i],t[i]];r.push(s)}return r}}).call(r.prototype),t.ElasticTabstopsLite=r;var i=e("../editor").Editor;e("../config").defineOptions(i.prototype,"editor",{useElasticTabstops:{set:function(e){e?(this.elasticTabstops||(this.elasticTabstops=new r(this)),this.commands.on("afterExec",this.elasticTabstops.onAfterExec),this.commands.on("exec",this.elasticTabstops.onExec),this.on("change",this.elasticTabstops.onChange)):this.elasticTabstops&&(this.commands.removeListener("afterExec",this.elasticTabstops.onAfterExec),this.commands.removeListener("exec",this.elasticTabstops.onExec),this.removeListener("change",this.elasticTabstops.onChange))}}})});
+                (function() {
+                    ace.require(["ace/ext/elastic_tabstops_lite"], function() {});
+                })();
+            
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-emmet.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-emmet.js
new file mode 100644
index 0000000..45888ac
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-emmet.js
@@ -0,0 +1,5 @@
+ace.define("ace/snippets",["require","exports","module","ace/lib/oop","ace/lib/event_emitter","ace/lib/lang","ace/range","ace/anchor","ace/keyboard/hash_handler","ace/tokenizer","ace/lib/dom","ace/editor"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=e("./lib/lang"),o=e("./range").Range,u=e("./anchor").Anchor,a=e("./keyboard/hash_handler").HashHandler,f=e("./tokenizer").Tokenizer,l=o.comparePoints,c=function(){this.snippetMap={},this.snippetNameMap={}};(function(){r.implement(this,i),this.getTokenizer=function(){function e(e,t,n){return e=e.substr(1),/^\d+$/.test(e)&&!n.inFormatString?[{tabstopId:parseInt(e,10)}]:[{text:e}]}function t(e){return"(?:[^\\\\"+e+"]|\\\\.)"}return c.$tokenizer=new f({start:[{regex:/:/,onMatch:function(e,t,n){return n.length&&n[0].expectIf?(n[0].expectIf=!1,n[0].elseBranch=n[0],[n[0]]):":"}},{regex:/\\./,onMatch:function(e,t,n){var r=e[1];return r=="}"&&n.length?e=r:"`$\\".indexOf(r)!=-1?e=r:n.inFormatString&&(r=="n"?e="\n":r=="t"?e="\n":"ulULE".indexOf(r)!=-1&&(e={changeCase:r,local:r>"a"})),[e]}},{regex:/}/,onMatch:function(e,t,n){return[n.length?n.shift():e]}},{regex:/\$(?:\d+|\w+)/,onMatch:e},{regex:/\$\{[\dA-Z_a-z]+/,onMatch:function(t,n,r){var i=e(t.substr(1),n,r);return r.unshift(i[0]),i},next:"snippetVar"},{regex:/\n/,token:"newline",merge:!1}],snippetVar:[{regex:"\\|"+t("\\|")+"*\\|",onMatch:function(e,t,n){n[0].choices=e.slice(1,-1).split(",")},next:"start"},{regex:"/("+t("/")+"+)/(?:("+t("/")+"*)/)(\\w*):?",onMatch:function(e,t,n){var r=n[0];return r.fmtString=e,e=this.splitRegex.exec(e),r.guard=e[1],r.fmt=e[2],r.flag=e[3],""},next:"start"},{regex:"`"+t("`")+"*`",onMatch:function(e,t,n){return n[0].code=e.splice(1,-1),""},next:"start"},{regex:"\\?",onMatch:function(e,t,n){n[0]&&(n[0].expectIf=!0)},next:"start"},{regex:"([^:}\\\\]|\\\\.)*:?",token:"",next:"start"}],formatString:[{regex:"/("+t("/")+"+)/",token:"regex"},{regex:"",onMatch:function(e,t,n){n.inFormatString=!0},next:"start"}]}),c.prototype.getTokenizer=function(){return c.$tokenizer},c.$tokenizer},this.tokenizeTmSnippet=function(e,t){return this.getTokenizer().getLineTokens(e,t).tokens.map(function(e){return e.value||e})},this.$getDefaultValue=function(e,t){if(/^[A-Z]\d+$/.test(t)){var n=t.substr(1);return(this.variables[t[0]+"__"]||{})[n]}if(/^\d+$/.test(t))return(this.variables.__||{})[t];t=t.replace(/^TM_/,"");if(!e)return;var r=e.session;switch(t){case"CURRENT_WORD":var i=r.getWordRange();case"SELECTION":case"SELECTED_TEXT":return r.getTextRange(i);case"CURRENT_LINE":return r.getLine(e.getCursorPosition().row);case"PREV_LINE":return r.getLine(e.getCursorPosition().row-1);case"LINE_INDEX":return e.getCursorPosition().column;case"LINE_NUMBER":return e.getCursorPosition().row+1;case"SOFT_TABS":return r.getUseSoftTabs()?"YES":"NO";case"TAB_SIZE":return r.getTabSize();case"FILENAME":case"FILEPATH":return"";case"FULLNAME":return"Ace"}},this.variables={},this.getVariableValue=function(e,t){return this.variables.hasOwnProperty(t)?this.variables[t](e,t)||"":this.$getDefaultValue(e,t)||""},this.tmStrFormat=function(e,t,n){var r=t.flag||"",i=t.guard;i=new RegExp(i,r.replace(/[^gi]/,""));var s=this.tokenizeTmSnippet(t.fmt,"formatString"),o=this,u=e.replace(i,function(){o.variables.__=arguments;var e=o.resolveVariables(s,n),t="E";for(var r=0;r<e.length;r++){var i=e[r];if(typeof i=="object"){e[r]="";if(i.changeCase&&i.local){var u=e[r+1];u&&typeof u=="string"&&(i.changeCase=="u"?e[r]=u[0].toUpperCase():e[r]=u[0].toLowerCase(),e[r+1]=u.substr(1))}else i.changeCase&&(t=i.changeCase)}else t=="U"?e[r]=i.toUpperCase():t=="L"&&(e[r]=i.toLowerCase())}return e.join("")});return this.variables.__=null,u},this.resolveVariables=function(e,t){function o(t){var n=e.indexOf(t,r+1);n!=-1&&(r=n)}var n=[];for(var r=0;r<e.length;r++){var i=e[r];if(typeof i=="string")n.push(i);else{if(typeof i!="object")continue;if(i.skip)o(i);else{if(i.processed<r)continue;if(i.text){var s=this.getVariableValue(t,i.text);s&&i.fmtString&&(s=this.tmStrFormat(s,i)),i.processed=r,i.expectIf==null?s&&(n.push(s),o(i)):s?i.skip=i.elseBranch:o(i)}else i.tabstopId!=null?n.push(i):i.changeCase!=null&&n.push(i)}}}return n},this.insertSnippetForSelection=function(e,t){function f(e){var t=[];for(var n=0;n<e.length;n++){var r=e[n];if(typeof r=="object"){if(a[r.tabstopId])continue;var i=e.lastIndexOf(r,n-1);r=t[i]||{tabstopId:r.tabstopId}}t[n]=r}return t}var n=e.getCursorPosition(),r=e.session.getLine(n.row),i=e.session.getTabString(),s=r.match(/^\s*/)[0];n.column<s.length&&(s=s.slice(0,n.column));var o=this.tokenizeTmSnippet(t);o=this.resolveVariables(o,e),o=o.map(function(e){return e=="\n"?e+s:typeof e=="string"?e.replace(/\t/g,i):e});var u=[];o.forEach(function(e,t){if(typeof e!="object")return;var n=e.tabstopId,r=u[n];r||(r=u[n]=[],r.index=n,r.value="");if(r.indexOf(e)!==-1)return;r.push(e);var i=o.indexOf(e,t+1);if(i===-1)return;var s=o.slice(t+1,i),a=s.some(function(e){return typeof e=="object"});a&&!r.value?r.value=s:s.length&&(!r.value||typeof r.value!="string")&&(r.value=s.join(""))}),u.forEach(function(e){e.length=0});var a={};for(var l=0;l<o.length;l++){var c=o[l];if(typeof c!="object")continue;var p=c.tabstopId,d=o.indexOf(c,l+1);if(a[p]){a[p]===c&&(a[p]=null);continue}var v=u[p],m=typeof v.value=="string"?[v.value]:f(v.value);m.unshift(l+1,Math.max(0,d-l)),m.push(c),a[p]=c,o.splice.apply(o,m),v.indexOf(c)===-1&&v.push(c)}var g=0,y=0,b="";o.forEach(function(e){typeof e=="string"?(e[0]==="\n"?(y=e.length-1,g++):y+=e.length,b+=e):e.start?e.end={row:g,column:y}:e.start={row:g,column:y}});var w=e.getSelectionRange(),E=e.session.replace(w,b),S=new h(e),x=e.inVirtualSelectionMode&&e.selection.index;S.addTabstops(u,w.start,E,x)},this.insertSnippet=function(e,t){var n=this;if(e.inVirtualSelectionMode)return n.insertSnippetForSelection(e,t);e.forEachSelection(function(){n.insertSnippetForSelection(e,t)},null,{keepOrder:!0}),e.tabstopManager&&e.tabstopManager.tabNext()},this.$getScope=function(e){var t=e.session.$mode.$id||"";t=t.split("/").pop();if(t==="html"||t==="php"){t==="php"&&!e.session.$mode.inlinePhp&&(t="html");var n=e.getCursorPosition(),r=e.session.getState(n.row);typeof r=="object"&&(r=r[0]),r.substring&&(r.substring(0,3)=="js-"?t="javascript":r.substring(0,4)=="css-"?t="css":r.substring(0,4)=="php-"&&(t="php"))}return t},this.getActiveScopes=function(e){var t=this.$getScope(e),n=[t],r=this.snippetMap;return r[t]&&r[t].includeScopes&&n.push.apply(n,r[t].includeScopes),n.push("_"),n},this.expandWithTab=function(e,t){var n=this,r=e.forEachSelection(function(){return n.expandSnippetForSelection(e,t)},null,{keepOrder:!0});return r&&e.tabstopManager&&e.tabstopManager.tabNext(),r},this.expandSnippetForSelection=function(e,t){var n=e.getCursorPosition(),r=e.session.getLine(n.row),i=r.substring(0,n.column),s=r.substr(n.column),o=this.snippetMap,u;return this.getActiveScopes(e).some(function(e){var t=o[e];return t&&(u=this.findMatchingSnippet(t,i,s)),!!u},this),u?t&&t.dryRun?!0:(e.session.doc.removeInLine(n.row,n.column-u.replaceBefore.length,n.column+u.replaceAfter.length),this.variables.M__=u.matchBefore,this.variables.T__=u.matchAfter,this.insertSnippetForSelection(e,u.content),this.variables.M__=this.variables.T__=null,!0):!1},this.findMatchingSnippet=function(e,t,n){for(var r=e.length;r--;){var i=e[r];if(i.startRe&&!i.startRe.test(t))continue;if(i.endRe&&!i.endRe.test(n))continue;if(!i.startRe&&!i.endRe)continue;return i.matchBefore=i.startRe?i.startRe.exec(t):[""],i.matchAfter=i.endRe?i.endRe.exec(n):[""],i.replaceBefore=i.triggerRe?i.triggerRe.exec(t)[0]:"",i.replaceAfter=i.endTriggerRe?i.endTriggerRe.exec(n)[0]:"",i}},this.snippetMap={},this.snippetNameMap={},this.register=function(e,t){function o(e){return e&&!/^\^?\(.*\)\$?$|^\\b$/.test(e)&&(e="(?:"+e+")"),e||""}function u(e,t,n){return e=o(e),t=o(t),n?(e=t+e,e&&e[e.length-1]!="$"&&(e+="$")):(e+=t,e&&e[0]!="^"&&(e="^"+e)),new RegExp(e)}function a(e){e.scope||(e.scope=t||"_"),t=e.scope,n[t]||(n[t]=[],r[t]={});var o=r[t];if(e.name){var a=o[e.name];a&&i.unregister(a),o[e.name]=e}n[t].push(e),e.tabTrigger&&!e.trigger&&(!e.guard&&/^\w/.test(e.tabTrigger)&&(e.guard="\\b"),e.trigger=s.escapeRegExp(e.tabTrigger));if(!e.trigger&&!e.guard&&!e.endTrigger&&!e.endGuard)return;e.startRe=u(e.trigger,e.guard,!0),e.triggerRe=new RegExp(e.trigger,"",!0),e.endRe=u(e.endTrigger,e.endGuard,!0),e.endTriggerRe=new RegExp(e.endTrigger,"",!0)}var n=this.snippetMap,r=this.snippetNameMap,i=this;e||(e=[]),e&&e.content?a(e):Array.isArray(e)&&e.forEach(a),this._signal("registerSnippets",{scope:t})},this.unregister=function(e,t){function i(e){var i=r[e.scope||t];if(i&&i[e.name]){delete i[e.name];var s=n[e.scope||t],o=s&&s.indexOf(e);o>=0&&s.splice(o,1)}}var n=this.snippetMap,r=this.snippetNameMap;e.content?i(e):Array.isArray(e)&&e.forEach(i)},this.parseSnippetFile=function(e){e=e.replace(/\r/g,"");var t=[],n={},r=/^#.*|^({[\s\S]*})\s*$|^(\S+) (.*)$|^((?:\n*\t.*)+)/gm,i;while(i=r.exec(e)){if(i[1])try{n=JSON.parse(i[1]),t.push(n)}catch(s){}if(i[4])n.content=i[4].replace(/^\t/gm,""),t.push(n),n={};else{var o=i[2],u=i[3];if(o=="regex"){var a=/\/((?:[^\/\\]|\\.)*)|$/g;n.guard=a.exec(u)[1],n.trigger=a.exec(u)[1],n.endTrigger=a.exec(u)[1],n.endGuard=a.exec(u)[1]}else o=="snippet"?(n.tabTrigger=u.match(/^\S*/)[0],n.name||(n.name=u)):n[o]=u}}return t},this.getSnippetByName=function(e,t){var n=this.snippetNameMap,r;return this.getActiveScopes(t).some(function(t){var i=n[t];return i&&(r=i[e]),!!r},this),r}}).call(c.prototype);var h=function(e){if(e.tabstopManager)return e.tabstopManager;e.tabstopManager=this,this.$onChange=this.onChange.bind(this),this.$onChangeSelection=s.delayedCall(this.onChangeSelection.bind(this)).schedule,this.$onChangeSession=this.onChangeSession.bind(this),this.$onAfterExec=this.onAfterExec.bind(this),this.attach(e)};(function(){this.attach=function(e){this.index=0,this.ranges=[],this.tabstops=[],this.$openTabstops=null,this.selectedTabstop=null,this.editor=e,this.editor.on("change",this.$onChange),this.editor.on("changeSelection",this.$onChangeSelection),this.editor.on("changeSession",this.$onChangeSession),this.editor.commands.on("afterExec",this.$onAfterExec),this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler)},this.detach=function(){this.tabstops.forEach(this.removeTabstopMarkers,this),this.ranges=null,this.tabstops=null,this.selectedTabstop=null,this.editor.removeListener("change",this.$onChange),this.editor.removeListener("changeSelection",this.$onChangeSelection),this.editor.removeListener("changeSession",this.$onChangeSession),this.editor.commands.removeListener("afterExec",this.$onAfterExec),this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler),this.editor.tabstopManager=null,this.editor=null},this.onChange=function(e){var t=e,n=e.action[0]=="r",r=e.start,i=e.end,s=r.row,o=i.row,u=o-s,a=i.column-r.column;n&&(u=-u,a=-a);if(!this.$inChange&&n){var f=this.selectedTabstop,c=f&&!f.some(function(e){return l(e.start,r)<=0&&l(e.end,i)>=0});if(c)return this.detach()}var h=this.ranges;for(var p=0;p<h.length;p++){var d=h[p];if(d.end.row<r.row)continue;if(n&&l(r,d.start)<0&&l(i,d.end)>0){this.removeRange(d),p--;continue}d.start.row==s&&d.start.column>r.column&&(d.start.column+=a),d.end.row==s&&d.end.column>=r.column&&(d.end.column+=a),d.start.row>=s&&(d.start.row+=u),d.end.row>=s&&(d.end.row+=u),l(d.start,d.end)>0&&this.removeRange(d)}h.length||this.detach()},this.updateLinkedFields=function(){var e=this.selectedTabstop;if(!e||!e.hasLinkedRanges)return;this.$inChange=!0;var n=this.editor.session,r=n.getTextRange(e.firstNonLinked);for(var i=e.length;i--;){var s=e[i];if(!s.linked)continue;var o=t.snippetManager.tmStrFormat(r,s.original);n.replace(s,o)}this.$inChange=!1},this.onAfterExec=function(e){e.command&&!e.command.readOnly&&this.updateLinkedFields()},this.onChangeSelection=function(){if(!this.editor)return;var e=this.editor.selection.lead,t=this.editor.selection.anchor,n=this.editor.selection.isEmpty();for(var r=this.ranges.length;r--;){if(this.ranges[r].linked)continue;var i=this.ranges[r].contains(e.row,e.column),s=n||this.ranges[r].contains(t.row,t.column);if(i&&s)return}this.detach()},this.onChangeSession=function(){this.detach()},this.tabNext=function(e){var t=this.tabstops.length,n=this.index+(e||1);n=Math.min(Math.max(n,1),t),n==t&&(n=0),this.selectTabstop(n),n===0&&this.detach()},this.selectTabstop=function(e){this.$openTabstops=null;var t=this.tabstops[this.index];t&&this.addTabstopMarkers(t),this.index=e,t=this.tabstops[this.index];if(!t||!t.length)return;this.selectedTabstop=t;if(!this.editor.inVirtualSelectionMode){var n=this.editor.multiSelect;n.toSingleRange(t.firstNonLinked.clone());for(var r=t.length;r--;){if(t.hasLinkedRanges&&t[r].linked)continue;n.addRange(t[r].clone(),!0)}n.ranges[0]&&n.addRange(n.ranges[0].clone())}else this.editor.selection.setRange(t.firstNonLinked);this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler)},this.addTabstops=function(e,t,n){this.$openTabstops||(this.$openTabstops=[]);if(!e[0]){var r=o.fromPoints(n,n);v(r.start,t),v(r.end,t),e[0]=[r],e[0].index=0}var i=this.index,s=[i+1,0],u=this.ranges;e.forEach(function(e,n){var r=this.$openTabstops[n]||e;for(var i=e.length;i--;){var a=e[i],f=o.fromPoints(a.start,a.end||a.start);d(f.start,t),d(f.end,t),f.original=a,f.tabstop=r,u.push(f),r!=e?r.unshift(f):r[i]=f,a.fmtString?(f.linked=!0,r.hasLinkedRanges=!0):r.firstNonLinked||(r.firstNonLinked=f)}r.firstNonLinked||(r.hasLinkedRanges=!1),r===e&&(s.push(r),this.$openTabstops[n]=r),this.addTabstopMarkers(r)},this),s.length>2&&(this.tabstops.length&&s.push(s.splice(2,1)[0]),this.tabstops.splice.apply(this.tabstops,s))},this.addTabstopMarkers=function(e){var t=this.editor.session;e.forEach(function(e){e.markerId||(e.markerId=t.addMarker(e,"ace_snippet-marker","text"))})},this.removeTabstopMarkers=function(e){var t=this.editor.session;e.forEach(function(e){t.removeMarker(e.markerId),e.markerId=null})},this.removeRange=function(e){var t=e.tabstop.indexOf(e);e.tabstop.splice(t,1),t=this.ranges.indexOf(e),this.ranges.splice(t,1),this.editor.session.removeMarker(e.markerId),e.tabstop.length||(t=this.tabstops.indexOf(e.tabstop),t!=-1&&this.tabstops.splice(t,1),this.tabstops.length||this.detach())},this.keyboardHandler=new a,this.keyboardHandler.bindKeys({Tab:function(e){if(t.snippetManager&&t.snippetManager.expandWithTab(e))return;e.tabstopManager.tabNext(1)},"Shift-Tab":function(e){e.tabstopManager.tabNext(-1)},Esc:function(e){e.tabstopManager.detach()},Return:function(e){return!1}})}).call(h.prototype);var p={};p.onChange=u.prototype.onChange,p.setPosition=function(e,t){this.pos.row=e,this.pos.column=t},p.update=function(e,t,n){this.$insertRight=n,this.pos=e,this.onChange(t)};var d=function(e,t){e.row==0&&(e.column+=t.column),e.row+=t.row},v=function(e,t){e.row==t.row&&(e.column-=t.column),e.row-=t.row};e("./lib/dom").importCssString(".ace_snippet-marker {    -moz-box-sizing: border-box;    box-sizing: border-box;    background: rgba(194, 193, 208, 0.09);    border: 1px dotted rgba(211, 208, 235, 0.62);    position: absolute;}"),t.snippetManager=new c;var m=e("./editor").Editor;(function(){this.insertSnippet=function(e,n){return t.snippetManager.insertSnippet(this,e,n)},this.expandSnippet=function(e){return t.snippetManager.expandWithTab(this,e)}}).call(m.prototype)}),ace.define("ace/ext/emmet",["require","exports","module","ace/keyboard/hash_handler","ace/editor","ace/snippets","ace/range","resources","resources","range","tabStops","resources","utils","actions","ace/config","ace/config"],function(e,t,n){"use strict";function f(){}var r=e("ace/keyboard/hash_handler").HashHandler,i=e("ace/editor").Editor,s=e("ace/snippets").snippetManager,o=e("ace/range").Range,u,a;f.prototype={setupContext:function(e){this.ace=e,this.indentation=e.session.getTabString(),u||(u=window.emmet),u.require("resources").setVariable("indentation",this.indentation),this.$syntax=null,this.$syntax=this.getSyntax()},getSelectionRange:function(){var e=this.ace.getSelectionRange(),t=this.ace.session.doc;return{start:t.positionToIndex(e.start),end:t.positionToIndex(e.end)}},createSelection:function(e,t){var n=this.ace.session.doc;this.ace.selection.setRange({start:n.indexToPosition(e),end:n.indexToPosition(t)})},getCurrentLineRange:function(){var e=this.ace,t=e.getCursorPosition().row,n=e.session.getLine(t).length,r=e.session.doc.positionToIndex({row:t,column:0});return{start:r,end:r+n}},getCaretPos:function(){var e=this.ace.getCursorPosition();return this.ace.session.doc.positionToIndex(e)},setCaretPos:function(e){var t=this.ace.session.doc.indexToPosition(e);this.ace.selection.moveToPosition(t)},getCurrentLine:function(){var e=this.ace.getCursorPosition().row;return this.ace.session.getLine(e)},replaceContent:function(e,t,n,r){n==null&&(n=t==null?this.getContent().length:t),t==null&&(t=0);var i=this.ace,u=i.session.doc,a=o.fromPoints(u.indexToPosition(t),u.indexToPosition(n));i.session.remove(a),a.end=a.start,e=this.$updateTabstops(e),s.insertSnippet(i,e)},getContent:function(){return this.ace.getValue()},getSyntax:function(){if(this.$syntax)return this.$syntax;var e=this.ace.session.$modeId.split("/").pop();if(e=="html"||e=="php"){var t=this.ace.getCursorPosition(),n=this.ace.session.getState(t.row);typeof n!="string"&&(n=n[0]),n&&(n=n.split("-"),n.length>1?e=n[0]:e=="php"&&(e="html"))}return e},getProfileName:function(){switch(this.getSyntax()){case"css":return"css";case"xml":case"xsl":return"xml";case"html":var e=u.require("resources").getVariable("profile");return e||(e=this.ace.session.getLines(0,2).join("").search(/<!DOCTYPE[^>]+XHTML/i)!=-1?"xhtml":"html"),e;default:var t=this.ace.session.$mode;return t.emmetConfig&&t.emmetConfig.profile||"xhtml"}},prompt:function(e){return prompt(e)},getSelection:function(){return this.ace.session.getTextRange()},getFilePath:function(){return""},$updateTabstops:function(e){var t=1e3,n=0,r=null,i=u.require("range"),s=u.require("tabStops"),o=u.require("resources").getVocabulary("user"),a={tabstop:function(e){var o=parseInt(e.group,10),u=o===0;u?o=++n:o+=t;var f=e.placeholder;f&&(f=s.processText(f,a));var l="${"+o+(f?":"+f:"")+"}";return u&&(r=i.create(e.start,l)),l},escape:function(e){return e=="$"?"\\$":e=="\\"?"\\\\":e}};return e=s.processText(e,a),o.variables.insert_final_tabstop&&!/\$\{0\}$/.test(e)?e+="${0}":r&&(e=u.require("utils").replaceSubstring(e,"${0}",r)),e}};var l={expand_abbreviation:{mac:"ctrl+alt+e",win:"alt+e"},match_pair_outward:{mac:"ctrl+d",win:"ctrl+,"},match_pair_inward:{mac:"ctrl+j",win:"ctrl+shift+0"},matching_pair:{mac:"ctrl+alt+j",win:"alt+j"},next_edit_point:"alt+right",prev_edit_point:"alt+left",toggle_comment:{mac:"command+/",win:"ctrl+/"},split_join_tag:{mac:"shift+command+'",win:"shift+ctrl+`"},remove_tag:{mac:"command+'",win:"shift+ctrl+;"},evaluate_math_expression:{mac:"shift+command+y",win:"shift+ctrl+y"},increment_number_by_1:"ctrl+up",decrement_number_by_1:"ctrl+down",increment_number_by_01:"alt+up",decrement_number_by_01:"alt+down",increment_number_by_10:{mac:"alt+command+up",win:"shift+alt+up"},decrement_number_by_10:{mac:"alt+command+down",win:"shift+alt+down"},select_next_item:{mac:"shift+command+.",win:"shift+ctrl+."},select_previous_item:{mac:"shift+command+,",win:"shift+ctrl+,"},reflect_css_value:{mac:"shift+command+r",win:"shift+ctrl+r"},encode_decode_data_url:{mac:"shift+ctrl+d",win:"ctrl+'"},expand_abbreviation_with_tab:"Tab",wrap_with_abbreviation:{mac:"shift+ctrl+a",win:"shift+ctrl+a"}},c=new f;t.commands=new r,t.runEmmetCommand=function v(e){try{c.setupContext(e);var t=u.require("actions");if(this.action=="expand_abbreviation_with_tab"){if(!e.selection.isEmpty())return!1;var n=e.selection.lead,r=e.session.getTokenAt(n.row,n.column);if(r&&/\btag\b/.test(r.type))return!1}if(this.action=="wrap_with_abbreviation")return setTimeout(function(){t.run("wrap_with_abbreviation",c)},0);var i=t.run(this.action,c)}catch(s){if(!u)return d(v.bind(this,e)),!0;e._signal("changeStatus",typeof s=="string"?s:s.message),console.log(s),i=!1}return i};for(var h in l)t.commands.addCommand({name:"emmet:"+h,action:h,bindKey:l[h],exec:t.runEmmetCommand,multiSelectAction:"forEach"});t.updateCommands=function(e,n){n?e.keyBinding.addKeyboardHandler(t.commands):e.keyBinding.removeKeyboardHandler(t.commands)},t.isSupportedMode=function(e){if(!e)return!1;if(e.emmetConfig)return!0;var t=e.$id||e;return/css|less|scss|sass|stylus|html|php|twig|ejs|handlebars/.test(t)},t.isAvailable=function(e,n){if(/(evaluate_math_expression|expand_abbreviation)$/.test(n))return!0;var r=e.session.$mode,i=t.isSupportedMode(r);if(i&&r.$modes)try{c.setupContext(e),/js|php/.test(c.getSyntax())&&(i=!1)}catch(s){}return i};var p=function(e,n){var r=n;if(!r)return;var i=t.isSupportedMode(r.session.$mode);e.enableEmmet===!1&&(i=!1),i&&d(),t.updateCommands(r,i)},d=function(t){typeof a=="string"&&e("ace/config").loadModule(a,function(){a=null,t&&t()})};t.AceEmmetEditor=f,e("ace/config").defineOptions(i.prototype,"editor",{enableEmmet:{set:function(e){this[e?"on":"removeListener"]("changeMode",p),p({enableEmmet:!!e},this)},value:!0}}),t.setCore=function(e){typeof e=="string"?a=e:u=e}});
+                (function() {
+                    ace.require(["ace/ext/emmet"], function() {});
+                })();
+            
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-error_marker.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-error_marker.js
new file mode 100644
index 0000000..dfefa20
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-error_marker.js
@@ -0,0 +1,5 @@
+;
+                (function() {
+                    ace.require(["ace/ext/error_marker"], function() {});
+                })();
+            
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-keybinding_menu.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-keybinding_menu.js
new file mode 100644
index 0000000..f73cf44
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-keybinding_menu.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/menu_tools/overlay_page",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";var r=e("../../lib/dom"),i="#ace_settingsmenu, #kbshortcutmenu {background-color: #F7F7F7;color: black;box-shadow: -5px 4px 5px rgba(126, 126, 126, 0.55);padding: 1em 0.5em 2em 1em;overflow: auto;position: absolute;margin: 0;bottom: 0;right: 0;top: 0;z-index: 9991;cursor: default;}.ace_dark #ace_settingsmenu, .ace_dark #kbshortcutmenu {box-shadow: -20px 10px 25px rgba(126, 126, 126, 0.25);background-color: rgba(255, 255, 255, 0.6);color: black;}.ace_optionsMenuEntry:hover {background-color: rgba(100, 100, 100, 0.1);-webkit-transition: all 0.5s;transition: all 0.3s}.ace_closeButton {background: rgba(245, 146, 146, 0.5);border: 1px solid #F48A8A;border-radius: 50%;padding: 7px;position: absolute;right: -8px;top: -8px;z-index: 1000;}.ace_closeButton{background: rgba(245, 146, 146, 0.9);}.ace_optionsMenuKey {color: darkslateblue;font-weight: bold;}.ace_optionsMenuCommand {color: darkcyan;font-weight: normal;}";r.importCssString(i),n.exports.overlayPage=function(t,n,i,s,o,u){function l(e){e.keyCode===27&&a.click()}i=i?"top: "+i+";":"",o=o?"bottom: "+o+";":"",s=s?"right: "+s+";":"",u=u?"left: "+u+";":"";var a=document.createElement("div"),f=document.createElement("div");a.style.cssText="margin: 0; padding: 0; position: fixed; top:0; bottom:0; left:0; right:0;z-index: 9990; background-color: rgba(0, 0, 0, 0.3);",a.addEventListener("click",function(){document.removeEventListener("keydown",l),a.parentNode.removeChild(a),t.focus(),a=null}),document.addEventListener("keydown",l),f.style.cssText=i+s+o+u,f.addEventListener("click",function(e){e.stopPropagation()});var c=r.createElement("div");c.style.position="relative";var h=r.createElement("div");h.className="ace_closeButton",h.addEventListener("click",function(){a.click()}),c.appendChild(h),f.appendChild(c),f.appendChild(n),a.appendChild(f),document.body.appendChild(a),t.blur()}}),ace.define("ace/ext/menu_tools/get_editor_keyboard_shortcuts",["require","exports","module","ace/lib/keys"],function(e,t,n){"use strict";var r=e("../../lib/keys");n.exports.getEditorKeybordShortcuts=function(e){var t=r.KEY_MODS,n=[],i={};return e.keyBinding.$handlers.forEach(function(e){var t=e.commandKeyBinding;for(var r in t){var s=r.replace(/(^|-)\w/g,function(e){return e.toUpperCase()}),o=t[r];Array.isArray(o)||(o=[o]),o.forEach(function(e){typeof e!="string"&&(e=e.name),i[e]?i[e].key+="|"+s:(i[e]={key:s,command:e},n.push(i[e]))})}}),n}}),ace.define("ace/ext/keybinding_menu",["require","exports","module","ace/editor","ace/ext/menu_tools/overlay_page","ace/ext/menu_tools/get_editor_keyboard_shortcuts"],function(e,t,n){"use strict";function i(t){if(!document.getElementById("kbshortcutmenu")){var n=e("./menu_tools/overlay_page").overlayPage,r=e("./menu_tools/get_editor_keyboard_shortcuts").getEditorKeybordShortcuts,i=r(t),s=document.createElement("div"),o=i.reduce(function(e,t){return e+'<div class="ace_optionsMenuEntry"><span class="ace_optionsMenuCommand">'+t.command+"</span> : "+'<span class="ace_optionsMenuKey">'+t.key+"</span></div>"},"");s.id="kbshortcutmenu",s.innerHTML="<h1>Keyboard Shortcuts</h1>"+o+"</div>",n(t,s,"0","0","0",null)}}var r=e("ace/editor").Editor;n.exports.init=function(e){r.prototype.showKeyboardShortcuts=function(){i(this)},e.commands.addCommands([{name:"showKeyboardShortcuts",bindKey:{win:"Ctrl-Alt-h",mac:"Command-Alt-h"},exec:function(e,t){e.showKeyboardShortcuts()}}])}});
+                (function() {
+                    ace.require(["ace/ext/keybinding_menu"], function() {});
+                })();
+            
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-language_tools.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-language_tools.js
new file mode 100644
index 0000000..99943a0
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-language_tools.js
@@ -0,0 +1,5 @@
+ace.define("ace/snippets",["require","exports","module","ace/lib/oop","ace/lib/event_emitter","ace/lib/lang","ace/range","ace/anchor","ace/keyboard/hash_handler","ace/tokenizer","ace/lib/dom","ace/editor"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=e("./lib/lang"),o=e("./range").Range,u=e("./anchor").Anchor,a=e("./keyboard/hash_handler").HashHandler,f=e("./tokenizer").Tokenizer,l=o.comparePoints,c=function(){this.snippetMap={},this.snippetNameMap={}};(function(){r.implement(this,i),this.getTokenizer=function(){function e(e,t,n){return e=e.substr(1),/^\d+$/.test(e)&&!n.inFormatString?[{tabstopId:parseInt(e,10)}]:[{text:e}]}function t(e){return"(?:[^\\\\"+e+"]|\\\\.)"}return c.$tokenizer=new f({start:[{regex:/:/,onMatch:function(e,t,n){return n.length&&n[0].expectIf?(n[0].expectIf=!1,n[0].elseBranch=n[0],[n[0]]):":"}},{regex:/\\./,onMatch:function(e,t,n){var r=e[1];return r=="}"&&n.length?e=r:"`$\\".indexOf(r)!=-1?e=r:n.inFormatString&&(r=="n"?e="\n":r=="t"?e="\n":"ulULE".indexOf(r)!=-1&&(e={changeCase:r,local:r>"a"})),[e]}},{regex:/}/,onMatch:function(e,t,n){return[n.length?n.shift():e]}},{regex:/\$(?:\d+|\w+)/,onMatch:e},{regex:/\$\{[\dA-Z_a-z]+/,onMatch:function(t,n,r){var i=e(t.substr(1),n,r);return r.unshift(i[0]),i},next:"snippetVar"},{regex:/\n/,token:"newline",merge:!1}],snippetVar:[{regex:"\\|"+t("\\|")+"*\\|",onMatch:function(e,t,n){n[0].choices=e.slice(1,-1).split(",")},next:"start"},{regex:"/("+t("/")+"+)/(?:("+t("/")+"*)/)(\\w*):?",onMatch:function(e,t,n){var r=n[0];return r.fmtString=e,e=this.splitRegex.exec(e),r.guard=e[1],r.fmt=e[2],r.flag=e[3],""},next:"start"},{regex:"`"+t("`")+"*`",onMatch:function(e,t,n){return n[0].code=e.splice(1,-1),""},next:"start"},{regex:"\\?",onMatch:function(e,t,n){n[0]&&(n[0].expectIf=!0)},next:"start"},{regex:"([^:}\\\\]|\\\\.)*:?",token:"",next:"start"}],formatString:[{regex:"/("+t("/")+"+)/",token:"regex"},{regex:"",onMatch:function(e,t,n){n.inFormatString=!0},next:"start"}]}),c.prototype.getTokenizer=function(){return c.$tokenizer},c.$tokenizer},this.tokenizeTmSnippet=function(e,t){return this.getTokenizer().getLineTokens(e,t).tokens.map(function(e){return e.value||e})},this.$getDefaultValue=function(e,t){if(/^[A-Z]\d+$/.test(t)){var n=t.substr(1);return(this.variables[t[0]+"__"]||{})[n]}if(/^\d+$/.test(t))return(this.variables.__||{})[t];t=t.replace(/^TM_/,"");if(!e)return;var r=e.session;switch(t){case"CURRENT_WORD":var i=r.getWordRange();case"SELECTION":case"SELECTED_TEXT":return r.getTextRange(i);case"CURRENT_LINE":return r.getLine(e.getCursorPosition().row);case"PREV_LINE":return r.getLine(e.getCursorPosition().row-1);case"LINE_INDEX":return e.getCursorPosition().column;case"LINE_NUMBER":return e.getCursorPosition().row+1;case"SOFT_TABS":return r.getUseSoftTabs()?"YES":"NO";case"TAB_SIZE":return r.getTabSize();case"FILENAME":case"FILEPATH":return"";case"FULLNAME":return"Ace"}},this.variables={},this.getVariableValue=function(e,t){return this.variables.hasOwnProperty(t)?this.variables[t](e,t)||"":this.$getDefaultValue(e,t)||""},this.tmStrFormat=function(e,t,n){var r=t.flag||"",i=t.guard;i=new RegExp(i,r.replace(/[^gi]/,""));var s=this.tokenizeTmSnippet(t.fmt,"formatString"),o=this,u=e.replace(i,function(){o.variables.__=arguments;var e=o.resolveVariables(s,n),t="E";for(var r=0;r<e.length;r++){var i=e[r];if(typeof i=="object"){e[r]="";if(i.changeCase&&i.local){var u=e[r+1];u&&typeof u=="string"&&(i.changeCase=="u"?e[r]=u[0].toUpperCase():e[r]=u[0].toLowerCase(),e[r+1]=u.substr(1))}else i.changeCase&&(t=i.changeCase)}else t=="U"?e[r]=i.toUpperCase():t=="L"&&(e[r]=i.toLowerCase())}return e.join("")});return this.variables.__=null,u},this.resolveVariables=function(e,t){function o(t){var n=e.indexOf(t,r+1);n!=-1&&(r=n)}var n=[];for(var r=0;r<e.length;r++){var i=e[r];if(typeof i=="string")n.push(i);else{if(typeof i!="object")continue;if(i.skip)o(i);else{if(i.processed<r)continue;if(i.text){var s=this.getVariableValue(t,i.text);s&&i.fmtString&&(s=this.tmStrFormat(s,i)),i.processed=r,i.expectIf==null?s&&(n.push(s),o(i)):s?i.skip=i.elseBranch:o(i)}else i.tabstopId!=null?n.push(i):i.changeCase!=null&&n.push(i)}}}return n},this.insertSnippetForSelection=function(e,t){function f(e){var t=[];for(var n=0;n<e.length;n++){var r=e[n];if(typeof r=="object"){if(a[r.tabstopId])continue;var i=e.lastIndexOf(r,n-1);r=t[i]||{tabstopId:r.tabstopId}}t[n]=r}return t}var n=e.getCursorPosition(),r=e.session.getLine(n.row),i=e.session.getTabString(),s=r.match(/^\s*/)[0];n.column<s.length&&(s=s.slice(0,n.column));var o=this.tokenizeTmSnippet(t);o=this.resolveVariables(o,e),o=o.map(function(e){return e=="\n"?e+s:typeof e=="string"?e.replace(/\t/g,i):e});var u=[];o.forEach(function(e,t){if(typeof e!="object")return;var n=e.tabstopId,r=u[n];r||(r=u[n]=[],r.index=n,r.value="");if(r.indexOf(e)!==-1)return;r.push(e);var i=o.indexOf(e,t+1);if(i===-1)return;var s=o.slice(t+1,i),a=s.some(function(e){return typeof e=="object"});a&&!r.value?r.value=s:s.length&&(!r.value||typeof r.value!="string")&&(r.value=s.join(""))}),u.forEach(function(e){e.length=0});var a={};for(var l=0;l<o.length;l++){var c=o[l];if(typeof c!="object")continue;var p=c.tabstopId,d=o.indexOf(c,l+1);if(a[p]){a[p]===c&&(a[p]=null);continue}var v=u[p],m=typeof v.value=="string"?[v.value]:f(v.value);m.unshift(l+1,Math.max(0,d-l)),m.push(c),a[p]=c,o.splice.apply(o,m),v.indexOf(c)===-1&&v.push(c)}var g=0,y=0,b="";o.forEach(function(e){typeof e=="string"?(e[0]==="\n"?(y=e.length-1,g++):y+=e.length,b+=e):e.start?e.end={row:g,column:y}:e.start={row:g,column:y}});var w=e.getSelectionRange(),E=e.session.replace(w,b),S=new h(e),x=e.inVirtualSelectionMode&&e.selection.index;S.addTabstops(u,w.start,E,x)},this.insertSnippet=function(e,t){var n=this;if(e.inVirtualSelectionMode)return n.insertSnippetForSelection(e,t);e.forEachSelection(function(){n.insertSnippetForSelection(e,t)},null,{keepOrder:!0}),e.tabstopManager&&e.tabstopManager.tabNext()},this.$getScope=function(e){var t=e.session.$mode.$id||"";t=t.split("/").pop();if(t==="html"||t==="php"){t==="php"&&!e.session.$mode.inlinePhp&&(t="html");var n=e.getCursorPosition(),r=e.session.getState(n.row);typeof r=="object"&&(r=r[0]),r.substring&&(r.substring(0,3)=="js-"?t="javascript":r.substring(0,4)=="css-"?t="css":r.substring(0,4)=="php-"&&(t="php"))}return t},this.getActiveScopes=function(e){var t=this.$getScope(e),n=[t],r=this.snippetMap;return r[t]&&r[t].includeScopes&&n.push.apply(n,r[t].includeScopes),n.push("_"),n},this.expandWithTab=function(e,t){var n=this,r=e.forEachSelection(function(){return n.expandSnippetForSelection(e,t)},null,{keepOrder:!0});return r&&e.tabstopManager&&e.tabstopManager.tabNext(),r},this.expandSnippetForSelection=function(e,t){var n=e.getCursorPosition(),r=e.session.getLine(n.row),i=r.substring(0,n.column),s=r.substr(n.column),o=this.snippetMap,u;return this.getActiveScopes(e).some(function(e){var t=o[e];return t&&(u=this.findMatchingSnippet(t,i,s)),!!u},this),u?t&&t.dryRun?!0:(e.session.doc.removeInLine(n.row,n.column-u.replaceBefore.length,n.column+u.replaceAfter.length),this.variables.M__=u.matchBefore,this.variables.T__=u.matchAfter,this.insertSnippetForSelection(e,u.content),this.variables.M__=this.variables.T__=null,!0):!1},this.findMatchingSnippet=function(e,t,n){for(var r=e.length;r--;){var i=e[r];if(i.startRe&&!i.startRe.test(t))continue;if(i.endRe&&!i.endRe.test(n))continue;if(!i.startRe&&!i.endRe)continue;return i.matchBefore=i.startRe?i.startRe.exec(t):[""],i.matchAfter=i.endRe?i.endRe.exec(n):[""],i.replaceBefore=i.triggerRe?i.triggerRe.exec(t)[0]:"",i.replaceAfter=i.endTriggerRe?i.endTriggerRe.exec(n)[0]:"",i}},this.snippetMap={},this.snippetNameMap={},this.register=function(e,t){function o(e){return e&&!/^\^?\(.*\)\$?$|^\\b$/.test(e)&&(e="(?:"+e+")"),e||""}function u(e,t,n){return e=o(e),t=o(t),n?(e=t+e,e&&e[e.length-1]!="$"&&(e+="$")):(e+=t,e&&e[0]!="^"&&(e="^"+e)),new RegExp(e)}function a(e){e.scope||(e.scope=t||"_"),t=e.scope,n[t]||(n[t]=[],r[t]={});var o=r[t];if(e.name){var a=o[e.name];a&&i.unregister(a),o[e.name]=e}n[t].push(e),e.tabTrigger&&!e.trigger&&(!e.guard&&/^\w/.test(e.tabTrigger)&&(e.guard="\\b"),e.trigger=s.escapeRegExp(e.tabTrigger));if(!e.trigger&&!e.guard&&!e.endTrigger&&!e.endGuard)return;e.startRe=u(e.trigger,e.guard,!0),e.triggerRe=new RegExp(e.trigger,"",!0),e.endRe=u(e.endTrigger,e.endGuard,!0),e.endTriggerRe=new RegExp(e.endTrigger,"",!0)}var n=this.snippetMap,r=this.snippetNameMap,i=this;e||(e=[]),e&&e.content?a(e):Array.isArray(e)&&e.forEach(a),this._signal("registerSnippets",{scope:t})},this.unregister=function(e,t){function i(e){var i=r[e.scope||t];if(i&&i[e.name]){delete i[e.name];var s=n[e.scope||t],o=s&&s.indexOf(e);o>=0&&s.splice(o,1)}}var n=this.snippetMap,r=this.snippetNameMap;e.content?i(e):Array.isArray(e)&&e.forEach(i)},this.parseSnippetFile=function(e){e=e.replace(/\r/g,"");var t=[],n={},r=/^#.*|^({[\s\S]*})\s*$|^(\S+) (.*)$|^((?:\n*\t.*)+)/gm,i;while(i=r.exec(e)){if(i[1])try{n=JSON.parse(i[1]),t.push(n)}catch(s){}if(i[4])n.content=i[4].replace(/^\t/gm,""),t.push(n),n={};else{var o=i[2],u=i[3];if(o=="regex"){var a=/\/((?:[^\/\\]|\\.)*)|$/g;n.guard=a.exec(u)[1],n.trigger=a.exec(u)[1],n.endTrigger=a.exec(u)[1],n.endGuard=a.exec(u)[1]}else o=="snippet"?(n.tabTrigger=u.match(/^\S*/)[0],n.name||(n.name=u)):n[o]=u}}return t},this.getSnippetByName=function(e,t){var n=this.snippetNameMap,r;return this.getActiveScopes(t).some(function(t){var i=n[t];return i&&(r=i[e]),!!r},this),r}}).call(c.prototype);var h=function(e){if(e.tabstopManager)return e.tabstopManager;e.tabstopManager=this,this.$onChange=this.onChange.bind(this),this.$onChangeSelection=s.delayedCall(this.onChangeSelection.bind(this)).schedule,this.$onChangeSession=this.onChangeSession.bind(this),this.$onAfterExec=this.onAfterExec.bind(this),this.attach(e)};(function(){this.attach=function(e){this.index=0,this.ranges=[],this.tabstops=[],this.$openTabstops=null,this.selectedTabstop=null,this.editor=e,this.editor.on("change",this.$onChange),this.editor.on("changeSelection",this.$onChangeSelection),this.editor.on("changeSession",this.$onChangeSession),this.editor.commands.on("afterExec",this.$onAfterExec),this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler)},this.detach=function(){this.tabstops.forEach(this.removeTabstopMarkers,this),this.ranges=null,this.tabstops=null,this.selectedTabstop=null,this.editor.removeListener("change",this.$onChange),this.editor.removeListener("changeSelection",this.$onChangeSelection),this.editor.removeListener("changeSession",this.$onChangeSession),this.editor.commands.removeListener("afterExec",this.$onAfterExec),this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler),this.editor.tabstopManager=null,this.editor=null},this.onChange=function(e){var t=e,n=e.action[0]=="r",r=e.start,i=e.end,s=r.row,o=i.row,u=o-s,a=i.column-r.column;n&&(u=-u,a=-a);if(!this.$inChange&&n){var f=this.selectedTabstop,c=f&&!f.some(function(e){return l(e.start,r)<=0&&l(e.end,i)>=0});if(c)return this.detach()}var h=this.ranges;for(var p=0;p<h.length;p++){var d=h[p];if(d.end.row<r.row)continue;if(n&&l(r,d.start)<0&&l(i,d.end)>0){this.removeRange(d),p--;continue}d.start.row==s&&d.start.column>r.column&&(d.start.column+=a),d.end.row==s&&d.end.column>=r.column&&(d.end.column+=a),d.start.row>=s&&(d.start.row+=u),d.end.row>=s&&(d.end.row+=u),l(d.start,d.end)>0&&this.removeRange(d)}h.length||this.detach()},this.updateLinkedFields=function(){var e=this.selectedTabstop;if(!e||!e.hasLinkedRanges)return;this.$inChange=!0;var n=this.editor.session,r=n.getTextRange(e.firstNonLinked);for(var i=e.length;i--;){var s=e[i];if(!s.linked)continue;var o=t.snippetManager.tmStrFormat(r,s.original);n.replace(s,o)}this.$inChange=!1},this.onAfterExec=function(e){e.command&&!e.command.readOnly&&this.updateLinkedFields()},this.onChangeSelection=function(){if(!this.editor)return;var e=this.editor.selection.lead,t=this.editor.selection.anchor,n=this.editor.selection.isEmpty();for(var r=this.ranges.length;r--;){if(this.ranges[r].linked)continue;var i=this.ranges[r].contains(e.row,e.column),s=n||this.ranges[r].contains(t.row,t.column);if(i&&s)return}this.detach()},this.onChangeSession=function(){this.detach()},this.tabNext=function(e){var t=this.tabstops.length,n=this.index+(e||1);n=Math.min(Math.max(n,1),t),n==t&&(n=0),this.selectTabstop(n),n===0&&this.detach()},this.selectTabstop=function(e){this.$openTabstops=null;var t=this.tabstops[this.index];t&&this.addTabstopMarkers(t),this.index=e,t=this.tabstops[this.index];if(!t||!t.length)return;this.selectedTabstop=t;if(!this.editor.inVirtualSelectionMode){var n=this.editor.multiSelect;n.toSingleRange(t.firstNonLinked.clone());for(var r=t.length;r--;){if(t.hasLinkedRanges&&t[r].linked)continue;n.addRange(t[r].clone(),!0)}n.ranges[0]&&n.addRange(n.ranges[0].clone())}else this.editor.selection.setRange(t.firstNonLinked);this.editor.keyBinding.addKeyboardHandler(this.keyboardHandler)},this.addTabstops=function(e,t,n){this.$openTabstops||(this.$openTabstops=[]);if(!e[0]){var r=o.fromPoints(n,n);v(r.start,t),v(r.end,t),e[0]=[r],e[0].index=0}var i=this.index,s=[i+1,0],u=this.ranges;e.forEach(function(e,n){var r=this.$openTabstops[n]||e;for(var i=e.length;i--;){var a=e[i],f=o.fromPoints(a.start,a.end||a.start);d(f.start,t),d(f.end,t),f.original=a,f.tabstop=r,u.push(f),r!=e?r.unshift(f):r[i]=f,a.fmtString?(f.linked=!0,r.hasLinkedRanges=!0):r.firstNonLinked||(r.firstNonLinked=f)}r.firstNonLinked||(r.hasLinkedRanges=!1),r===e&&(s.push(r),this.$openTabstops[n]=r),this.addTabstopMarkers(r)},this),s.length>2&&(this.tabstops.length&&s.push(s.splice(2,1)[0]),this.tabstops.splice.apply(this.tabstops,s))},this.addTabstopMarkers=function(e){var t=this.editor.session;e.forEach(function(e){e.markerId||(e.markerId=t.addMarker(e,"ace_snippet-marker","text"))})},this.removeTabstopMarkers=function(e){var t=this.editor.session;e.forEach(function(e){t.removeMarker(e.markerId),e.markerId=null})},this.removeRange=function(e){var t=e.tabstop.indexOf(e);e.tabstop.splice(t,1),t=this.ranges.indexOf(e),this.ranges.splice(t,1),this.editor.session.removeMarker(e.markerId),e.tabstop.length||(t=this.tabstops.indexOf(e.tabstop),t!=-1&&this.tabstops.splice(t,1),this.tabstops.length||this.detach())},this.keyboardHandler=new a,this.keyboardHandler.bindKeys({Tab:function(e){if(t.snippetManager&&t.snippetManager.expandWithTab(e))return;e.tabstopManager.tabNext(1)},"Shift-Tab":function(e){e.tabstopManager.tabNext(-1)},Esc:function(e){e.tabstopManager.detach()},Return:function(e){return!1}})}).call(h.prototype);var p={};p.onChange=u.prototype.onChange,p.setPosition=function(e,t){this.pos.row=e,this.pos.column=t},p.update=function(e,t,n){this.$insertRight=n,this.pos=e,this.onChange(t)};var d=function(e,t){e.row==0&&(e.column+=t.column),e.row+=t.row},v=function(e,t){e.row==t.row&&(e.column-=t.column),e.row-=t.row};e("./lib/dom").importCssString(".ace_snippet-marker {    -moz-box-sizing: border-box;    box-sizing: border-box;    background: rgba(194, 193, 208, 0.09);    border: 1px dotted rgba(211, 208, 235, 0.62);    position: absolute;}"),t.snippetManager=new c;var m=e("./editor").Editor;(function(){this.insertSnippet=function(e,n){return t.snippetManager.insertSnippet(this,e,n)},this.expandSnippet=function(e){return t.snippetManager.expandWithTab(this,e)}}).call(m.prototype)}),ace.define("ace/autocomplete/popup",["require","exports","module","ace/virtual_renderer","ace/editor","ace/range","ace/lib/event","ace/lib/lang","ace/lib/dom"],function(e,t,n){"use strict";var r=e("../virtual_renderer").VirtualRenderer,i=e("../editor").Editor,s=e("../range").Range,o=e("../lib/event"),u=e("../lib/lang"),a=e("../lib/dom"),f=function(e){var t=new r(e);t.$maxLines=4;var n=new i(t);return n.setHighlightActiveLine(!1),n.setShowPrintMargin(!1),n.renderer.setShowGutter(!1),n.renderer.setHighlightGutterLine(!1),n.$mouseHandler.$focusWaitTimout=0,n.$highlightTagPending=!0,n},l=function(e){var t=a.createElement("div"),n=new f(t);e&&e.appendChild(t),t.style.display="none",n.renderer.content.style.cursor="default",n.renderer.setStyle("ace_autocomplete"),n.setOption("displayIndentGuides",!1),n.setOption("dragDelay",150);var r=function(){};n.focus=r,n.$isFocused=!0,n.renderer.$cursorLayer.restartTimer=r,n.renderer.$cursorLayer.element.style.opacity=0,n.renderer.$maxLines=8,n.renderer.$keepTextAreaAtCursor=!1,n.setHighlightActiveLine(!1),n.session.highlight(""),n.session.$searchHighlight.clazz="ace_highlight-marker",n.on("mousedown",function(e){var t=e.getDocumentPosition();n.selection.moveToPosition(t),c.start.row=c.end.row=t.row,e.stop()});var i,l=new s(-1,0,-1,Infinity),c=new s(-1,0,-1,Infinity);c.id=n.session.addMarker(c,"ace_active-line","fullLine"),n.setSelectOnHover=function(e){e?l.id&&(n.session.removeMarker(l.id),l.id=null):l.id=n.session.addMarker(l,"ace_line-hover","fullLine")},n.setSelectOnHover(!1),n.on("mousemove",function(e){if(!i){i=e;return}if(i.x==e.x&&i.y==e.y)return;i=e,i.scrollTop=n.renderer.scrollTop;var t=i.getDocumentPosition().row;l.start.row!=t&&(l.id||n.setRow(t),p(t))}),n.renderer.on("beforeRender",function(){if(i&&l.start.row!=-1){i.$pos=null;var e=i.getDocumentPosition().row;l.id||n.setRow(e),p(e,!0)}}),n.renderer.on("afterRender",function(){var e=n.getRow(),t=n.renderer.$textLayer,r=t.element.childNodes[e-t.config.firstRow];if(r==t.selectedNode)return;t.selectedNode&&a.removeCssClass(t.selectedNode,"ace_selected"),t.selectedNode=r,r&&a.addCssClass(r,"ace_selected")});var h=function(){p(-1)},p=function(e,t){e!==l.start.row&&(l.start.row=l.end.row=e,t||n.session._emit("changeBackMarker"),n._emit("changeHoverMarker"))};n.getHoveredRow=function(){return l.start.row},o.addListener(n.container,"mouseout",h),n.on("hide",h),n.on("changeSelection",h),n.session.doc.getLength=function(){return n.data.length},n.session.doc.getLine=function(e){var t=n.data[e];return typeof t=="string"?t:t&&t.value||""};var d=n.session.bgTokenizer;return d.$tokenizeRow=function(e){var t=n.data[e],r=[];if(!t)return r;typeof t=="string"&&(t={value:t}),t.caption||(t.caption=t.value||t.name);var i=-1,s,o;for(var u=0;u<t.caption.length;u++)o=t.caption[u],s=t.matchMask&1<<u?1:0,i!==s?(r.push({type:t.className||""+(s?"completion-highlight":""),value:o}),i=s):r[r.length-1].value+=o;if(t.meta){var a=n.renderer.$size.scrollerWidth/n.renderer.layerConfig.characterWidth,f=t.meta;f.length+t.caption.length>a-2&&(f=f.substr(0,a-t.caption.length-3)+"\u2026"),r.push({type:"rightAlignedText",value:f})}return r},d.$updateOnChange=r,d.start=r,n.session.$computeWidth=function(){return this.screenWidth=0},n.$blockScrolling=Infinity,n.isOpen=!1,n.isTopdown=!1,n.data=[],n.setData=function(e){n.setValue(u.stringRepeat("\n",e.length),-1),n.data=e||[],n.setRow(0)},n.getData=function(e){return n.data[e]},n.getRow=function(){return c.start.row},n.setRow=function(e){e=Math.max(0,Math.min(this.data.length,e)),c.start.row!=e&&(n.selection.clearSelection(),c.start.row=c.end.row=e||0,n.session._emit("changeBackMarker"),n.moveCursorTo(e||0,0),n.isOpen&&n._signal("select"))},n.on("changeSelection",function(){n.isOpen&&n.setRow(n.selection.lead.row),n.renderer.scrollCursorIntoView()}),n.hide=function(){this.container.style.display="none",this._signal("hide"),n.isOpen=!1},n.show=function(e,t,r){var s=this.container,o=window.innerHeight,u=window.innerWidth,a=this.renderer,f=a.$maxLines*t*1.4,l=e.top+this.$borderSize;l+f>o-t&&!r?(s.style.top="",s.style.bottom=o-l+"px",n.isTopdown=!1):(l+=t,s.style.top=l+"px",s.style.bottom="",n.isTopdown=!0),s.style.display="",this.renderer.$textLayer.checkForSizeChanges();var c=e.left;c+s.offsetWidth>u&&(c=u-s.offsetWidth),s.style.left=c+"px",this._signal("show"),i=null,n.isOpen=!0},n.getTextLeftOffset=function(){return this.$borderSize+this.renderer.$padding+this.$imageSize},n.$imageSize=0,n.$borderSize=1,n};a.importCssString(".ace_editor.ace_autocomplete .ace_marker-layer .ace_active-line {    background-color: #CAD6FA;    z-index: 1;}.ace_editor.ace_autocomplete .ace_line-hover {    border: 1px solid #abbffe;    margin-top: -1px;    background: rgba(233,233,253,0.4);}.ace_editor.ace_autocomplete .ace_line-hover {    position: absolute;    z-index: 2;}.ace_editor.ace_autocomplete .ace_scroller {   background: none;   border: none;   box-shadow: none;}.ace_rightAlignedText {    color: gray;    display: inline-block;    position: absolute;    right: 4px;    text-align: right;    z-index: -1;}.ace_editor.ace_autocomplete .ace_completion-highlight{    color: #000;    text-shadow: 0 0 0.01em;}.ace_editor.ace_autocomplete {    width: 280px;    z-index: 200000;    background: #fbfbfb;    color: #444;    border: 1px lightgray solid;    position: fixed;    box-shadow: 2px 3px 5px rgba(0,0,0,.2);    line-height: 1.4;}"),t.AcePopup=l}),ace.define("ace/autocomplete/util",["require","exports","module"],function(e,t,n){"use strict";t.parForEach=function(e,t,n){var r=0,i=e.length;i===0&&n();for(var s=0;s<i;s++)t(e[s],function(e,t){r++,r===i&&n(e,t)})};var r=/[a-zA-Z_0-9\$\-\u00A2-\uFFFF]/;t.retrievePrecedingIdentifier=function(e,t,n){n=n||r;var i=[];for(var s=t-1;s>=0;s--){if(!n.test(e[s]))break;i.push(e[s])}return i.reverse().join("")},t.retrieveFollowingIdentifier=function(e,t,n){n=n||r;var i=[];for(var s=t;s<e.length;s++){if(!n.test(e[s]))break;i.push(e[s])}return i},t.getCompletionPrefix=function(e){var t=e.getCursorPosition(),n=e.session.getLine(t.row),r;return e.completers.forEach(function(e){e.identifierRegexps&&e.identifierRegexps.forEach(function(e){!r&&e&&(r=this.retrievePrecedingIdentifier(n,t.column,e))}.bind(this))}.bind(this)),r||this.retrievePrecedingIdentifier(n,t.column)}}),ace.define("ace/autocomplete",["require","exports","module","ace/keyboard/hash_handler","ace/autocomplete/popup","ace/autocomplete/util","ace/lib/event","ace/lib/lang","ace/lib/dom","ace/snippets"],function(e,t,n){"use strict";var r=e("./keyboard/hash_handler").HashHandler,i=e("./autocomplete/popup").AcePopup,s=e("./autocomplete/util"),o=e("./lib/event"),u=e("./lib/lang"),a=e("./lib/dom"),f=e("./snippets").snippetManager,l=function(){this.autoInsert=!1,this.autoSelect=!0,this.exactMatch=!1,this.gatherCompletionsId=0,this.keyboardHandler=new r,this.keyboardHandler.bindKeys(this.commands),this.blurListener=this.blurListener.bind(this),this.changeListener=this.changeListener.bind(this),this.mousedownListener=this.mousedownListener.bind(this),this.mousewheelListener=this.mousewheelListener.bind(this),this.changeTimer=u.delayedCall(function(){this.updateCompletions(!0)}.bind(this)),this.tooltipTimer=u.delayedCall(this.updateDocTooltip.bind(this),50)};(function(){this.$init=function(){return this.popup=new i(document.body||document.documentElement),this.popup.on("click",function(e){this.insertMatch(),e.stop()}.bind(this)),this.popup.focus=this.editor.focus.bind(this.editor),this.popup.on("show",this.tooltipTimer.bind(null,null)),this.popup.on("select",this.tooltipTimer.bind(null,null)),this.popup.on("changeHoverMarker",this.tooltipTimer.bind(null,null)),this.popup},this.getPopup=function(){return this.popup||this.$init()},this.openPopup=function(e,t,n){this.popup||this.$init(),this.popup.setData(this.completions.filtered),e.keyBinding.addKeyboardHandler(this.keyboardHandler);var r=e.renderer;this.popup.setRow(this.autoSelect?0:-1);if(!n){this.popup.setTheme(e.getTheme()),this.popup.setFontSize(e.getFontSize());var i=r.layerConfig.lineHeight,s=r.$cursorLayer.getPixelPosition(this.base,!0);s.left-=this.popup.getTextLeftOffset();var o=e.container.getBoundingClientRect();s.top+=o.top-r.layerConfig.offset,s.left+=o.left-e.renderer.scrollLeft,s.left+=r.gutterWidth,this.popup.show(s,i)}else n&&!t&&this.detach()},this.detach=function(){this.editor.keyBinding.removeKeyboardHandler(this.keyboardHandler),this.editor.off("changeSelection",this.changeListener),this.editor.off("blur",this.blurListener),this.editor.off("mousedown",this.mousedownListener),this.editor.off("mousewheel",this.mousewheelListener),this.changeTimer.cancel(),this.hideDocTooltip(),this.gatherCompletionsId+=1,this.popup&&this.popup.isOpen&&this.popup.hide(),this.base&&this.base.detach(),this.activated=!1,this.completions=this.base=null},this.changeListener=function(e){var t=this.editor.selection.lead;(t.row!=this.base.row||t.column<this.base.column)&&this.detach(),this.activated?this.changeTimer.schedule():this.detach()},this.blurListener=function(e){var t=document.activeElement,n=this.editor.textInput.getElement(),r=e.relatedTarget&&e.relatedTarget==this.tooltipNode,i=this.popup&&this.popup.container;t!=n&&t.parentNode!=i&&!r&&t!=this.tooltipNode&&e.relatedTarget!=n&&this.detach()},this.mousedownListener=function(e){this.detach()},this.mousewheelListener=function(e){this.detach()},this.goTo=function(e){var t=this.popup.getRow(),n=this.popup.session.getLength()-1;switch(e){case"up":t=t<=0?n:t-1;break;case"down":t=t>=n?-1:t+1;break;case"start":t=0;break;case"end":t=n}this.popup.setRow(t)},this.insertMatch=function(e,t){e||(e=this.popup.getData(this.popup.getRow()));if(!e)return!1;if(e.completer&&e.completer.insertMatch)e.completer.insertMatch(this.editor,e);else{if(this.completions.filterText){var n=this.editor.selection.getAllRanges();for(var r=0,i;i=n[r];r++)i.start.column-=this.completions.filterText.length,this.editor.session.remove(i)}e.snippet?f.insertSnippet(this.editor,e.snippet):this.editor.execCommand("insertstring",e.value||e)}this.detach()},this.commands={Up:function(e){e.completer.goTo("up")},Down:function(e){e.completer.goTo("down")},"Ctrl-Up|Ctrl-Home":function(e){e.completer.goTo("start")},"Ctrl-Down|Ctrl-End":function(e){e.completer.goTo("end")},Esc:function(e){e.completer.detach()},Return:function(e){return e.completer.insertMatch()},"Shift-Return":function(e){e.completer.insertMatch(null,{deleteSuffix:!0})},Tab:function(e){var t=e.completer.insertMatch();if(!!t||!!e.tabstopManager)return t;e.completer.goTo("down")},PageUp:function(e){e.completer.popup.gotoPageUp()},PageDown:function(e){e.completer.popup.gotoPageDown()}},this.gatherCompletions=function(e,t){var n=e.getSession(),r=e.getCursorPosition(),i=n.getLine(r.row),o=s.getCompletionPrefix(e);this.base=n.doc.createAnchor(r.row,r.column-o.length),this.base.$insertRight=!0;var u=[],a=e.completers.length;return e.completers.forEach(function(i,s){i.getCompletions(e,n,r,o,function(r,i){!r&&i&&(u=u.concat(i));var s=e.getCursorPosition(),f=n.getLine(s.row);t(null,{prefix:o,matches:u,finished:--a===0})})}),!0},this.showPopup=function(e){this.editor&&this.detach(),this.activated=!0,this.editor=e,e.completer!=this&&(e.completer&&e.completer.detach(),e.completer=this),e.on("changeSelection",this.changeListener),e.on("blur",this.blurListener),e.on("mousedown",this.mousedownListener),e.on("mousewheel",this.mousewheelListener),this.updateCompletions()},this.updateCompletions=function(e){if(e&&this.base&&this.completions){var t=this.editor.getCursorPosition(),n=this.editor.session.getTextRange({start:this.base,end:t});if(n==this.completions.filterText)return;this.completions.setFilter(n);if(!this.completions.filtered.length)return this.detach();if(this.completions.filtered.length==1&&this.completions.filtered[0].value==n&&!this.completions.filtered[0].snippet)return this.detach();this.openPopup(this.editor,n,e);return}var r=this.gatherCompletionsId;this.gatherCompletions(this.editor,function(t,n){var i=function(){if(!n.finished)return;return this.detach()}.bind(this),s=n.prefix,o=n&&n.matches;if(!o||!o.length)return i();if(s.indexOf(n.prefix)!==0||r!=this.gatherCompletionsId)return;this.completions=new c(o),this.exactMatch&&(this.completions.exactMatch=!0),this.completions.setFilter(s);var u=this.completions.filtered;if(!u.length)return i();if(u.length==1&&u[0].value==s&&!u[0].snippet)return i();if(this.autoInsert&&u.length==1&&n.finished)return this.insertMatch(u[0]);this.openPopup(this.editor,s,e)}.bind(this))},this.cancelContextMenu=function(){this.editor.$mouseHandler.cancelContextMenu()},this.updateDocTooltip=function(){var e=this.popup,t=e.data,n=t&&(t[e.getHoveredRow()]||t[e.getRow()]),r=null;if(!n||!this.editor||!this.popup.isOpen)return this.hideDocTooltip();this.editor.completers.some(function(e){return e.getDocTooltip&&(r=e.getDocTooltip(n)),r}),r||(r=n),typeof r=="string"&&(r={docText:r});if(!r||!r.docHTML&&!r.docText)return this.hideDocTooltip();this.showDocTooltip(r)},this.showDocTooltip=function(e){this.tooltipNode||(this.tooltipNode=a.createElement("div"),this.tooltipNode.className="ace_tooltip ace_doc-tooltip",this.tooltipNode.style.margin=0,this.tooltipNode.style.pointerEvents="auto",this.tooltipNode.tabIndex=-1,this.tooltipNode.onblur=this.blurListener.bind(this));var t=this.tooltipNode;e.docHTML?t.innerHTML=e.docHTML:e.docText&&(t.textContent=e.docText),t.parentNode||document.body.appendChild(t);var n=this.popup,r=n.container.getBoundingClientRect();t.style.top=n.container.style.top,t.style.bottom=n.container.style.bottom,window.innerWidth-r.right<320?(t.style.right=window.innerWidth-r.left+"px",t.style.left=""):(t.style.left=r.right+1+"px",t.style.right=""),t.style.display="block"},this.hideDocTooltip=function(){this.tooltipTimer.cancel();if(!this.tooltipNode)return;var e=this.tooltipNode;!this.editor.isFocused()&&document.activeElement==e&&this.editor.focus(),this.tooltipNode=null,e.parentNode&&e.parentNode.removeChild(e)}}).call(l.prototype),l.startCommand={name:"startAutocomplete",exec:function(e){e.completer||(e.completer=new l),e.completer.autoInsert=!1,e.completer.autoSelect=!0,e.completer.showPopup(e),e.completer.cancelContextMenu()},bindKey:"Ctrl-Space|Ctrl-Shift-Space|Alt-Space"};var c=function(e,t){this.all=e,this.filtered=e,this.filterText=t||"",this.exactMatch=!1};(function(){this.setFilter=function(e){if(e.length>this.filterText&&e.lastIndexOf(this.filterText,0)===0)var t=this.filtered;else var t=this.all;this.filterText=e,t=this.filterCompletions(t,this.filterText),t=t.sort(function(e,t){return t.exactMatch-e.exactMatch||t.score-e.score});var n=null;t=t.filter(function(e){var t=e.snippet||e.caption||e.value;return t===n?!1:(n=t,!0)}),this.filtered=t},this.filterCompletions=function(e,t){var n=[],r=t.toUpperCase(),i=t.toLowerCase();e:for(var s=0,o;o=e[s];s++){var u=o.value||o.caption||o.snippet;if(!u)continue;var a=-1,f=0,l=0,c,h;if(this.exactMatch){if(t!==u.substr(0,t.length))continue e}else for(var p=0;p<t.length;p++){var d=u.indexOf(i[p],a+1),v=u.indexOf(r[p],a+1);c=d>=0?v<0||d<v?d:v:v;if(c<0)continue e;h=c-a-1,h>0&&(a===-1&&(l+=10),l+=h),f|=1<<c,a=c}o.matchMask=f,o.exactMatch=l?0:1,o.score=(o.score||0)-l,n.push(o)}return n}}).call(c.prototype),t.Autocomplete=l,t.FilteredList=c}),ace.define("ace/autocomplete/text_completer",["require","exports","module","ace/range"],function(e,t,n){function s(e,t){var n=e.getTextRange(r.fromPoints({row:0,column:0},t));return n.split(i).length-1}function o(e,t){var n=s(e,t),r=e.getValue().split(i),o=Object.create(null),u=r[n];return r.forEach(function(e,t){if(!e||e===u)return;var i=Math.abs(n-t),s=r.length-i;o[e]?o[e]=Math.max(s,o[e]):o[e]=s}),o}var r=e("../range").Range,i=/[^a-zA-Z_0-9\$\-\u00C0-\u1FFF\u2C00-\uD7FF\w]+/;t.getCompletions=function(e,t,n,r,i){var s=o(t,n,r),u=Object.keys(s);i(null,u.map(function(e){return{caption:e,value:e,score:s[e],meta:"local"}}))}}),ace.define("ace/ext/language_tools",["require","exports","module","ace/snippets","ace/autocomplete","ace/config","ace/lib/lang","ace/autocomplete/util","ace/autocomplete/text_completer","ace/editor","ace/config"],function(e,t,n){"use strict";var r=e("../snippets").snippetManager,i=e("../autocomplete").Autocomplete,s=e("../config"),o=e("../lib/lang"),u=e("../autocomplete/util"),a=e("../autocomplete/text_completer"),f={getCompletions:function(e,t,n,r,i){if(t.$mode.completer)return t.$mode.completer.getCompletions(e,t,n,r,i);var s=e.session.getState(n.row),o=t.$mode.getCompletions(s,t,n,r);i(null,o)}},l={getCompletions:function(e,t,n,i,s){var o=r.snippetMap,u=[];r.getActiveScopes(e).forEach(function(e){var t=o[e]||[];for(var n=t.length;n--;){var r=t[n],i=r.name||r.tabTrigger;if(!i)continue;u.push({caption:i,snippet:r.content,meta:r.tabTrigger&&!r.name?r.tabTrigger+"\u21e5 ":"snippet",type:"snippet"})}},this),s(null,u)},getDocTooltip:function(e){e.type=="snippet"&&!e.docHTML&&(e.docHTML=["<b>",o.escapeHTML(e.caption),"</b>","<hr></hr>",o.escapeHTML(e.snippet)].join(""))}},c=[l,a,f];t.setCompleters=function(e){c.length=0,e&&c.push.apply(c,e)},t.addCompleter=function(e){c.push(e)},t.textCompleter=a,t.keyWordCompleter=f,t.snippetCompleter=l;var h={name:"expandSnippet",exec:function(e){return r.expandWithTab(e)},bindKey:"Tab"},p=function(e,t){d(t.session.$mode)},d=function(e){var t=e.$id;r.files||(r.files={}),v(t),e.modes&&e.modes.forEach(d)},v=function(e){if(!e||r.files[e])return;var t=e.replace("mode","snippets");r.files[e]={},s.loadModule(t,function(t){t&&(r.files[e]=t,!t.snippets&&t.snippetText&&(t.snippets=r.parseSnippetFile(t.snippetText)),r.register(t.snippets||[],t.scope),t.includeScopes&&(r.snippetMap[t.scope].includeScopes=t.includeScopes,t.includeScopes.forEach(function(e){v("ace/mode/"+e)})))})},m=function(e){var t=e.editor,n=t.completer&&t.completer.activated;if(e.command.name==="backspace")n&&!u.getCompletionPrefix(t)&&t.completer.detach();else if(e.command.name==="insertstring"){var r=u.getCompletionPrefix(t);r&&!n&&(t.completer||(t.completer=new i),t.completer.autoInsert=!1,t.completer.showPopup(t))}},g=e("../editor").Editor;e("../config").defineOptions(g.prototype,"editor",{enableBasicAutocompletion:{set:function(e){e?(this.completers||(this.completers=Array.isArray(e)?e:c),this.commands.addCommand(i.startCommand)):this.commands.removeCommand(i.startCommand)},value:!1},enableLiveAutocompletion:{set:function(e){e?(this.completers||(this.completers=Array.isArray(e)?e:c),this.commands.on("afterExec",m)):this.commands.removeListener("afterExec",m)},value:!1},enableSnippets:{set:function(e){e?(this.commands.addCommand(h),this.on("changeMode",p),p(null,this)):(this.commands.removeCommand(h),this.off("changeMode",p))},value:!1}})});
+                (function() {
+                    ace.require(["ace/ext/language_tools"], function() {});
+                })();
+            
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-linking.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-linking.js
new file mode 100644
index 0000000..69f8791
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-linking.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/linking",["require","exports","module","ace/editor","ace/config"],function(e,t,n){function i(e){var t=e.editor,n=e.getAccelKey();if(n){var t=e.editor,r=e.getDocumentPosition(),i=t.session,s=i.getTokenAt(r.row,r.column);t._emit("linkHover",{position:r,token:s})}}function s(e){var t=e.getAccelKey(),n=e.getButton();if(n==0&&t){var r=e.editor,i=e.getDocumentPosition(),s=r.session,o=s.getTokenAt(i.row,i.column);r._emit("linkClick",{position:i,token:o})}}var r=e("ace/editor").Editor;e("../config").defineOptions(r.prototype,"editor",{enableLinking:{set:function(e){e?(this.on("click",s),this.on("mousemove",i)):(this.off("click",s),this.off("mousemove",i))},value:!1}})});
+                (function() {
+                    ace.require(["ace/ext/linking"], function() {});
+                })();
+            
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-modelist.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-modelist.js
new file mode 100644
index 0000000..a792627
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-modelist.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/modelist",["require","exports","module"],function(e,t,n){"use strict";function i(e){var t=a.text,n=e.split(/[\/\\]/).pop();for(var i=0;i<r.length;i++)if(r[i].supportsFile(n)){t=r[i];break}return t}var r=[],s=function(e,t,n){this.name=e,this.caption=t,this.mode="ace/mode/"+e,this.extensions=n;var r;/\^/.test(n)?r=n.replace(/\|(\^)?/g,function(e,t){return"$|"+(t?"^":"^.*\\.")})+"$":r="^.*\\.("+n+")$",this.extRe=new RegExp(r,"gi")};s.prototype.supportsFile=function(e){return e.match(this.extRe)};var o={ABAP:["abap"],ABC:["abc"],ActionScript:["as"],ADA:["ada|adb"],Apache_Conf:["^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd"],AsciiDoc:["asciidoc|adoc"],Assembly_x86:["asm|a"],AutoHotKey:["ahk"],BatchFile:["bat|cmd"],C_Cpp:["cpp|c|cc|cxx|h|hh|hpp|ino"],C9Search:["c9search_results"],Cirru:["cirru|cr"],Clojure:["clj|cljs"],Cobol:["CBL|COB"],coffee:["coffee|cf|cson|^Cakefile"],ColdFusion:["cfm"],CSharp:["cs"],CSS:["css"],Curly:["curly"],D:["d|di"],Dart:["dart"],Diff:["diff|patch"],Dockerfile:["^Dockerfile"],Dot:["dot"],Dummy:["dummy"],DummySyntax:["dummy"],Eiffel:["e|ge"],EJS:["ejs"],Elixir:["ex|exs"],Elm:["elm"],Erlang:["erl|hrl"],Forth:["frt|fs|ldr"],FTL:["ftl"],Gcode:["gcode"],Gherkin:["feature"],Gitignore:["^.gitignore"],Glsl:["glsl|frag|vert"],Gobstones:["gbs"],golang:["go"],Groovy:["groovy"],HAML:["haml"],Handlebars:["hbs|handlebars|tpl|mustache"],Haskell:["hs"],haXe:["hx"],HTML:["html|htm|xhtml"],HTML_Elixir:["eex|html.eex"],HTML_Ruby:["erb|rhtml|html.erb"],INI:["ini|conf|cfg|prefs"],Io:["io"],Jack:["jack"],Jade:["jade"],Java:["java"],JavaScript:["js|jsm|jsx"],JSON:["json"],JSONiq:["jq"],JSP:["jsp"],JSX:["jsx"],Julia:["jl"],LaTeX:["tex|latex|ltx|bib"],Lean:["lean|hlean"],LESS:["less"],Liquid:["liquid"],Lisp:["lisp"],LiveScript:["ls"],LogiQL:["logic|lql"],LSL:["lsl"],Lua:["lua"],LuaPage:["lp"],Lucene:["lucene"],Makefile:["^Makefile|^GNUmakefile|^makefile|^OCamlMakefile|make"],Markdown:["md|markdown"],Mask:["mask"],MATLAB:["matlab"],Maze:["mz"],MEL:["mel"],MUSHCode:["mc|mush"],MySQL:["mysql"],Nix:["nix"],NSIS:["nsi|nsh"],ObjectiveC:["m|mm"],OCaml:["ml|mli"],Pascal:["pas|p"],Perl:["pl|pm"],pgSQL:["pgsql"],PHP:["php|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp|module"],Powershell:["ps1"],Praat:["praat|praatscript|psc|proc"],Prolog:["plg|prolog"],Properties:["properties"],Protobuf:["proto"],Python:["py"],R:["r"],Razor:["cshtml"],RDoc:["Rd"],RHTML:["Rhtml"],RST:["rst"],Ruby:["rb|ru|gemspec|rake|^Guardfile|^Rakefile|^Gemfile"],Rust:["rs"],SASS:["sass"],SCAD:["scad"],Scala:["scala"],Scheme:["scm|sm|rkt|oak|scheme"],SCSS:["scss"],SH:["sh|bash|^.bashrc"],SJS:["sjs"],Smarty:["smarty|tpl"],snippets:["snippets"],Soy_Template:["soy"],Space:["space"],SQL:["sql"],SQLServer:["sqlserver"],Stylus:["styl|stylus"],SVG:["svg"],Swift:["swift"],Tcl:["tcl"],Tex:["tex"],Text:["txt"],Textile:["textile"],Toml:["toml"],Twig:["twig|swig"],Typescript:["ts|typescript|str"],Vala:["vala"],VBScript:["vbs|vb"],Velocity:["vm"],Verilog:["v|vh|sv|svh"],VHDL:["vhd|vhdl"],Wollok:["wlk|wpgm|wtest"],XML:["xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl|xaml"],XQuery:["xq"],YAML:["yaml|yml"],Django:["html"]},u={ObjectiveC:"Objective-C",CSharp:"C#",golang:"Go",C_Cpp:"C and C++",coffee:"CoffeeScript",HTML_Ruby:"HTML (Ruby)",HTML_Elixir:"HTML (Elixir)",FTL:"FreeMarker"},a={};for(var f in o){var l=o[f],c=(u[f]||f).replace(/_/g," "),h=f.toLowerCase(),p=new s(h,c,l[0]);a[h]=p,r.push(p)}n.exports={getModeForPath:i,modes:r,modesByName:a}});
+                (function() {
+                    ace.require(["ace/ext/modelist"], function() {});
+                })();
+            
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-old_ie.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-old_ie.js
new file mode 100644
index 0000000..7bea1c0
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-old_ie.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/searchbox",["require","exports","module","ace/lib/dom","ace/lib/lang","ace/lib/event","ace/keyboard/hash_handler","ace/lib/keys"],function(e,t,n){"use strict";var r=e("../lib/dom"),i=e("../lib/lang"),s=e("../lib/event"),o=".ace_search {background-color: #ddd;border: 1px solid #cbcbcb;border-top: 0 none;max-width: 325px;overflow: hidden;margin: 0;padding: 4px;padding-right: 6px;padding-bottom: 0;position: absolute;top: 0px;z-index: 99;white-space: normal;}.ace_search.left {border-left: 0 none;border-radius: 0px 0px 5px 0px;left: 0;}.ace_search.right {border-radius: 0px 0px 0px 5px;border-right: 0 none;right: 0;}.ace_search_form, .ace_replace_form {border-radius: 3px;border: 1px solid #cbcbcb;float: left;margin-bottom: 4px;overflow: hidden;}.ace_search_form.ace_nomatch {outline: 1px solid red;}.ace_search_field {background-color: white;border-right: 1px solid #cbcbcb;border: 0 none;-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;float: left;height: 22px;outline: 0;padding: 0 7px;width: 214px;margin: 0;}.ace_searchbtn,.ace_replacebtn {background: #fff;border: 0 none;border-left: 1px solid #dcdcdc;cursor: pointer;float: left;height: 22px;margin: 0;position: relative;}.ace_searchbtn:last-child,.ace_replacebtn:last-child {border-top-right-radius: 3px;border-bottom-right-radius: 3px;}.ace_searchbtn:disabled {background: none;cursor: default;}.ace_searchbtn {background-position: 50% 50%;background-repeat: no-repeat;width: 27px;}.ace_searchbtn.prev {background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAFCAYAAAB4ka1VAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADFJREFUeNpiSU1NZUAC/6E0I0yACYskCpsJiySKIiY0SUZk40FyTEgCjGgKwTRAgAEAQJUIPCE+qfkAAAAASUVORK5CYII=);    }.ace_searchbtn.next {background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAFCAYAAAB4ka1VAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADRJREFUeNpiTE1NZQCC/0DMyIAKwGJMUAYDEo3M/s+EpvM/mkKwCQxYjIeLMaELoLMBAgwAU7UJObTKsvAAAAAASUVORK5CYII=);    }.ace_searchbtn_close {background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAcCAYAAABRVo5BAAAAZ0lEQVR42u2SUQrAMAhDvazn8OjZBilCkYVVxiis8H4CT0VrAJb4WHT3C5xU2a2IQZXJjiQIRMdkEoJ5Q2yMqpfDIo+XY4k6h+YXOyKqTIj5REaxloNAd0xiKmAtsTHqW8sR2W5f7gCu5nWFUpVjZwAAAABJRU5ErkJggg==) no-repeat 50% 0;border-radius: 50%;border: 0 none;color: #656565;cursor: pointer;float: right;font: 16px/16px Arial;height: 14px;margin: 5px 1px 9px 5px;padding: 0;text-align: center;width: 14px;}.ace_searchbtn_close:hover {background-color: #656565;background-position: 50% 100%;color: white;}.ace_replacebtn.prev {width: 54px}.ace_replacebtn.next {width: 27px}.ace_button {margin-left: 2px;cursor: pointer;-webkit-user-select: none;-moz-user-select: none;-o-user-select: none;-ms-user-select: none;user-select: none;overflow: hidden;opacity: 0.7;border: 1px solid rgba(100,100,100,0.23);padding: 1px;-moz-box-sizing: border-box;box-sizing:    border-box;color: black;}.ace_button:hover {background-color: #eee;opacity:1;}.ace_button:active {background-color: #ddd;}.ace_button.checked {border-color: #3399ff;opacity:1;}.ace_search_options{margin-bottom: 3px;text-align: right;-webkit-user-select: none;-moz-user-select: none;-o-user-select: none;-ms-user-select: none;user-select: none;}",u=e("../keyboard/hash_handler").HashHandler,a=e("../lib/keys");r.importCssString(o,"ace_searchbox");var f='<div class="ace_search right">    <button type="button" action="hide" class="ace_searchbtn_close"></button>    <div class="ace_search_form">        <input class="ace_search_field" placeholder="Search for" spellcheck="false"></input>        <button type="button" action="findNext" class="ace_searchbtn next"></button>        <button type="button" action="findPrev" class="ace_searchbtn prev"></button>        <button type="button" action="findAll" class="ace_searchbtn" title="Alt-Enter">All</button>    </div>    <div class="ace_replace_form">        <input class="ace_search_field" placeholder="Replace with" spellcheck="false"></input>        <button type="button" action="replaceAndFindNext" class="ace_replacebtn">Replace</button>        <button type="button" action="replaceAll" class="ace_replacebtn">All</button>    </div>    <div class="ace_search_options">        <span action="toggleRegexpMode" class="ace_button" title="RegExp Search">.*</span>        <span action="toggleCaseSensitive" class="ace_button" title="CaseSensitive Search">Aa</span>        <span action="toggleWholeWords" class="ace_button" title="Whole Word Search">\\b</span>    </div></div>'.replace(/>\s+/g,">"),l=function(e,t,n){var i=r.createElement("div");i.innerHTML=f,this.element=i.firstChild,this.$init(),this.setEditor(e)};(function(){this.setEditor=function(e){e.searchBox=this,e.container.appendChild(this.element),this.editor=e},this.$initElements=function(e){this.searchBox=e.querySelector(".ace_search_form"),this.replaceBox=e.querySelector(".ace_replace_form"),this.searchOptions=e.querySelector(".ace_search_options"),this.regExpOption=e.querySelector("[action=toggleRegexpMode]"),this.caseSensitiveOption=e.querySelector("[action=toggleCaseSensitive]"),this.wholeWordOption=e.querySelector("[action=toggleWholeWords]"),this.searchInput=this.searchBox.querySelector(".ace_search_field"),this.replaceInput=this.replaceBox.querySelector(".ace_search_field")},this.$init=function(){var e=this.element;this.$initElements(e);var t=this;s.addListener(e,"mousedown",function(e){setTimeout(function(){t.activeInput.focus()},0),s.stopPropagation(e)}),s.addListener(e,"click",function(e){var n=e.target||e.srcElement,r=n.getAttribute("action");r&&t[r]?t[r]():t.$searchBarKb.commands[r]&&t.$searchBarKb.commands[r].exec(t),s.stopPropagation(e)}),s.addCommandKeyListener(e,function(e,n,r){var i=a.keyCodeToString(r),o=t.$searchBarKb.findKeyCommand(n,i);o&&o.exec&&(o.exec(t),s.stopEvent(e))}),this.$onChange=i.delayedCall(function(){t.find(!1,!1)}),s.addListener(this.searchInput,"input",function(){t.$onChange.schedule(20)}),s.addListener(this.searchInput,"focus",function(){t.activeInput=t.searchInput,t.searchInput.value&&t.highlight()}),s.addListener(this.replaceInput,"focus",function(){t.activeInput=t.replaceInput,t.searchInput.value&&t.highlight()})},this.$closeSearchBarKb=new u([{bindKey:"Esc",name:"closeSearchBar",exec:function(e){e.searchBox.hide()}}]),this.$searchBarKb=new u,this.$searchBarKb.bindKeys({"Ctrl-f|Command-f":function(e){var t=e.isReplace=!e.isReplace;e.replaceBox.style.display=t?"":"none",e.searchInput.focus()},"Ctrl-H|Command-Option-F":function(e){e.replaceBox.style.display="",e.replaceInput.focus()},"Ctrl-G|Command-G":function(e){e.findNext()},"Ctrl-Shift-G|Command-Shift-G":function(e){e.findPrev()},esc:function(e){setTimeout(function(){e.hide()})},Return:function(e){e.activeInput==e.replaceInput&&e.replace(),e.findNext()},"Shift-Return":function(e){e.activeInput==e.replaceInput&&e.replace(),e.findPrev()},"Alt-Return":function(e){e.activeInput==e.replaceInput&&e.replaceAll(),e.findAll()},Tab:function(e){(e.activeInput==e.replaceInput?e.searchInput:e.replaceInput).focus()}}),this.$searchBarKb.addCommands([{name:"toggleRegexpMode",bindKey:{win:"Alt-R|Alt-/",mac:"Ctrl-Alt-R|Ctrl-Alt-/"},exec:function(e){e.regExpOption.checked=!e.regExpOption.checked,e.$syncOptions()}},{name:"toggleCaseSensitive",bindKey:{win:"Alt-C|Alt-I",mac:"Ctrl-Alt-R|Ctrl-Alt-I"},exec:function(e){e.caseSensitiveOption.checked=!e.caseSensitiveOption.checked,e.$syncOptions()}},{name:"toggleWholeWords",bindKey:{win:"Alt-B|Alt-W",mac:"Ctrl-Alt-B|Ctrl-Alt-W"},exec:function(e){e.wholeWordOption.checked=!e.wholeWordOption.checked,e.$syncOptions()}}]),this.$syncOptions=function(){r.setCssClass(this.regExpOption,"checked",this.regExpOption.checked),r.setCssClass(this.wholeWordOption,"checked",this.wholeWordOption.checked),r.setCssClass(this.caseSensitiveOption,"checked",this.caseSensitiveOption.checked),this.find(!1,!1)},this.highlight=function(e){this.editor.session.highlight(e||this.editor.$search.$options.re),this.editor.renderer.updateBackMarkers()},this.find=function(e,t,n){var i=this.editor.find(this.searchInput.value,{skipCurrent:e,backwards:t,wrap:!0,regExp:this.regExpOption.checked,caseSensitive:this.caseSensitiveOption.checked,wholeWord:this.wholeWordOption.checked,preventScroll:n}),s=!i&&this.searchInput.value;r.setCssClass(this.searchBox,"ace_nomatch",s),this.editor._emit("findSearchBox",{match:!s}),this.highlight()},this.findNext=function(){this.find(!0,!1)},this.findPrev=function(){this.find(!0,!0)},this.findAll=function(){var e=this.editor.findAll(this.searchInput.value,{regExp:this.regExpOption.checked,caseSensitive:this.caseSensitiveOption.checked,wholeWord:this.wholeWordOption.checked}),t=!e&&this.searchInput.value;r.setCssClass(this.searchBox,"ace_nomatch",t),this.editor._emit("findSearchBox",{match:!t}),this.highlight(),this.hide()},this.replace=function(){this.editor.getReadOnly()||this.editor.replace(this.replaceInput.value)},this.replaceAndFindNext=function(){this.editor.getReadOnly()||(this.editor.replace(this.replaceInput.value),this.findNext())},this.replaceAll=function(){this.editor.getReadOnly()||this.editor.replaceAll(this.replaceInput.value)},this.hide=function(){this.element.style.display="none",this.editor.keyBinding.removeKeyboardHandler(this.$closeSearchBarKb),this.editor.focus()},this.show=function(e,t){this.element.style.display="",this.replaceBox.style.display=t?"":"none",this.isReplace=t,e&&(this.searchInput.value=e),this.find(!1,!1,!0),this.searchInput.focus(),this.searchInput.select(),this.editor.keyBinding.addKeyboardHandler(this.$closeSearchBarKb)},this.isFocused=function(){var e=document.activeElement;return e==this.searchInput||e==this.replaceInput}}).call(l.prototype),t.SearchBox=l,t.Search=function(e,t){var n=e.searchBox||new l(e);n.show(e.session.getTextRange(),t)}}),ace.define("ace/ext/old_ie",["require","exports","module","ace/lib/useragent","ace/tokenizer","ace/ext/searchbox","ace/mode/text"],function(require,exports,module){"use strict";function patch(obj,name,regexp,replacement){eval("obj['"+name+"']="+obj[name].toString().replace(regexp,replacement))}var MAX_TOKEN_COUNT=1e3,useragent=require("../lib/useragent"),TokenizerModule=require("../tokenizer");useragent.isIE&&useragent.isIE<10&&window.top.document.compatMode==="BackCompat"&&(useragent.isOldIE=!0);if(typeof document!="undefined"&&!document.documentElement.querySelector){useragent.isOldIE=!0;var qs=function(e,t){if(t.charAt(0)==".")var n=t.slice(1);else var r=t.match(/(\w+)=(\w+)/),i=r&&r[1],s=r&&r[2];for(var o=0;o<e.all.length;o++){var u=e.all[o];if(n){if(u.className.indexOf(n)!=-1)return u}else if(i&&u.getAttribute(i)==s)return u}},sb=require("./searchbox").SearchBox.prototype;patch(sb,"$initElements",/([^\s=]*).querySelector\((".*?")\)/g,"qs($1, $2)")}var compliantExecNpcg=/()??/.exec("")[1]===undefined;if(compliantExecNpcg)return;var proto=TokenizerModule.Tokenizer.prototype;TokenizerModule.Tokenizer_orig=TokenizerModule.Tokenizer,proto.getLineTokens_orig=proto.getLineTokens,patch(TokenizerModule,"Tokenizer","ruleRegExps.push(adjustedregex);\n",function(e){return e+'        if (state[i].next && RegExp(adjustedregex).test(""))\n            rule._qre = RegExp(adjustedregex, "g");\n        '}),TokenizerModule.Tokenizer.prototype=proto,patch(proto,"getLineTokens",/if \(match\[i \+ 1\] === undefined\)\s*continue;/,"if (!match[i + 1]) {\n        if (value)continue;\n        var qre = state[mapping[i]]._qre;\n        if (!qre) continue;\n        qre.lastIndex = lastIndex;\n        if (!qre.exec(line) || qre.lastIndex != lastIndex)\n            continue;\n    }"),patch(require("../mode/text").Mode.prototype,"getTokenizer",/Tokenizer/,"TokenizerModule.Tokenizer"),useragent.isOldIE=!0});
+                (function() {
+                    ace.require(["ace/ext/old_ie"], function() {});
+                })();
+            
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-searchbox.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-searchbox.js
new file mode 100644
index 0000000..e677a05
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-searchbox.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/searchbox",["require","exports","module","ace/lib/dom","ace/lib/lang","ace/lib/event","ace/keyboard/hash_handler","ace/lib/keys"],function(e,t,n){"use strict";var r=e("../lib/dom"),i=e("../lib/lang"),s=e("../lib/event"),o=".ace_search {background-color: #ddd;border: 1px solid #cbcbcb;border-top: 0 none;max-width: 325px;overflow: hidden;margin: 0;padding: 4px;padding-right: 6px;padding-bottom: 0;position: absolute;top: 0px;z-index: 99;white-space: normal;}.ace_search.left {border-left: 0 none;border-radius: 0px 0px 5px 0px;left: 0;}.ace_search.right {border-radius: 0px 0px 0px 5px;border-right: 0 none;right: 0;}.ace_search_form, .ace_replace_form {border-radius: 3px;border: 1px solid #cbcbcb;float: left;margin-bottom: 4px;overflow: hidden;}.ace_search_form.ace_nomatch {outline: 1px solid red;}.ace_search_field {background-color: white;border-right: 1px solid #cbcbcb;border: 0 none;-webkit-box-sizing: border-box;-moz-box-sizing: border-box;box-sizing: border-box;float: left;height: 22px;outline: 0;padding: 0 7px;width: 214px;margin: 0;}.ace_searchbtn,.ace_replacebtn {background: #fff;border: 0 none;border-left: 1px solid #dcdcdc;cursor: pointer;float: left;height: 22px;margin: 0;position: relative;}.ace_searchbtn:last-child,.ace_replacebtn:last-child {border-top-right-radius: 3px;border-bottom-right-radius: 3px;}.ace_searchbtn:disabled {background: none;cursor: default;}.ace_searchbtn {background-position: 50% 50%;background-repeat: no-repeat;width: 27px;}.ace_searchbtn.prev {background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAFCAYAAAB4ka1VAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADFJREFUeNpiSU1NZUAC/6E0I0yACYskCpsJiySKIiY0SUZk40FyTEgCjGgKwTRAgAEAQJUIPCE+qfkAAAAASUVORK5CYII=);    }.ace_searchbtn.next {background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAFCAYAAAB4ka1VAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADRJREFUeNpiTE1NZQCC/0DMyIAKwGJMUAYDEo3M/s+EpvM/mkKwCQxYjIeLMaELoLMBAgwAU7UJObTKsvAAAAAASUVORK5CYII=);    }.ace_searchbtn_close {background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAcCAYAAABRVo5BAAAAZ0lEQVR42u2SUQrAMAhDvazn8OjZBilCkYVVxiis8H4CT0VrAJb4WHT3C5xU2a2IQZXJjiQIRMdkEoJ5Q2yMqpfDIo+XY4k6h+YXOyKqTIj5REaxloNAd0xiKmAtsTHqW8sR2W5f7gCu5nWFUpVjZwAAAABJRU5ErkJggg==) no-repeat 50% 0;border-radius: 50%;border: 0 none;color: #656565;cursor: pointer;float: right;font: 16px/16px Arial;height: 14px;margin: 5px 1px 9px 5px;padding: 0;text-align: center;width: 14px;}.ace_searchbtn_close:hover {background-color: #656565;background-position: 50% 100%;color: white;}.ace_replacebtn.prev {width: 54px}.ace_replacebtn.next {width: 27px}.ace_button {margin-left: 2px;cursor: pointer;-webkit-user-select: none;-moz-user-select: none;-o-user-select: none;-ms-user-select: none;user-select: none;overflow: hidden;opacity: 0.7;border: 1px solid rgba(100,100,100,0.23);padding: 1px;-moz-box-sizing: border-box;box-sizing:    border-box;color: black;}.ace_button:hover {background-color: #eee;opacity:1;}.ace_button:active {background-color: #ddd;}.ace_button.checked {border-color: #3399ff;opacity:1;}.ace_search_options{margin-bottom: 3px;text-align: right;-webkit-user-select: none;-moz-user-select: none;-o-user-select: none;-ms-user-select: none;user-select: none;}",u=e("../keyboard/hash_handler").HashHandler,a=e("../lib/keys");r.importCssString(o,"ace_searchbox");var f='<div class="ace_search right">    <button type="button" action="hide" class="ace_searchbtn_close"></button>    <div class="ace_search_form">        <input class="ace_search_field" placeholder="Search for" spellcheck="false"></input>        <button type="button" action="findNext" class="ace_searchbtn next"></button>        <button type="button" action="findPrev" class="ace_searchbtn prev"></button>        <button type="button" action="findAll" class="ace_searchbtn" title="Alt-Enter">All</button>    </div>    <div class="ace_replace_form">        <input class="ace_search_field" placeholder="Replace with" spellcheck="false"></input>        <button type="button" action="replaceAndFindNext" class="ace_replacebtn">Replace</button>        <button type="button" action="replaceAll" class="ace_replacebtn">All</button>    </div>    <div class="ace_search_options">        <span action="toggleRegexpMode" class="ace_button" title="RegExp Search">.*</span>        <span action="toggleCaseSensitive" class="ace_button" title="CaseSensitive Search">Aa</span>        <span action="toggleWholeWords" class="ace_button" title="Whole Word Search">\\b</span>    </div></div>'.replace(/>\s+/g,">"),l=function(e,t,n){var i=r.createElement("div");i.innerHTML=f,this.element=i.firstChild,this.$init(),this.setEditor(e)};(function(){this.setEditor=function(e){e.searchBox=this,e.container.appendChild(this.element),this.editor=e},this.$initElements=function(e){this.searchBox=e.querySelector(".ace_search_form"),this.replaceBox=e.querySelector(".ace_replace_form"),this.searchOptions=e.querySelector(".ace_search_options"),this.regExpOption=e.querySelector("[action=toggleRegexpMode]"),this.caseSensitiveOption=e.querySelector("[action=toggleCaseSensitive]"),this.wholeWordOption=e.querySelector("[action=toggleWholeWords]"),this.searchInput=this.searchBox.querySelector(".ace_search_field"),this.replaceInput=this.replaceBox.querySelector(".ace_search_field")},this.$init=function(){var e=this.element;this.$initElements(e);var t=this;s.addListener(e,"mousedown",function(e){setTimeout(function(){t.activeInput.focus()},0),s.stopPropagation(e)}),s.addListener(e,"click",function(e){var n=e.target||e.srcElement,r=n.getAttribute("action");r&&t[r]?t[r]():t.$searchBarKb.commands[r]&&t.$searchBarKb.commands[r].exec(t),s.stopPropagation(e)}),s.addCommandKeyListener(e,function(e,n,r){var i=a.keyCodeToString(r),o=t.$searchBarKb.findKeyCommand(n,i);o&&o.exec&&(o.exec(t),s.stopEvent(e))}),this.$onChange=i.delayedCall(function(){t.find(!1,!1)}),s.addListener(this.searchInput,"input",function(){t.$onChange.schedule(20)}),s.addListener(this.searchInput,"focus",function(){t.activeInput=t.searchInput,t.searchInput.value&&t.highlight()}),s.addListener(this.replaceInput,"focus",function(){t.activeInput=t.replaceInput,t.searchInput.value&&t.highlight()})},this.$closeSearchBarKb=new u([{bindKey:"Esc",name:"closeSearchBar",exec:function(e){e.searchBox.hide()}}]),this.$searchBarKb=new u,this.$searchBarKb.bindKeys({"Ctrl-f|Command-f":function(e){var t=e.isReplace=!e.isReplace;e.replaceBox.style.display=t?"":"none",e.searchInput.focus()},"Ctrl-H|Command-Option-F":function(e){e.replaceBox.style.display="",e.replaceInput.focus()},"Ctrl-G|Command-G":function(e){e.findNext()},"Ctrl-Shift-G|Command-Shift-G":function(e){e.findPrev()},esc:function(e){setTimeout(function(){e.hide()})},Return:function(e){e.activeInput==e.replaceInput&&e.replace(),e.findNext()},"Shift-Return":function(e){e.activeInput==e.replaceInput&&e.replace(),e.findPrev()},"Alt-Return":function(e){e.activeInput==e.replaceInput&&e.replaceAll(),e.findAll()},Tab:function(e){(e.activeInput==e.replaceInput?e.searchInput:e.replaceInput).focus()}}),this.$searchBarKb.addCommands([{name:"toggleRegexpMode",bindKey:{win:"Alt-R|Alt-/",mac:"Ctrl-Alt-R|Ctrl-Alt-/"},exec:function(e){e.regExpOption.checked=!e.regExpOption.checked,e.$syncOptions()}},{name:"toggleCaseSensitive",bindKey:{win:"Alt-C|Alt-I",mac:"Ctrl-Alt-R|Ctrl-Alt-I"},exec:function(e){e.caseSensitiveOption.checked=!e.caseSensitiveOption.checked,e.$syncOptions()}},{name:"toggleWholeWords",bindKey:{win:"Alt-B|Alt-W",mac:"Ctrl-Alt-B|Ctrl-Alt-W"},exec:function(e){e.wholeWordOption.checked=!e.wholeWordOption.checked,e.$syncOptions()}}]),this.$syncOptions=function(){r.setCssClass(this.regExpOption,"checked",this.regExpOption.checked),r.setCssClass(this.wholeWordOption,"checked",this.wholeWordOption.checked),r.setCssClass(this.caseSensitiveOption,"checked",this.caseSensitiveOption.checked),this.find(!1,!1)},this.highlight=function(e){this.editor.session.highlight(e||this.editor.$search.$options.re),this.editor.renderer.updateBackMarkers()},this.find=function(e,t,n){var i=this.editor.find(this.searchInput.value,{skipCurrent:e,backwards:t,wrap:!0,regExp:this.regExpOption.checked,caseSensitive:this.caseSensitiveOption.checked,wholeWord:this.wholeWordOption.checked,preventScroll:n}),s=!i&&this.searchInput.value;r.setCssClass(this.searchBox,"ace_nomatch",s),this.editor._emit("findSearchBox",{match:!s}),this.highlight()},this.findNext=function(){this.find(!0,!1)},this.findPrev=function(){this.find(!0,!0)},this.findAll=function(){var e=this.editor.findAll(this.searchInput.value,{regExp:this.regExpOption.checked,caseSensitive:this.caseSensitiveOption.checked,wholeWord:this.wholeWordOption.checked}),t=!e&&this.searchInput.value;r.setCssClass(this.searchBox,"ace_nomatch",t),this.editor._emit("findSearchBox",{match:!t}),this.highlight(),this.hide()},this.replace=function(){this.editor.getReadOnly()||this.editor.replace(this.replaceInput.value)},this.replaceAndFindNext=function(){this.editor.getReadOnly()||(this.editor.replace(this.replaceInput.value),this.findNext())},this.replaceAll=function(){this.editor.getReadOnly()||this.editor.replaceAll(this.replaceInput.value)},this.hide=function(){this.element.style.display="none",this.editor.keyBinding.removeKeyboardHandler(this.$closeSearchBarKb),this.editor.focus()},this.show=function(e,t){this.element.style.display="",this.replaceBox.style.display=t?"":"none",this.isReplace=t,e&&(this.searchInput.value=e),this.find(!1,!1,!0),this.searchInput.focus(),this.searchInput.select(),this.editor.keyBinding.addKeyboardHandler(this.$closeSearchBarKb)},this.isFocused=function(){var e=document.activeElement;return e==this.searchInput||e==this.replaceInput}}).call(l.prototype),t.SearchBox=l,t.Search=function(e,t){var n=e.searchBox||new l(e);n.show(e.session.getTextRange(),t)}});
+                (function() {
+                    ace.require(["ace/ext/searchbox"], function() {});
+                })();
+            
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-settings_menu.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-settings_menu.js
new file mode 100644
index 0000000..2a63322
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-settings_menu.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/menu_tools/element_generator",["require","exports","module"],function(e,t,n){"use strict";n.exports.createOption=function(t){var n,r=document.createElement("option");for(n in t)t.hasOwnProperty(n)&&(n==="selected"?r.setAttribute(n,t[n]):r[n]=t[n]);return r},n.exports.createCheckbox=function(t,n,r){var i=document.createElement("input");return i.setAttribute("type","checkbox"),i.setAttribute("id",t),i.setAttribute("name",t),i.setAttribute("value",n),i.setAttribute("class",r),n&&i.setAttribute("checked","checked"),i},n.exports.createInput=function(t,n,r){var i=document.createElement("input");return i.setAttribute("type","text"),i.setAttribute("id",t),i.setAttribute("name",t),i.setAttribute("value",n),i.setAttribute("class",r),i},n.exports.createLabel=function(t,n){var r=document.createElement("label");return r.setAttribute("for",n),r.textContent=t,r},n.exports.createSelection=function(t,r,i){var s=document.createElement("select");return s.setAttribute("id",t),s.setAttribute("name",t),s.setAttribute("class",i),r.forEach(function(e){s.appendChild(n.exports.createOption(e))}),s}}),ace.define("ace/ext/modelist",["require","exports","module"],function(e,t,n){"use strict";function i(e){var t=a.text,n=e.split(/[\/\\]/).pop();for(var i=0;i<r.length;i++)if(r[i].supportsFile(n)){t=r[i];break}return t}var r=[],s=function(e,t,n){this.name=e,this.caption=t,this.mode="ace/mode/"+e,this.extensions=n;var r;/\^/.test(n)?r=n.replace(/\|(\^)?/g,function(e,t){return"$|"+(t?"^":"^.*\\.")})+"$":r="^.*\\.("+n+")$",this.extRe=new RegExp(r,"gi")};s.prototype.supportsFile=function(e){return e.match(this.extRe)};var o={ABAP:["abap"],ABC:["abc"],ActionScript:["as"],ADA:["ada|adb"],Apache_Conf:["^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd"],AsciiDoc:["asciidoc|adoc"],Assembly_x86:["asm|a"],AutoHotKey:["ahk"],BatchFile:["bat|cmd"],C_Cpp:["cpp|c|cc|cxx|h|hh|hpp|ino"],C9Search:["c9search_results"],Cirru:["cirru|cr"],Clojure:["clj|cljs"],Cobol:["CBL|COB"],coffee:["coffee|cf|cson|^Cakefile"],ColdFusion:["cfm"],CSharp:["cs"],CSS:["css"],Curly:["curly"],D:["d|di"],Dart:["dart"],Diff:["diff|patch"],Dockerfile:["^Dockerfile"],Dot:["dot"],Dummy:["dummy"],DummySyntax:["dummy"],Eiffel:["e|ge"],EJS:["ejs"],Elixir:["ex|exs"],Elm:["elm"],Erlang:["erl|hrl"],Forth:["frt|fs|ldr"],FTL:["ftl"],Gcode:["gcode"],Gherkin:["feature"],Gitignore:["^.gitignore"],Glsl:["glsl|frag|vert"],Gobstones:["gbs"],golang:["go"],Groovy:["groovy"],HAML:["haml"],Handlebars:["hbs|handlebars|tpl|mustache"],Haskell:["hs"],haXe:["hx"],HTML:["html|htm|xhtml"],HTML_Elixir:["eex|html.eex"],HTML_Ruby:["erb|rhtml|html.erb"],INI:["ini|conf|cfg|prefs"],Io:["io"],Jack:["jack"],Jade:["jade"],Java:["java"],JavaScript:["js|jsm|jsx"],JSON:["json"],JSONiq:["jq"],JSP:["jsp"],JSX:["jsx"],Julia:["jl"],LaTeX:["tex|latex|ltx|bib"],Lean:["lean|hlean"],LESS:["less"],Liquid:["liquid"],Lisp:["lisp"],LiveScript:["ls"],LogiQL:["logic|lql"],LSL:["lsl"],Lua:["lua"],LuaPage:["lp"],Lucene:["lucene"],Makefile:["^Makefile|^GNUmakefile|^makefile|^OCamlMakefile|make"],Markdown:["md|markdown"],Mask:["mask"],MATLAB:["matlab"],Maze:["mz"],MEL:["mel"],MUSHCode:["mc|mush"],MySQL:["mysql"],Nix:["nix"],NSIS:["nsi|nsh"],ObjectiveC:["m|mm"],OCaml:["ml|mli"],Pascal:["pas|p"],Perl:["pl|pm"],pgSQL:["pgsql"],PHP:["php|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp|module"],Powershell:["ps1"],Praat:["praat|praatscript|psc|proc"],Prolog:["plg|prolog"],Properties:["properties"],Protobuf:["proto"],Python:["py"],R:["r"],Razor:["cshtml"],RDoc:["Rd"],RHTML:["Rhtml"],RST:["rst"],Ruby:["rb|ru|gemspec|rake|^Guardfile|^Rakefile|^Gemfile"],Rust:["rs"],SASS:["sass"],SCAD:["scad"],Scala:["scala"],Scheme:["scm|sm|rkt|oak|scheme"],SCSS:["scss"],SH:["sh|bash|^.bashrc"],SJS:["sjs"],Smarty:["smarty|tpl"],snippets:["snippets"],Soy_Template:["soy"],Space:["space"],SQL:["sql"],SQLServer:["sqlserver"],Stylus:["styl|stylus"],SVG:["svg"],Swift:["swift"],Tcl:["tcl"],Tex:["tex"],Text:["txt"],Textile:["textile"],Toml:["toml"],Twig:["twig|swig"],Typescript:["ts|typescript|str"],Vala:["vala"],VBScript:["vbs|vb"],Velocity:["vm"],Verilog:["v|vh|sv|svh"],VHDL:["vhd|vhdl"],Wollok:["wlk|wpgm|wtest"],XML:["xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl|xaml"],XQuery:["xq"],YAML:["yaml|yml"],Django:["html"]},u={ObjectiveC:"Objective-C",CSharp:"C#",golang:"Go",C_Cpp:"C and C++",coffee:"CoffeeScript",HTML_Ruby:"HTML (Ruby)",HTML_Elixir:"HTML (Elixir)",FTL:"FreeMarker"},a={};for(var f in o){var l=o[f],c=(u[f]||f).replace(/_/g," "),h=f.toLowerCase(),p=new s(h,c,l[0]);a[h]=p,r.push(p)}n.exports={getModeForPath:i,modes:r,modesByName:a}}),ace.define("ace/ext/themelist",["require","exports","module","ace/lib/fixoldbrowsers"],function(e,t,n){"use strict";e("ace/lib/fixoldbrowsers");var r=[["Chrome"],["Clouds"],["Crimson Editor"],["Dawn"],["Dreamweaver"],["Eclipse"],["GitHub"],["IPlastic"],["Solarized Light"],["TextMate"],["Tomorrow"],["XCode"],["Kuroir"],["KatzenMilch"],["SQL Server","sqlserver","light"],["Ambiance","ambiance","dark"],["Chaos","chaos","dark"],["Clouds Midnight","clouds_midnight","dark"],["Cobalt","cobalt","dark"],["idle Fingers","idle_fingers","dark"],["krTheme","kr_theme","dark"],["Merbivore","merbivore","dark"],["Merbivore Soft","merbivore_soft","dark"],["Mono Industrial","mono_industrial","dark"],["Monokai","monokai","dark"],["Pastel on dark","pastel_on_dark","dark"],["Solarized Dark","solarized_dark","dark"],["Terminal","terminal","dark"],["Tomorrow Night","tomorrow_night","dark"],["Tomorrow Night Blue","tomorrow_night_blue","dark"],["Tomorrow Night Bright","tomorrow_night_bright","dark"],["Tomorrow Night 80s","tomorrow_night_eighties","dark"],["Twilight","twilight","dark"],["Vibrant Ink","vibrant_ink","dark"]];t.themesByName={},t.themes=r.map(function(e){var n=e[1]||e[0].replace(/ /g,"_").toLowerCase(),r={caption:e[0],theme:"ace/theme/"+n,isDark:e[2]=="dark",name:n};return t.themesByName[n]=r,r})}),ace.define("ace/ext/menu_tools/add_editor_menu_options",["require","exports","module","ace/ext/modelist","ace/ext/themelist"],function(e,t,n){"use strict";n.exports.addEditorMenuOptions=function(n){var r=e("../modelist"),i=e("../themelist");n.menuOptions={setNewLineMode:[{textContent:"unix",value:"unix"},{textContent:"windows",value:"windows"},{textContent:"auto",value:"auto"}],setTheme:[],setMode:[],setKeyboardHandler:[{textContent:"ace",value:""},{textContent:"vim",value:"ace/keyboard/vim"},{textContent:"emacs",value:"ace/keyboard/emacs"},{textContent:"textarea",value:"ace/keyboard/textarea"},{textContent:"sublime",value:"ace/keyboard/sublime"}]},n.menuOptions.setTheme=i.themes.map(function(e){return{textContent:e.caption,value:e.theme}}),n.menuOptions.setMode=r.modes.map(function(e){return{textContent:e.name,value:e.mode}})}}),ace.define("ace/ext/menu_tools/get_set_functions",["require","exports","module"],function(e,t,n){"use strict";n.exports.getSetFunctions=function(t){var n=[],r={editor:t,session:t.session,renderer:t.renderer},i=[],s=["setOption","setUndoManager","setDocument","setValue","setBreakpoints","setScrollTop","setScrollLeft","setSelectionStyle","setWrapLimitRange"];return["renderer","session","editor"].forEach(function(e){var t=r[e],o=e;for(var u in t)s.indexOf(u)===-1&&/^set/.test(u)&&i.indexOf(u)===-1&&(i.push(u),n.push({functionName:u,parentObj:t,parentName:o}))}),n}}),ace.define("ace/ext/menu_tools/generate_settings_menu",["require","exports","module","ace/ext/menu_tools/element_generator","ace/ext/menu_tools/add_editor_menu_options","ace/ext/menu_tools/get_set_functions","ace/ace"],function(e,t,n){"use strict";var r=e("./element_generator"),i=e("./add_editor_menu_options").addEditorMenuOptions,s=e("./get_set_functions").getSetFunctions;n.exports.generateSettingsMenu=function(n){function u(){o.sort(function(e,t){var n=e.getAttribute("contains"),r=t.getAttribute("contains");return n.localeCompare(r)})}function a(){var t=document.createElement("div");t.setAttribute("id","ace_settingsmenu"),o.forEach(function(e){t.appendChild(e)});var n=t.appendChild(document.createElement("div")),r=e("../../ace").version;return n.style.padding="1em",n.textContent="Ace version "+r,t}function f(e,t,i,s){var o,u=document.createElement("div");return u.setAttribute("contains",i),u.setAttribute("class","ace_optionsMenuEntry"),u.setAttribute("style","clear: both;"),u.appendChild(r.createLabel(i.replace(/^set/,"").replace(/([A-Z])/g," $1").trim(),i)),Array.isArray(s)?(o=r.createSelection(i,s,t),o.addEventListener("change",function(t){try{n.menuOptions[t.target.id].forEach(function(e){e.textContent!==t.target.textContent&&delete e.selected}),e[t.target.id](t.target.value)}catch(r){throw new Error(r)}})):typeof s=="boolean"?(o=r.createCheckbox(i,s,t),o.addEventListener("change",function(t){try{e[t.target.id](!!t.target.checked)}catch(n){throw new Error(n)}})):(o=r.createInput(i,s,t),o.addEventListener("change",function(t){try{t.target.value==="true"?e[t.target.id](!0):t.target.value==="false"?e[t.target.id](!1):e[t.target.id](t.target.value)}catch(n){throw new Error(n)}})),o.style.cssText="float:right;",u.appendChild(o),u}function l(e,t,r,i){var s=n.menuOptions[e],o=t[i]();return typeof o=="object"&&(o=o.$id),s.forEach(function(e){e.value===o&&(e.selected="selected")}),f(t,r,e,s)}function c(e){var t=e.functionName,r=e.parentObj,i=e.parentName,s,u=t.replace(/^set/,"get");if(n.menuOptions[t]!==undefined)o.push(l(t,r,i,u));else if(typeof r[u]=="function")try{s=r[u](),typeof s=="object"&&(s=s.$id),o.push(f(r,i,t,s))}catch(a){}}var o=[];return i(n),s(n).forEach(function(e){c(e)}),u(),a()}}),ace.define("ace/ext/menu_tools/overlay_page",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";var r=e("../../lib/dom"),i="#ace_settingsmenu, #kbshortcutmenu {background-color: #F7F7F7;color: black;box-shadow: -5px 4px 5px rgba(126, 126, 126, 0.55);padding: 1em 0.5em 2em 1em;overflow: auto;position: absolute;margin: 0;bottom: 0;right: 0;top: 0;z-index: 9991;cursor: default;}.ace_dark #ace_settingsmenu, .ace_dark #kbshortcutmenu {box-shadow: -20px 10px 25px rgba(126, 126, 126, 0.25);background-color: rgba(255, 255, 255, 0.6);color: black;}.ace_optionsMenuEntry:hover {background-color: rgba(100, 100, 100, 0.1);-webkit-transition: all 0.5s;transition: all 0.3s}.ace_closeButton {background: rgba(245, 146, 146, 0.5);border: 1px solid #F48A8A;border-radius: 50%;padding: 7px;position: absolute;right: -8px;top: -8px;z-index: 1000;}.ace_closeButton{background: rgba(245, 146, 146, 0.9);}.ace_optionsMenuKey {color: darkslateblue;font-weight: bold;}.ace_optionsMenuCommand {color: darkcyan;font-weight: normal;}";r.importCssString(i),n.exports.overlayPage=function(t,n,i,s,o,u){function l(e){e.keyCode===27&&a.click()}i=i?"top: "+i+";":"",o=o?"bottom: "+o+";":"",s=s?"right: "+s+";":"",u=u?"left: "+u+";":"";var a=document.createElement("div"),f=document.createElement("div");a.style.cssText="margin: 0; padding: 0; position: fixed; top:0; bottom:0; left:0; right:0;z-index: 9990; background-color: rgba(0, 0, 0, 0.3);",a.addEventListener("click",function(){document.removeEventListener("keydown",l),a.parentNode.removeChild(a),t.focus(),a=null}),document.addEventListener("keydown",l),f.style.cssText=i+s+o+u,f.addEventListener("click",function(e){e.stopPropagation()});var c=r.createElement("div");c.style.position="relative";var h=r.createElement("div");h.className="ace_closeButton",h.addEventListener("click",function(){a.click()}),c.appendChild(h),f.appendChild(c),f.appendChild(n),a.appendChild(f),document.body.appendChild(a),t.blur()}}),ace.define("ace/ext/settings_menu",["require","exports","module","ace/ext/menu_tools/generate_settings_menu","ace/ext/menu_tools/overlay_page","ace/editor"],function(e,t,n){"use strict";function s(e){var t=document.getElementById("ace_settingsmenu");t||i(e,r(e),"0","0","0")}var r=e("./menu_tools/generate_settings_menu").generateSettingsMenu,i=e("./menu_tools/overlay_page").overlayPage;n.exports.init=function(t){var n=e("ace/editor").Editor;n.prototype.showSettingsMenu=function(){s(this)}}});
+                (function() {
+                    ace.require(["ace/ext/settings_menu"], function() {});
+                })();
+            
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-spellcheck.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-spellcheck.js
new file mode 100644
index 0000000..15c0f86
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-spellcheck.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/spellcheck",["require","exports","module","ace/lib/event","ace/editor","ace/config"],function(e,t,n){"use strict";var r=e("../lib/event");t.contextMenuHandler=function(e){var t=e.target,n=t.textInput.getElement();if(!t.selection.isEmpty())return;var i=t.getCursorPosition(),s=t.session.getWordRange(i.row,i.column),o=t.session.getTextRange(s);t.session.tokenRe.lastIndex=0;if(!t.session.tokenRe.test(o))return;var u="",a=o+" "+u;n.value=a,n.setSelectionRange(o.length,o.length+1),n.setSelectionRange(0,0),n.setSelectionRange(0,o.length);var f=!1;r.addListener(n,"keydown",function l(){r.removeListener(n,"keydown",l),f=!0}),t.textInput.setInputHandler(function(e){console.log(e,a,n.selectionStart,n.selectionEnd);if(e==a)return"";if(e.lastIndexOf(a,0)===0)return e.slice(a.length);if(e.substr(n.selectionEnd)==a)return e.slice(0,-a.length);if(e.slice(-2)==u){var r=e.slice(0,-2);if(r.slice(-1)==" ")return f?r.substring(0,n.selectionEnd):(r=r.slice(0,-1),t.session.replace(s,r),"")}return e})};var i=e("../editor").Editor;e("../config").defineOptions(i.prototype,"editor",{spellcheck:{set:function(e){var n=this.textInput.getElement();n.spellcheck=!!e,e?this.on("nativecontextmenu",t.contextMenuHandler):this.removeListener("nativecontextmenu",t.contextMenuHandler)},value:!0}})});
+                (function() {
+                    ace.require(["ace/ext/spellcheck"], function() {});
+                })();
+            
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-split.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-split.js
new file mode 100644
index 0000000..31b3ee7
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-split.js
@@ -0,0 +1,5 @@
+ace.define("ace/split",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter","ace/editor","ace/virtual_renderer","ace/edit_session"],function(e,t,n){"use strict";function l(e,t){this.$u=e,this.$doc=t}var r=e("./lib/oop"),i=e("./lib/lang"),s=e("./lib/event_emitter").EventEmitter,o=e("./editor").Editor,u=e("./virtual_renderer").VirtualRenderer,a=e("./edit_session").EditSession,f=function(e,t,n){this.BELOW=1,this.BESIDE=0,this.$container=e,this.$theme=t,this.$splits=0,this.$editorCSS="",this.$editors=[],this.$orientation=this.BESIDE,this.setSplits(n||1),this.$cEditor=this.$editors[0],this.on("focus",function(e){this.$cEditor=e}.bind(this))};(function(){r.implement(this,s),this.$createEditor=function(){var e=document.createElement("div");e.className=this.$editorCSS,e.style.cssText="position: absolute; top:0px; bottom:0px",this.$container.appendChild(e);var t=new o(new u(e,this.$theme));return t.on("focus",function(){this._emit("focus",t)}.bind(this)),this.$editors.push(t),t.setFontSize(this.$fontSize),t},this.setSplits=function(e){var t;if(e<1)throw"The number of splits have to be > 0!";if(e==this.$splits)return;if(e>this.$splits){while(this.$splits<this.$editors.length&&this.$splits<e)t=this.$editors[this.$splits],this.$container.appendChild(t.container),t.setFontSize(this.$fontSize),this.$splits++;while(this.$splits<e)this.$createEditor(),this.$splits++}else while(this.$splits>e)t=this.$editors[this.$splits-1],this.$container.removeChild(t.container),this.$splits--;this.resize()},this.getSplits=function(){return this.$splits},this.getEditor=function(e){return this.$editors[e]},this.getCurrentEditor=function(){return this.$cEditor},this.focus=function(){this.$cEditor.focus()},this.blur=function(){this.$cEditor.blur()},this.setTheme=function(e){this.$editors.forEach(function(t){t.setTheme(e)})},this.setKeyboardHandler=function(e){this.$editors.forEach(function(t){t.setKeyboardHandler(e)})},this.forEach=function(e,t){this.$editors.forEach(e,t)},this.$fontSize="",this.setFontSize=function(e){this.$fontSize=e,this.forEach(function(t){t.setFontSize(e)})},this.$cloneSession=function(e){var t=new a(e.getDocument(),e.getMode()),n=e.getUndoManager();if(n){var r=new l(n,t);t.setUndoManager(r)}return t.$informUndoManager=i.delayedCall(function(){t.$deltas=[]}),t.setTabSize(e.getTabSize()),t.setUseSoftTabs(e.getUseSoftTabs()),t.setOverwrite(e.getOverwrite()),t.setBreakpoints(e.getBreakpoints()),t.setUseWrapMode(e.getUseWrapMode()),t.setUseWorker(e.getUseWorker()),t.setWrapLimitRange(e.$wrapLimitRange.min,e.$wrapLimitRange.max),t.$foldData=e.$cloneFoldData(),t},this.setSession=function(e,t){var n;t==null?n=this.$cEditor:n=this.$editors[t];var r=this.$editors.some(function(t){return t.session===e});return r&&(e=this.$cloneSession(e)),n.setSession(e),e},this.getOrientation=function(){return this.$orientation},this.setOrientation=function(e){if(this.$orientation==e)return;this.$orientation=e,this.resize()},this.resize=function(){var e=this.$container.clientWidth,t=this.$container.clientHeight,n;if(this.$orientation==this.BESIDE){var r=e/this.$splits;for(var i=0;i<this.$splits;i++)n=this.$editors[i],n.container.style.width=r+"px",n.container.style.top="0px",n.container.style.left=i*r+"px",n.container.style.height=t+"px",n.resize()}else{var s=t/this.$splits;for(var i=0;i<this.$splits;i++)n=this.$editors[i],n.container.style.width=e+"px",n.container.style.top=i*s+"px",n.container.style.left="0px",n.container.style.height=s+"px",n.resize()}}}).call(f.prototype),function(){this.execute=function(e){this.$u.execute(e)},this.undo=function(){var e=this.$u.undo(!0);e&&this.$doc.selection.setSelectionRange(e)},this.redo=function(){var e=this.$u.redo(!0);e&&this.$doc.selection.setSelectionRange(e)},this.reset=function(){this.$u.reset()},this.hasUndo=function(){return this.$u.hasUndo()},this.hasRedo=function(){return this.$u.hasRedo()}}.call(l.prototype),t.Split=f}),ace.define("ace/ext/split",["require","exports","module","ace/split"],function(e,t,n){"use strict";n.exports=e("../split")});
+                (function() {
+                    ace.require(["ace/ext/split"], function() {});
+                })();
+            
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-static_highlight.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-static_highlight.js
new file mode 100644
index 0000000..46fe45d
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-static_highlight.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/static_highlight",["require","exports","module","ace/edit_session","ace/layer/text","ace/config","ace/lib/dom"],function(e,t,n){"use strict";var r=e("../edit_session").EditSession,i=e("../layer/text").Text,s=".ace_static_highlight {font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'Droid Sans Mono', monospace;font-size: 12px;white-space: pre-wrap}.ace_static_highlight .ace_gutter {width: 2em;text-align: right;padding: 0 3px 0 0;margin-right: 3px;}.ace_static_highlight.ace_show_gutter .ace_line {padding-left: 2.6em;}.ace_static_highlight .ace_line { position: relative; }.ace_static_highlight .ace_gutter-cell {-moz-user-select: -moz-none;-khtml-user-select: none;-webkit-user-select: none;user-select: none;top: 0;bottom: 0;left: 0;position: absolute;}.ace_static_highlight .ace_gutter-cell:before {content: counter(ace_line, decimal);counter-increment: ace_line;}.ace_static_highlight {counter-reset: ace_line;}",o=e("../config"),u=e("../lib/dom"),a=function(){this.config={}};a.prototype=i.prototype;var f=function(e,t,n){var r=e.className.match(/lang-(\w+)/),i=t.mode||r&&"ace/mode/"+r[1];if(!i)return!1;var s=t.theme||"ace/theme/textmate",o="",a=[];if(e.firstElementChild){var l=0;for(var c=0;c<e.childNodes.length;c++){var h=e.childNodes[c];h.nodeType==3?(l+=h.data.length,o+=h.data):a.push(l,h)}}else o=u.getInnerText(e),t.trim&&(o=o.trim());f.render(o,i,s,t.firstLineNumber,!t.showGutter,function(t){u.importCssString(t.css,"ace_highlight"),e.innerHTML=t.html;var r=e.firstChild.firstChild;for(var i=0;i<a.length;i+=2){var s=t.session.doc.indexToPosition(a[i]),o=a[i+1],f=r.children[s.row];f&&f.appendChild(o)}n&&n()})};f.render=function(e,t,n,i,s,u){function h(){var r=f.renderSync(e,t,n,i,s);return u?u(r):r}var a=1,l=r.prototype.$modes;typeof n=="string"&&(a++,o.loadModule(["theme",n],function(e){n=e,--a||h()}));var c;return t&&typeof t=="object"&&!t.getTokenizer&&(c=t,t=c.path),typeof t=="string"&&(a++,o.loadModule(["mode",t],function(e){if(!l[t]||c)l[t]=new e.Mode(c);t=l[t],--a||h()})),--a||h()},f.renderSync=function(e,t,n,i,o){i=parseInt(i||1,10);var u=new r("");u.setUseWorker(!1),u.setMode(t);var f=new a;f.setSession(u),u.setValue(e);var l=[],c=u.getLength();for(var h=0;h<c;h++)l.push("<div class='ace_line'>"),o||l.push("<span class='ace_gutter ace_gutter-cell' unselectable='on'></span>"),f.$renderLine(l,h,!0,!1),l.push("\n</div>");var p="<div class='"+n.cssClass+"'>"+"<div class='ace_static_highlight"+(o?"":" ace_show_gutter")+"' style='counter-reset:ace_line "+(i-1)+"'>"+l.join("")+"</div>"+"</div>";return f.destroy(),{css:s+n.cssText,html:p,session:u}},n.exports=f,n.exports.highlight=f});
+                (function() {
+                    ace.require(["ace/ext/static_highlight"], function() {});
+                })();
+            
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-statusbar.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-statusbar.js
new file mode 100644
index 0000000..a5ab7ed
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-statusbar.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/statusbar",["require","exports","module","ace/lib/dom","ace/lib/lang"],function(e,t,n){"use strict";var r=e("ace/lib/dom"),i=e("ace/lib/lang"),s=function(e,t){this.element=r.createElement("div"),this.element.className="ace_status-indicator",this.element.style.cssText="display: inline-block;",t.appendChild(this.element);var n=i.delayedCall(function(){this.updateStatus(e)}.bind(this)).schedule.bind(null,100);e.on("changeStatus",n),e.on("changeSelection",n),e.on("keyboardActivity",n)};(function(){this.updateStatus=function(e){function n(e,n){e&&t.push(e,n||"|")}var t=[];n(e.keyBinding.getStatusText(e)),e.commands.recording&&n("REC");var r=e.selection,i=r.lead;if(!r.isEmpty()){var s=e.getSelectionRange();n("("+(s.end.row-s.start.row)+":"+(s.end.column-s.start.column)+")"," ")}n(i.row+":"+i.column," "),r.rangeCount&&n("["+r.rangeCount+"]"," "),t.pop(),this.element.textContent=t.join("")}}).call(s.prototype),t.StatusBar=s});
+                (function() {
+                    ace.require(["ace/ext/statusbar"], function() {});
+                })();
+            
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-textarea.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-textarea.js
new file mode 100644
index 0000000..a53935b
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-textarea.js
@@ -0,0 +1,5 @@
+ace.define("ace/theme/textmate",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";t.isDark=!1,t.cssClass="ace-tm",t.cssText='.ace-tm .ace_gutter {background: #f0f0f0;color: #333;}.ace-tm .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-tm .ace_fold {background-color: #6B72E6;}.ace-tm {background-color: #FFFFFF;color: black;}.ace-tm .ace_cursor {color: black;}.ace-tm .ace_invisible {color: rgb(191, 191, 191);}.ace-tm .ace_storage,.ace-tm .ace_keyword {color: blue;}.ace-tm .ace_constant {color: rgb(197, 6, 11);}.ace-tm .ace_constant.ace_buildin {color: rgb(88, 72, 246);}.ace-tm .ace_constant.ace_language {color: rgb(88, 92, 246);}.ace-tm .ace_constant.ace_library {color: rgb(6, 150, 14);}.ace-tm .ace_invalid {background-color: rgba(255, 0, 0, 0.1);color: red;}.ace-tm .ace_support.ace_function {color: rgb(60, 76, 114);}.ace-tm .ace_support.ace_constant {color: rgb(6, 150, 14);}.ace-tm .ace_support.ace_type,.ace-tm .ace_support.ace_class {color: rgb(109, 121, 222);}.ace-tm .ace_keyword.ace_operator {color: rgb(104, 118, 135);}.ace-tm .ace_string {color: rgb(3, 106, 7);}.ace-tm .ace_comment {color: rgb(76, 136, 107);}.ace-tm .ace_comment.ace_doc {color: rgb(0, 102, 255);}.ace-tm .ace_comment.ace_doc.ace_tag {color: rgb(128, 159, 191);}.ace-tm .ace_constant.ace_numeric {color: rgb(0, 0, 205);}.ace-tm .ace_variable {color: rgb(49, 132, 149);}.ace-tm .ace_xml-pe {color: rgb(104, 104, 91);}.ace-tm .ace_entity.ace_name.ace_function {color: #0000A2;}.ace-tm .ace_heading {color: rgb(12, 7, 255);}.ace-tm .ace_list {color:rgb(185, 6, 144);}.ace-tm .ace_meta.ace_tag {color:rgb(0, 22, 142);}.ace-tm .ace_string.ace_regex {color: rgb(255, 0, 0)}.ace-tm .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-tm.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px white;}.ace-tm .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-tm .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-tm .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-tm .ace_marker-layer .ace_active-line {background: rgba(0, 0, 0, 0.07);}.ace-tm .ace_gutter-active-line {background-color : #dcdcdc;}.ace-tm .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-tm .ace_indent-guide {background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y;}';var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)}),ace.define("ace/ext/textarea",["require","exports","module","ace/lib/event","ace/lib/useragent","ace/lib/net","ace/ace","ace/theme/textmate"],function(e,t,n){"use strict";function a(e,t){for(var n in t)e.style[n]=t[n]}function f(e,t){if(e.type!="textarea")throw new Error("Textarea required!");var n=e.parentNode,i=document.createElement("div"),s=function(){var t="position:relative;";["margin-top","margin-left","margin-right","margin-bottom"].forEach(function(n){t+=n+":"+u(e,i,n)+";"});var n=u(e,i,"width")||e.clientWidth+"px",r=u(e,i,"height")||e.clientHeight+"px";t+="height:"+r+";width:"+n+";",t+="display:inline-block;",i.setAttribute("style",t)};r.addListener(window,"resize",s),s(),n.insertBefore(i,e.nextSibling);while(n!==document){if(n.tagName.toUpperCase()==="FORM"){var o=n.onsubmit;n.onsubmit=function(n){e.value=t(),o&&o.call(this,n)};break}n=n.parentNode}return i}function l(t,n,r){s.loadScript(t,function(){e([n],r)})}function c(e,t,n,r,i,s){function a(e){return e==="true"||e==1}var o=e.getSession(),u=e.renderer;return s=s||l,e.setDisplaySettings=function(t){t==null&&(t=n.style.display=="none"),t?(n.style.display="block",n.hideButton.focus(),e.on("focus",function r(){e.removeListener("focus",r),n.style.display="none"})):e.focus()},e.$setOption=e.setOption,e.$getOption=e.getOption,e.setOption=function(t,n){switch(t){case"mode":e.$setOption("mode","ace/mode/"+n);break;case"theme":e.$setOption("theme","ace/theme/"+n);break;case"keybindings":switch(n){case"vim":e.setKeyboardHandler("ace/keyboard/vim");break;case"emacs":e.setKeyboardHandler("ace/keyboard/emacs");break;default:e.setKeyboardHandler(null)}break;case"softWrap":case"fontSize":e.$setOption(t,n);break;default:e.$setOption(t,a(n))}},e.getOption=function(t){switch(t){case"mode":return e.$getOption("mode").substr("ace/mode/".length);case"theme":return e.$getOption("theme").substr("ace/theme/".length);case"keybindings":var n=e.getKeyboardHandler();switch(n&&n.$id){case"ace/keyboard/vim":return"vim";case"ace/keyboard/emacs":return"emacs";default:return"ace"}break;default:return e.$getOption(t)}},e.setOptions(i),e}function h(e,n,i){function f(e,t,n,r){if(!n){e.push("<input type='checkbox' title='",t,"' ",r+""=="true"?"checked='true'":"","'></input>");return}e.push("<select title='"+t+"'>");for(var i in n)e.push("<option value='"+i+"' "),r==i&&e.push(" selected "),e.push(">",n[i],"</option>");e.push("</select>")}var s=null,o={mode:"Mode:",wrap:"Soft Wrap:",theme:"Theme:",fontSize:"Font Size:",showGutter:"Display Gutter:",keybindings:"Keyboard",showPrintMargin:"Show Print Margin:",useSoftTabs:"Use Soft Tabs:",showInvisibles:"Show Invisibles"},u={mode:{text:"Plain",javascript:"JavaScript",xml:"XML",html:"HTML",css:"CSS",scss:"SCSS",python:"Python",php:"PHP",java:"Java",ruby:"Ruby",c_cpp:"C/C++",coffee:"CoffeeScript",json:"json",perl:"Perl",clojure:"Clojure",ocaml:"OCaml",csharp:"C#",haxe:"haXe",svg:"SVG",textile:"Textile",groovy:"Groovy",liquid:"Liquid",Scala:"Scala"},theme:{clouds:"Clouds",clouds_midnight:"Clouds Midnight",cobalt:"Cobalt",crimson_editor:"Crimson Editor",dawn:"Dawn",eclipse:"Eclipse",idle_fingers:"Idle Fingers",kr_theme:"Kr Theme",merbivore:"Merbivore",merbivore_soft:"Merbivore Soft",mono_industrial:"Mono Industrial",monokai:"Monokai",pastel_on_dark:"Pastel On Dark",solarized_dark:"Solarized Dark",solarized_light:"Solarized Light",textmate:"Textmate",twilight:"Twilight",vibrant_ink:"Vibrant Ink"},showGutter:s,fontSize:{"10px":"10px","11px":"11px","12px":"12px","14px":"14px","16px":"16px"},wrap:{off:"Off",40:"40",80:"80",free:"Free"},keybindings:{ace:"ace",vim:"vim",emacs:"emacs"},showPrintMargin:s,useSoftTabs:s,showInvisibles:s},a=[];a.push("<table><tr><th>Setting</th><th>Value</th></tr>");for(var l in t.defaultOptions)a.push("<tr><td>",o[l],"</td>"),a.push("<td>"),f(a,l,u[l],i.getOption(l)),a.push("</td></tr>");a.push("</table>"),e.innerHTML=a.join("");var c=function(e){var t=e.currentTarget;i.setOption(t.title,t.value)},h=function(e){var t=e.currentTarget;i.setOption(t.title,t.checked)},p=e.getElementsByTagName("select");for(var d=0;d<p.length;d++)p[d].onchange=c;var v=e.getElementsByTagName("input");for(var d=0;d<v.length;d++)v[d].onclick=h;var m=document.createElement("input");m.type="button",m.value="Hide",r.addListener(m,"click",function(){i.setDisplaySettings(!1)}),e.appendChild(m),e.hideButton=m}var r=e("../lib/event"),i=e("../lib/useragent"),s=e("../lib/net"),o=e("../ace");e("../theme/textmate"),n.exports=t=o;var u=function(e,t,n){var r=e.style[n];r||(window.getComputedStyle?r=window.getComputedStyle(e,"").getPropertyValue(n):r=e.currentStyle[n]);if(!r||r=="auto"||r=="intrinsic")r=t.style[n];return r};t.transformTextarea=function(e,n){var s,u=f(e,function(){return s.getValue()});e.style.display="none",u.style.background="white";var p=document.createElement("div");a(p,{top:"0px",left:"0px",right:"0px",bottom:"0px",border:"1px solid gray",position:"absolute"}),u.appendChild(p);var d=document.createElement("div");a(d,{position:"absolute",right:"0px",bottom:"0px",background:"red",cursor:"nw-resize",borderStyle:"solid",borderWidth:"9px 8px 10px 9px",width:"2px",borderColor:"lightblue gray gray lightblue",zIndex:101});var v=document.createElement("div"),m={top:"0px",left:"20%",right:"0px",bottom:"0px",position:"absolute",padding:"5px",zIndex:100,color:"white",display:"none",overflow:"auto",fontSize:"14px",boxShadow:"-5px 2px 3px gray"};i.isOldIE?m.backgroundColor="#333":m.backgroundColor="rgba(0, 0, 0, 0.6)",a(v,m),u.appendChild(v),n=n||t.defaultOptions;var g=o.edit(p);s=g.getSession(),s.setValue(e.value||e.innerHTML),g.focus(),u.appendChild(d),c(g,p,v,o,n,l),h(v,d,g);var y="";return r.addListener(d,"mousemove",function(e){var t=this.getBoundingClientRect(),n=e.clientX-t.left,r=e.clientY-t.top;n+r<(t.width+t.height)/2?(this.style.cursor="pointer",y="toggle"):(y="resize",this.style.cursor="nw-resize")}),r.addListener(d,"mousedown",function(e){if(y=="toggle"){g.setDisplaySettings();return}u.style.zIndex=1e5;var t=u.getBoundingClientRect(),n=t.width+t.left-e.clientX,i=t.height+t.top-e.clientY;r.capture(d,function(e){u.style.width=e.clientX-t.left+n+"px",u.style.height=e.clientY-t.top+i+"px",g.resize()},function(){})}),g},t.defaultOptions={mode:"javascript",theme:"textmate",wrap:"off",fontSize:"12px",showGutter:"false",keybindings:"ace",showPrintMargin:"false",useSoftTabs:"true",showInvisibles:"false"}});
+                (function() {
+                    ace.require(["ace/ext/textarea"], function() {});
+                })();
+            
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-themelist.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-themelist.js
new file mode 100644
index 0000000..245c792
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-themelist.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/themelist",["require","exports","module","ace/lib/fixoldbrowsers"],function(e,t,n){"use strict";e("ace/lib/fixoldbrowsers");var r=[["Chrome"],["Clouds"],["Crimson Editor"],["Dawn"],["Dreamweaver"],["Eclipse"],["GitHub"],["IPlastic"],["Solarized Light"],["TextMate"],["Tomorrow"],["XCode"],["Kuroir"],["KatzenMilch"],["SQL Server","sqlserver","light"],["Ambiance","ambiance","dark"],["Chaos","chaos","dark"],["Clouds Midnight","clouds_midnight","dark"],["Cobalt","cobalt","dark"],["idle Fingers","idle_fingers","dark"],["krTheme","kr_theme","dark"],["Merbivore","merbivore","dark"],["Merbivore Soft","merbivore_soft","dark"],["Mono Industrial","mono_industrial","dark"],["Monokai","monokai","dark"],["Pastel on dark","pastel_on_dark","dark"],["Solarized Dark","solarized_dark","dark"],["Terminal","terminal","dark"],["Tomorrow Night","tomorrow_night","dark"],["Tomorrow Night Blue","tomorrow_night_blue","dark"],["Tomorrow Night Bright","tomorrow_night_bright","dark"],["Tomorrow Night 80s","tomorrow_night_eighties","dark"],["Twilight","twilight","dark"],["Vibrant Ink","vibrant_ink","dark"]];t.themesByName={},t.themes=r.map(function(e){var n=e[1]||e[0].replace(/ /g,"_").toLowerCase(),r={caption:e[0],theme:"ace/theme/"+n,isDark:e[2]=="dark",name:n};return t.themesByName[n]=r,r})});
+                (function() {
+                    ace.require(["ace/ext/themelist"], function() {});
+                })();
+            
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-whitespace.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-whitespace.js
new file mode 100644
index 0000000..14af281
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/ext-whitespace.js
@@ -0,0 +1,5 @@
+ace.define("ace/ext/whitespace",["require","exports","module","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../lib/lang");t.$detectIndentation=function(e,t){function c(e){var t=0;for(var r=e;r<n.length;r+=e)t+=n[r]||0;return t}var n=[],r=[],i=0,s=0,o=Math.min(e.length,1e3);for(var u=0;u<o;u++){var a=e[u];if(!/^\s*[^*+\-\s]/.test(a))continue;if(a[0]=="	")i++,s=-Number.MAX_VALUE;else{var f=a.match(/^ */)[0].length;if(f&&a[f]!="	"){var l=f-s;l>0&&!(s%l)&&!(f%l)&&(r[l]=(r[l]||0)+1),n[f]=(n[f]||0)+1}s=f}while(u<o&&a[a.length-1]=="\\")a=e[u++]}var h=r.reduce(function(e,t){return e+t},0),p={score:0,length:0},d=0;for(var u=1;u<12;u++){var v=c(u);u==1?(d=v,v=n[1]?.9:.8,n.length||(v=0)):v/=d,r[u]&&(v+=r[u]/h),v>p.score&&(p={score:v,length:u})}if(p.score&&p.score>1.4)var m=p.length;if(i>d+1){if(m==1||d<i/4||p.score<1.8)m=undefined;return{ch:"	",length:m}}if(d>i+1)return{ch:" ",length:m}},t.detectIndentation=function(e){var n=e.getLines(0,1e3),r=t.$detectIndentation(n)||{};return r.ch&&e.setUseSoftTabs(r.ch==" "),r.length&&e.setTabSize(r.length),r},t.trimTrailingSpace=function(e,t){var n=e.getDocument(),r=n.getAllLines(),i=t?-1:0;for(var s=0,o=r.length;s<o;s++){var u=r[s],a=u.search(/\s+$/);a>i&&n.removeInLine(s,a,u.length)}},t.convertIndentation=function(e,t,n){var i=e.getTabString()[0],s=e.getTabSize();n||(n=s),t||(t=i);var o=t=="	"?t:r.stringRepeat(t,n),u=e.doc,a=u.getAllLines(),f={},l={};for(var c=0,h=a.length;c<h;c++){var p=a[c],d=p.match(/^\s*/)[0];if(d){var v=e.$getStringScreenWidth(d)[0],m=Math.floor(v/s),g=v%s,y=f[m]||(f[m]=r.stringRepeat(o,m));y+=l[g]||(l[g]=r.stringRepeat(" ",g)),y!=d&&(u.removeInLine(c,0,d.length),u.insertInLine({row:c,column:0},y))}}e.setTabSize(n),e.setUseSoftTabs(t==" ")},t.$parseStringArg=function(e){var t={};/t/.test(e)?t.ch="	":/s/.test(e)&&(t.ch=" ");var n=e.match(/\d+/);return n&&(t.length=parseInt(n[0],10)),t},t.$parseArg=function(e){return e?typeof e=="string"?t.$parseStringArg(e):typeof e.text=="string"?t.$parseStringArg(e.text):e:{}},t.commands=[{name:"detectIndentation",exec:function(e){t.detectIndentation(e.session)}},{name:"trimTrailingSpace",exec:function(e){t.trimTrailingSpace(e.session)}},{name:"convertIndentation",exec:function(e,n){var r=t.$parseArg(n);t.convertIndentation(e.session,r.ch,r.length)}},{name:"setIndentation",exec:function(e,n){var r=t.$parseArg(n);r.length&&e.session.setTabSize(r.length),r.ch&&e.session.setUseSoftTabs(r.ch==" ")}}]});
+                (function() {
+                    ace.require(["ace/ext/whitespace"], function() {});
+                })();
+            
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/keybinding-emacs.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/keybinding-emacs.js
new file mode 100644
index 0000000..aa84336
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/keybinding-emacs.js
@@ -0,0 +1 @@
+ace.define("ace/occur",["require","exports","module","ace/lib/oop","ace/range","ace/search","ace/edit_session","ace/search_highlight","ace/lib/dom"],function(e,t,n){"use strict";function a(){}var r=e("./lib/oop"),i=e("./range").Range,s=e("./search").Search,o=e("./edit_session").EditSession,u=e("./search_highlight").SearchHighlight;r.inherits(a,s),function(){this.enter=function(e,t){if(!t.needle)return!1;var n=e.getCursorPosition();this.displayOccurContent(e,t);var r=this.originalToOccurPosition(e.session,n);return e.moveCursorToPosition(r),!0},this.exit=function(e,t){var n=t.translatePosition&&e.getCursorPosition(),r=n&&this.occurToOriginalPosition(e.session,n);return this.displayOriginalContent(e),r&&e.moveCursorToPosition(r),!0},this.highlight=function(e,t){var n=e.$occurHighlight=e.$occurHighlight||e.addDynamicMarker(new u(null,"ace_occur-highlight","text"));n.setRegexp(t),e._emit("changeBackMarker")},this.displayOccurContent=function(e,t){this.$originalSession=e.session;var n=this.matchingLines(e.session,t),r=n.map(function(e){return e.content}),i=new o(r.join("\n"));i.$occur=this,i.$occurMatchingLines=n,e.setSession(i),this.$useEmacsStyleLineStart=this.$originalSession.$useEmacsStyleLineStart,i.$useEmacsStyleLineStart=this.$useEmacsStyleLineStart,this.highlight(i,t.re),i._emit("changeBackMarker")},this.displayOriginalContent=function(e){e.setSession(this.$originalSession),this.$originalSession.$useEmacsStyleLineStart=this.$useEmacsStyleLineStart},this.originalToOccurPosition=function(e,t){var n=e.$occurMatchingLines,r={row:0,column:0};if(!n)return r;for(var i=0;i<n.length;i++)if(n[i].row===t.row)return{row:i,column:t.column};return r},this.occurToOriginalPosition=function(e,t){var n=e.$occurMatchingLines;return!n||!n[t.row]?t:{row:n[t.row].row,column:t.column}},this.matchingLines=function(e,t){t=r.mixin({},t);if(!e||!t.needle)return[];var n=new s;return n.set(t),n.findAll(e).reduce(function(t,n){var r=n.start.row,i=t[t.length-1];return i&&i.row===r?t:t.concat({row:r,content:e.getLine(r)})},[])}}.call(a.prototype);var f=e("./lib/dom");f.importCssString(".ace_occur-highlight {\n    border-radius: 4px;\n    background-color: rgba(87, 255, 8, 0.25);\n    position: absolute;\n    z-index: 4;\n    -moz-box-sizing: border-box;\n    -webkit-box-sizing: border-box;\n    box-sizing: border-box;\n    box-shadow: 0 0 4px rgb(91, 255, 50);\n}\n.ace_dark .ace_occur-highlight {\n    background-color: rgb(80, 140, 85);\n    box-shadow: 0 0 4px rgb(60, 120, 70);\n}\n","incremental-occur-highlighting"),t.Occur=a}),ace.define("ace/commands/occur_commands",["require","exports","module","ace/config","ace/occur","ace/keyboard/hash_handler","ace/lib/oop"],function(e,t,n){function f(){}var r=e("../config"),i=e("../occur").Occur,s={name:"occur",exec:function(e,t){var n=!!e.session.$occur,r=(new i).enter(e,t);r&&!n&&f.installIn(e)},readOnly:!0},o=[{name:"occurexit",bindKey:"esc|Ctrl-G",exec:function(e){var t=e.session.$occur;if(!t)return;t.exit(e,{}),e.session.$occur||f.uninstallFrom(e)},readOnly:!0},{name:"occuraccept",bindKey:"enter",exec:function(e){var t=e.session.$occur;if(!t)return;t.exit(e,{translatePosition:!0}),e.session.$occur||f.uninstallFrom(e)},readOnly:!0}],u=e("../keyboard/hash_handler").HashHandler,a=e("../lib/oop");a.inherits(f,u),function(){this.isOccurHandler=!0,this.attach=function(e){u.call(this,o,e.commands.platform),this.$editor=e};var e=this.handleKeyboard;this.handleKeyboard=function(t,n,r,i){var s=e.call(this,t,n,r,i);return s&&s.command?s:undefined}}.call(f.prototype),f.installIn=function(e){var t=new this;e.keyBinding.addKeyboardHandler(t),e.commands.addCommands(o)},f.uninstallFrom=function(e){e.commands.removeCommands(o);var t=e.getKeyboardHandler();t.isOccurHandler&&e.keyBinding.removeKeyboardHandler(t)},t.occurStartCommand=s}),ace.define("ace/commands/incremental_search_commands",["require","exports","module","ace/config","ace/lib/oop","ace/keyboard/hash_handler","ace/commands/occur_commands"],function(e,t,n){function u(e){this.$iSearch=e}var r=e("../config"),i=e("../lib/oop"),s=e("../keyboard/hash_handler").HashHandler,o=e("./occur_commands").occurStartCommand;t.iSearchStartCommands=[{name:"iSearch",bindKey:{win:"Ctrl-F",mac:"Command-F"},exec:function(e,t){r.loadModule(["core","ace/incremental_search"],function(n){var r=n.iSearch=n.iSearch||new n.IncrementalSearch;r.activate(e,t.backwards),t.jumpToFirstMatch&&r.next(t)})},readOnly:!0},{name:"iSearchBackwards",exec:function(e,t){e.execCommand("iSearch",{backwards:!0})},readOnly:!0},{name:"iSearchAndGo",bindKey:{win:"Ctrl-K",mac:"Command-G"},exec:function(e,t){e.execCommand("iSearch",{jumpToFirstMatch:!0,useCurrentOrPrevSearch:!0})},readOnly:!0},{name:"iSearchBackwardsAndGo",bindKey:{win:"Ctrl-Shift-K",mac:"Command-Shift-G"},exec:function(e){e.execCommand("iSearch",{jumpToFirstMatch:!0,backwards:!0,useCurrentOrPrevSearch:!0})},readOnly:!0}],t.iSearchCommands=[{name:"restartSearch",bindKey:{win:"Ctrl-F",mac:"Command-F"},exec:function(e){e.cancelSearch(!0)}},{name:"searchForward",bindKey:{win:"Ctrl-S|Ctrl-K",mac:"Ctrl-S|Command-G"},exec:function(e,t){t.useCurrentOrPrevSearch=!0,e.next(t)}},{name:"searchBackward",bindKey:{win:"Ctrl-R|Ctrl-Shift-K",mac:"Ctrl-R|Command-Shift-G"},exec:function(e,t){t.useCurrentOrPrevSearch=!0,t.backwards=!0,e.next(t)}},{name:"extendSearchTerm",exec:function(e,t){e.addString(t)}},{name:"extendSearchTermSpace",bindKey:"space",exec:function(e){e.addString(" ")}},{name:"shrinkSearchTerm",bindKey:"backspace",exec:function(e){e.removeChar()}},{name:"confirmSearch",bindKey:"return",exec:function(e){e.deactivate()}},{name:"cancelSearch",bindKey:"esc|Ctrl-G",exec:function(e){e.deactivate(!0)}},{name:"occurisearch",bindKey:"Ctrl-O",exec:function(e){var t=i.mixin({},e.$options);e.deactivate(),o.exec(e.$editor,t)}},{name:"yankNextWord",bindKey:"Ctrl-w",exec:function(e){var t=e.$editor,n=t.selection.getRangeOfMovements(function(e){e.moveCursorWordRight()}),r=t.session.getTextRange(n);e.addString(r)}},{name:"yankNextChar",bindKey:"Ctrl-Alt-y",exec:function(e){var t=e.$editor,n=t.selection.getRangeOfMovements(function(e){e.moveCursorRight()}),r=t.session.getTextRange(n);e.addString(r)}},{name:"recenterTopBottom",bindKey:"Ctrl-l",exec:function(e){e.$editor.execCommand("recenterTopBottom")}},{name:"selectAllMatches",bindKey:"Ctrl-space",exec:function(e){var t=e.$editor,n=t.session.$isearchHighlight,r=n&&n.cache?n.cache.reduce(function(e,t){return e.concat(t?t:[])},[]):[];e.deactivate(!1),r.forEach(t.selection.addRange.bind(t.selection))}},{name:"searchAsRegExp",bindKey:"Alt-r",exec:function(e){e.convertNeedleToRegExp()}}].map(function(e){return e.readOnly=!0,e.isIncrementalSearchCommand=!0,e.scrollIntoView="animate-cursor",e}),i.inherits(u,s),function(){this.attach=function(e){var n=this.$iSearch;s.call(this,t.iSearchCommands,e.commands.platform),this.$commandExecHandler=e.commands.addEventListener("exec",function(t){if(!t.command.isIncrementalSearchCommand)return n.deactivate();t.stopPropagation(),t.preventDefault();var r=e.session.getScrollTop(),i=t.command.exec(n,t.args||{});return e.renderer.scrollCursorIntoView(null,.5),e.renderer.animateScrolling(r),i})},this.detach=function(e){if(!this.$commandExecHandler)return;e.commands.removeEventListener("exec",this.$commandExecHandler),delete this.$commandExecHandler};var e=this.handleKeyboard;this.handleKeyboard=function(t,n,r,i){if((n===1||n===8)&&r==="v"||n===1&&r==="y")return null;var s=e.call(this,t,n,r,i);if(s.command)return s;if(n==-1){var o=this.commands.extendSearchTerm;if(o)return{command:o,args:r}}return!1}}.call(u.prototype),t.IncrementalSearchKeyboardHandler=u}),ace.define("ace/incremental_search",["require","exports","module","ace/lib/oop","ace/range","ace/search","ace/search_highlight","ace/commands/incremental_search_commands","ace/lib/dom","ace/commands/command_manager","ace/editor","ace/config"],function(e,t,n){"use strict";function f(){this.$options={wrap:!1,skipCurrent:!1},this.$keyboardHandler=new a(this)}function l(e){return e instanceof RegExp}function c(e){var t=String(e),n=t.indexOf("/"),r=t.lastIndexOf("/");return{expression:t.slice(n+1,r),flags:t.slice(r+1)}}function h(e,t){try{return new RegExp(e,t)}catch(n){return e}}function p(e){return h(e.expression,e.flags)}var r=e("./lib/oop"),i=e("./range").Range,s=e("./search").Search,o=e("./search_highlight").SearchHighlight,u=e("./commands/incremental_search_commands"),a=u.IncrementalSearchKeyboardHandler;r.inherits(f,s),function(){this.activate=function(e,t){this.$editor=e,this.$startPos=this.$currentPos=e.getCursorPosition(),this.$options.needle="",this.$options.backwards=t,e.keyBinding.addKeyboardHandler(this.$keyboardHandler),this.$originalEditorOnPaste=e.onPaste,e.onPaste=this.onPaste.bind(this),this.$mousedownHandler=e.addEventListener("mousedown",this.onMouseDown.bind(this)),this.selectionFix(e),this.statusMessage(!0)},this.deactivate=function(e){this.cancelSearch(e);var t=this.$editor;t.keyBinding.removeKeyboardHandler(this.$keyboardHandler),this.$mousedownHandler&&(t.removeEventListener("mousedown",this.$mousedownHandler),delete this.$mousedownHandler),t.onPaste=this.$originalEditorOnPaste,this.message("")},this.selectionFix=function(e){e.selection.isEmpty()&&!e.session.$emacsMark&&e.clearSelection()},this.highlight=function(e){var t=this.$editor.session,n=t.$isearchHighlight=t.$isearchHighlight||t.addDynamicMarker(new o(null,"ace_isearch-result","text"));n.setRegexp(e),t._emit("changeBackMarker")},this.cancelSearch=function(e){var t=this.$editor;return this.$prevNeedle=this.$options.needle,this.$options.needle="",e?(t.moveCursorToPosition(this.$startPos),this.$currentPos=this.$startPos):t.pushEmacsMark&&t.pushEmacsMark(this.$startPos,!1),this.highlight(null),i.fromPoints(this.$currentPos,this.$currentPos)},this.highlightAndFindWithNeedle=function(e,t){if(!this.$editor)return null;var n=this.$options;t&&(n.needle=t.call(this,n.needle||"")||"");if(n.needle.length===0)return this.statusMessage(!0),this.cancelSearch(!0);n.start=this.$currentPos;var r=this.$editor.session,s=this.find(r),o=this.$editor.emacsMark?!!this.$editor.emacsMark():!this.$editor.selection.isEmpty();return s&&(n.backwards&&(s=i.fromPoints(s.end,s.start)),this.$editor.selection.setRange(i.fromPoints(o?this.$startPos:s.end,s.end)),e&&(this.$currentPos=s.end),this.highlight(n.re)),this.statusMessage(s),s},this.addString=function(e){return this.highlightAndFindWithNeedle(!1,function(t){if(!l(t))return t+e;var n=c(t);return n.expression+=e,p(n)})},this.removeChar=function(e){return this.highlightAndFindWithNeedle(!1,function(e){if(!l(e))return e.substring(0,e.length-1);var t=c(e);return t.expression=t.expression.substring(0,t.expression.length-1),p(t)})},this.next=function(e){return e=e||{},this.$options.backwards=!!e.backwards,this.$currentPos=this.$editor.getCursorPosition(),this.highlightAndFindWithNeedle(!0,function(t){return e.useCurrentOrPrevSearch&&t.length===0?this.$prevNeedle||"":t})},this.onMouseDown=function(e){return this.deactivate(),!0},this.onPaste=function(e){this.addString(e)},this.convertNeedleToRegExp=function(){return this.highlightAndFindWithNeedle(!1,function(e){return l(e)?e:h(e,"ig")})},this.convertNeedleToString=function(){return this.highlightAndFindWithNeedle(!1,function(e){return l(e)?c(e).expression:e})},this.statusMessage=function(e){var t=this.$options,n="";n+=t.backwards?"reverse-":"",n+="isearch: "+t.needle,n+=e?"":" (not found)",this.message(n)},this.message=function(e){this.$editor.showCommandLine?(this.$editor.showCommandLine(e),this.$editor.focus()):console.log(e)}}.call(f.prototype),t.IncrementalSearch=f;var d=e("./lib/dom");d.importCssString&&d.importCssString(".ace_marker-layer .ace_isearch-result {  position: absolute;  z-index: 6;  -moz-box-sizing: border-box;  -webkit-box-sizing: border-box;  box-sizing: border-box;}div.ace_isearch-result {  border-radius: 4px;  background-color: rgba(255, 200, 0, 0.5);  box-shadow: 0 0 4px rgb(255, 200, 0);}.ace_dark div.ace_isearch-result {  background-color: rgb(100, 110, 160);  box-shadow: 0 0 4px rgb(80, 90, 140);}","incremental-search-highlighting");var v=e("./commands/command_manager");(function(){this.setupIncrementalSearch=function(e,t){if(this.usesIncrementalSearch==t)return;this.usesIncrementalSearch=t;var n=u.iSearchStartCommands,r=t?"addCommands":"removeCommands";this[r](n)}}).call(v.CommandManager.prototype);var m=e("./editor").Editor;e("./config").defineOptions(m.prototype,"editor",{useIncrementalSearch:{set:function(e){this.keyBinding.$handlers.forEach(function(t){t.setupIncrementalSearch&&t.setupIncrementalSearch(this,e)}),this._emit("incrementalSearchSettingChanged",{isEnabled:e})}}})}),ace.define("ace/keyboard/emacs",["require","exports","module","ace/lib/dom","ace/incremental_search","ace/commands/incremental_search_commands","ace/keyboard/hash_handler","ace/lib/keys"],function(e,t,n){"use strict";var r=e("../lib/dom");e("../incremental_search");var i=e("../commands/incremental_search_commands"),s=function(e,t){var n=this.scroller.getBoundingClientRect(),r=Math.floor((e+this.scrollLeft-n.left-this.$padding)/this.characterWidth),i=Math.floor((t+this.scrollTop-n.top)/this.lineHeight);return this.session.screenToDocumentPosition(i,r)},o=e("./hash_handler").HashHandler;t.handler=new o,t.handler.isEmacs=!0,t.handler.$id="ace/keyboard/emacs";var u=!1,a,f;t.handler.attach=function(e){u||(u=!0,r.importCssString("            .emacs-mode .ace_cursor{                border: 1px rgba(50,250,50,0.8) solid!important;                -moz-box-sizing: border-box!important;                -webkit-box-sizing: border-box!important;                box-sizing: border-box!important;                background-color: rgba(0,250,0,0.9);                opacity: 0.5;            }            .emacs-mode .ace_hidden-cursors .ace_cursor{                opacity: 1;                background-color: transparent;            }            .emacs-mode .ace_overwrite-cursors .ace_cursor {                opacity: 1;                background-color: transparent;                border-width: 0 0 2px 2px !important;            }            .emacs-mode .ace_text-layer {                z-index: 4            }            .emacs-mode .ace_cursor-layer {                z-index: 2            }","emacsMode")),a=e.session.$selectLongWords,e.session.$selectLongWords=!0,f=e.session.$useEmacsStyleLineStart,e.session.$useEmacsStyleLineStart=!0,e.session.$emacsMark=null,e.session.$emacsMarkRing=e.session.$emacsMarkRing||[],e.emacsMark=function(){return this.session.$emacsMark},e.setEmacsMark=function(e){this.session.$emacsMark=e},e.pushEmacsMark=function(e,t){var n=this.session.$emacsMark;n&&this.session.$emacsMarkRing.push(n),!e||t?this.setEmacsMark(e):this.session.$emacsMarkRing.push(e)},e.popEmacsMark=function(){var e=this.emacsMark();return e?(this.setEmacsMark(null),e):this.session.$emacsMarkRing.pop()},e.getLastEmacsMark=function(e){return this.session.$emacsMark||this.session.$emacsMarkRing.slice(-1)[0]},e.emacsMarkForSelection=function(e){var t=this.selection,n=this.multiSelect?this.multiSelect.getAllRanges().length:1,r=t.index||0,i=this.session.$emacsMarkRing,s=i.length-(n-r),o=i[s]||t.anchor;return e&&i.splice(s,1,"row"in e&&"column"in e?e:undefined),o},e.on("click",c),e.on("changeSession",l),e.renderer.screenToTextCoordinates=s,e.setStyle("emacs-mode"),e.commands.addCommands(v),t.handler.platform=e.commands.platform,e.$emacsModeHandler=this,e.addEventListener("copy",this.onCopy),e.addEventListener("paste",this.onPaste)},t.handler.detach=function(e){delete e.renderer.screenToTextCoordinates,e.session.$selectLongWords=a,e.session.$useEmacsStyleLineStart=f,e.removeEventListener("click",c),e.removeEventListener("changeSession",l),e.unsetStyle("emacs-mode"),e.commands.removeCommands(v),e.removeEventListener("copy",this.onCopy),e.removeEventListener("paste",this.onPaste),e.$emacsModeHandler=null};var l=function(e){e.oldSession&&(e.oldSession.$selectLongWords=a,e.oldSession.$useEmacsStyleLineStart=f),a=e.session.$selectLongWords,e.session.$selectLongWords=!0,f=e.session.$useEmacsStyleLineStart,e.session.$useEmacsStyleLineStart=!0,e.session.hasOwnProperty("$emacsMark")||(e.session.$emacsMark=null),e.session.hasOwnProperty("$emacsMarkRing")||(e.session.$emacsMarkRing=[])},c=function(e){e.editor.session.$emacsMark=null},h=e("../lib/keys").KEY_MODS,p={C:"ctrl",S:"shift",M:"alt",CMD:"command"},d=["C-S-M-CMD","S-M-CMD","C-M-CMD","C-S-CMD","C-S-M","M-CMD","S-CMD","S-M","C-CMD","C-M","C-S","CMD","M","S","C"];d.forEach(function(e){var t=0;e.split("-").forEach(function(e){t|=h[p[e]]}),p[t]=e.toLowerCase()+"-"}),t.handler.onCopy=function(e,n){if(n.$handlesEmacsOnCopy)return;n.$handlesEmacsOnCopy=!0,t.handler.commands.killRingSave.exec(n),n.$handlesEmacsOnCopy=!1},t.handler.onPaste=function(e,t){t.pushEmacsMark(t.getCursorPosition())},t.handler.bindKey=function(e,t){typeof e=="object"&&(e=e[this.platform]);if(!e)return;var n=this.commandKeyBinding;e.split("|").forEach(function(e){e=e.toLowerCase(),n[e]=t;var r=e.split(" ").slice(0,-1);r.reduce(function(e,t,n){var r=e[n-1]?e[n-1]+" ":"";return e.concat([r+t])},[]).forEach(function(e){n[e]||(n[e]="null")})},this)},t.handler.getStatusText=function(e,t){var n="";return t.count&&(n+=t.count),t.keyChain&&(n+=" "+t.keyChain),n},t.handler.handleKeyboard=function(e,t,n,r){if(r===-1)return undefined;var i=e.editor;i._signal("changeStatus");if(t==-1){i.pushEmacsMark();if(e.count){var s=(new Array(e.count+1)).join(n);return e.count=null,{command:"insertstring",args:s}}}var o=p[t];if(o=="c-"||e.count){var u=parseInt(n[n.length-1]);if(typeof u=="number"&&!isNaN(u))return e.count=Math.max(e.count,0)||0,e.count=10*e.count+u,{command:"null"}}o&&(n=o+n),e.keyChain&&(n=e.keyChain+=" "+n);var a=this.commandKeyBinding[n];e.keyChain=a=="null"?n:"";if(!a)return undefined;if(a==="null")return{command:"null"};if(a==="universalArgument")return e.count=-4,{command:"null"};var f;typeof a!="string"&&(f=a.args,a.command&&(a=a.command),a==="goorselect"&&(a=i.emacsMark()?f[1]:f[0],f=null));if(typeof a=="string"){(a==="insertstring"||a==="splitline"||a==="togglecomment")&&i.pushEmacsMark(),a=this.commands[a]||i.commands.commands[a];if(!a)return undefined}!a.readOnly&&!a.isYank&&(e.lastCommand=null),!a.readOnly&&i.emacsMark()&&i.setEmacsMark(null);if(e.count){var u=e.count;e.count=0;if(!a||!a.handlesCount)return{args:f,command:{exec:function(e,t){for(var n=0;n<u;n++)a.exec(e,t)},multiSelectAction:a.multiSelectAction}};f||(f={}),typeof f=="object"&&(f.count=u)}return{command:a,args:f}},t.emacsKeys={"Up|C-p":{command:"goorselect",args:["golineup","selectup"]},"Down|C-n":{command:"goorselect",args:["golinedown","selectdown"]},"Left|C-b":{command:"goorselect",args:["gotoleft","selectleft"]},"Right|C-f":{command:"goorselect",args:["gotoright","selectright"]},"C-Left|M-b":{command:"goorselect",args:["gotowordleft","selectwordleft"]},"C-Right|M-f":{command:"goorselect",args:["gotowordright","selectwordright"]},"Home|C-a":{command:"goorselect",args:["gotolinestart","selecttolinestart"]},"End|C-e":{command:"goorselect",args:["gotolineend","selecttolineend"]},"C-Home|S-M-,":{command:"goorselect",args:["gotostart","selecttostart"]},"C-End|S-M-.":{command:"goorselect",args:["gotoend","selecttoend"]},"S-Up|S-C-p":"selectup","S-Down|S-C-n":"selectdown","S-Left|S-C-b":"selectleft","S-Right|S-C-f":"selectright","S-C-Left|S-M-b":"selectwordleft","S-C-Right|S-M-f":"selectwordright","S-Home|S-C-a":"selecttolinestart","S-End|S-C-e":"selecttolineend","S-C-Home":"selecttostart","S-C-End":"selecttoend","C-l":"recenterTopBottom","M-s":"centerselection","M-g":"gotoline","C-x C-p":"selectall","C-Down":{command:"goorselect",args:["gotopagedown","selectpagedown"]},"C-Up":{command:"goorselect",args:["gotopageup","selectpageup"]},"PageDown|C-v":{command:"goorselect",args:["gotopagedown","selectpagedown"]},"PageUp|M-v":{command:"goorselect",args:["gotopageup","selectpageup"]},"S-C-Down":"selectpagedown","S-C-Up":"selectpageup","C-s":"iSearch","C-r":"iSearchBackwards","M-C-s":"findnext","M-C-r":"findprevious","S-M-5":"replace",Backspace:"backspace","Delete|C-d":"del","Return|C-m":{command:"insertstring",args:"\n"},"C-o":"splitline","M-d|C-Delete":{command:"killWord",args:"right"},"C-Backspace|M-Backspace|M-Delete":{command:"killWord",args:"left"},"C-k":"killLine","C-y|S-Delete":"yank","M-y":"yankRotate","C-g":"keyboardQuit","C-w|C-S-W":"killRegion","M-w":"killRingSave","C-Space":"setMark","C-x C-x":"exchangePointAndMark","C-t":"transposeletters","M-u":"touppercase","M-l":"tolowercase","M-/":"autocomplete","C-u":"universalArgument","M-;":"togglecomment","C-/|C-x u|S-C--|C-z":"undo","S-C-/|S-C-x u|C--|S-C-z":"redo","C-x r":"selectRectangularRegion","M-x":{command:"focusCommandLine",args:"M-x "}},t.handler.bindKeys(t.emacsKeys),t.handler.addCommands({recenterTopBottom:function(e){var t=e.renderer,n=t.$cursorLayer.getPixelPosition(),r=t.$size.scrollerHeight-t.lineHeight,i=t.scrollTop;Math.abs(n.top-i)<2?i=n.top-r:Math.abs(n.top-i-r*.5)<2?i=n.top:i=n.top-r*.5,e.session.setScrollTop(i)},selectRectangularRegion:function(e){e.multiSelect.toggleBlockSelection()},setMark:{exec:function(e,t){function u(){var t=e.popEmacsMark();t&&e.moveCursorToPosition(t)}if(t&&t.count){e.inMultiSelectMode?e.forEachSelection(u):u(),u();return}var n=e.emacsMark(),r=e.selection.getAllRanges(),i=r.map(function(e){return{row:e.start.row,column:e.start.column}}),s=!0,o=r.every(function(e){return e.isEmpty()});if(s&&(n||!o)){e.inMultiSelectMode?e.forEachSelection({exec:e.clearSelection.bind(e)}):e.clearSelection(),n&&e.pushEmacsMark(null);return}if(!n){i.forEach(function(t){e.pushEmacsMark(t)}),e.setEmacsMark(i[i.length-1]);return}},readOnly:!0,handlesCount:!0},exchangePointAndMark:{exec:function(t,n){var r=t.selection;if(!n.count&&!r.isEmpty()){r.setSelectionRange(r.getRange(),!r.isBackwards());return}if(n.count){var i={row:r.lead.row,column:r.lead.column};r.clearSelection(),r.moveCursorToPosition(t.emacsMarkForSelection(i))}else r.selectToPosition(t.emacsMarkForSelection())},readOnly:!0,handlesCount:!0,multiSelectAction:"forEach"},killWord:{exec:function(e,n){e.clearSelection(),n=="left"?e.selection.selectWordLeft():e.selection.selectWordRight();var r=e.getSelectionRange(),i=e.session.getTextRange(r);t.killRing.add(i),e.session.remove(r),e.clearSelection()},multiSelectAction:"forEach"},killLine:function(e){e.pushEmacsMark(null),e.clearSelection();var n=e.getSelectionRange(),r=e.session.getLine(n.start.row);n.end.column=r.length,r=r.substr(n.start.column);var i=e.session.getFoldLine(n.start.row);i&&n.end.row!=i.end.row&&(n.end.row=i.end.row,r="x"),/^\s*$/.test(r)&&(n.end.row++,r=e.session.getLine(n.end.row),n.end.column=/^\s*$/.test(r)?r.length:0);var s=e.session.getTextRange(n);e.prevOp.command==this?t.killRing.append(s):t.killRing.add(s),e.session.remove(n),e.clearSelection()},yank:function(e){e.onPaste(t.killRing.get()||""),e.keyBinding.$data.lastCommand="yank"},yankRotate:function(e){if(e.keyBinding.$data.lastCommand!="yank")return;e.undo(),e.session.$emacsMarkRing.pop(),e.onPaste(t.killRing.rotate()),e.keyBinding.$data.lastCommand="yank"},killRegion:{exec:function(e){t.killRing.add(e.getCopyText()),e.commands.byName.cut.exec(e),e.setEmacsMark(null)},readOnly:!0,multiSelectAction:"forEach"},killRingSave:{exec:function(e){e.$handlesEmacsOnCopy=!0;var n=e.session.$emacsMarkRing.slice(),r=[];t.killRing.add(e.getCopyText()),setTimeout(function(){function t(){var t=e.selection,n=t.getRange(),i=t.isBackwards()?n.end:n.start;r.push({row:i.row,column:i.column}),t.clearSelection()}e.$handlesEmacsOnCopy=!1,e.inMultiSelectMode?e.forEachSelection({exec:t}):t(),e.session.$emacsMarkRing=n.concat(r.reverse())},0)},readOnly:!0},keyboardQuit:function(e){e.selection.clearSelection(),e.setEmacsMark(null),e.keyBinding.$data.count=null},focusCommandLine:function(e,t){e.showCommandLine&&e.showCommandLine(t)}}),t.handler.addCommands(i.iSearchStartCommands);var v=t.handler.commands;v.yank.isYank=!0,v.yankRotate.isYank=!0,t.killRing={$data:[],add:function(e){e&&this.$data.push(e),this.$data.length>30&&this.$data.shift()},append:function(e){var t=this.$data.length-1,n=this.$data[t]||"";e&&(n+=e),n&&(this.$data[t]=n)},get:function(e){return e=e||1,this.$data.slice(this.$data.length-e,this.$data.length).reverse().join("\n")},pop:function(){return this.$data.length>1&&this.$data.pop(),this.get()},rotate:function(){return this.$data.unshift(this.$data.pop()),this.get()}}})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/keybinding-vim.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/keybinding-vim.js
new file mode 100644
index 0000000..53c9301
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/keybinding-vim.js
@@ -0,0 +1 @@
+ace.define("ace/keyboard/vim",["require","exports","module","ace/range","ace/lib/event_emitter","ace/lib/dom","ace/lib/oop","ace/lib/keys","ace/lib/event","ace/search","ace/lib/useragent","ace/search_highlight","ace/commands/multi_select_commands","ace/mode/text","ace/multi_select"],function(e,t,n){"use strict";function r(){function t(e){return typeof e!="object"?e+"":"line"in e?e.line+":"+e.ch:"anchor"in e?t(e.anchor)+"->"+t(e.head):Array.isArray(e)?"["+e.map(function(e){return t(e)})+"]":JSON.stringify(e)}var e="";for(var n=0;n<arguments.length;n++){var r=arguments[n],i=t(r);e+=i+"  "}console.log(e)}function m(e){return{row:e.line,column:e.ch}}function g(e){return new E(e.row,e.column)}function x(e){e.setOption("disableInput",!0),e.setOption("showCursorWhenSelecting",!1),v.signal(e,"vim-mode-change",{mode:"normal"}),e.on("cursorActivity",Jn),tt(e),v.on(e.getInputField(),"paste",M(e))}function T(e){e.setOption("disableInput",!1),e.off("cursorActivity",Jn),v.off(e.getInputField(),"paste",M(e)),e.state.vim=null}function N(e,t){this==v.keyMap.vim&&v.rmClass(e.getWrapperElement(),"cm-fat-cursor"),(!t||t.attach!=C)&&T(e,!1)}function C(e,t){this==v.keyMap.vim&&v.addClass(e.getWrapperElement(),"cm-fat-cursor"),(!t||t.attach!=C)&&x(e)}function k(e,t){if(!t)return undefined;var n=O(e);if(!n)return!1;var r=v.Vim.findKey(t,n);return typeof r=="function"&&v.signal(t,"vim-keypress",n),r}function O(e){if(e.charAt(0)=="'")return e.charAt(1);var t=e.split(/-(?!$)/),n=t[t.length-1];if(t.length==1&&t[0].length==1)return!1;if(t.length==2&&t[0]=="Shift"&&n.length==1)return!1;var r=!1;for(var i=0;i<t.length;i++){var s=t[i];s in L?t[i]=L[s]:r=!0,s in A&&(t[i]=A[s])}return r?(X(n)&&(t[t.length-1]=n.toLowerCase()),"<"+t.join("-")+">"):!1}function M(e){var t=e.state.vim;return t.onPasteFn||(t.onPasteFn=function(){t.insertMode||(e.setCursor(St(e.getCursor(),0,1)),yt.enterInsertMode(e,{},t))}),t.onPasteFn}function H(e,t){var n=[];for(var r=e;r<e+t;r++)n.push(String.fromCharCode(r));return n}function R(e,t){return t>=e.firstLine()&&t<=e.lastLine()}function U(e){return/^[a-z]$/.test(e)}function z(e){return"()[]{}".indexOf(e)!=-1}function W(e){return _.test(e)}function X(e){return/^[A-Z]$/.test(e)}function V(e){return/^\s*$/.test(e)}function $(e,t){for(var n=0;n<t.length;n++)if(t[n]==e)return!0;return!1}function K(e,t,n,r,i){if(t===undefined&&!i)throw Error("defaultValue is required unless callback is provided");n||(n="string"),J[e]={type:n,defaultValue:t,callback:i};if(r)for(var s=0;s<r.length;s++)J[r[s]]=J[e];t&&Q(e,t)}function Q(e,t,n,r){var i=J[e];r=r||{};var s=r.scope;if(!i)throw Error("Unknown option: "+e);if(i.type=="boolean"){if(t&&t!==!0)throw Error("Invalid argument: "+e+"="+t);t!==!1&&(t=!0)}i.callback?(s!=="local"&&i.callback(t,undefined),s!=="global"&&n&&i.callback(t,n)):(s!=="local"&&(i.value=i.type=="boolean"?!!t:t),s!=="global"&&n&&(n.state.vim.options[e]={value:t}))}function G(e,t,n){var r=J[e];n=n||{};var i=n.scope;if(!r)throw Error("Unknown option: "+e);if(r.callback){var s=t&&r.callback(undefined,t);if(i!=="global"&&s!==undefined)return s;if(i!=="local")return r.callback();return}var s=i!=="global"&&t&&t.state.vim.options[e];return(s||i!=="local"&&r||{}).value}function et(){this.latestRegister=undefined,this.isPlaying=!1,this.isRecording=!1,this.replaySearchQueries=[],this.onRecordingDone=undefined,this.lastInsertModeChanges=Z()}function tt(e){return e.state.vim||(e.state.vim={inputState:new ot,lastEditInputState:undefined,lastEditActionCommand:undefined,lastHPos:-1,lastHSPos:-1,lastMotion:null,marks:{},fakeCursor:null,insertMode:!1,insertModeRepeat:undefined,visualMode:!1,visualLine:!1,visualBlock:!1,lastSelection:null,lastPastedText:null,sel:{},options:{}}),e.state.vim}function rt(){nt={searchQuery:null,searchIsReversed:!1,lastSubstituteReplacePart:undefined,jumpList:Y(),macroModeState:new et,lastChararacterSearch:{increment:0,forward:!0,selectedCharacter:""},registerController:new lt({}),searchHistoryController:new ct({}),exCommandHistoryController:new ct({})};for(var e in J){var t=J[e];t.value=t.defaultValue}}function ot(){this.prefixRepeat=[],this.motionRepeat=[],this.operator=null,this.operatorArgs=null,this.motion=null,this.motionArgs=null,this.keyBuffer=[],this.registerName=null}function ut(e,t){e.state.vim.inputState=new ot,v.signal(e,"vim-command-done",t)}function at(e,t,n){this.clear(),this.keyBuffer=[e||""],this.insertModeChanges=[],this.searchQueries=[],this.linewise=!!t,this.blockwise=!!n}function ft(e,t){var n=nt.registerController.registers[e];if(!e||e.length!=1)throw Error("Register name must be 1 character");n[e]=t,q.push(e)}function lt(e){this.registers=e,this.unnamedRegister=e['"']=new at,e["."]=new at,e[":"]=new at,e["/"]=new at}function ct(){this.historyBuffer=[],this.iterator,this.initialPrefix=null}function dt(e,t){pt[e]=t}function vt(e,t){var n=[];for(var r=0;r<t;r++)n.push(e);return n}function gt(e,t){mt[e]=t}function bt(e,t){yt[e]=t}function wt(e,t,n){var r=Math.min(Math.max(e.firstLine(),t.line),e.lastLine()),i=Pt(e,r)-1;i=n?i+1:i;var s=Math.min(Math.max(0,t.ch),i);return E(r,s)}function Et(e){var t={};for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}function St(e,t,n){return typeof t=="object"&&(n=t.ch,t=t.line),E(e.line+t,e.ch+n)}function xt(e,t){return{line:t.line-e.line,ch:t.line-e.line}}function Tt(e,t,n,r){var i,s=[],o=[];for(var u=0;u<t.length;u++){var a=t[u];if(n=="insert"&&a.context!="insert"||a.context&&a.context!=n||r.operator&&a.type=="action"||!(i=Nt(e,a.keys)))continue;i=="partial"&&s.push(a),i=="full"&&o.push(a)}return{partial:s.length&&s,full:o.length&&o}}function Nt(e,t){if(t.slice(-11)=="<character>"){var n=t.length-11,r=e.slice(0,n),i=t.slice(0,n);return r==i&&e.length>n?"full":i.indexOf(r)==0?"partial":!1}return e==t?"full":t.indexOf(e)==0?"partial":!1}function Ct(e){var t=/^.*(<[\w\-]+>)$/.exec(e),n=t?t[1]:e.slice(-1);if(n.length>1)switch(n){case"<CR>":n="\n";break;case"<Space>":n=" ";break;default:}return n}function kt(e,t,n){return function(){for(var r=0;r<n;r++)t(e)}}function Lt(e){return E(e.line,e.ch)}function At(e,t){return e.ch==t.ch&&e.line==t.line}function Ot(e,t){return e.line<t.line?!0:e.line==t.line&&e.ch<t.ch?!0:!1}function Mt(e,t){return arguments.length>2&&(t=Mt.apply(undefined,Array.prototype.slice.call(arguments,1))),Ot(e,t)?e:t}function _t(e,t){return arguments.length>2&&(t=_t.apply(undefined,Array.prototype.slice.call(arguments,1))),Ot(e,t)?t:e}function Dt(e,t,n){var r=Ot(e,t),i=Ot(t,n);return r&&i}function Pt(e,t){return e.getLine(t).length}function Ht(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}function Bt(e){return e.replace(/([.?*+$\[\]\/\\(){}|\-])/g,"\\$1")}function jt(e,t,n){var r=Pt(e,t),i=(new Array(n-r+1)).join(" ");e.setCursor(E(t,r)),e.replaceRange(i,e.getCursor())}function Ft(e,t){var n=[],r=e.listSelections(),i=Lt(e.clipPos(t)),s=!At(t,i),o=e.getCursor("head"),u=qt(r,o),a=At(r[u].head,r[u].anchor),f=r.length-1,l=f-u>u?f:0,c=r[l].anchor,h=Math.min(c.line,i.line),p=Math.max(c.line,i.line),d=c.ch,v=i.ch,m=r[l].head.ch-d,g=v-d;m>0&&g<=0?(d++,s||v--):m<0&&g>=0?(d--,a||v++):m<0&&g==-1&&(d--,v++);for(var y=h;y<=p;y++){var b={anchor:new E(y,d),head:new E(y,v)};n.push(b)}return u=i.line==p?n.length-1:0,e.setSelections(n),t.ch=v,c.ch=d,c}function It(e,t,n){var r=[];for(var i=0;i<n;i++){var s=St(t,i,0);r.push({anchor:s,head:s})}e.setSelections(r,0)}function qt(e,t,n){for(var r=0;r<e.length;r++){var i=n!="head"&&At(e[r].anchor,t),s=n!="anchor"&&At(e[r].head,t);if(i||s)return r}return-1}function Rt(e,t){var n=t.lastSelection,r=function(){var t=e.listSelections(),n=t[0],r=t[t.length-1],i=Ot(n.anchor,n.head)?n.anchor:n.head,s=Ot(r.anchor,r.head)?r.head:r.anchor;return[i,s]},i=function(){var t=e.getCursor(),r=e.getCursor(),i=n.visualBlock;if(i){var s=i.width,o=i.height;r=E(t.line+o,t.ch+s);var u=[];for(var a=t.line;a<r.line;a++){var f=E(a,t.ch),l=E(a,r.ch),c={anchor:f,head:l};u.push(c)}e.setSelections(u)}else{var h=n.anchorMark.find(),p=n.headMark.find(),d=p.line-h.line,v=p.ch-h.ch;r={line:r.line+d,ch:d?r.ch:v+r.ch},n.visualLine&&(t=E(t.line,0),r=E(r.line,Pt(e,r.line))),e.setSelection(t,r)}return[t,r]};return t.visualMode?r():i()}function Ut(e,t){var n=t.sel.anchor,r=t.sel.head;t.lastPastedText&&(r=e.posFromIndex(e.indexFromPos(n)+t.lastPastedText.length),t.lastPastedText=null),t.lastSelection={anchorMark:e.setBookmark(n),headMark:e.setBookmark(r),anchor:Lt(n),head:Lt(r),visualMode:t.visualMode,visualLine:t.visualLine,visualBlock:t.visualBlock}}function zt(e,t,n){var r=e.state.vim.sel,i=r.head,s=r.anchor,o;return Ot(n,t)&&(o=n,n=t,t=o),Ot(i,s)?(i=Mt(t,i),s=_t(s,n)):(s=Mt(t,s),i=_t(i,n),i=St(i,0,-1),i.ch==-1&&i.line!=e.firstLine()&&(i=E(i.line-1,Pt(e,i.line-1)))),[s,i]}function Wt(e,t,n){var r=e.state.vim;t=t||r.sel;var n=n||r.visualLine?"line":r.visualBlock?"block":"char",i=Xt(e,t,n);e.setSelections(i.ranges,i.primary),Kn(e)}function Xt(e,t,n,r){var i=Lt(t.head),s=Lt(t.anchor);if(n=="char"){var o=!r&&!Ot(t.head,t.anchor)?1:0,u=Ot(t.head,t.anchor)?1:0;return i=St(t.head,0,o),s=St(t.anchor,0,u),{ranges:[{anchor:s,head:i}],primary:0}}if(n=="line"){if(!Ot(t.head,t.anchor)){s.ch=0;var a=e.lastLine();i.line>a&&(i.line=a),i.ch=Pt(e,i.line)}else i.ch=0,s.ch=Pt(e,s.line);return{ranges:[{anchor:s,head:i}],primary:0}}if(n=="block"){var f=Math.min(s.line,i.line),l=Math.min(s.ch,i.ch),c=Math.max(s.line,i.line),h=Math.max(s.ch,i.ch)+1,p=c-f+1,d=i.line==f?0:p-1,v=[];for(var m=0;m<p;m++)v.push({anchor:E(f+m,l),head:E(f+m,h)});return{ranges:v,primary:d}}}function Vt(e){var t=e.getCursor("head");return e.getSelection().length==1&&(t=Mt(t,e.getCursor("anchor"))),t}function $t(e,t){var n=e.state.vim;t!==!1&&e.setCursor(wt(e,n.sel.head)),Ut(e,n),n.visualMode=!1,n.visualLine=!1,n.visualBlock=!1,v.signal(e,"vim-mode-change",{mode:"normal"}),n.fakeCursor&&n.fakeCursor.clear()}function Jt(e,t,n){var r=e.getRange(t,n);if(/\n\s*$/.test(r)){var i=r.split("\n");i.pop();var s;for(var s=i.pop();i.length>0&&s&&V(s);s=i.pop())n.line--,n.ch=0;s?(n.line--,n.ch=Pt(e,n.line)):n.ch=0}}function Kt(e,t,n){t.ch=0,n.ch=0,n.line++}function Qt(e){if(!e)return 0;var t=e.search(/\S/);return t==-1?e.length:t}function Gt(e,t,n,r,i){var s=Vt(e),o=e.getLine(s.line),u=s.ch,a=i?D[0]:P[0];while(!a(o.charAt(u))){u++;if(u>=o.length)return null}r?a=P[0]:(a=D[0],a(o.charAt(u))||(a=D[1]));var f=u,l=u;while(a(o.charAt(f))&&f<o.length)f++;while(a(o.charAt(l))&&l>=0)l--;l++;if(t){var c=f;while(/\s/.test(o.charAt(f))&&f<o.length)f++;if(c==f){var h=l;while(/\s/.test(o.charAt(l-1))&&l>0)l--;l||(l=h)}}return{start:E(s.line,l),end:E(s.line,f)}}function Yt(e,t,n){At(t,n)||nt.jumpList.add(e,t,n)}function Zt(e,t){nt.lastChararacterSearch.increment=e,nt.lastChararacterSearch.forward=t.forward,nt.lastChararacterSearch.selectedCharacter=t.selectedCharacter}function nn(e,t,n,r){var i=Lt(e.getCursor()),s=n?1:-1,o=n?e.lineCount():-1,u=i.ch,a=i.line,f=e.getLine(a),l={lineText:f,nextCh:f.charAt(u),lastCh:null,index:u,symb:r,reverseSymb:(n?{")":"(","}":"{"}:{"(":")","{":"}"})[r],forward:n,depth:0,curMoveThrough:!1},c=en[r];if(!c)return i;var h=tn[c].init,p=tn[c].isComplete;h&&h(l);while(a!==o&&t){l.index+=s,l.nextCh=l.lineText.charAt(l.index);if(!l.nextCh){a+=s,l.lineText=e.getLine(a)||"";if(s>0)l.index=0;else{var d=l.lineText.length;l.index=d>0?d-1:0}l.nextCh=l.lineText.charAt(l.index)}p(l)&&(i.line=a,i.ch=l.index,t--)}return l.nextCh||l.curMoveThrough?E(a,l.index):i}function rn(e,t,n,r,i){var s=t.line,o=t.ch,u=e.getLine(s),a=n?1:-1,f=r?P:D;if(i&&u==""){s+=a,u=e.getLine(s);if(!R(e,s))return null;o=n?0:u.length}for(;;){if(i&&u=="")return{from:0,to:0,line:s};var l=a>0?u.length:-1,c=l,h=l;while(o!=l){var p=!1;for(var d=0;d<f.length&&!p;++d)if(f[d](u.charAt(o))){c=o;while(o!=l&&f[d](u.charAt(o)))o+=a;h=o,p=c!=h;if(c==t.ch&&s==t.line&&h==c+a)continue;return{from:Math.min(c,h+1),to:Math.max(c,h),line:s}}p||(o+=a)}s+=a;if(!R(e,s))return null;u=e.getLine(s),o=a>0?0:u.length}throw new Error("The impossible happened.")}function sn(e,t,n,r,i,s){var o=Lt(t),u=[];(r&&!i||!r&&i)&&n++;var a=!r||!i;for(var f=0;f<n;f++){var l=rn(e,t,r,s,a);if(!l){var c=Pt(e,e.lastLine());u.push(r?{line:e.lastLine(),from:c,to:c}:{line:0,from:0,to:0});break}u.push(l),t=E(l.line,r?l.to-1:l.from)}var h=u.length!=n,p=u[0],d=u.pop();return r&&!i?(!h&&(p.from!=o.ch||p.line!=o.line)&&(d=u.pop()),E(d.line,d.from)):r&&i?E(d.line,d.to-1):!r&&i?(!h&&(p.to!=o.ch||p.line!=o.line)&&(d=u.pop()),E(d.line,d.to)):E(d.line,d.from)}function on(e,t,n,r){var i=e.getCursor(),s=i.ch,o;for(var u=0;u<t;u++){var a=e.getLine(i.line);o=fn(s,a,r,n,!0);if(o==-1)return null;s=o}return E(e.getCursor().line,o)}function un(e,t){var n=e.getCursor().line;return wt(e,E(n,t-1))}function an(e,t,n,r){if(!$(n,I))return;t.marks[n]&&t.marks[n].clear(),t.marks[n]=e.setBookmark(r)}function fn(e,t,n,r,i){var s;return r?(s=t.indexOf(n,e+1),s!=-1&&!i&&(s-=1)):(s=t.lastIndexOf(n,e-1),s!=-1&&!i&&(s+=1)),s}function ln(e,t,n,r,i){function c(t){return!/\S/.test(e.getLine(t))}function h(e,t,n){return n?c(e)!=c(e+t):!c(e)&&c(e+t)}function p(t){r=r>0?1:-1;var n=e.ace.session.getFoldLine(t);n&&t+r>n.start.row&&t+r<n.end.row&&(r=(r>0?n.end.row:n.start.row)-t)}var s=t.line,o=e.firstLine(),u=e.lastLine(),a,f,l=s;if(r){while(o<=l&&l<=u&&n>0)p(l),h(l,r)&&n--,l+=r;return new E(l,0)}var d=e.state.vim;if(d.visualLine&&h(s,1,!0)){var v=d.sel.anchor;h(v.line,-1,!0)&&(!i||v.line!=s)&&(s+=1)}var m=c(s);for(l=s;l<=u&&n;l++)h(l,1,!0)&&(!i||c(l)!=m)&&n--;f=new E(l,0),l>u&&!m?m=!0:i=!1;for(l=s;l>o;l--)if(!i||c(l)==m||l==s)if(h(l,-1,!0))break;return a=new E(l,0),{start:a,end:f}}function cn(e,t,n,r){var i=t,s,o,u={"(":/[()]/,")":/[()]/,"[":/[[\]]/,"]":/[[\]]/,"{":/[{}]/,"}":/[{}]/}[n],a={"(":"(",")":"(","[":"[","]":"[","{":"{","}":"{"}[n],f=e.getLine(i.line).charAt(i.ch),l=f===a?1:0;s=e.scanForBracket(E(i.line,i.ch+l),-1,null,{bracketRegex:u}),o=e.scanForBracket(E(i.line,i.ch+l),1,null,{bracketRegex:u});if(!s||!o)return{start:i,end:i};s=s.pos,o=o.pos;if(s.line==o.line&&s.ch>o.ch||s.line>o.line){var c=s;s=o,o=c}return r?o.ch+=1:s.ch+=1,{start:s,end:o}}function hn(e,t,n,r){var i=Lt(t),s=e.getLine(i.line),o=s.split(""),u,a,f,l,c=o.indexOf(n);i.ch<c?i.ch=c:c<i.ch&&o[i.ch]==n&&(a=i.ch,--i.ch);if(o[i.ch]==n&&!a)u=i.ch+1;else for(f=i.ch;f>-1&&!u;f--)o[f]==n&&(u=f+1);if(u&&!a)for(f=u,l=o.length;f<l&&!a;f++)o[f]==n&&(a=f);return!u||!a?{start:i,end:i}:(r&&(--u,++a),{start:E(i.line,u),end:E(i.line,a)})}function pn(){}function dn(e){var t=e.state.vim;return t.searchState_||(t.searchState_=new pn)}function vn(e,t,n,r,i){e.openDialog?e.openDialog(t,r,{bottom:!0,value:i.value,onKeyDown:i.onKeyDown,onKeyUp:i.onKeyUp,selectValueOnOpen:!1}):r(prompt(n,""))}function mn(e){var t=gn(e)||[];if(!t.length)return[];var n=[];if(t[0]!==0)return;for(var r=0;r<t.length;r++)typeof t[r]=="number"&&n.push(e.substring(t[r]+1,t[r+1]));return n}function gn(e){var t=!1,n=[];for(var r=0;r<e.length;r++){var i=e.charAt(r);!t&&i=="/"&&n.push(r),t=!t&&i=="\\"}return n}function yn(e){var t="|(){",n="}",r=!1,i=[];for(var s=-1;s<e.length;s++){var o=e.charAt(s)||"",u=e.charAt(s+1)||"",a=u&&t.indexOf(u)!=-1;r?((o!=="\\"||!a)&&i.push(o),r=!1):o==="\\"?(r=!0,u&&n.indexOf(u)!=-1&&(a=!0),(!a||u==="\\")&&i.push(o)):(i.push(o),a&&u!=="\\"&&i.push("\\"))}return i.join("")}function wn(e){var t=!1,n=[];for(var r=-1;r<e.length;r++){var i=e.charAt(r)||"",s=e.charAt(r+1)||"";bn[i+s]?(n.push(bn[i+s]),r++):t?(n.push(i),t=!1):i==="\\"?(t=!0,W(s)||s==="$"?n.push("$"):s!=="/"&&s!=="\\"&&n.push("\\")):(i==="$"&&n.push("$"),n.push(i),s==="/"&&n.push("\\"))}return n.join("")}function Sn(e){var t=new v.StringStream(e),n=[];while(!t.eol()){while(t.peek()&&t.peek()!="\\")n.push(t.next());var r=!1;for(var i in En)if(t.match(i,!0)){r=!0,n.push(En[i]);break}r||n.push(t.next())}return n.join("")}function xn(e,t,n){var r=nt.registerController.getRegister("/");r.setText(e);if(e instanceof RegExp)return e;var i=gn(e),s,o;if(!i.length)s=e;else{s=e.substring(0,i[0]);var u=e.substring(i[0]);o=u.indexOf("i")!=-1}if(!s)return null;G("pcre")||(s=yn(s)),n&&(t=/^[^A-Z]*$/.test(s));var a=new RegExp(s,t||o?"i":undefined);return a}function Tn(e,t){e.openNotification?e.openNotification('<span style="color: red">'+t+"</span>",{bottom:!0,duration:5e3}):alert(t)}function Nn(e,t){var n="";return e&&(n+='<span style="font-family: monospace">'+e+"</span>"),n+='<input type="text"/> <span style="color: #888">',t&&(n+='<span style="color: #888">',n+=t,n+="</span>"),n}function kn(e,t){var n=(t.prefix||"")+" "+(t.desc||""),r=Nn(t.prefix,t.desc);vn(e,r,n,t.onClose,t)}function Ln(e,t){if(e instanceof RegExp&&t instanceof RegExp){var n=["global","multiline","ignoreCase","source"];for(var r=0;r<n.length;r++){var i=n[r];if(e[i]!==t[i])return!1}return!0}return!1}function An(e,t,n,r){if(!t)return;var i=dn(e),s=xn(t,!!n,!!r);if(!s)return;return Mn(e,s),Ln(s,i.getQuery())?s:(i.setQuery(s),s)}function On(e){if(e.source.charAt(0)=="^")var t=!0;return{token:function(n){if(t&&!n.sol()){n.skipToEnd();return}var r=n.match(e,!1);if(r){if(r[0].length==0)return n.next(),"searching";if(!n.sol()){n.backUp(1);if(!e.exec(n.next()+r[0]))return n.next(),null}return n.match(e),"searching"}while(!n.eol()){n.next();if(n.match(e,!1))break}},query:e}}function Mn(e,t){var n=dn(e),r=n.getOverlay();if(!r||t!=r.query)r&&e.removeOverlay(r),r=On(t),e.addOverlay(r),e.showMatchesOnScrollbar&&(n.getScrollbarAnnotate()&&n.getScrollbarAnnotate().clear(),n.setScrollbarAnnotate(e.showMatchesOnScrollbar(t))),n.setOverlay(r)}function _n(e,t,n,r){return r===undefined&&(r=1),e.operation(function(){var i=e.getCursor(),s=e.getSearchCursor(n,i);for(var o=0;o<r;o++){var u=s.find(t);o==0&&u&&At(s.from(),i)&&(u=s.find(t));if(!u){s=e.getSearchCursor(n,t?E(e.lastLine()):E(e.firstLine(),0));if(!s.find(t))return}}return s.from()})}function Dn(e){var t=dn(e);e.removeOverlay(dn(e).getOverlay()),t.setOverlay(null),t.getScrollbarAnnotate()&&(t.getScrollbarAnnotate().clear(),t.setScrollbarAnnotate(null))}function Pn(e,t,n){return typeof e!="number"&&(e=e.line),t instanceof Array?$(e,t):n?e>=t&&e<=n:e==t}function Hn(e){var t=e.ace.renderer;return{top:t.getFirstFullyVisibleRow(),bottom:t.getLastFullyVisibleRow()}}function In(e,t,n,r,i,s,o,u,a){function c(){e.operation(function(){while(!f)h(),p();d()})}function h(){var t=e.getRange(s.from(),s.to()),n=t.replace(o,u);s.replace(n)}function p(){while(s.findNext()&&Pn(s.from(),r,i)){if(!n&&l&&s.from().line==l.line)continue;e.scrollIntoView(s.from(),30),e.setSelection(s.from(),s.to()),l=s.from(),f=!1;return}f=!0}function d(t){t&&t(),e.focus();if(l){e.setCursor(l);var n=e.state.vim;n.exMode=!1,n.lastHPos=n.lastHSPos=l.ch}a&&a()}function m(t,n,r){v.e_stop(t);var i=v.keyName(t);switch(i){case"Y":h(),p();break;case"N":p();break;case"A":var s=a;a=undefined,e.operation(c),a=s;break;case"L":h();case"Q":case"Esc":case"Ctrl-C":case"Ctrl-[":d(r)}return f&&d(r),!0}e.state.vim.exMode=!0;var f=!1,l=s.from();p();if(f){Tn(e,"No matches for "+o.source);return}if(!t){c(),a&&a();return}kn(e,{prefix:"replace with <strong>"+u+"</strong> (y/n/a/q/l)",onKeyDown:m})}function qn(e){var t=e.state.vim,n=nt.macroModeState,r=nt.registerController.getRegister("."),i=n.isPlaying,s=n.lastInsertModeChanges,o=[];if(!i){var u=s.inVisualBlock?t.lastSelection.visualBlock.height:1,a=s.changes,o=[],f=0;while(f<a.length)o.push(a[f]),a[f]instanceof Gn?f++:f+=u;s.changes=o,e.off("change",$n),v.off(e.getInputField(),"keydown",Yn)}!i&&t.insertModeRepeat>1&&(Zn(e,t,t.insertModeRepeat-1,!0),t.lastEditInputState.repeatOverride=t.insertModeRepeat),delete t.insertModeRepeat,t.insertMode=!1,e.setCursor(e.getCursor().line,e.getCursor().ch-1),e.setOption("keyMap","vim"),e.setOption("disableInput",!0),e.toggleOverwrite(!1),r.setText(s.changes.join("")),v.signal(e,"vim-mode-change",{mode:"normal"}),n.isRecording&&Xn(n)}function Rn(e){b.unshift(e)}function Un(e,t,n,r,i){var s={keys:e,type:t};s[t]=n,s[t+"Args"]=r;for(var o in i)s[o]=i[o];Rn(s)}function zn(e,t,n,r){var i=nt.registerController.getRegister(r);if(r==":"){i.keyBuffer[0]&&Fn.processCommand(e,i.keyBuffer[0]),n.isPlaying=!1;return}var s=i.keyBuffer,o=0;n.isPlaying=!0,n.replaySearchQueries=i.searchQueries.slice(0);for(var u=0;u<s.length;u++){var a=s[u],f,l;while(a){f=/<\w+-.+?>|<\w+>|./.exec(a),l=f[0],a=a.substring(f.index+l.length),v.Vim.handleKey(e,l,"macro");if(t.insertMode){var c=i.insertModeChanges[o++].changes;nt.macroModeState.lastInsertModeChanges.changes=c,er(e,c,1),qn(e)}}}n.isPlaying=!1}function Wn(e,t){if(e.isPlaying)return;var n=e.latestRegister,r=nt.registerController.getRegister(n);r&&r.pushText(t)}function Xn(e){if(e.isPlaying)return;var t=e.latestRegister,n=nt.registerController.getRegister(t);n&&n.pushInsertModeChanges&&n.pushInsertModeChanges(e.lastInsertModeChanges)}function Vn(e,t){if(e.isPlaying)return;var n=e.latestRegister,r=nt.registerController.getRegister(n);r&&r.pushSearchQuery&&r.pushSearchQuery(t)}function $n(e,t){var n=nt.macroModeState,r=n.lastInsertModeChanges;if(!n.isPlaying)while(t){r.expectCursorActivityForChange=!0;if(t.origin=="+input"||t.origin=="paste"||t.origin===undefined){var i=t.text.join("\n");r.changes.push(i)}t=t.next}}function Jn(e){var t=e.state.vim;if(t.insertMode){var n=nt.macroModeState;if(n.isPlaying)return;var r=n.lastInsertModeChanges;r.expectCursorActivityForChange?r.expectCursorActivityForChange=!1:r.changes=[]}else e.curOp.isVimOp||Qn(e,t);t.visualMode&&Kn(e)}function Kn(e){var t=e.state.vim,n=wt(e,Lt(t.sel.head)),r=St(n,0,1);t.fakeCursor&&t.fakeCursor.clear(),t.fakeCursor=e.markText(n,r,{className:"cm-animate-fat-cursor"})}function Qn(e,t){var n=e.getCursor("anchor"),r=e.getCursor("head");t.visualMode&&!e.somethingSelected()?$t(e,!1):!t.visualMode&&!t.insertMode&&e.somethingSelected()&&(t.visualMode=!0,t.visualLine=!1,v.signal(e,"vim-mode-change",{mode:"visual"}));if(t.visualMode){var i=Ot(r,n)?0:-1,s=Ot(r,n)?-1:0;r=St(r,0,i),n=St(n,0,s),t.sel={anchor:n,head:r},an(e,t,"<",Mt(r,n)),an(e,t,">",_t(r,n))}else t.insertMode||(t.lastHPos=e.getCursor().ch)}function Gn(e){this.keyName=e}function Yn(e){function i(){return n.changes.push(new Gn(r)),!0}var t=nt.macroModeState,n=t.lastInsertModeChanges,r=v.keyName(e);if(!r)return;(r.indexOf("Delete")!=-1||r.indexOf("Backspace")!=-1)&&v.lookupKey(r,"vim-insert",i)}function Zn(e,t,n,r){function u(){s?ht.processAction(e,t,t.lastEditActionCommand):ht.evalInput(e,t)}function a(n){if(i.lastInsertModeChanges.changes.length>0){n=t.lastEditActionCommand?n:1;var r=i.lastInsertModeChanges;er(e,r.changes,n)}}var i=nt.macroModeState;i.isPlaying=!0;var s=!!t.lastEditActionCommand,o=t.inputState;t.inputState=t.lastEditInputState;if(s&&t.lastEditActionCommand.interlaceInsertRepeat)for(var f=0;f<n;f++)u(),a(1);else r||u(),a(n);t.inputState=o,t.insertMode&&!r&&qn(e),i.isPlaying=!1}function er(e,t,n){function r(t){return typeof t=="string"?v.commands[t](e):t(e),!0}var i=e.getCursor("head"),s=nt.macroModeState.lastInsertModeChanges.inVisualBlock;if(s){var o=e.state.vim,u=o.lastSelection,a=xt(u.anchor,u.head);It(e,i,a.line+1),n=e.listSelections().length,e.setCursor(i)}for(var f=0;f<n;f++){s&&e.setCursor(St(i,f,0));for(var l=0;l<t.length;l++){var c=t[l];if(c instanceof Gn)v.lookupKey(c.keyName,"vim-insert",r);else{var h=e.getCursor();e.replaceRange(c,h,h)}}}s&&e.setCursor(St(i,0,1))}function nr(e,t,n){t.length>1&&t[0]=="n"&&(t=t.replace("numpad","")),t=tr[t]||t;var r="";return n.ctrlKey&&(r+="C-"),n.altKey&&(r+="A-"),n.shiftKey&&(r+="S-"),r+=t,r.length>1&&(r="<"+r+">"),r}function ir(e){var t=new e.constructor;return Object.keys(e).forEach(function(n){var r=e[n];Array.isArray(r)?r=r.slice():r&&typeof r=="object"&&r.constructor!=Object&&(r=ir(r)),t[n]=r}),e.sel&&(t.sel={head:e.sel.head&&Lt(e.sel.head),anchor:e.sel.anchor&&Lt(e.sel.anchor)}),t}function sr(e,t,n){var r=!1,i=S.maybeInitVimState_(e),s=i.visualBlock||i.wasInVisualBlock;i.wasInVisualBlock&&!e.ace.inMultiSelectMode?i.wasInVisualBlock=!1:e.ace.inMultiSelectMode&&i.visualBlock&&(i.wasInVisualBlock=!0);if(t=="<Esc>"&&!i.insertMode&&!i.visualMode&&e.ace.inMultiSelectMode)e.ace.exitMultiSelectMode();else if(s||!e.ace.inMultiSelectMode||e.ace.inVirtualSelectionMode)r=S.handleKey(e,t,n);else{var o=ir(i);e.operation(function(){e.ace.forEachSelection(function(){var i=e.ace.selection;e.state.vim.lastHPos=i.$desiredColumn==null?i.lead.column:i.$desiredColumn;var s=e.getCursor("head"),u=e.getCursor("anchor"),a=Ot(s,u)?0:-1,f=Ot(s,u)?-1:0;s=St(s,0,a),u=St(u,0,f),e.state.vim.sel.head=s,e.state.vim.sel.anchor=u,r=rr(e,t,n),i.$desiredColumn=e.state.vim.lastHPos==-1?null:e.state.vim.lastHPos,e.virtualSelectionMode()&&(e.state.vim=ir(o))}),e.curOp.cursorActivity&&!r&&(e.curOp.cursorActivity=!1)},!0)}return r}function ar(e,t){t.off("beforeEndOperation",ar);var n=t.state.cm.vimCmd;n&&t.execCommand(n.exec?n:n.name,n.args),t.curOp=t.prevOp}var i=e("../range").Range,s=e("../lib/event_emitter").EventEmitter,o=e("../lib/dom"),u=e("../lib/oop"),a=e("../lib/keys"),f=e("../lib/event"),l=e("../search").Search,c=e("../lib/useragent"),h=e("../search_highlight").SearchHighlight,p=e("../commands/multi_select_commands"),d=e("../mode/text").Mode.prototype.tokenRe;e("../multi_select");var v=function(e){this.ace=e,this.state={},this.marks={},this.$uid=0,this.onChange=this.onChange.bind(this),this.onSelectionChange=this.onSelectionChange.bind(this),this.onBeforeEndOperation=this.onBeforeEndOperation.bind(this),this.ace.on("change",this.onChange),this.ace.on("changeSelection",this.onSelectionChange),this.ace.on("beforeEndOperation",this.onBeforeEndOperation)};v.Pos=function(e,t){if(!(this instanceof E))return new E(e,t);this.line=e,this.ch=t},v.defineOption=function(e,t,n){},v.commands={redo:function(e){e.ace.redo()},undo:function(e){e.ace.undo()},newlineAndIndent:function(e){e.ace.insert("\n")}},v.keyMap={},v.addClass=v.rmClass=v.e_stop=function(){},v.keyName=function(e){if(e.key)return e.key;var t=a[e.keyCode]||"";return t.length==1&&(t=t.toUpperCase()),t=f.getModifierString(e).replace(/(^|-)\w/g,function(e){return e.toUpperCase()})+t,t},v.keyMap["default"]=function(e){return function(t){var n=t.ace.commands.commandKeyBinding[e.toLowerCase()];return n&&t.ace.execCommand(n)!==!1}},v.lookupKey=function fr(e,t,n){typeof t=="string"&&(t=v.keyMap[t]);var r=typeof t=="function"?t(e):t[e];if(r===!1)return"nothing";if(r==="...")return"multi";if(r!=null&&n(r))return"handled";if(t.fallthrough){if(!Array.isArray(t.fallthrough))return fr(e,t.fallthrough,n);for(var i=0;i<t.fallthrough.length;i++){var s=fr(e,t.fallthrough[i],n);if(s)return s}}},v.signal=function(e,t,n){return e._signal(t,n)},v.on=f.addListener,v.off=f.removeListener,v.isWordChar=function(e){return e<""?/^\w$/.test(e):(d.lastIndex=0,d.test(e))},function(){u.implement(v.prototype,s),this.destroy=function(){this.ace.off("change",this.onChange),this.ace.off("changeSelection",this.onSelectionChange),this.ace.off("beforeEndOperation",this.onBeforeEndOperation),this.removeOverlay()},this.virtualSelectionMode=function(){return this.ace.inVirtualSelectionMode&&this.ace.selection.index},this.onChange=function(e){if(e.action[0]=="i"){var t={text:e.lines},n=this.curOp=this.curOp||{};n.changeHandlers||(n.changeHandlers=this._eventRegistry.change&&this._eventRegistry.change.slice());if(this.virtualSelectionMode())return;n.lastChange?n.lastChange.next=n.lastChange=t:n.lastChange=n.change=t}this.$updateMarkers(e)},this.onSelectionChange=function(){var e=this.curOp=this.curOp||{};e.cursorActivityHandlers||(e.cursorActivityHandlers=this._eventRegistry.cursorActivity&&this._eventRegistry.cursorActivity.slice()),this.curOp.cursorActivity=!0,this.ace.inMultiSelectMode&&this.ace.keyBinding.removeKeyboardHandler(p.keyboardHandler)},this.operation=function(e,t){if(!t&&this.curOp||t&&this.curOp&&this.curOp.force)return e();(t||!this.ace.curOp)&&this.curOp&&this.onBeforeEndOperation();if(!this.ace.curOp){var n=this.ace.prevOp;this.ace.startOperation({command:{name:"vim",scrollIntoView:"cursor"}})}var r=this.curOp=this.curOp||{};this.curOp.force=t;var i=e();return this.ace.curOp&&this.ace.curOp.command.name=="vim"&&(this.ace.endOperation(),!r.cursorActivity&&!r.lastChange&&n&&(this.ace.prevOp=n)),(t||!this.ace.curOp)&&this.curOp&&this.onBeforeEndOperation(),i},this.onBeforeEndOperation=function(){var e=this.curOp;e&&(e.change&&this.signal("change",e.change,e),e&&e.cursorActivity&&this.signal("cursorActivity",null,e),this.curOp=null)},this.signal=function(e,t,n){var r=n?n[e+"Handlers"]:(this._eventRegistry||{})[e];if(!r)return;r=r.slice();for(var i=0;i<r.length;i++)r[i](this,t)},this.firstLine=function(){return 0},this.lastLine=function(){return this.ace.session.getLength()-1},this.lineCount=function(){return this.ace.session.getLength()},this.setCursor=function(e,t){typeof e=="object"&&(t=e.ch,e=e.line),this.ace.inVirtualSelectionMode||this.ace.exitMultiSelectMode(),this.ace.session.unfold({row:e,column:t}),this.ace.selection.moveTo(e,t)},this.getCursor=function(e){var t=this.ace.selection,n=e=="anchor"?t.isEmpty()?t.lead:t.anchor:e=="head"||!e?t.lead:t.getRange()[e];return g(n)},this.listSelections=function(e){var t=this.ace.multiSelect.rangeList.ranges;return!t.length||this.ace.inVirtualSelectionMode?[{anchor:this.getCursor("anchor"),head:this.getCursor("head")}]:t.map(function(e){return{anchor:this.clipPos(g(e.cursor==e.end?e.start:e.end)),head:this.clipPos(g(e.cursor))}},this)},this.setSelections=function(e,t){var n=this.ace.multiSelect,r=e.map(function(e){var t=m(e.anchor),n=m(e.head),r=i.comparePoints(t,n)<0?new i.fromPoints(t,n):new i.fromPoints(n,t);return r.cursor=i.comparePoints(r.start,n)?r.end:r.start,r});if(this.ace.inVirtualSelectionMode){this.ace.selection.fromOrientedRange(r[0]);return}t?r[t]&&r.push(r.splice(t,1)[0]):r=r.reverse(),n.toSingleRange(r[0].clone());var s=this.ace.session;for(var o=0;o<r.length;o++){var u=s.$clipRangeToDocument(r[o]);n.addRange(u)}},this.setSelection=function(e,t,n){var r=this.ace.selection;r.moveTo(e.line,e.ch),r.selectTo(t.line,t.ch),n&&n.origin=="*mouse"&&this.onBeforeEndOperation()},this.somethingSelected=function(e){return!this.ace.selection.isEmpty()},this.clipPos=function(e){var t=this.ace.session.$clipPositionToDocument(e.line,e.ch);return g(t)},this.markText=function(e){return{clear:function(){},find:function(){}}},this.$updateMarkers=function(e){var t=e.action=="insert",n=e.start,r=e.end,s=(r.row-n.row)*(t?1:-1),o=(r.column-n.column)*(t?1:-1);t&&(r=n);for(var u in this.marks){var a=this.marks[u],f=i.comparePoints(a,n);if(f<0)continue;if(f===0&&t){if(a.bias!=1){a.bias==-1;continue}f=1}var l=t?f:i.comparePoints(a,r);if(l>0){a.row+=s,a.column+=a.row==r.row?o:0;continue}!t&&l<=0&&(a.row=n.row,a.column=n.column,l===0&&(a.bias=1))}};var e=function(e,t,n,r){this.cm=e,this.id=t,this.row=n,this.column=r,e.marks[this.id]=this};e.prototype.clear=function(){delete this.cm.marks[this.id]},e.prototype.find=function(){return g(this)},this.setBookmark=function(t,n){var r=new e(this,this.$uid++,t.line,t.ch);if(!n||!n.insertLeft)r.$insertRight=!0;return this.marks[r.id]=r,r},this.moveH=function(e,t){if(t=="char"){var n=this.ace.selection;n.clearSelection(),n.moveCursorBy(0,e)}},this.findPosV=function(e,t,n,r){if(n=="page"){var i=this.ace.renderer,s=i.layerConfig;t*=Math.floor(s.height/s.lineHeight),n="line"}if(n=="line"){var o=this.ace.session.documentToScreenPosition(e.line,e.ch);r!=null&&(o.column=r),o.row+=t,o.row=Math.min(Math.max(0,o.row),this.ace.session.getScreenLength()-1);var u=this.ace.session.screenToDocumentPosition(o.row,o.column);return g(u)}debugger},this.charCoords=function(e,t){if(t=="div"||!t){var n=this.ace.session.documentToScreenPosition(e.line,e.ch);return{left:n.column,top:n.row}}if(t=="local"){var r=this.ace.renderer,n=this.ace.session.documentToScreenPosition(e.line,e.ch),i=r.layerConfig.lineHeight,s=r.layerConfig.characterWidth,o=i*n.row;return{left:n.column*s,top:o,bottom:o+i}}},this.coordsChar=function(e,t){var n=this.ace.renderer;if(t=="local"){var r=Math.max(0,Math.floor(e.top/n.lineHeight)),i=Math.max(0,Math.floor(e.left/n.characterWidth)),s=n.session.screenToDocumentPosition(r,i);return g(s)}if(t=="div")throw"not implemented"},this.getSearchCursor=function(e,t,n){var r=!1,i=!1;e instanceof RegExp&&!e.global&&(r=!e.ignoreCase,e=e.source,i=!0);var s=new l;t.ch==undefined&&(t.ch=Number.MAX_VALUE);var o={row:t.line,column:t.ch},u=this,a=null;return{findNext:function(){return this.find(!1)},findPrevious:function(){return this.find(!0)},find:function(t){s.setOptions({needle:e,caseSensitive:r,wrap:!1,backwards:t,regExp:i,start:a||o});var n=s.find(u.ace.session);return n&&n.isEmpty()&&u.getLine(n.start.row).length==n.start.column&&(s.$options.start=n,n=s.find(u.ace.session)),a=n,a},from:function(){return a&&g(a.start)},to:function(){return a&&g(a.end)},replace:function(e){a&&(a.end=u.ace.session.doc.replace(a,e))}}},this.scrollTo=function(e,t){var n=this.ace.renderer,r=n.layerConfig,i=r.maxHeight;i-=(n.$size.scrollerHeight-n.lineHeight)*n.$scrollPastEnd,t!=null&&this.ace.session.setScrollTop(Math.max(0,Math.min(t,i))),e!=null&&this.ace.session.setScrollLeft(Math.max(0,Math.min(e,r.width)))},this.scrollInfo=function(){return 0},this.scrollIntoView=function(e,t){if(e){var n=this.ace.renderer,r={top:0,bottom:t};n.scrollCursorIntoView(m(e),n.lineHeight*2/n.$size.scrollerHeight,r)}},this.getLine=function(e){return this.ace.session.getLine(e)},this.getRange=function(e,t){return this.ace.session.getTextRange(new i(e.line,e.ch,t.line,t.ch))},this.replaceRange=function(e,t,n){return n||(n=t),this.ace.session.replace(new i(t.line,t.ch,n.line,n.ch),e)},this.replaceSelections=function(e){var t=this.ace.selection;if(this.ace.inVirtualSelectionMode){this.ace.session.replace(t.getRange(),e[0]||"");return}t.inVirtualSelectionMode=!0;var n=t.rangeList.ranges;n.length||(n=[this.ace.multiSelect.getRange()]);for(var r=n.length;r--;)this.ace.session.replace(n[r],e[r]||"");t.inVirtualSelectionMode=!1},this.getSelection=function(){return this.ace.getSelectedText()},this.getSelections=function(){return this.listSelections().map(function(e){return this.getRange(e.anchor,e.head)},this)},this.getInputField=function(){return this.ace.textInput.getElement()},this.getWrapperElement=function(){return this.ace.containter};var t={indentWithTabs:"useSoftTabs",indentUnit:"tabSize",tabSize:"tabSize",firstLineNumber:"firstLineNumber",readOnly:"readOnly"};this.setOption=function(e,n){this.state[e]=n;switch(e){case"indentWithTabs":e=t[e],n=!n;break;default:e=t[e]}e&&this.ace.setOption(e,n)},this.getOption=function(e,n){var r=t[e];r&&(n=this.ace.getOption(r));switch(e){case"indentWithTabs":return e=t[e],!n}return r?n:this.state[e]},this.toggleOverwrite=function(e){return this.state.overwrite=e,this.ace.setOverwrite(e)},this.addOverlay=function(e){if(!this.$searchHighlight||!this.$searchHighlight.session){var t=new h(null,"ace_highlight-marker","text"),n=this.ace.session.addDynamicMarker(t);t.id=n.id,t.session=this.ace.session,t.destroy=function(e){t.session.off("change",t.updateOnChange),t.session.off("changeEditor",t.destroy),t.session.removeMarker(t.id),t.session=null},t.updateOnChange=function(e){var n=e.start.row;n==e.end.row?t.cache[n]=undefined:t.cache.splice(n,t.cache.length)},t.session.on("changeEditor",t.destroy),t.session.on("change",t.updateOnChange)}var r=new RegExp(e.query.source,"gmi");this.$searchHighlight=e.highlight=t,this.$searchHighlight.setRegexp(r),this.ace.renderer.updateBackMarkers()},this.removeOverlay=function(e){this.$searchHighlight&&this.$searchHighlight.session&&this.$searchHighlight.destroy()},this.getScrollInfo=function(){var e=this.ace.renderer,t=e.layerConfig;return{left:e.scrollLeft,top:e.scrollTop,height:t.maxHeight,width:t.width,clientHeight:t.height,clientWidth:t.width}},this.getValue=function(){return this.ace.getValue()},this.setValue=function(e){return this.ace.setValue(e)},this.getTokenTypeAt=function(e){var t=this.ace.session.getTokenAt(e.line,e.ch);return t&&/comment|string/.test(t.type)?"string":""},this.findMatchingBracket=function(e){var t=this.ace.session.findMatchingBracket(m(e));return{to:t&&g(t)}},this.indentLine=function(e,t){t===!0?this.ace.session.indentRows(e,e,"	"):t===!1&&this.ace.session.outdentRows(new i(e,0,e,0))},this.indexFromPos=function(e){return this.ace.session.doc.positionToIndex(m(e))},this.posFromIndex=function(e){return g(this.ace.session.doc.indexToPosition(e))},this.focus=function(e){return this.ace.focus()},this.blur=function(e){return this.ace.blur()},this.defaultTextHeight=function(e){return this.ace.renderer.layerConfig.lineHeight},this.scanForBracket=function(e,t,n,r){var i=r.bracketRegex.source;if(t==1)var s=this.ace.session.$findClosingBracket(i.slice(1,2),m(e),/paren|text/);else var s=this.ace.session.$findOpeningBracket(i.slice(-2,-1),{row:e.line,column:e.ch+1},/paren|text/);return s&&{pos:g(s)}},this.refresh=function(){return this.ace.resize(!0)},this.getMode=function(){return{name:this.getOption("mode")}}}.call(v.prototype);var y=v.StringStream=function(e,t){this.pos=this.start=0,this.string=e,this.tabSize=t||8,this.lastColumnPos=this.lastColumnValue=0,this.lineStart=0};y.prototype={eol:function(){return this.pos>=this.string.length},sol:function(){return this.pos==this.lineStart},peek:function(){return this.string.charAt(this.pos)||undefined},next:function(){if(this.pos<this.string.length)return this.string.charAt(this.pos++)},eat:function(e){var t=this.string.charAt(this.pos);if(typeof e=="string")var n=t==e;else var n=t&&(e.test?e.test(t):e(t));if(n)return++this.pos,t},eatWhile:function(e){var t=this.pos;while(this.eat(e));return this.pos>t},eatSpace:function(){var e=this.pos;while(/[\s\u00a0]/.test(this.string.charAt(this.pos)))++this.pos;return this.pos>e},skipToEnd:function(){this.pos=this.string.length},skipTo:function(e){var t=this.string.indexOf(e,this.pos);if(t>-1)return this.pos=t,!0},backUp:function(e){this.pos-=e},column:function(){throw"not implemented"},indentation:function(){throw"not implemented"},match:function(e,t,n){if(typeof e!="string"){var s=this.string.slice(this.pos).match(e);return s&&s.index>0?null:(s&&t!==!1&&(this.pos+=s[0].length),s)}var r=function(e){return n?e.toLowerCase():e},i=this.string.substr(this.pos,e.length);if(r(i)==r(e))return t!==!1&&(this.pos+=e.length),!0},current:function(){return this.string.slice(this.start,this.pos)},hideFirstChars:function(e,t){this.lineStart+=e;try{return t()}finally{this.lineStart-=e}}},v.defineExtension=function(e,t){v.prototype[e]=t},o.importCssString(".normal-mode .ace_cursor{  border: 1px solid red;  background-color: red;  opacity: 0.5;}.normal-mode .ace_hidden-cursors .ace_cursor{  background-color: transparent;}.ace_dialog {  position: absolute;  left: 0; right: 0;  background: white;  z-index: 15;  padding: .1em .8em;  overflow: hidden;  color: #333;}.ace_dialog-top {  border-bottom: 1px solid #eee;  top: 0;}.ace_dialog-bottom {  border-top: 1px solid #eee;  bottom: 0;}.ace_dialog input {  border: none;  outline: none;  background: transparent;  width: 20em;  color: inherit;  font-family: monospace;}","vimMode"),function(){function e(e,t,n){var r=e.ace.container,i;return i=r.appendChild(document.createElement("div")),n?i.className="ace_dialog ace_dialog-bottom":i.className="ace_dialog ace_dialog-top",typeof t=="string"?i.innerHTML=t:i.appendChild(t),i}function t(e,t){e.state.currentNotificationClose&&e.state.currentNotificationClose(),e.state.currentNotificationClose=t}v.defineExtension("openDialog",function(n,r,i){function a(e){if(typeof e=="string")f.value=e;else{if(o)return;o=!0,s.parentNode.removeChild(s),u.focus(),i.onClose&&i.onClose(s)}}if(this.virtualSelectionMode())return;i||(i={}),t(this,null);var s=e(this,n,i.bottom),o=!1,u=this,f=s.getElementsByTagName("input")[0],l;if(f)i.value&&(f.value=i.value,i.select!==!1&&f.select()),i.onInput&&v.on(f,"input",function(e){i.onInput(e,f.value,a)}),i.onKeyUp&&v.on(f,"keyup",function(e){i.onKeyUp(e,f.value,a)}),v.on(f,"keydown",function(e){if(i&&i.onKeyDown&&i.onKeyDown(e,f.value,a))return;if(e.keyCode==27||i.closeOnEnter!==!1&&e.keyCode==13)f.blur(),v.e_stop(e),a();e.keyCode==13&&r(f.value)}),i.closeOnBlur!==!1&&v.on(f,"blur",a),f.focus();else if(l=s.getElementsByTagName("button")[0])v.on(l,"click",function(){a(),u.focus()}),i.closeOnBlur!==!1&&v.on(l,"blur",a),l.focus();return a}),v.defineExtension("openNotification",function(n,r){function a(){if(s)return;s=!0,clearTimeout(o),i.parentNode.removeChild(i)}if(this.virtualSelectionMode())return;t(this,a);var i=e(this,n,r&&r.bottom),s=!1,o,u=r&&typeof r.duration!="undefined"?r.duration:5e3;return v.on(i,"click",function(e){v.e_preventDefault(e),a()}),u&&(o=setTimeout(a,u)),a})}();var b=[{keys:"<Left>",type:"keyToKey",toKeys:"h"},{keys:"<Right>",type:"keyToKey",toKeys:"l"},{keys:"<Up>",type:"keyToKey",toKeys:"k"},{keys:"<Down>",type:"keyToKey",toKeys:"j"},{keys:"<Space>",type:"keyToKey",toKeys:"l"},{keys:"<BS>",type:"keyToKey",toKeys:"h",context:"normal"},{keys:"<C-Space>",type:"keyToKey",toKeys:"W"},{keys:"<C-BS>",type:"keyToKey",toKeys:"B",context:"normal"},{keys:"<S-Space>",type:"keyToKey",toKeys:"w"},{keys:"<S-BS>",type:"keyToKey",toKeys:"b",context:"normal"},{keys:"<C-n>",type:"keyToKey",toKeys:"j"},{keys:"<C-p>",type:"keyToKey",toKeys:"k"},{keys:"<C-[>",type:"keyToKey",toKeys:"<Esc>"},{keys:"<C-c>",type:"keyToKey",toKeys:"<Esc>"},{keys:"<C-[>",type:"keyToKey",toKeys:"<Esc>",context:"insert"},{keys:"<C-c>",type:"keyToKey",toKeys:"<Esc>",context:"insert"},{keys:"s",type:"keyToKey",toKeys:"cl",context:"normal"},{keys:"s",type:"keyToKey",toKeys:"xi",context:"visual"},{keys:"S",type:"keyToKey",toKeys:"cc",context:"normal"},{keys:"S",type:"keyToKey",toKeys:"dcc",context:"visual"},{keys:"<Home>",type:"keyToKey",toKeys:"0"},{keys:"<End>",type:"keyToKey",toKeys:"$"},{keys:"<PageUp>",type:"keyToKey",toKeys:"<C-b>"},{keys:"<PageDown>",type:"keyToKey",toKeys:"<C-f>"},{keys:"<CR>",type:"keyToKey",toKeys:"j^",context:"normal"},{keys:"H",type:"motion",motion:"moveToTopLine",motionArgs:{linewise:!0,toJumplist:!0}},{keys:"M",type:"motion",motion:"moveToMiddleLine",motionArgs:{linewise:!0,toJumplist:!0}},{keys:"L",type:"motion",motion:"moveToBottomLine",motionArgs:{linewise:!0,toJumplist:!0}},{keys:"h",type:"motion",motion:"moveByCharacters",motionArgs:{forward:!1}},{keys:"l",type:"motion",motion:"moveByCharacters",motionArgs:{forward:!0}},{keys:"j",type:"motion",motion:"moveByLines",motionArgs:{forward:!0,linewise:!0}},{keys:"k",type:"motion",motion:"moveByLines",motionArgs:{forward:!1,linewise:!0}},{keys:"gj",type:"motion",motion:"moveByDisplayLines",motionArgs:{forward:!0}},{keys:"gk",type:"motion",motion:"moveByDisplayLines",motionArgs:{forward:!1}},{keys:"w",type:"motion",motion:"moveByWords",motionArgs:{forward:!0,wordEnd:!1}},{keys:"W",type:"motion",motion:"moveByWords",motionArgs:{forward:!0,wordEnd:!1,bigWord:!0}},{keys:"e",type:"motion",motion:"moveByWords",motionArgs:{forward:!0,wordEnd:!0,inclusive:!0}},{keys:"E",type:"motion",motion:"moveByWords",motionArgs:{forward:!0,wordEnd:!0,bigWord:!0,inclusive:!0}},{keys:"b",type:"motion",motion:"moveByWords",motionArgs:{forward:!1,wordEnd:!1}},{keys:"B",type:"motion",motion:"moveByWords",motionArgs:{forward:!1,wordEnd:!1,bigWord:!0}},{keys:"ge",type:"motion",motion:"moveByWords",motionArgs:{forward:!1,wordEnd:!0,inclusive:!0}},{keys:"gE",type:"motion",motion:"moveByWords",motionArgs:{forward:!1,wordEnd:!0,bigWord:!0,inclusive:!0}},{keys:"{",type:"motion",motion:"moveByParagraph",motionArgs:{forward:!1,toJumplist:!0}},{keys:"}",type:"motion",motion:"moveByParagraph",motionArgs:{forward:!0,toJumplist:!0}},{keys:"<C-f>",type:"motion",motion:"moveByPage",motionArgs:{forward:!0}},{keys:"<C-b>",type:"motion",motion:"moveByPage",motionArgs:{forward:!1}},{keys:"<C-d>",type:"motion",motion:"moveByScroll",motionArgs:{forward:!0,explicitRepeat:!0}},{keys:"<C-u>",type:"motion",motion:"moveByScroll",motionArgs:{forward:!1,explicitRepeat:!0}},{keys:"gg",type:"motion",motion:"moveToLineOrEdgeOfDocument",motionArgs:{forward:!1,explicitRepeat:!0,linewise:!0,toJumplist:!0}},{keys:"G",type:"motion",motion:"moveToLineOrEdgeOfDocument",motionArgs:{forward:!0,explicitRepeat:!0,linewise:!0,toJumplist:!0}},{keys:"0",type:"motion",motion:"moveToStartOfLine"},{keys:"^",type:"motion",motion:"moveToFirstNonWhiteSpaceCharacter"},{keys:"+",type:"motion",motion:"moveByLines",motionArgs:{forward:!0,toFirstChar:!0}},{keys:"-",type:"motion",motion:"moveByLines",motionArgs:{forward:!1,toFirstChar:!0}},{keys:"_",type:"motion",motion:"moveByLines",motionArgs:{forward:!0,toFirstChar:!0,repeatOffset:-1}},{keys:"$",type:"motion",motion:"moveToEol",motionArgs:{inclusive:!0}},{keys:"%",type:"motion",motion:"moveToMatchedSymbol",motionArgs:{inclusive:!0,toJumplist:!0}},{keys:"f<character>",type:"motion",motion:"moveToCharacter",motionArgs:{forward:!0,inclusive:!0}},{keys:"F<character>",type:"motion",motion:"moveToCharacter",motionArgs:{forward:!1}},{keys:"t<character>",type:"motion",motion:"moveTillCharacter",motionArgs:{forward:!0,inclusive:!0}},{keys:"T<character>",type:"motion",motion:"moveTillCharacter",motionArgs:{forward:!1}},{keys:";",type:"motion",motion:"repeatLastCharacterSearch",motionArgs:{forward:!0}},{keys:",",type:"motion",motion:"repeatLastCharacterSearch",motionArgs:{forward:!1}},{keys:"'<character>",type:"motion",motion:"goToMark",motionArgs:{toJumplist:!0,linewise:!0}},{keys:"`<character>",type:"motion",motion:"goToMark",motionArgs:{toJumplist:!0}},{keys:"]`",type:"motion",motion:"jumpToMark",motionArgs:{forward:!0}},{keys:"[`",type:"motion",motion:"jumpToMark",motionArgs:{forward:!1}},{keys:"]'",type:"motion",motion:"jumpToMark",motionArgs:{forward:!0,linewise:!0}},{keys:"['",type:"motion",motion:"jumpToMark",motionArgs:{forward:!1,linewise:!0}},{keys:"]p",type:"action",action:"paste",isEdit:!0,actionArgs:{after:!0,isEdit:!0,matchIndent:!0}},{keys:"[p",type:"action",action:"paste",isEdit:!0,actionArgs:{after:!1,isEdit:!0,matchIndent:!0}},{keys:"]<character>",type:"motion",motion:"moveToSymbol",motionArgs:{forward:!0,toJumplist:!0}},{keys:"[<character>",type:"motion",motion:"moveToSymbol",motionArgs:{forward:!1,toJumplist:!0}},{keys:"|",type:"motion",motion:"moveToColumn"},{keys:"o",type:"motion",motion:"moveToOtherHighlightedEnd",context:"visual"},{keys:"O",type:"motion",motion:"moveToOtherHighlightedEnd",motionArgs:{sameLine:!0},context:"visual"},{keys:"d",type:"operator",operator:"delete"},{keys:"y",type:"operator",operator:"yank"},{keys:"c",type:"operator",operator:"change"},{keys:">",type:"operator",operator:"indent",operatorArgs:{indentRight:!0}},{keys:"<",type:"operator",operator:"indent",operatorArgs:{indentRight:!1}},{keys:"g~",type:"operator",operator:"changeCase"},{keys:"gu",type:"operator",operator:"changeCase",operatorArgs:{toLower:!0},isEdit:!0},{keys:"gU",type:"operator",operator:"changeCase",operatorArgs:{toLower:!1},isEdit:!0},{keys:"n",type:"motion",motion:"findNext",motionArgs:{forward:!0,toJumplist:!0}},{keys:"N",type:"motion",motion:"findNext",motionArgs:{forward:!1,toJumplist:!0}},{keys:"x",type:"operatorMotion",operator:"delete",motion:"moveByCharacters",motionArgs:{forward:!0},operatorMotionArgs:{visualLine:!1}},{keys:"X",type:"operatorMotion",operator:"delete",motion:"moveByCharacters",motionArgs:{forward:!1},operatorMotionArgs:{visualLine:!0}},{keys:"D",type:"operatorMotion",operator:"delete",motion:"moveToEol",motionArgs:{inclusive:!0},context:"normal"},{keys:"D",type:"operator",operator:"delete",operatorArgs:{linewise:!0},context:"visual"},{keys:"Y",type:"operatorMotion",operator:"yank",motion:"moveToEol",motionArgs:{inclusive:!0},context:"normal"},{keys:"Y",type:"operator",operator:"yank",operatorArgs:{linewise:!0},context:"visual"},{keys:"C",type:"operatorMotion",operator:"change",motion:"moveToEol",motionArgs:{inclusive:!0},context:"normal"},{keys:"C",type:"operator",operator:"change",operatorArgs:{linewise:!0},context:"visual"},{keys:"~",type:"operatorMotion",operator:"changeCase",motion:"moveByCharacters",motionArgs:{forward:!0},operatorArgs:{shouldMoveCursor:!0},context:"normal"},{keys:"~",type:"operator",operator:"changeCase",context:"visual"},{keys:"<C-w>",type:"operatorMotion",operator:"delete",motion:"moveByWords",motionArgs:{forward:!1,wordEnd:!1},context:"insert"},{keys:"<C-i>",type:"action",action:"jumpListWalk",actionArgs:{forward:!0}},{keys:"<C-o>",type:"action",action:"jumpListWalk",actionArgs:{forward:!1}},{keys:"<C-e>",type:"action",action:"scroll",actionArgs:{forward:!0,linewise:!0}},{keys:"<C-y>",type:"action",action:"scroll",actionArgs:{forward:!1,linewise:!0}},{keys:"a",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"charAfter"},context:"normal"},{keys:"A",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"eol"},context:"normal"},{keys:"A",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"endOfSelectedArea"},context:"visual"},{keys:"i",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"inplace"},context:"normal"},{keys:"I",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"firstNonBlank"},context:"normal"},{keys:"I",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"startOfSelectedArea"},context:"visual"},{keys:"o",type:"action",action:"newLineAndEnterInsertMode",isEdit:!0,interlaceInsertRepeat:!0,actionArgs:{after:!0},context:"normal"},{keys:"O",type:"action",action:"newLineAndEnterInsertMode",isEdit:!0,interlaceInsertRepeat:!0,actionArgs:{after:!1},context:"normal"},{keys:"v",type:"action",action:"toggleVisualMode"},{keys:"V",type:"action",action:"toggleVisualMode",actionArgs:{linewise:!0}},{keys:"<C-v>",type:"action",action:"toggleVisualMode",actionArgs:{blockwise:!0}},{keys:"gv",type:"action",action:"reselectLastSelection"},{keys:"J",type:"action",action:"joinLines",isEdit:!0},{keys:"p",type:"action",action:"paste",isEdit:!0,actionArgs:{after:!0,isEdit:!0}},{keys:"P",type:"action",action:"paste",isEdit:!0,actionArgs:{after:!1,isEdit:!0}},{keys:"r<character>",type:"action",action:"replace",isEdit:!0},{keys:"@<character>",type:"action",action:"replayMacro"},{keys:"q<character>",type:"action",action:"enterMacroRecordMode"},{keys:"R",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{replace:!0}},{keys:"u",type:"action",action:"undo",context:"normal"},{keys:"u",type:"operator",operator:"changeCase",operatorArgs:{toLower:!0},context:"visual",isEdit:!0},{keys:"U",type:"operator",operator:"changeCase",operatorArgs:{toLower:!1},context:"visual",isEdit:!0},{keys:"<C-r>",type:"action",action:"redo"},{keys:"m<character>",type:"action",action:"setMark"},{keys:'"<character>',type:"action",action:"setRegister"},{keys:"zz",type:"action",action:"scrollToCursor",actionArgs:{position:"center"}},{keys:"z.",type:"action",action:"scrollToCursor",actionArgs:{position:"center"},motion:"moveToFirstNonWhiteSpaceCharacter"},{keys:"zt",type:"action",action:"scrollToCursor",actionArgs:{position:"top"}},{keys:"z<CR>",type:"action",action:"scrollToCursor",actionArgs:{position:"top"},motion:"moveToFirstNonWhiteSpaceCharacter"},{keys:"z-",type:"action",action:"scrollToCursor",actionArgs:{position:"bottom"}},{keys:"zb",type:"action",action:"scrollToCursor",actionArgs:{position:"bottom"},motion:"moveToFirstNonWhiteSpaceCharacter"},{keys:".",type:"action",action:"repeatLastEdit"},{keys:"<C-a>",type:"action",action:"incrementNumberToken",isEdit:!0,actionArgs:{increase:!0,backtrack:!1}},{keys:"<C-x>",type:"action",action:"incrementNumberToken",isEdit:!0,actionArgs:{increase:!1,backtrack:!1}},{keys:"a<character>",type:"motion",motion:"textObjectManipulation"},{keys:"i<character>",type:"motion",motion:"textObjectManipulation",motionArgs:{textObjectInner:!0}},{keys:"/",type:"search",searchArgs:{forward:!0,querySrc:"prompt",toJumplist:!0}},{keys:"?",type:"search",searchArgs:{forward:!1,querySrc:"prompt",toJumplist:!0}},{keys:"*",type:"search",searchArgs:{forward:!0,querySrc:"wordUnderCursor",wholeWordOnly:!0,toJumplist:!0}},{keys:"#",type:"search",searchArgs:{forward:!1,querySrc:"wordUnderCursor",wholeWordOnly:!0,toJumplist:!0}},{keys:"g*",type:"search",searchArgs:{forward:!0,querySrc:"wordUnderCursor",toJumplist:!0}},{keys:"g#",type:"search",searchArgs:{forward:!1,querySrc:"wordUnderCursor",toJumplist:!0}},{keys:":",type:"ex"}],w=[{name:"colorscheme",shortName:"colo"},{name:"map"},{name:"imap",shortName:"im"},{name:"nmap",shortName:"nm"},{name:"vmap",shortName:"vm"},{name:"unmap"},{name:"write",shortName:"w"},{name:"undo",shortName:"u"},{name:"redo",shortName:"red"},{name:"set",shortName:"se"},{name:"set",shortName:"se"},{name:"setlocal",shortName:"setl"},{name:"setglobal",shortName:"setg"},{name:"sort",shortName:"sor"},{name:"substitute",shortName:"s",possiblyAsync:!0},{name:"nohlsearch",shortName:"noh"},{name:"delmarks",shortName:"delm"},{name:"registers",shortName:"reg",excludeFromCommandHistory:!0},{name:"global",shortName:"g"}],E=v.Pos,S=function(){return st};v.defineOption("vimMode",!1,function(e,t,n){t&&e.getOption("keyMap")!="vim"?e.setOption("keyMap","vim"):!t&&n!=v.Init&&/^vim/.test(e.getOption("keyMap"))&&e.setOption("keyMap","default")});var L={Shift:"S",Ctrl:"C",Alt:"A",Cmd:"D",Mod:"A"},A={Enter:"CR",Backspace:"BS",Delete:"Del"},_=/[\d]/,D=[v.isWordChar,function(e){return e&&!v.isWordChar(e)&&!/\s/.test(e)}],P=[function(e){return/\S/.test(e)}],B=H(65,26),j=H(97,26),F=H(48,10),I=[].concat(B,j,F,["<",">"]),q=[].concat(B,j,F,["-",'"',".",":","/"]),J={};K("filetype",undefined,"string",["ft"],function(e,t){if(t===undefined)return;if(e===undefined){var n=t.getOption("mode");return n=="null"?"":n}var n=e==""?"null":e;t.setOption("mode",n)});var Y=function(){function s(s,o,u){function l(n){var r=++t%e,o=i[r];o&&o.clear(),i[r]=s.setBookmark(n)}var a=t%e,f=i[a];if(f){var c=f.find();c&&!At(c,o)&&l(o)}else l(o);l(u),n=t,r=t-e+1,r<0&&(r=0)}function o(s,o){t+=o,t>n?t=n:t<r&&(t=r);var u=i[(e+t)%e];if(u&&!u.find()){var a=o>0?1:-1,f,l=s.getCursor();do{t+=a,u=i[(e+t)%e];if(u&&(f=u.find())&&!At(l,f))break}while(t<n&&t>r)}return u}var e=100,t=-1,n=0,r=0,i=new Array(e);return{cachedCursor:undefined,add:s,move:o}},Z=function(e){return e?{changes:e.changes,expectCursorActivityForChange:e.expectCursorActivityForChange}:{changes:[],expectCursorActivityForChange:!1}};et.prototype={exitMacroRecordMode:function(){var e=nt.macroModeState;e.onRecordingDone&&e.onRecordingDone(),e.onRecordingDone=undefined,e.isRecording=!1},enterMacroRecordMode:function(e,t){var n=nt.registerController.getRegister(t);n&&(n.clear(),this.latestRegister=t,e.openDialog&&(this.onRecordingDone=e.openDialog("(recording)["+t+"]",null,{bottom:!0})),this.isRecording=!0)}};var nt,it,st={buildKeyMap:function(){},getRegisterController:function(){return nt.registerController},resetVimGlobalState_:rt,getVimGlobalState_:function(){return nt},maybeInitVimState_:tt,suppressErrorLogging:!1,InsertModeKey:Gn,map:function(e,t,n){Fn.map(e,t,n)},unmap:function(e,t){Fn.unmap(e,t||"normal")},setOption:Q,getOption:G,defineOption:K,defineEx:function(e,t,n){if(!t)t=e;else if(e.indexOf(t)!==0)throw new Error('(Vim.defineEx) "'+t+'" is not a prefix of "'+e+'", command not registered');jn[e]=n,Fn.commandMap_[t]={name:e,shortName:t,type:"api"}},handleKey:function(e,t,n){var r=this.findKey(e,t,n);if(typeof r=="function")return r()},findKey:function(e,t,n){function i(){var r=nt.macroModeState;if(r.isRecording){if(t=="q")return r.exitMacroRecordMode(),ut(e),!0;n!="mapping"&&Wn(r,t)}}function s(){if(t=="<Esc>")return ut(e),r.visualMode?$t(e):r.insertMode&&qn(e),!0}function o(n){var r;while(n)r=/<\w+-.+?>|<\w+>|./.exec(n),t=r[0],n=n.substring(r.index+t.length),v.Vim.handleKey(e,t,"mapping")}function u(){if(s())return!0;var n=r.inputState.keyBuffer=r.inputState.keyBuffer+t,i=t.length==1,o=ht.matchCommand(n,b,r.inputState,"insert");while(n.length>1&&o.type!="full"){var n=r.inputState.keyBuffer=n.slice(1),u=ht.matchCommand(n,b,r.inputState,"insert");u.type!="none"&&(o=u)}if(o.type=="none")return ut(e),!1;if(o.type=="partial")return it&&window.clearTimeout(it),it=window.setTimeout(function(){r.insertMode&&r.inputState.keyBuffer&&ut(e)},G("insertModeEscKeysTimeout")),!i;it&&window.clearTimeout(it);if(i){var a=e.getCursor();e.replaceRange("",St(a,0,-(n.length-1)),a,"+input")}return ut(e),o.command}function a(){if(i()||s())return!0;var n=r.inputState.keyBuffer=r.inputState.keyBuffer+t;if(/^[1-9]\d*$/.test(n))return!0;var o=/^(\d*)(.*)$/.exec(n);if(!o)return ut(e),!1;var u=r.visualMode?"visual":"normal",a=ht.matchCommand(o[2]||o[1],b,r.inputState,u);if(a.type=="none")return ut(e),!1;if(a.type=="partial")return!0;r.inputState.keyBuffer="";var o=/^(\d*)(.*)$/.exec(n);return o[1]&&o[1]!="0"&&r.inputState.pushRepeatDigit(o[1]),a.command}var r=tt(e),f;return r.insertMode?f=u():f=a(),f===!1?undefined:f===!0?function(){return!0}:function(){if((f.operator||f.isEdit)&&e.getOption("readOnly"))return;return e.operation(function(){e.curOp.isVimOp=!0;try{f.type=="keyToKey"?o(f.toKeys):ht.processCommand(e,r,f)}catch(t){throw e.state.vim=undefined,tt(e),v.Vim.suppressErrorLogging||console.log(t),t}return!0})}},handleEx:function(e,t){Fn.processCommand(e,t)},defineMotion:dt,defineAction:bt,defineOperator:gt,mapCommand:Un,_mapCommand:Rn,defineRegister:ft,exitVisualMode:$t,exitInsertMode:qn};ot.prototype.pushRepeatDigit=function(e){this.operator?this.motionRepeat=this.motionRepeat.concat(e):this.prefixRepeat=this.prefixRepeat.concat(e)},ot.prototype.getRepeat=function(){var e=0;if(this.prefixRepeat.length>0||this.motionRepeat.length>0)e=1,this.prefixRepeat.length>0&&(e*=parseInt(this.prefixRepeat.join(""),10)),this.motionRepeat.length>0&&(e*=parseInt(this.motionRepeat.join(""),10));return e},at.prototype={setText:function(e,t,n){this.keyBuffer=[e||""],this.linewise=!!t,this.blockwise=!!n},pushText:function(e,t){t&&(this.linewise||this.keyBuffer.push("\n"),this.linewise=!0),this.keyBuffer.push(e)},pushInsertModeChanges:function(e){this.insertModeChanges.push(Z(e))},pushSearchQuery:function(e){this.searchQueries.push(e)},clear:function(){this.keyBuffer=[],this.insertModeChanges=[],this.searchQueries=[],this.linewise=!1},toString:function(){return this.keyBuffer.join("")}},lt.prototype={pushText:function(e,t,n,r,i){r&&n.charAt(0)=="\n"&&(n=n.slice(1)+"\n"),r&&n.charAt(n.length-1)!=="\n"&&(n+="\n");var s=this.isValidRegister(e)?this.getRegister(e):null;if(!s){switch(t){case"yank":this.registers[0]=new at(n,r,i);break;case"delete":case"change":n.indexOf("\n")==-1?this.registers["-"]=new at(n,r):(this.shiftNumericRegisters_(),this.registers[1]=new at(n,r))}this.unnamedRegister.setText(n,r,i);return}var o=X(e);o?s.pushText(n,r):s.setText(n,r,i),this.unnamedRegister.setText(s.toString(),r)},getRegister:function(e){return this.isValidRegister(e)?(e=e.toLowerCase(),this.registers[e]||(this.registers[e]=new at),this.registers[e]):this.unnamedRegister},isValidRegister:function(e){return e&&$(e,q)},shiftNumericRegisters_:function(){for(var e=9;e>=2;e--)this.registers[e]=this.getRegister(""+(e-1))}},ct.prototype={nextMatch:function(e,t){var n=this.historyBuffer,r=t?-1:1;this.initialPrefix===null&&(this.initialPrefix=e);for(var i=this.iterator+r;t?i>=0:i<n.length;i+=r){var s=n[i];for(var o=0;o<=s.length;o++)if(this.initialPrefix==s.substring(0,o))return this.iterator=i,s}if(i>=n.length)return this.iterator=n.length,this.initialPrefix;if(i<0)return e},pushInput:function(e){var t=this.historyBuffer.indexOf(e);t>-1&&this.historyBuffer.splice(t,1),e.length&&this.historyBuffer.push(e)},reset:function(){this.initialPrefix=null,this.iterator=this.historyBuffer.length}};var ht={matchCommand:function(e,t,n,r){var i=Tt(e,t,r,n);if(!i.full&&!i.partial)return{type:"none"};if(!i.full&&i.partial)return{type:"partial"};var s;for(var o=0;o<i.full.length;o++){var u=i.full[o];s||(s=u)}return s.keys.slice(-11)=="<character>"&&(n.selectedCharacter=Ct(e)),{type:"full",command:s}},processCommand:function(e,t,n){t.inputState.repeatOverride=n.repeatOverride;switch(n.type){case"motion":this.processMotion(e,t,n);break;case"operator":this.processOperator(e,t,n);break;case"operatorMotion":this.processOperatorMotion(e,t,n);break;case"action":this.processAction(e,t,n);break;case"search":this.processSearch(e,t,n);break;case"ex":case"keyToEx":this.processEx(e,t,n);break;default:}},processMotion:function(e,t,n){t.inputState.motion=n.motion,t.inputState.motionArgs=Et(n.motionArgs),this.evalInput(e,t)},processOperator:function(e,t,n){var r=t.inputState;if(r.operator){if(r.operator==n.operator){r.motion="expandToLine",r.motionArgs={linewise:!0},this.evalInput(e,t);return}ut(e)}r.operator=n.operator,r.operatorArgs=Et(n.operatorArgs),t.visualMode&&this.evalInput(e,t)},processOperatorMotion:function(e,t,n){var r=t.visualMode,i=Et(n.operatorMotionArgs);i&&r&&i.visualLine&&(t.visualLine=!0),this.processOperator(e,t,n),r||this.processMotion(e,t,n)},processAction:function(e,t,n){var r=t.inputState,i=r.getRepeat(),s=!!i,o=Et(n.actionArgs)||{};r.selectedCharacter&&(o.selectedCharacter=r.selectedCharacter),n.operator&&this.processOperator(e,t,n),n.motion&&this.processMotion(e,t,n),(n.motion||n.operator)&&this.evalInput(e,t),o.repeat=i||1,o.repeatIsExplicit=s,o.registerName=r.registerName,ut(e),t.lastMotion=null,n.isEdit&&this.recordLastEdit(t,r,n),yt[n.action](e,o,t)},processSearch:function(e,t,n){function a(r,i,s){nt.searchHistoryController.pushInput(r),nt.searchHistoryController.reset();try{An(e,r,i,s)}catch(o){Tn(e,"Invalid regex: "+r),ut(e);return}ht.processMotion(e,t,{type:"motion",motion:"findNext",motionArgs:{forward:!0,toJumplist:n.searchArgs.toJumplist}})}function f(t){e.scrollTo(u.left,u.top),a(t,!0,!0);var n=nt.macroModeState;n.isRecording&&Vn(n,t)}function l(t,n,i){var s=v.keyName(t),o;s=="Up"||s=="Down"?(o=s=="Up"?!0:!1,n=nt.searchHistoryController.nextMatch(n,o)||"",i(n)):s!="Left"&&s!="Right"&&s!="Ctrl"&&s!="Alt"&&s!="Shift"&&nt.searchHistoryController.reset();var a;try{a=An(e,n,!0,!0)}catch(t){}a?e.scrollIntoView(_n(e,!r,a),30):(Dn(e),e.scrollTo(u.left,u.top))}function c(t,n,r){var i=v.keyName(t);i=="Esc"||i=="Ctrl-C"||i=="Ctrl-["||i=="Backspace"&&n==""?(nt.searchHistoryController.pushInput(n),nt.searchHistoryController.reset(),An(e,o),Dn(e),e.scrollTo(u.left,u.top),v.e_stop(t),ut(e),r(),e.focus()):i=="Ctrl-U"&&(v.e_stop(t),r(""))}if(!e.getSearchCursor)return;var r=n.searchArgs.forward,i=n.searchArgs.wholeWordOnly;dn(e).setReversed(!r);var s=r?"/":"?",o=dn(e).getQuery(),u=e.getScrollInfo();switch(n.searchArgs.querySrc){case"prompt":var h=nt.macroModeState;if(h.isPlaying){var p=h.replaySearchQueries.shift();a(p,!0,!1)}else kn(e,{onClose:f,prefix:s,desc:Cn,onKeyUp:l,onKeyDown:c});break;case"wordUnderCursor":var d=Gt(e,!1,!0,!1,!0),m=!0;d||(d=Gt(e,!1,!0,!1,!1),m=!1);if(!d)return;var p=e.getLine(d.start.line).substring(d.start.ch,d.end.ch);m&&i?p="\\b"+p+"\\b":p=Bt(p),nt.jumpList.cachedCursor=e.getCursor(),e.setCursor(d.start),a(p,!0,!1)}},processEx:function(e,t,n){function r(t){nt.exCommandHistoryController.pushInput(t),nt.exCommandHistoryController.reset(),Fn.processCommand(e,t)}function i(t,n,r){var i=v.keyName(t),s;if(i=="Esc"||i=="Ctrl-C"||i=="Ctrl-["||i=="Backspace"&&n=="")nt.exCommandHistoryController.pushInput(n),nt.exCommandHistoryController.reset(),v.e_stop(t),ut(e),r(),e.focus();i=="Up"||i=="Down"?(s=i=="Up"?!0:!1,n=nt.exCommandHistoryController.nextMatch(n,s)||"",r(n)):i=="Ctrl-U"?(v.e_stop(t),r("")):i!="Left"&&i!="Right"&&i!="Ctrl"&&i!="Alt"&&i!="Shift"&&nt.exCommandHistoryController.reset()}n.type=="keyToEx"?Fn.processCommand(e,n.exArgs.input):t.visualMode?kn(e,{onClose:r,prefix:":",value:"'<,'>",onKeyDown:i}):kn(e,{onClose:r,prefix:":",onKeyDown:i})},evalInput:function(e,t){var n=t.inputState,r=n.motion,i=n.motionArgs||{},s=n.operator,o=n.operatorArgs||{},u=n.registerName,a=t.sel,f=Lt(t.visualMode?wt(e,a.head):e.getCursor("head")),l=Lt(t.visualMode?wt(e,a.anchor):e.getCursor("anchor")),c=Lt(f),h=Lt(l),p,d,v;s&&this.recordLastEdit(t,n),n.repeatOverride!==undefined?v=n.repeatOverride:v=n.getRepeat();if(v>0&&i.explicitRepeat)i.repeatIsExplicit=!0;else if(i.noRepeat||!i.explicitRepeat&&v===0)v=1,i.repeatIsExplicit=!1;n.selectedCharacter&&(i.selectedCharacter=o.selectedCharacter=n.selectedCharacter),i.repeat=v,ut(e);if(r){var m=pt[r](e,f,i,t);t.lastMotion=pt[r];if(!m)return;if(i.toJumplist){!s&&e.ace.curOp!=null&&(e.ace.curOp.command.scrollIntoView="center-animate");var g=nt.jumpList,y=g.cachedCursor;y?(Yt(e,y,m),delete g.cachedCursor):Yt(e,f,m)}m instanceof Array?(d=m[0],p=m[1]):p=m,p||(p=Lt(f));if(t.visualMode){if(!t.visualBlock||p.ch!==Infinity)p=wt(e,p,t.visualBlock);d&&(d=wt(e,d,!0)),d=d||h,a.anchor=d,a.head=p,Wt(e),an(e,t,"<",Ot(d,p)?d:p),an(e,t,">",Ot(d,p)?p:d)}else s||(p=wt(e,p),e.setCursor(p.line,p.ch))}if(s){if(o.lastSel){d=h;var b=o.lastSel,w=Math.abs(b.head.line-b.anchor.line),S=Math.abs(b.head.ch-b.anchor.ch);b.visualLine?p=E(h.line+w,h.ch):b.visualBlock?p=E(h.line+w,h.ch+S):b.head.line==b.anchor.line?p=E(h.line,h.ch+S):p=E(h.line+w,h.ch),t.visualMode=!0,t.visualLine=b.visualLine,t.visualBlock=b.visualBlock,a=t.sel={anchor:d,head:p},Wt(e)}else t.visualMode&&(o.lastSel={anchor:Lt(a.anchor),head:Lt(a.head),visualBlock:t.visualBlock,visualLine:t.visualLine});var x,T,N,C,k;if(t.visualMode){x=Mt(a.head,a.anchor),T=_t(a.head,a.anchor),N=t.visualLine||o.linewise,C=t.visualBlock?"block":N?"line":"char",k=Xt(e,{anchor:x,head:T},C);if(N){var L=k.ranges;if(C=="block")for(var A=0;A<L.length;A++)L[A].head.ch=Pt(e,L[A].head.line);else C=="line"&&(L[0].head=E(L[0].head.line+1,0))}}else{x=Lt(d||h),T=Lt(p||c);if(Ot(T,x)){var O=x;x=T,T=O}N=i.linewise||o.linewise,N?Kt(e,x,T):i.forward&&Jt(e,x,T),C="char";var M=!i.inclusive||N;k=Xt(e,{anchor:x,head:T},C,M)}e.setSelections(k.ranges,k.primary),t.lastMotion=null,o.repeat=v,o.registerName=u,o.linewise=N;var _=mt[s](e,o,k.ranges,h,p);t.visualMode&&$t(e,_!=null),_&&e.setCursor(_)}},recordLastEdit:function(e,t,n){var r=nt.macroModeState;if(r.isPlaying)return;e.lastEditInputState=t,e.lastEditActionCommand=n,r.lastInsertModeChanges.changes=[],r.lastInsertModeChanges.expectCursorActivityForChange=!1}},pt={moveToTopLine:function(e,t,n){var r=Hn(e).top+n.repeat-1;return E(r,Qt(e.getLine(r)))},moveToMiddleLine:function(e){var t=Hn(e),n=Math.floor((t.top+t.bottom)*.5);return E(n,Qt(e.getLine(n)))},moveToBottomLine:function(e,t,n){var r=Hn(e).bottom-n.repeat+1;return E(r,Qt(e.getLine(r)))},expandToLine:function(e,t,n){var r=t;return E(r.line+n.repeat-1,Infinity)},findNext:function(e,t,n){var r=dn(e),i=r.getQuery();if(!i)return;var s=!n.forward;return s=r.isReversed()?!s:s,Mn(e,i),_n(e,s,i,n.repeat)},goToMark:function(e,t,n,r){var i=r.marks[n.selectedCharacter];if(i){var s=i.find();return n.linewise?{line:s.line,ch:Qt(e.getLine(s.line))}:s}return null},moveToOtherHighlightedEnd:function(e,t,n,r){if(r.visualBlock&&n.sameLine){var i=r.sel;return[wt(e,E(i.anchor.line,i.head.ch)),wt(e,E(i.head.line,i.anchor.ch))]}return[r.sel.head,r.sel.anchor]},jumpToMark:function(e,t,n,r){var i=t;for(var s=0;s<n.repeat;s++){var o=i;for(var u in r.marks){if(!U(u))continue;var a=r.marks[u].find(),f=n.forward?Ot(a,o):Ot(o,a);if(f)continue;if(n.linewise&&a.line==o.line)continue;var l=At(o,i),c=n.forward?Dt(o,a,i):Dt(i,a,o);if(l||c)i=a}}return n.linewise&&(i=E(i.line,Qt(e.getLine(i.line)))),i},moveByCharacters:function(e,t,n){var r=t,i=n.repeat,s=n.forward?r.ch+i:r.ch-i;return E(r.line,s)},moveByLines:function(e,t,n,r){var i=t,s=i.ch;switch(r.lastMotion){case this.moveByLines:case this.moveByDisplayLines:case this.moveByScroll:case this.moveToColumn:case this.moveToEol:s=r.lastHPos;break;default:r.lastHPos=s}var o=n.repeat+(n.repeatOffset||0),u=n.forward?i.line+o:i.line-o,a=e.firstLine(),f=e.lastLine();if(u<a&&i.line==a||u>f&&i.line==f)return;var l=e.ace.session.getFoldLine(u);return l&&(n.forward?u>l.start.row&&(u=l.end.row+1):u=l.start.row),n.toFirstChar&&(s=Qt(e.getLine(u)),r.lastHPos=s),r.lastHSPos=e.charCoords(E(u,s),"div").left,E(u,s)},moveByDisplayLines:function(e,t,n,r){var i=t;switch(r.lastMotion){case this.moveByDisplayLines:case this.moveByScroll:case this.moveByLines:case this.moveToColumn:case this.moveToEol:break;default:r.lastHSPos=e.charCoords(i,"div").left}var s=n.repeat,o=e.findPosV(i,n.forward?s:-s,"line",r.lastHSPos);if(o.hitSide)if(n.forward)var u=e.charCoords(o,"div"),a={top:u.top+8,left:r.lastHSPos},o=e.coordsChar(a,"div");else{var f=e.charCoords(E(e.firstLine(),0),"div");f.left=r.lastHSPos,o=e.coordsChar(f,"div")}return r.lastHPos=o.ch,o},moveByPage:function(e,t,n){var r=t,i=n.repeat;return e.findPosV(r,n.forward?i:-i,"page")},moveByParagraph:function(e,t,n){var r=n.forward?1:-1;return ln(e,t,n.repeat,r)},moveByScroll:function(e,t,n,r){var i=e.getScrollInfo(),s=null,o=n.repeat;o||(o=i.clientHeight/(2*e.defaultTextHeight()));var u=e.charCoords(t,"local");n.repeat=o;var s=pt.moveByDisplayLines(e,t,n,r);if(!s)return null;var a=e.charCoords(s,"local");return e.scrollTo(null,i.top+a.top-u.top),s},moveByWords:function(e,t,n){return sn(e,t,n.repeat,!!n.forward,!!n.wordEnd,!!n.bigWord)},moveTillCharacter:function(e,t,n){var r=n.repeat,i=on(e,r,n.forward,n.selectedCharacter),s=n.forward?-1:1;return Zt(s,n),i?(i.ch+=s,i):null},moveToCharacter:function(e,t,n){var r=n.repeat;return Zt(0,n),on(e,r,n.forward,n.selectedCharacter)||t},moveToSymbol:function(e,t,n){var r=n.repeat;return nn(e,r,n.forward,n.selectedCharacter)||t},moveToColumn:function(e,t,n,r){var i=n.repeat;return r.lastHPos=i-1,r.lastHSPos=e.charCoords(t,"div").left,un(e,i)},moveToEol:function(e,t,n,r){var i=t;r.lastHPos=Infinity;var s=E(i.line+n.repeat-1,Infinity),o=e.clipPos(s);return o.ch--,r.lastHSPos=e.charCoords(o,"div").left,s},moveToFirstNonWhiteSpaceCharacter:function(e,t){var n=t;return E(n.line,Qt(e.getLine(n.line)))},moveToMatchedSymbol:function(e,t){var n=t,r=n.line,i=n.ch,s=e.getLine(r),o;do{o=s.charAt(i++);if(o&&z(o)){var u=e.getTokenTypeAt(E(r,i));if(u!=="string"&&u!=="comment")break}}while(o);if(o){var a=e.findMatchingBracket(E(r,i));return a.to}return n},moveToStartOfLine:function(e,t){return E(t.line,0)},moveToLineOrEdgeOfDocument:function(e,t,n){var r=n.forward?e.lastLine():e.firstLine();return n.repeatIsExplicit&&(r=n.repeat-e.getOption("firstLineNumber")),E(r,Qt(e.getLine(r)))},textObjectManipulation:function(e,t,n,r){var i={"(":")",")":"(","{":"}","}":"{","[":"]","]":"["},s={"'":!0,'"':!0},o=n.selectedCharacter;o=="b"?o="(":o=="B"&&(o="{");var u=!n.textObjectInner,a;if(i[o])a=cn(e,t,o,u);else if(s[o])a=hn(e,t,o,u);else if(o==="W")a=Gt(e,u,!0,!0);else if(o==="w")a=Gt(e,u,!0,!1);else{if(o!=="p")return null;a=ln(e,t,n.repeat,0,u),n.linewise=!0;if(r.visualMode)r.visualLine||(r.visualLine=!0);else{var f=r.inputState.operatorArgs;f&&(f.linewise=!0),a.end.line--}}return e.state.vim.visualMode?zt(e,a.start,a.end):[a.start,a.end]},repeatLastCharacterSearch:function(e,t,n){var r=nt.lastChararacterSearch,i=n.repeat,s=n.forward===r.forward,o=(r.increment?1:0)*(s?-1:1);e.moveH(-o,"char"),n.inclusive=s?!0:!1;var u=on(e,i,s,r.selectedCharacter);return u?(u.ch+=o,u):(e.moveH(o,"char"),t)}},mt={change:function(e,t,n){var r,i,s=e.state.vim;nt.macroModeState.lastInsertModeChanges.inVisualBlock=s.visualBlock;if(!s.visualMode){var o=n[0].anchor,u=n[0].head;i=e.getRange(o,u);var a=s.lastEditInputState||{};if(a.motion=="moveByWords"&&!V(i)){var f=/\s+$/.exec(i);f&&a.motionArgs&&a.motionArgs.forward&&(u=St(u,0,-f[0].length),i=i.slice(0,-f[0].length))}var l=new E(o.line-1,Number.MAX_VALUE),c=e.firstLine()==e.lastLine();u.line>e.lastLine()&&t.linewise&&!c?e.replaceRange("",l,u):e.replaceRange("",o,u),t.linewise&&(c||(e.setCursor(l),v.commands.newlineAndIndent(e)),o.ch=Number.MAX_VALUE),r=o}else{i=e.getSelection();var h=vt("",n.length);e.replaceSelections(h),r=Mt(n[0].head,n[0].anchor)}nt.registerController.pushText(t.registerName,"change",i,t.linewise,n.length>1),yt.enterInsertMode(e,{head:r},e.state.vim)},"delete":function(e,t,n){var r,i,s=e.state.vim;if(!s.visualBlock){var o=n[0].anchor,u=n[0].head;t.linewise&&u.line!=e.firstLine()&&o.line==e.lastLine()&&o.line==u.line-1&&(o.line==e.firstLine()?o.ch=0:o=E(o.line-1,Pt(e,o.line-1))),i=e.getRange(o,u),e.replaceRange("",o,u),r=o,t.linewise&&(r=pt.moveToFirstNonWhiteSpaceCharacter(e,o))}else{i=e.getSelection();var a=vt("",n.length);e.replaceSelections(a),r=n[0].anchor}return nt.registerController.pushText(t.registerName,"delete",i,t.linewise,s.visualBlock),wt(e,r)},indent:function(e,t,n){var r=e.state.vim,i=n[0].anchor.line,s=r.visualBlock?n[n.length-1].anchor.line:n[0].head.line,o=r.visualMode?t.repeat:1;t.linewise&&s--;for(var u=i;u<=s;u++)for(var a=0;a<o;a++)e.indentLine(u,t.indentRight);return pt.moveToFirstNonWhiteSpaceCharacter(e,n[0].anchor)},changeCase:function(e,t,n,r,i){var s=e.getSelections(),o=[],u=t.toLower;for(var a=0;a<s.length;a++){var f=s[a],l="";if(u===!0)l=f.toLowerCase();else if(u===!1)l=f.toUpperCase();else for(var c=0;c<f.length;c++){var h=f.charAt(c);l+=X(h)?h.toLowerCase():h.toUpperCase()}o.push(l)}return e.replaceSelections(o),t.shouldMoveCursor?i:!e.state.vim.visualMode&&t.linewise&&n[0].anchor.line+1==n[0].head.line?pt.moveToFirstNonWhiteSpaceCharacter(e,r):t.linewise?r:Mt(n[0].anchor,n[0].head)},yank:function(e,t,n,r){var i=e.state.vim,s=e.getSelection(),o=i.visualMode?Mt(i.sel.anchor,i.sel.head,n[0].head,n[0].anchor):r;return nt.registerController.pushText(t.registerName,"yank",s,t.linewise,i.visualBlock),o}},yt={jumpListWalk:function(e,t,n){if(n.visualMode)return;var r=t.repeat,i=t.forward,s=nt.jumpList,o=s.move(e,i?r:-r),u=o?o.find():undefined;u=u?u:e.getCursor(),e.setCursor(u),e.ace.curOp.command.scrollIntoView="center-animate"},scroll:function(e,t,n){if(n.visualMode)return;var r=t.repeat||1,i=e.defaultTextHeight(),s=e.getScrollInfo().top,o=i*r,u=t.forward?s+o:s-o,a=Lt(e.getCursor()),f=e.charCoords(a,"local");if(t.forward)u>f.top?(a.line+=(u-f.top)/i,a.line=Math.ceil(a.line),e.setCursor(a),f=e.charCoords(a,"local"),e.scrollTo(null,f.top)):e.scrollTo(null,u);else{var l=u+e.getScrollInfo().clientHeight;l<f.bottom?(a.line-=(f.bottom-l)/i,a.line=Math.floor(a.line),e.setCursor(a),f=e.charCoords(a,"local"),e.scrollTo(null,f.bottom-e.getScrollInfo().clientHeight)):e.scrollTo(null,u)}},scrollToCursor:function(e,t){var n=e.getCursor().line,r=e.charCoords(E(n,0),"local"),i=e.getScrollInfo().clientHeight,s=r.top,o=r.bottom-s;switch(t.position){case"center":s=s-i/2+o;break;case"bottom":s=s-i+o*1.4;break;case"top":s+=o*.4}e.scrollTo(null,s)},replayMacro:function(e,t,n){var r=t.selectedCharacter,i=t.repeat,s=nt.macroModeState;r=="@"&&(r=s.latestRegister);while(i--)zn(e,n,s,r)},enterMacroRecordMode:function(e,t){var n=nt.macroModeState,r=t.selectedCharacter;n.enterMacroRecordMode(e,r)},enterInsertMode:function(e,t,n){if(e.getOption("readOnly"))return;n.insertMode=!0,n.insertModeRepeat=t&&t.repeat||1;var r=t?t.insertAt:null,i=n.sel,s=t.head||e.getCursor("head"),o=e.listSelections().length;if(r=="eol")s=E(s.line,Pt(e,s.line));else if(r=="charAfter")s=St(s,0,1);else if(r=="firstNonBlank")s=pt.moveToFirstNonWhiteSpaceCharacter(e,s);else if(r=="startOfSelectedArea")n.visualBlock?(s=E(Math.min(i.head.line,i.anchor.line),Math.min(i.head.ch,i.anchor.ch)),o=Math.abs(i.head.line-i.anchor.line)+1):i.head.line<i.anchor.line?s=i.head:s=E(i.anchor.line,0);else if(r=="endOfSelectedArea")n.visualBlock?(s=E(Math.min(i.head.line,i.anchor.line),Math.max(i.head.ch+1,i.anchor.ch)),o=Math.abs(i.head.line-i.anchor.line)+1):i.head.line>=i.anchor.line?s=St(i.head,0,1):s=E(i.anchor.line,0);else if(r=="inplace"&&n.visualMode)return;e.setOption("keyMap","vim-insert"),e.setOption("disableInput",!1),t&&t.replace?(e.toggleOverwrite(!0),e.setOption("keyMap","vim-replace"),v.signal(e,"vim-mode-change",{mode:"replace"})):(e.setOption("keyMap","vim-insert"),v.signal(e,"vim-mode-change",{mode:"insert"})),nt.macroModeState.isPlaying||(e.on("change",$n),v.on(e.getInputField(),"keydown",Yn)),n.visualMode&&$t(e),It(e,s,o)},toggleVisualMode:function(e,t,n){var r=t.repeat,i=e.getCursor(),s;n.visualMode?n.visualLine^t.linewise||n.visualBlock^t.blockwise?(n.visualLine=!!t.linewise,n.visualBlock=!!t.blockwise,v.signal(e,"vim-mode-change",{mode:"visual",subMode:n.visualLine?"linewise":n.visualBlock?"blockwise":""}),Wt(e)):$t(e):(n.visualMode=!0,n.visualLine=!!t.linewise,n.visualBlock=!!t.blockwise,s=wt(e,E(i.line,i.ch+r-1),!0),n.sel={anchor:i,head:s},v.signal(e,"vim-mode-change",{mode:"visual",subMode:n.visualLine?"linewise":n.visualBlock?"blockwise":""}),Wt(e),an(e,n,"<",Mt(i,s)),an(e,n,">",_t(i,s)))},reselectLastSelection:function(e,t,n){var r=n.lastSelection;n.visualMode&&Ut(e,n);if(r){var i=r.anchorMark.find(),s=r.headMark.find();if(!i||!s)return;n.sel={anchor:i,head:s},n.visualMode=!0,n.visualLine=r.visualLine,n.visualBlock=r.visualBlock,Wt(e),an(e,n,"<",Mt(i,s)),an(e,n,">",_t(i,s)),v.signal(e,"vim-mode-change",{mode:"visual",subMode:n.visualLine?"linewise":n.visualBlock?"blockwise":""})}},joinLines:function(e,t,n){var r,i;if(n.visualMode){r=e.getCursor("anchor"),i=e.getCursor("head");if(Ot(i,r)){var s=i;i=r,r=s}i.ch=Pt(e,i.line)-1}else{var o=Math.max(t.repeat,2);r=e.getCursor(),i=wt(e,E(r.line+o-1,Infinity))}var u=0;for(var a=r.line;a<i.line;a++){u=Pt(e,r.line);var s=E(r.line+1,Pt(e,r.line+1)),f=e.getRange(r,s);f=f.replace(/\n\s*/g," "),e.replaceRange(f,r,s)}var l=E(r.line,u);n.visualMode&&$t(e,!1),e.setCursor(l)},newLineAndEnterInsertMode:function(e,t,n){n.insertMode=!0;var r=Lt(e.getCursor());if(r.line===e.firstLine()&&!t.after)e.replaceRange("\n",E(e.firstLine(),0)),e.setCursor(e.firstLine(),0);else{r.line=t.after?r.line:r.line-1,r.ch=Pt(e,r.line),e.setCursor(r);var i=v.commands.newlineAndIndentContinueComment||v.commands.newlineAndIndent;i(e)}this.enterInsertMode(e,{repeat:t.repeat},n)},paste:function(e,t,n){var r=Lt(e.getCursor()),i=nt.registerController.getRegister(t.registerName),s=i.toString();if(!s)return;if(t.matchIndent){var o=e.getOption("tabSize"),u=function(e){var t=e.split("	").length-1,n=e.split(" ").length-1;return t*o+n*1},a=e.getLine(e.getCursor().line),f=u(a.match(/^\s*/)[0]),l=s.replace(/\n$/,""),c=s!==l,h=u(s.match(/^\s*/)[0]),s=l.replace(/^\s*/gm,function(t){var n=f+(u(t)-h);if(n<0)return"";if(e.getOption("indentWithTabs")){var r=Math.floor(n/o);return Array(r+1).join("	")}return Array(n+1).join(" ")});s+=c?"\n":""}if(t.repeat>1)var s=Array(t.repeat+1).join(s);var p=i.linewise,d=i.blockwise;if(p&&!d)n.visualMode?s=n.visualLine?s.slice(0,-1):"\n"+s.slice(0,s.length-1)+"\n":t.after?(s="\n"+s.slice(0,s.length-1),r.ch=Pt(e,r.line)):r.ch=0;else{if(d){s=s.split("\n");for(var v=0;v<s.length;v++)s[v]=s[v]==""?" ":s[v]}r.ch+=t.after?1:0}var m,g;if(n.visualMode){n.lastPastedText=s;var y,b=Rt(e,n),w=b[0],S=b[1],x=e.getSelection(),T=e.listSelections(),N=(new Array(T.length)).join("1").split("1");n.lastSelection&&(y=n.lastSelection.headMark.find()),nt.registerController.unnamedRegister.setText(x),d?(e.replaceSelections(N),S=E(w.line+s.length-1,w.ch),e.setCursor(w),Ft(e,S),e.replaceSelections(s),m=w):n.visualBlock?(e.replaceSelections(N),e.setCursor(w),e.replaceRange(s,w,w),m=w):(e.replaceRange(s,w,S),m=e.posFromIndex(e.indexFromPos(w)+s.length-1)),y&&(n.lastSelection.headMark=e.setBookmark(y)),p&&(m.ch=0)}else if(d){e.setCursor(r);for(var v=0;v<s.length;v++){var C=r.line+v;C>e.lastLine()&&e.replaceRange("\n",E(C,0));var k=Pt(e,C);k<r.ch&&jt(e,C,r.ch)}e.setCursor(r),Ft(e,E(r.line+s.length-1,r.ch)),e.replaceSelections(s),m=r}else e.replaceRange(s,r),p&&t.after?m=E(r.line+1,Qt(e.getLine(r.line+1))):p&&!t.after?m=E(r.line,Qt(e.getLine(r.line))):!p&&t.after?(g=e.indexFromPos(r),m=e.posFromIndex(g+s.length-1)):(g=e.indexFromPos(r),m=e.posFromIndex(g+s.length));n.visualMode&&$t(e,!1),e.setCursor(m)},undo:function(e,t){e.operation(function(){kt(e,v.commands.undo,t.repeat)(),e.setCursor(e.getCursor("anchor"))})},redo:function(e,t){kt(e,v.commands.redo,t.repeat)()},setRegister:function(e,t,n){n.inputState.registerName=t.selectedCharacter},setMark:function(e,t,n){var r=t.selectedCharacter;an(e,n,r,e.getCursor())},replace:function(e,t,n){var r=t.selectedCharacter,i=e.getCursor(),s,o,u=e.listSelections();if(n.visualMode)i=e.getCursor("start"),o=e.getCursor("end");else{var a=e.getLine(i.line);s=i.ch+t.repeat,s>a.length&&(s=a.length),o=E(i.line,s)}if(r=="\n")n.visualMode||e.replaceRange("",i,o),(v.commands.newlineAndIndentContinueComment||v.commands.newlineAndIndent)(e);else{var f=e.getRange(i,o);f=f.replace(/[^\n]/g,r);if(n.visualBlock){var l=(new Array(e.getOption("tabSize")+1)).join(" ");f=e.getSelection(),f=f.replace(/\t/g,l).replace(/[^\n]/g,r).split("\n"),e.replaceSelections(f)}else e.replaceRange(f,i,o);n.visualMode?(i=Ot(u[0].anchor,u[0].head)?u[0].anchor:u[0].head,e.setCursor(i),$t(e,!1)):e.setCursor(St(o,0,-1))}},incrementNumberToken:function(e,t){var n=e.getCursor(),r=e.getLine(n.line),i=/-?\d+/g,s,o,u,a,f;while((s=i.exec(r))!==null){f=s[0],o=s.index,u=o+f.length;if(n.ch<u)break}if(!t.backtrack&&u<=n.ch)return;if(!f)return;var l=t.increase?1:-1,c=parseInt(f)+l*t.repeat,h=E(n.line,o),p=E(n.line,u);a=c.toString(),e.replaceRange(a,h,p),e.setCursor(E(n.line,o+a.length-1))},repeatLastEdit:function(e,t,n){var r=n.lastEditInputState;if(!r)return;var i=t.repeat;i&&t.repeatIsExplicit?n.lastEditInputState.repeatOverride=i:i=n.lastEditInputState.repeatOverride||i,Zn(e,n,i,!1)},exitInsertMode:qn},en={"(":"bracket",")":"bracket","{":"bracket","}":"bracket","[":"section","]":"section","*":"comment","/":"comment",m:"method",M:"method","#":"preprocess"},tn={bracket:{isComplete:function(e){if(e.nextCh===e.symb){e.depth++;if(e.depth>=1)return!0}else e.nextCh===e.reverseSymb&&e.depth--;return!1}},section:{init:function(e){e.curMoveThrough=!0,e.symb=(e.forward?"]":"[")===e.symb?"{":"}"},isComplete:function(e){return e.index===0&&e.nextCh===e.symb}},comment:{isComplete:function(e){var t=e.lastCh==="*"&&e.nextCh==="/";return e.lastCh=e.nextCh,t}},method:{init:function(e){e.symb=e.symb==="m"?"{":"}",e.reverseSymb=e.symb==="{"?"}":"{"},isComplete:function(e){return e.nextCh===e.symb?!0:!1}},preprocess:{init:function(e){e.index=0},isComplete:function(e){if(e.nextCh==="#"){var t=e.lineText.match(/#(\w+)/)[1];if(t==="endif"){if(e.forward&&e.depth===0)return!0;e.depth++}else if(t==="if"){if(!e.forward&&e.depth===0)return!0;e.depth--}if(t==="else"&&e.depth===0)return!0}return!1}}};K("pcre",!0,"boolean"),pn.prototype={getQuery:function(){return nt.query},setQuery:function(e){nt.query=e},getOverlay:function(){return this.searchOverlay},setOverlay:function(e){this.searchOverlay=e},isReversed:function(){return nt.isReversed},setReversed:function(e){nt.isReversed=e},getScrollbarAnnotate:function(){return this.annotate},setScrollbarAnnotate:function(e){this.annotate=e}};var bn={"\\n":"\n","\\r":"\r","\\t":"	"},En={"\\/":"/","\\\\":"\\","\\n":"\n","\\r":"\r","\\t":"	"},Cn="(Javascript regexp)",Bn=function(){this.buildCommandMap_()};Bn.prototype={processCommand:function(e,t,n){var r=this;e.operation(function(){e.curOp.isVimOp=!0,r._processCommand(e,t,n)})},_processCommand:function(e,t,n){var r=e.state.vim,i=nt.registerController.getRegister(":"),s=i.toString();r.visualMode&&$t(e);var o=new v.StringStream(t);i.setText(t);var u=n||{};u.input=t;try{this.parseInput_(e,o,u)}catch(a){throw Tn(e,a),a}var f,l;if(!u.commandName)u.line!==undefined&&(l="move");else{f=this.matchCommand_(u.commandName);if(f){l=f.name,f.excludeFromCommandHistory&&i.setText(s),this.parseCommandArgs_(o,u,f);if(f.type=="exToKey"){for(var c=0;c<f.toKeys.length;c++)v.Vim.handleKey(e,f.toKeys[c],"mapping");return}if(f.type=="exToEx"){this.processCommand(e,f.toInput);return}}}if(!l){Tn(e,'Not an editor command ":'+t+'"');return}try{jn[l](e,u),(!f||!f.possiblyAsync)&&u.callback&&u.callback()}catch(a){throw Tn(e,a),a}},parseInput_:function(e,t,n){t.eatWhile(":"),t.eat("%")?(n.line=e.firstLine(),n.lineEnd=e.lastLine()):(n.line=this.parseLineSpec_(e,t),n.line!==undefined&&t.eat(",")&&(n.lineEnd=this.parseLineSpec_(e,t)));var r=t.match(/^(\w+)/);return r?n.commandName=r[1]:n.commandName=t.match(/.*/)[0],n},parseLineSpec_:function(e,t){var n=t.match(/^(\d+)/);if(n)return parseInt(n[1],10)-1;switch(t.next()){case".":return e.getCursor().line;case"$":return e.lastLine();case"'":var r=e.state.vim.marks[t.next()];if(r&&r.find())return r.find().line;throw new Error("Mark not set");default:return t.backUp(1),undefined}},parseCommandArgs_:function(e,t,n){if(e.eol())return;t.argString=e.match(/.*/)[0];var r=n.argDelimiter||/\s+/,i=Ht(t.argString).split(r);i.length&&i[0]&&(t.args=i)},matchCommand_:function(e){for(var t=e.length;t>0;t--){var n=e.substring(0,t);if(this.commandMap_[n]){var r=this.commandMap_[n];if(r.name.indexOf(e)===0)return r}}return null},buildCommandMap_:function(){this.commandMap_={};for(var e=0;e<w.length;e++){var t=w[e],n=t.shortName||t.name;this.commandMap_[n]=t}},map:function(e,t,n){if(e!=":"&&e.charAt(0)==":"){if(n)throw Error("Mode not supported for ex mappings");var r=e.substring(1);t!=":"&&t.charAt(0)==":"?this.commandMap_[r]={name:r,type:"exToEx",toInput:t.substring(1),user:!0}:this.commandMap_[r]={name:r,type:"exToKey",toKeys:t,user:!0}}else if(t!=":"&&t.charAt(0)==":"){var i={keys:e,type:"keyToEx",exArgs:{input:t.substring(1)},user:!0};n&&(i.context=n),b.unshift(i)}else{var i={keys:e,type:"keyToKey",toKeys:t,user:!0};n&&(i.context=n),b.unshift(i)}},unmap:function(e,t){if(e!=":"&&e.charAt(0)==":"){if(t)throw Error("Mode not supported for ex mappings");var n=e.substring(1);if(this.commandMap_[n]&&this.commandMap_[n].user){delete this.commandMap_[n];return}}else{var r=e;for(var i=0;i<b.length;i++)if(r==b[i].keys&&b[i].context===t&&b[i].user){b.splice(i,1);return}}throw Error("No such mapping.")}};var jn={colorscheme:function(e,t){if(!t.args||t.args.length<1){Tn(e,e.getOption("theme"));return}e.setOption("theme",t.args[0])},map:function(e,t,n){var r=t.args;if(!r||r.length<2){e&&Tn(e,"Invalid mapping: "+t.input);return}Fn.map(r[0],r[1],n)},imap:function(e,t){this.map(e,t,"insert")},nmap:function(e,t){this.map(e,t,"normal")},vmap:function(e,t){this.map(e,t,"visual")},unmap:function(e,t,n){var r=t.args;if(!r||r.length<1){e&&Tn(e,"No such mapping: "+t.input);return}Fn.unmap(r[0],n)},move:function(e,t){ht.processCommand(e,e.state.vim,{type:"motion",motion:"moveToLineOrEdgeOfDocument",motionArgs:{forward:!1,explicitRepeat:!0,linewise:!0},repeatOverride:t.line+1})},set:function(e,t){var n=t.args,r=t.setCfg||{};if(!n||n.length<1){e&&Tn(e,"Invalid mapping: "+t.input);return}var i=n[0].split("="),s=i[0],o=i[1],u=!1;if(s.charAt(s.length-1)=="?"){if(o)throw Error("Trailing characters: "+t.argString);s=s.substring(0,s.length-1),u=!0}o===undefined&&s.substring(0,2)=="no"&&(s=s.substring(2),o=!1);var a=J[s]&&J[s].type=="boolean";a&&o==undefined&&(o=!0);if(!a&&o===undefined||u){var f=G(s,e,r);f===!0||f===!1?Tn(e," "+(f?"":"no")+s):Tn(e,"  "+s+"="+f)}else Q(s,o,e,r)},setlocal:function(e,t){t.setCfg={scope:"local"},this.set(e,t)},setglobal:function(e,t){t.setCfg={scope:"global"},this.set(e,t)},registers:function(e,t){var n=t.args,r=nt.registerController.registers,i="----------Registers----------<br><br>";if(!n)for(var s in r){var o=r[s].toString();o.length&&(i+='"'+s+"    "+o+"<br>")}else{var s;n=n.join("");for(var u=0;u<n.length;u++){s=n.charAt(u);if(!nt.registerController.isValidRegister(s))continue;var a=r[s]||new at;i+='"'+s+"    "+a.toString()+"<br>"}}Tn(e,i)},sort:function(e,t){function o(){if(t.argString){var e=new v.StringStream(t.argString);e.eat("!")&&(n=!0);if(e.eol())return;if(!e.eatSpace())return"Invalid arguments";var o=e.match(/[a-z]+/);if(o){o=o[0],r=o.indexOf("i")!=-1,i=o.indexOf("u")!=-1;var u=o.indexOf("d")!=-1&&1,a=o.indexOf("x")!=-1&&1,f=o.indexOf("o")!=-1&&1;if(u+a+f>1)return"Invalid arguments";s=u&&"decimal"||a&&"hex"||f&&"octal"}if(e.match(/\/.*\//))return"patterns not supported"}}function b(e,t){if(n){var i;i=e,e=t,t=i}r&&(e=e.toLowerCase(),t=t.toLowerCase());var o=s&&p.exec(e),u=s&&p.exec(t);return o?(o=parseInt((o[1]+o[2]).toLowerCase(),d),u=parseInt((u[1]+u[2]).toLowerCase(),d),o-u):e<t?-1:1}var n,r,i,s,u=o();if(u){Tn(e,u+": "+t.argString);return}var a=t.line||e.firstLine(),f=t.lineEnd||t.line||e.lastLine();if(a==f)return;var l=E(a,0),c=E(f,Pt(e,f)),h=e.getRange(l,c).split("\n"),p=s=="decimal"?/(-?)([\d]+)/:s=="hex"?/(-?)(?:0x)?([0-9a-f]+)/i:s=="octal"?/([0-7]+)/:null,d=s=="decimal"?10:s=="hex"?16:s=="octal"?8:null,m=[],g=[];if(s)for(var y=0;y<h.length;y++)p.exec(h[y])?m.push(h[y]):g.push(h[y]);else g=h;m.sort(b),g.sort(b),h=n?m.concat(g):g.concat(m);if(i){var w=h,S;h=[];for(var y=0;y<w.length;y++)w[y]!=S&&h.push(w[y]),S=w[y]}e.replaceRange(h.join("\n"),l,c)},global:function(e,t){var n=t.argString;if(!n){Tn(e,"Regular Expression missing from global");return}var r=t.line!==undefined?t.line:e.firstLine(),i=t.lineEnd||t.line||e.lastLine(),s=mn(n),o=n,u;s.length&&(o=s[0],u=s.slice(1,s.length).join("/"));if(o)try{An(e,o,!0,!0)}catch(a){Tn(e,"Invalid regex: "+o);return}var f=dn(e).getQuery(),l=[],c="";for(var h=r;h<=i;h++){var p=f.test(e.getLine(h));p&&(l.push(h+1),c+=e.getLine(h)+"<br>")}if(!u){Tn(e,c);return}var d=0,v=function(){if(d<l.length){var t=l[d]+u;Fn.processCommand(e,t,{callback:v})}d++};v()},substitute:function(e,t){if(!e.getSearchCursor)throw new Error("Search feature not available. Requires searchcursor.js or any other getSearchCursor implementation.");var n=t.argString,r=n?mn(n):[],i,s="",o,u,a,f=!1,l=!1;if(r.length)i=r[0],s=r[1],s!==undefined&&(G("pcre")?s=Sn(s):s=wn(s),nt.lastSubstituteReplacePart=s),o=r[2]?r[2].split(" "):[];else if(n&&n.length){Tn(e,"Substitutions should be of the form :s/pattern/replace/");return}o&&(u=o[0],a=parseInt(o[1]),u&&(u.indexOf("c")!=-1&&(f=!0,u.replace("c","")),u.indexOf("g")!=-1&&(l=!0,u.replace("g","")),i=i+"/"+u));if(i)try{An(e,i,!0,!0)}catch(c){Tn(e,"Invalid regex: "+i);return}s=s||nt.lastSubstituteReplacePart;if(s===undefined){Tn(e,"No previous substitute regular expression");return}var h=dn(e),p=h.getQuery(),d=t.line!==undefined?t.line:e.getCursor().line,v=t.lineEnd||d;d==e.firstLine()&&v==e.lastLine()&&(v=Infinity),a&&(d=v,v=d+a-1);var m=wt(e,E(d,0)),g=e.getSearchCursor(p,m);In(e,f,l,d,v,g,p,s,t.callback)},redo:v.commands.redo,undo:v.commands.undo,write:function(e){v.commands.save?v.commands.save(e):e.save()},nohlsearch:function(e){Dn(e)},delmarks:function(e,t){if(!t.argString||!Ht(t.argString)){Tn(e,"Argument required");return}var n=e.state.vim,r=new v.StringStream(Ht(t.argString));while(!r.eol()){r.eatSpace();var i=r.pos;if(!r.match(/[a-zA-Z]/,!1)){Tn(e,"Invalid argument: "+t.argString.substring(i));return}var s=r.next();if(r.match("-",!0)){if(!r.match(/[a-zA-Z]/,!1)){Tn(e,"Invalid argument: "+t.argString.substring(i));return}var o=s,u=r.next();if(!(U(o)&&U(u)||X(o)&&X(u))){Tn(e,"Invalid argument: "+o+"-");return}var a=o.charCodeAt(0),f=u.charCodeAt(0);if(a>=f){Tn(e,"Invalid argument: "+t.argString.substring(i));return}for(var l=0;l<=f-a;l++){var c=String.fromCharCode(a+l);delete n.marks[c]}}else delete n.marks[s]}}},Fn=new Bn;v.keyMap.vim={attach:C,detach:N,call:k},K("insertModeEscKeysTimeout",200,"number"),v.keyMap["vim-insert"]={"Ctrl-N":"autocomplete","Ctrl-P":"autocomplete",Enter:function(e){var t=v.commands.newlineAndIndentContinueComment||v.commands.newlineAndIndent;t(e)},fallthrough:["default"],attach:C,detach:N,call:k},v.keyMap["vim-replace"]={Backspace:"goCharLeft",fallthrough:["vim-insert"],attach:C,detach:N,call:k},rt(),v.Vim=S(),S=v.Vim;var tr={"return":"CR",backspace:"BS","delete":"Del",esc:"Esc",left:"Left",right:"Right",up:"Up",down:"Down",space:"Space",home:"Home",end:"End",pageup:"PageUp",pagedown:"PageDown",enter:"CR"},rr=S.handleKey.bind(S);S.handleKey=function(e,t,n){return e.operation(function(){return rr(e,t,n)},!0)},t.CodeMirror=v;var or=S.maybeInitVimState_;t.handler={$id:"ace/keyboard/vim",drawCursor:function(e,t,n,r,s){var o=this.state.vim||{},u=n.characterWidth,a=n.lineHeight,f=t.top,l=t.left;if(!o.insertMode){var c=r.cursor?i.comparePoints(r.cursor,r.start)<=0:s.selection.isBackwards()||s.selection.isEmpty();!c&&l>u&&(l-=u)}!o.insertMode&&o.status&&(a/=2,f+=a),e.left=l+"px",e.top=f+"px",e.width=u+"px",e.height=a+"px"},handleKeyboard:function(e,t,n,r,i){var s=e.editor,o=s.state.cm,u=or(o);if(r==-1)return;if(n=="c"&&t==1){if(!c.isMac&&s.getCopyText())return s.once("copy",function(){s.selection.clearSelection()}),{command:"null",passEvent:!0}}else u.insertMode||c.isMac&&this.handleMacRepeat(e,t,n)&&(t=-1,n=e.inputChar);if(t==-1||t&1||t===0&&n.length>1){var a=u.insertMode,f=nr(t,n,i||{});u.status==null&&(u.status="");var l=sr(o,f,"user");u=or(o),l&&u.status!=null?u.status+=f:u.status==null&&(u.status=""),o._signal("changeStatus");if(!l&&(t!=-1||a))return;return{command:"null",passEvent:!l}}},attach:function(e){e.state||(e.state={});var t=new v(e);e.state.cm=t,e.$vimModeHandler=this,v.keyMap.vim.attach(t),or(t).status=null,t.on("vim-command-done",function(){if(t.virtualSelectionMode())return;or(t).status=null,t.ace._signal("changeStatus"),t.ace.session.markUndoGroup()}),t.on("changeStatus",function(){t.ace.renderer.updateCursor(),t.ace._signal("changeStatus")}),t.on("vim-mode-change",function(){if(t.virtualSelectionMode())return;t.ace.renderer.setStyle("normal-mode",!or(t).insertMode),t._signal("changeStatus")}),t.ace.renderer.setStyle("normal-mode",!or(t).insertMode),e.renderer.$cursorLayer.drawCursor=this.drawCursor.bind(t),this.updateMacCompositionHandlers(e,!0)},detach:function(e){var t=e.state.cm;v.keyMap.vim.detach(t),t.destroy(),e.state.cm=null,e.$vimModeHandler=null,e.renderer.$cursorLayer.drawCursor=null,e.renderer.setStyle("normal-mode",!1),this.updateMacCompositionHandlers(e,!1)},getStatusText:function(e){var t=e.state.cm,n=or(t);if(n.insertMode)return"INSERT";var r="";return n.visualMode&&(r+="VISUAL",n.visualLine&&(r+=" LINE"),n.visualBlock&&(r+=" BLOCK")),n.status&&(r+=(r?" ":"")+n.status),r},handleMacRepeat:function(e,t,n){if(t==-1)e.inputChar=n,e.lastEvent="input";else if(e.inputChar&&e.$lastHash==t&&e.$lastKey==n){if(e.lastEvent=="input")e.lastEvent="input1";else if(e.lastEvent=="input1")return!0}else e.$lastHash=t,e.$lastKey=n,e.lastEvent="keypress"},updateMacCompositionHandlers:function(e,t){var n=function(t){var n=e.state.cm,r=or(n);if(!r.insertMode){var i=this.textInput.getElement();i.blur(),i.focus(),i.value=t}else this.onCompositionUpdateOrig(t)},r=function(t){var n=e.state.cm,r=or(n);r.insertMode||this.onCompositionStartOrig(t)};t?e.onCompositionUpdateOrig||(e.onCompositionUpdateOrig=e.onCompositionUpdate,e.onCompositionUpdate=n,e.onCompositionStartOrig=e.onCompositionStart,e.onCompositionStart=r):e.onCompositionUpdateOrig&&(e.onCompositionUpdate=e.onCompositionUpdateOrig,e.onCompositionUpdateOrig=null,e.onCompositionStart=e.onCompositionStartOrig,e.onCompositionStartOrig=null)}};var ur={getText:function(e,t){return(Math.abs(e.selection.lead.row-t)||t+1+(t<9?"\u00b7":""))+""},getWidth:function(e,t,n){return e.getLength().toString().length*n.characterWidth},update:function(e,t){t.renderer.$loop.schedule(t.renderer.CHANGE_GUTTER)},attach:function(e){e.renderer.$gutterLayer.$renderer=this,e.on("changeSelection",this.update)},detach:function(e){e.renderer.$gutterLayer.$renderer=null,e.off("changeSelection",this.update)}};S.defineOption({name:"wrap",set:function(e,t){t&&t.ace.setOption("wrap",e)},type:"boolean"},!1),S.defineEx("write","w",function(){console.log(":write is not implemented")}),b.push({keys:"zc",type:"action",action:"fold",actionArgs:{open:!1}},{keys:"zC",type:"action",action:"fold",actionArgs:{open:!1,all:!0}},{keys:"zo",type:"action",action:"fold",actionArgs:{open:!0}},{keys:"zO",type:"action",action:"fold",actionArgs:{open:!0,all:!0}},{keys:"za",type:"action",action:"fold",actionArgs:{toggle:!0}},{keys:"zA",type:"action",action:"fold",actionArgs:{toggle:!0,all:!0}},{keys:"zf",type:"action",action:"fold",actionArgs:{open:!0,all:!0}},{keys:"zd",type:"action",action:"fold",actionArgs:{open:!0,all:!0}},{keys:"<C-A-k>",type:"action",action:"aceCommand",actionArgs:{name:"addCursorAbove"}},{keys:"<C-A-j>",type:"action",action:"aceCommand",actionArgs:{name:"addCursorBelow"}},{keys:"<C-A-S-k>",type:"action",action:"aceCommand",actionArgs:{name:"addCursorAboveSkipCurrent"}},{keys:"<C-A-S-j>",type:"action",action:"aceCommand",actionArgs:{name:"addCursorBelowSkipCurrent"}},{keys:"<C-A-h>",type:"action",action:"aceCommand",actionArgs:{name:"selectMoreBefore"}},{keys:"<C-A-l>",type:"action",action:"aceCommand",actionArgs:{name:"selectMoreAfter"}},{keys:"<C-A-S-h>",type:"action",action:"aceCommand",actionArgs:{name:"selectNextBefore"}},{keys:"<C-A-S-l>",type:"action",action:"aceCommand",actionArgs:{name:"selectNextAfter"}}),yt.aceCommand=function(e,t,n){e.vimCmd=t,e.ace.inVirtualSelectionMode?e.ace.on("beforeEndOperation",ar):ar(null,e.ace)},yt.fold=function(e,t,n){e.ace.execCommand(["toggleFoldWidget","toggleFoldWidget","foldOther","unfoldall"][(t.all?2:0)+(t.open?1:0)])},t.handler.defaultKeymap=b,t.handler.actions=yt,t.Vim=S,S.map("Y","yy","normal")})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/mode-javascript.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/mode-javascript.js
new file mode 100644
index 0000000..26a8bdc
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/mode-javascript.js
@@ -0,0 +1 @@
+ace.define("ace/mode/doc_comment_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:"comment.doc.tag",regex:"@[\\w\\d_]+"},s.getTagRule(),{defaultToken:"comment.doc",caseInsensitive:!0}]}};r.inherits(s,i),s.getTagRule=function(e){return{token:"comment.doc.tag.storage.type",regex:"\\b(?:TODO|FIXME|XXX|HACK)\\b"}},s.getStartRule=function(e){return{token:"comment.doc",regex:"\\/\\*(?=\\*)",next:e}},s.getEndRule=function(e){return{token:"comment.doc",regex:"\\*\\/",next:e}},t.DocCommentHighlightRules=s}),ace.define("ace/mode/javascript_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/doc_comment_highlight_rules","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";function a(){var e=o.replace("\\d","\\d\\-"),t={onMatch:function(e,t,n){var r=e.charAt(1)=="/"?2:1;if(r==1)t!=this.nextState?n.unshift(this.next,this.nextState,0):n.unshift(this.next),n[2]++;else if(r==2&&t==this.nextState){n[1]--;if(!n[1]||n[1]<0)n.shift(),n.shift()}return[{type:"meta.tag.punctuation."+(r==1?"":"end-")+"tag-open.xml",value:e.slice(0,r)},{type:"meta.tag.tag-name.xml",value:e.substr(r)}]},regex:"</?"+e+"",next:"jsxAttributes",nextState:"jsx"};this.$rules.start.unshift(t);var n={regex:"{",token:"paren.quasi.start",push:"start"};this.$rules.jsx=[n,t,{include:"reference"},{defaultToken:"string"}],this.$rules.jsxAttributes=[{token:"meta.tag.punctuation.tag-close.xml",regex:"/?>",onMatch:function(e,t,n){return t==n[0]&&n.shift(),e.length==2&&(n[0]==this.nextState&&n[1]--,(!n[1]||n[1]<0)&&n.splice(0,2)),this.next=n[0]||"start",[{type:this.token,value:e}]},nextState:"jsx"},n,f("jsxAttributes"),{token:"entity.other.attribute-name.xml",regex:e},{token:"keyword.operator.attribute-equals.xml",regex:"="},{token:"text.tag-whitespace.xml",regex:"\\s+"},{token:"string.attribute-value.xml",regex:"'",stateName:"jsx_attr_q",push:[{token:"string.attribute-value.xml",regex:"'",next:"pop"},{include:"reference"},{defaultToken:"string.attribute-value.xml"}]},{token:"string.attribute-value.xml",regex:'"',stateName:"jsx_attr_qq",push:[{token:"string.attribute-value.xml",regex:'"',next:"pop"},{include:"reference"},{defaultToken:"string.attribute-value.xml"}]},t],this.$rules.reference=[{token:"constant.language.escape.reference.xml",regex:"(?:&#[0-9]+;)|(?:&#x[0-9a-fA-F]+;)|(?:&[a-zA-Z0-9_:\\.-]+;)"}]}function f(e){return[{token:"comment",regex:/\/\*/,next:[i.getTagRule(),{token:"comment",regex:"\\*\\/",next:e||"pop"},{defaultToken:"comment",caseInsensitive:!0}]},{token:"comment",regex:"\\/\\/",next:[i.getTagRule(),{token:"comment",regex:"$|^",next:e||"pop"},{defaultToken:"comment",caseInsensitive:!0}]}]}var r=e("../lib/oop"),i=e("./doc_comment_highlight_rules").DocCommentHighlightRules,s=e("./text_highlight_rules").TextHighlightRules,o="[a-zA-Z\\$_\u00a1-\uffff][a-zA-Z\\d\\$_\u00a1-\uffff]*\\b",u=function(e){var t=this.createKeywordMapper({"variable.language":"Array|Boolean|Date|Function|Iterator|Number|Object|RegExp|String|Proxy|Namespace|QName|XML|XMLList|ArrayBuffer|Float32Array|Float64Array|Int16Array|Int32Array|Int8Array|Uint16Array|Uint32Array|Uint8Array|Uint8ClampedArray|Error|EvalError|InternalError|RangeError|ReferenceError|StopIteration|SyntaxError|TypeError|URIError|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|eval|isFinite|isNaN|parseFloat|parseInt|JSON|Math|this|arguments|prototype|window|document",keyword:"const|yield|import|get|set|break|case|catch|continue|default|delete|do|else|finally|for|function|if|in|instanceof|new|return|switch|throw|try|typeof|let|var|while|with|debugger|__parent__|__count__|escape|unescape|with|__proto__|class|enum|extends|super|export|implements|private|public|interface|package|protected|static","storage.type":"const|let|var|function","constant.language":"null|Infinity|NaN|undefined","support.function":"alert","constant.language.boolean":"true|false"},"identifier"),n="case|do|else|finally|in|instanceof|return|throw|try|typeof|yield|void",r="\\\\(?:x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|u{[0-9a-fA-F]{1,6}}|[0-2][0-7]{0,2}|3[0-7][0-7]?|[4-7][0-7]?|.)";this.$rules={no_regex:[i.getStartRule("doc-start"),f("no_regex"),{token:"string",regex:"'(?=.)",next:"qstring"},{token:"string",regex:'"(?=.)',next:"qqstring"},{token:"constant.numeric",regex:/0(?:[xX][0-9a-fA-F]+|[bB][01]+)\b/},{token:"constant.numeric",regex:/[+-]?\d[\d_]*(?:(?:\.\d*)?(?:[eE][+-]?\d+)?)?\b/},{token:["storage.type","punctuation.operator","support.function","punctuation.operator","entity.name.function","text","keyword.operator"],regex:"("+o+")(\\.)(prototype)(\\.)("+o+")(\\s*)(=)",next:"function_arguments"},{token:["storage.type","punctuation.operator","entity.name.function","text","keyword.operator","text","storage.type","text","paren.lparen"],regex:"("+o+")(\\.)("+o+")(\\s*)(=)(\\s*)(function)(\\s*)(\\()",next:"function_arguments"},{token:["entity.name.function","text","keyword.operator","text","storage.type","text","paren.lparen"],regex:"("+o+")(\\s*)(=)(\\s*)(function)(\\s*)(\\()",next:"function_arguments"},{token:["storage.type","punctuation.operator","entity.name.function","text","keyword.operator","text","storage.type","text","entity.name.function","text","paren.lparen"],regex:"("+o+")(\\.)("+o+")(\\s*)(=)(\\s*)(function)(\\s+)(\\w+)(\\s*)(\\()",next:"function_arguments"},{token:["storage.type","text","entity.name.function","text","paren.lparen"],regex:"(function)(\\s+)("+o+")(\\s*)(\\()",next:"function_arguments"},{token:["entity.name.function","text","punctuation.operator","text","storage.type","text","paren.lparen"],regex:"("+o+")(\\s*)(:)(\\s*)(function)(\\s*)(\\()",next:"function_arguments"},{token:["text","text","storage.type","text","paren.lparen"],regex:"(:)(\\s*)(function)(\\s*)(\\()",next:"function_arguments"},{token:"keyword",regex:"(?:"+n+")\\b",next:"start"},{token:["support.constant"],regex:/that\b/},{token:["storage.type","punctuation.operator","support.function.firebug"],regex:/(console)(\.)(warn|info|log|error|time|trace|timeEnd|assert)\b/},{token:t,regex:o},{token:"punctuation.operator",regex:/[.](?![.])/,next:"property"},{token:"keyword.operator",regex:/--|\+\+|\.{3}|===|==|=|!=|!==|<+=?|>+=?|!|&&|\|\||\?\:|[!$%&*+\-~\/^]=?/,next:"start"},{token:"punctuation.operator",regex:/[?:,;.]/,next:"start"},{token:"paren.lparen",regex:/[\[({]/,next:"start"},{token:"paren.rparen",regex:/[\])}]/},{token:"comment",regex:/^#!.*$/}],property:[{token:"text",regex:"\\s+"},{token:["storage.type","punctuation.operator","entity.name.function","text","keyword.operator","text","storage.type","text","entity.name.function","text","paren.lparen"],regex:"("+o+")(\\.)("+o+")(\\s*)(=)(\\s*)(function)(?:(\\s+)(\\w+))?(\\s*)(\\()",next:"function_arguments"},{token:"punctuation.operator",regex:/[.](?![.])/},{token:"support.function",regex:/(s(?:h(?:ift|ow(?:Mod(?:elessDialog|alDialog)|Help))|croll(?:X|By(?:Pages|Lines)?|Y|To)?|t(?:op|rike)|i(?:n|zeToContent|debar|gnText)|ort|u(?:p|b(?:str(?:ing)?)?)|pli(?:ce|t)|e(?:nd|t(?:Re(?:sizable|questHeader)|M(?:i(?:nutes|lliseconds)|onth)|Seconds|Ho(?:tKeys|urs)|Year|Cursor|Time(?:out)?|Interval|ZOptions|Date|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Date|FullYear)|FullYear|Active)|arch)|qrt|lice|avePreferences|mall)|h(?:ome|andleEvent)|navigate|c(?:har(?:CodeAt|At)|o(?:s|n(?:cat|textual|firm)|mpile)|eil|lear(?:Timeout|Interval)?|a(?:ptureEvents|ll)|reate(?:StyleSheet|Popup|EventObject))|t(?:o(?:GMTString|S(?:tring|ource)|U(?:TCString|pperCase)|Lo(?:caleString|werCase))|est|a(?:n|int(?:Enabled)?))|i(?:s(?:NaN|Finite)|ndexOf|talics)|d(?:isableExternalCapture|ump|etachEvent)|u(?:n(?:shift|taint|escape|watch)|pdateCommands)|j(?:oin|avaEnabled)|p(?:o(?:p|w)|ush|lugins.refresh|a(?:ddings|rse(?:Int|Float)?)|r(?:int|ompt|eference))|e(?:scape|nableExternalCapture|val|lementFromPoint|x(?:p|ec(?:Script|Command)?))|valueOf|UTC|queryCommand(?:State|Indeterm|Enabled|Value)|f(?:i(?:nd|le(?:ModifiedDate|Size|CreatedDate|UpdatedDate)|xed)|o(?:nt(?:size|color)|rward)|loor|romCharCode)|watch|l(?:ink|o(?:ad|g)|astIndexOf)|a(?:sin|nchor|cos|t(?:tachEvent|ob|an(?:2)?)|pply|lert|b(?:s|ort))|r(?:ou(?:nd|teEvents)|e(?:size(?:By|To)|calc|turnValue|place|verse|l(?:oad|ease(?:Capture|Events)))|andom)|g(?:o|et(?:ResponseHeader|M(?:i(?:nutes|lliseconds)|onth)|Se(?:conds|lection)|Hours|Year|Time(?:zoneOffset)?|Da(?:y|te)|UTC(?:M(?:i(?:nutes|lliseconds)|onth)|Seconds|Hours|Da(?:y|te)|FullYear)|FullYear|A(?:ttention|llResponseHeaders)))|m(?:in|ove(?:B(?:y|elow)|To(?:Absolute)?|Above)|ergeAttributes|a(?:tch|rgins|x))|b(?:toa|ig|o(?:ld|rderWidths)|link|ack))\b(?=\()/},{token:"support.function.dom",regex:/(s(?:ub(?:stringData|mit)|plitText|e(?:t(?:NamedItem|Attribute(?:Node)?)|lect))|has(?:ChildNodes|Feature)|namedItem|c(?:l(?:ick|o(?:se|neNode))|reate(?:C(?:omment|DATASection|aption)|T(?:Head|extNode|Foot)|DocumentFragment|ProcessingInstruction|E(?:ntityReference|lement)|Attribute))|tabIndex|i(?:nsert(?:Row|Before|Cell|Data)|tem)|open|delete(?:Row|C(?:ell|aption)|T(?:Head|Foot)|Data)|focus|write(?:ln)?|a(?:dd|ppend(?:Child|Data))|re(?:set|place(?:Child|Data)|move(?:NamedItem|Child|Attribute(?:Node)?)?)|get(?:NamedItem|Element(?:sBy(?:Name|TagName|ClassName)|ById)|Attribute(?:Node)?)|blur)\b(?=\()/},{token:"support.constant",regex:/(s(?:ystemLanguage|cr(?:ipts|ollbars|een(?:X|Y|Top|Left))|t(?:yle(?:Sheets)?|atus(?:Text|bar)?)|ibling(?:Below|Above)|ource|uffixes|e(?:curity(?:Policy)?|l(?:ection|f)))|h(?:istory|ost(?:name)?|as(?:h|Focus))|y|X(?:MLDocument|SLDocument)|n(?:ext|ame(?:space(?:s|URI)|Prop))|M(?:IN_VALUE|AX_VALUE)|c(?:haracterSet|o(?:n(?:structor|trollers)|okieEnabled|lorDepth|mp(?:onents|lete))|urrent|puClass|l(?:i(?:p(?:boardData)?|entInformation)|osed|asses)|alle(?:e|r)|rypto)|t(?:o(?:olbar|p)|ext(?:Transform|Indent|Decoration|Align)|ags)|SQRT(?:1_2|2)|i(?:n(?:ner(?:Height|Width)|put)|ds|gnoreCase)|zIndex|o(?:scpu|n(?:readystatechange|Line)|uter(?:Height|Width)|p(?:sProfile|ener)|ffscreenBuffering)|NEGATIVE_INFINITY|d(?:i(?:splay|alog(?:Height|Top|Width|Left|Arguments)|rectories)|e(?:scription|fault(?:Status|Ch(?:ecked|arset)|View)))|u(?:ser(?:Profile|Language|Agent)|n(?:iqueID|defined)|pdateInterval)|_content|p(?:ixelDepth|ort|ersonalbar|kcs11|l(?:ugins|atform)|a(?:thname|dding(?:Right|Bottom|Top|Left)|rent(?:Window|Layer)?|ge(?:X(?:Offset)?|Y(?:Offset)?))|r(?:o(?:to(?:col|type)|duct(?:Sub)?|mpter)|e(?:vious|fix)))|e(?:n(?:coding|abledPlugin)|x(?:ternal|pando)|mbeds)|v(?:isibility|endor(?:Sub)?|Linkcolor)|URLUnencoded|P(?:I|OSITIVE_INFINITY)|f(?:ilename|o(?:nt(?:Size|Family|Weight)|rmName)|rame(?:s|Element)|gColor)|E|whiteSpace|l(?:i(?:stStyleType|n(?:eHeight|kColor))|o(?:ca(?:tion(?:bar)?|lName)|wsrc)|e(?:ngth|ft(?:Context)?)|a(?:st(?:M(?:odified|atch)|Index|Paren)|yer(?:s|X)|nguage))|a(?:pp(?:MinorVersion|Name|Co(?:deName|re)|Version)|vail(?:Height|Top|Width|Left)|ll|r(?:ity|guments)|Linkcolor|bove)|r(?:ight(?:Context)?|e(?:sponse(?:XML|Text)|adyState))|global|x|m(?:imeTypes|ultiline|enubar|argin(?:Right|Bottom|Top|Left))|L(?:N(?:10|2)|OG(?:10E|2E))|b(?:o(?:ttom|rder(?:Width|RightWidth|BottomWidth|Style|Color|TopWidth|LeftWidth))|ufferDepth|elow|ackground(?:Color|Image)))\b/},{token:"identifier",regex:o},{regex:"",token:"empty",next:"no_regex"}],start:[i.getStartRule("doc-start"),f("start"),{token:"string.regexp",regex:"\\/",next:"regex"},{token:"text",regex:"\\s+|^$",next:"start"},{token:"empty",regex:"",next:"no_regex"}],regex:[{token:"regexp.keyword.operator",regex:"\\\\(?:u[\\da-fA-F]{4}|x[\\da-fA-F]{2}|.)"},{token:"string.regexp",regex:"/[sxngimy]*",next:"no_regex"},{token:"invalid",regex:/\{\d+\b,?\d*\}[+*]|[+*$^?][+*]|[$^][?]|\?{3,}/},{token:"constant.language.escape",regex:/\(\?[:=!]|\)|\{\d+\b,?\d*\}|[+*]\?|[()$^+*?.]/},{token:"constant.language.delimiter",regex:/\|/},{token:"constant.language.escape",regex:/\[\^?/,next:"regex_character_class"},{token:"empty",regex:"$",next:"no_regex"},{defaultToken:"string.regexp"}],regex_character_class:[{token:"regexp.charclass.keyword.operator",regex:"\\\\(?:u[\\da-fA-F]{4}|x[\\da-fA-F]{2}|.)"},{token:"constant.language.escape",regex:"]",next:"regex"},{token:"constant.language.escape",regex:"-"},{token:"empty",regex:"$",next:"no_regex"},{defaultToken:"string.regexp.charachterclass"}],function_arguments:[{token:"variable.parameter",regex:o},{token:"punctuation.operator",regex:"[, ]+"},{token:"punctuation.operator",regex:"$"},{token:"empty",regex:"",next:"no_regex"}],qqstring:[{token:"constant.language.escape",regex:r},{token:"string",regex:"\\\\$",next:"qqstring"},{token:"string",regex:'"|$',next:"no_regex"},{defaultToken:"string"}],qstring:[{token:"constant.language.escape",regex:r},{token:"string",regex:"\\\\$",next:"qstring"},{token:"string",regex:"'|$",next:"no_regex"},{defaultToken:"string"}]};if(!e||!e.noES6)this.$rules.no_regex.unshift({regex:"[{}]",onMatch:function(e,t,n){this.next=e=="{"?this.nextState:"";if(e=="{"&&n.length)n.unshift("start",t);else if(e=="}"&&n.length){n.shift(),this.next=n.shift();if(this.next.indexOf("string")!=-1||this.next.indexOf("jsx")!=-1)return"paren.quasi.end"}return e=="{"?"paren.lparen":"paren.rparen"},nextState:"start"},{token:"string.quasi.start",regex:/`/,push:[{token:"constant.language.escape",regex:r},{token:"paren.quasi.start",regex:/\${/,push:"start"},{token:"string.quasi.end",regex:/`/,next:"pop"},{defaultToken:"string.quasi"}]}),(!e||!e.noJSX)&&a.call(this);this.embedRules(i,"doc-",[i.getEndRule("no_regex")]),this.normalizeRules()};r.inherits(u,s),t.JavaScriptHighlightRules=u}),ace.define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"],function(e,t,n){"use strict";var r=e("../range").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return/^\s+$/.test(e)?/^\s*\}/.test(t):!1},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\s*\})/);if(!i)return 0;var s=i[1].length,o=e.findMatchingBracket({row:t,column:s});if(!o||o.row==t)return 0;var u=this.$getIndent(e.getLine(o.row));e.replace(new r(t,0,t,s-1),u)},this.$getIndent=function(e){return e.match(/^\s*/)[0]}}).call(i.prototype),t.MatchingBraceOutdent=i}),ace.define("ace/mode/behaviour/cstyle",["require","exports","module","ace/lib/oop","ace/mode/behaviour","ace/token_iterator","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../behaviour").Behaviour,s=e("../../token_iterator").TokenIterator,o=e("../../lib/lang"),u=["text","paren.rparen","punctuation.operator"],a=["text","paren.rparen","punctuation.operator","comment"],f,l={},c=function(e){var t=-1;e.multiSelect&&(t=e.selection.index,l.rangeCount!=e.multiSelect.rangeCount&&(l={rangeCount:e.multiSelect.rangeCount}));if(l[t])return f=l[t];f=l[t]={autoInsertedBrackets:0,autoInsertedRow:-1,autoInsertedLineEnd:"",maybeInsertedBrackets:0,maybeInsertedRow:-1,maybeInsertedLineStart:"",maybeInsertedLineEnd:""}},h=function(e,t,n,r){var i=e.end.row-e.start.row;return{text:n+t+r,selection:[0,e.start.column+1,i,e.end.column+(i?0:1)]}},p=function(){this.add("braces","insertion",function(e,t,n,r,i){var s=n.getCursorPosition(),u=r.doc.getLine(s.row);if(i=="{"){c(n);var a=n.getSelectionRange(),l=r.doc.getTextRange(a);if(l!==""&&l!=="{"&&n.getWrapBehavioursEnabled())return h(a,l,"{","}");if(p.isSaneInsertion(n,r))return/[\]\}\)]/.test(u[s.column])||n.inMultiSelectMode?(p.recordAutoInsert(n,r,"}"),{text:"{}",selection:[1,1]}):(p.recordMaybeInsert(n,r,"{"),{text:"{",selection:[1,1]})}else if(i=="}"){c(n);var d=u.substring(s.column,s.column+1);if(d=="}"){var v=r.$findOpeningBracket("}",{column:s.column+1,row:s.row});if(v!==null&&p.isAutoInsertedClosing(s,u,i))return p.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}else{if(i=="\n"||i=="\r\n"){c(n);var m="";p.isMaybeInsertedClosing(s,u)&&(m=o.stringRepeat("}",f.maybeInsertedBrackets),p.clearMaybeInsertedClosing());var d=u.substring(s.column,s.column+1);if(d==="}"){var g=r.findMatchingBracket({row:s.row,column:s.column+1},"}");if(!g)return null;var y=this.$getIndent(r.getLine(g.row))}else{if(!m){p.clearMaybeInsertedClosing();return}var y=this.$getIndent(u)}var b=y+r.getTabString();return{text:"\n"+b+"\n"+y+m,selection:[1,b.length,1,b.length]}}p.clearMaybeInsertedClosing()}}),this.add("braces","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="{"){c(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.end.column,i.end.column+1);if(u=="}")return i.end.column++,i;f.maybeInsertedBrackets--}}),this.add("parens","insertion",function(e,t,n,r,i){if(i=="("){c(n);var s=n.getSelectionRange(),o=r.doc.getTextRange(s);if(o!==""&&n.getWrapBehavioursEnabled())return h(s,o,"(",")");if(p.isSaneInsertion(n,r))return p.recordAutoInsert(n,r,")"),{text:"()",selection:[1,1]}}else if(i==")"){c(n);var u=n.getCursorPosition(),a=r.doc.getLine(u.row),f=a.substring(u.column,u.column+1);if(f==")"){var l=r.$findOpeningBracket(")",{column:u.column+1,row:u.row});if(l!==null&&p.isAutoInsertedClosing(u,a,i))return p.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}}),this.add("parens","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="("){c(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u==")")return i.end.column++,i}}),this.add("brackets","insertion",function(e,t,n,r,i){if(i=="["){c(n);var s=n.getSelectionRange(),o=r.doc.getTextRange(s);if(o!==""&&n.getWrapBehavioursEnabled())return h(s,o,"[","]");if(p.isSaneInsertion(n,r))return p.recordAutoInsert(n,r,"]"),{text:"[]",selection:[1,1]}}else if(i=="]"){c(n);var u=n.getCursorPosition(),a=r.doc.getLine(u.row),f=a.substring(u.column,u.column+1);if(f=="]"){var l=r.$findOpeningBracket("]",{column:u.column+1,row:u.row});if(l!==null&&p.isAutoInsertedClosing(u,a,i))return p.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}}),this.add("brackets","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="["){c(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u=="]")return i.end.column++,i}}),this.add("string_dquotes","insertion",function(e,t,n,r,i){if(i=='"'||i=="'"){c(n);var s=i,o=n.getSelectionRange(),u=r.doc.getTextRange(o);if(u!==""&&u!=="'"&&u!='"'&&n.getWrapBehavioursEnabled())return h(o,u,s,s);if(!u){var a=n.getCursorPosition(),f=r.doc.getLine(a.row),l=f.substring(a.column-1,a.column),p=f.substring(a.column,a.column+1),d=r.getTokenAt(a.row,a.column),v=r.getTokenAt(a.row,a.column+1);if(l=="\\"&&d&&/escape/.test(d.type))return null;var m=d&&/string|escape/.test(d.type),g=!v||/string|escape/.test(v.type),y;if(p==s)y=m!==g;else{if(m&&!g)return null;if(m&&g)return null;var b=r.$mode.tokenRe;b.lastIndex=0;var w=b.test(l);b.lastIndex=0;var E=b.test(l);if(w||E)return null;if(p&&!/[\s;,.})\]\\]/.test(p))return null;y=!0}return{text:y?s+s:"",selection:[1,1]}}}}),this.add("string_dquotes","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&(s=='"'||s=="'")){c(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u==s)return i.end.column++,i}})};p.isSaneInsertion=function(e,t){var n=e.getCursorPosition(),r=new s(t,n.row,n.column);if(!this.$matchTokenType(r.getCurrentToken()||"text",u)){var i=new s(t,n.row,n.column+1);if(!this.$matchTokenType(i.getCurrentToken()||"text",u))return!1}return r.stepForward(),r.getCurrentTokenRow()!==n.row||this.$matchTokenType(r.getCurrentToken()||"text",a)},p.$matchTokenType=function(e,t){return t.indexOf(e.type||e)>-1},p.recordAutoInsert=function(e,t,n){var r=e.getCursorPosition(),i=t.doc.getLine(r.row);this.isAutoInsertedClosing(r,i,f.autoInsertedLineEnd[0])||(f.autoInsertedBrackets=0),f.autoInsertedRow=r.row,f.autoInsertedLineEnd=n+i.substr(r.column),f.autoInsertedBrackets++},p.recordMaybeInsert=function(e,t,n){var r=e.getCursorPosition(),i=t.doc.getLine(r.row);this.isMaybeInsertedClosing(r,i)||(f.maybeInsertedBrackets=0),f.maybeInsertedRow=r.row,f.maybeInsertedLineStart=i.substr(0,r.column)+n,f.maybeInsertedLineEnd=i.substr(r.column),f.maybeInsertedBrackets++},p.isAutoInsertedClosing=function(e,t,n){return f.autoInsertedBrackets>0&&e.row===f.autoInsertedRow&&n===f.autoInsertedLineEnd[0]&&t.substr(e.column)===f.autoInsertedLineEnd},p.isMaybeInsertedClosing=function(e,t){return f.maybeInsertedBrackets>0&&e.row===f.maybeInsertedRow&&t.substr(e.column)===f.maybeInsertedLineEnd&&t.substr(0,e.column)==f.maybeInsertedLineStart},p.popAutoInsertedClosing=function(){f.autoInsertedLineEnd=f.autoInsertedLineEnd.substr(1),f.autoInsertedBrackets--},p.clearMaybeInsertedClosing=function(){f&&(f.maybeInsertedBrackets=0,f.maybeInsertedRow=-1)},r.inherits(p,i),t.CstyleBehaviour=p}),ace.define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(e){e&&(this.foldingStartMarker=new RegExp(this.foldingStartMarker.source.replace(/\|[^|]*?$/,"|"+e.start)),this.foldingStopMarker=new RegExp(this.foldingStopMarker.source.replace(/\|[^|]*?$/,"|"+e.end)))};r.inherits(o,s),function(){this.foldingStartMarker=/(\{|\[)[^\}\]]*$|^\s*(\/\*)/,this.foldingStopMarker=/^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/,this.singleLineBlockCommentRe=/^\s*(\/\*).*\*\/\s*$/,this.tripleStarBlockCommentRe=/^\s*(\/\*\*\*).*\*\/\s*$/,this.startRegionRe=/^\s*(\/\*|\/\/)#?region\b/,this._getFoldWidgetBase=this.getFoldWidget,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);if(this.singleLineBlockCommentRe.test(r)&&!this.startRegionRe.test(r)&&!this.tripleStarBlockCommentRe.test(r))return"";var i=this._getFoldWidgetBase(e,t,n);return!i&&this.startRegionRe.test(r)?"start":i},this.getFoldWidgetRange=function(e,t,n,r){var i=e.getLine(n);if(this.startRegionRe.test(i))return this.getCommentRegionBlock(e,i,n);var s=i.match(this.foldingStartMarker);if(s){var o=s.index;if(s[1])return this.openingBracketBlock(e,s[1],n,o);var u=e.getCommentFoldRange(n,o+s[0].length,1);return u&&!u.isMultiLine()&&(r?u=this.getSectionRange(e,n):t!="all"&&(u=null)),u}if(t==="markbegin")return;var s=i.match(this.foldingStopMarker);if(s){var o=s.index+s[0].length;return s[1]?this.closingBracketBlock(e,s[1],n,o):e.getCommentFoldRange(n,o,-1)}},this.getSectionRange=function(e,t){var n=e.getLine(t),r=n.search(/\S/),s=t,o=n.length;t+=1;var u=t,a=e.getLength();while(++t<a){n=e.getLine(t);var f=n.search(/\S/);if(f===-1)continue;if(r>f)break;var l=this.getFoldWidgetRange(e,"all",t);if(l){if(l.start.row<=s)break;if(l.isMultiLine())t=l.end.row;else if(r==f)break}u=t}return new i(s,o,u,e.getLine(u).length)},this.getCommentRegionBlock=function(e,t,n){var r=t.search(/\s*$/),s=e.getLength(),o=n,u=/^\s*(?:\/\*|\/\/|--)#?(end)?region\b/,a=1;while(++n<s){t=e.getLine(n);var f=u.exec(t);if(!f)continue;f[1]?a--:a++;if(!a)break}var l=n;if(l>o)return new i(o,r,l,t.length)}}.call(o.prototype)}),ace.define("ace/mode/javascript",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/javascript_highlight_rules","ace/mode/matching_brace_outdent","ace/range","ace/worker/worker_client","ace/mode/behaviour/cstyle","ace/mode/folding/cstyle"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./javascript_highlight_rules").JavaScriptHighlightRules,o=e("./matching_brace_outdent").MatchingBraceOutdent,u=e("../range").Range,a=e("../worker/worker_client").WorkerClient,f=e("./behaviour/cstyle").CstyleBehaviour,l=e("./folding/cstyle").FoldMode,c=function(){this.HighlightRules=s,this.$outdent=new o,this.$behaviour=new f,this.foldingRules=new l};r.inherits(c,i),function(){this.lineCommentStart="//",this.blockComment={start:"/*",end:"*/"},this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t),i=this.getTokenizer().getLineTokens(t,e),s=i.tokens,o=i.state;if(s.length&&s[s.length-1].type=="comment")return r;if(e=="start"||e=="no_regex"){var u=t.match(/^.*(?:\bcase\b.*\:|[\{\(\[])\s*$/);u&&(r+=n)}else if(e=="doc-start"){if(o=="start"||o=="no_regex")return"";var u=t.match(/^\s*(\/?)\*/);u&&(u[1]&&(r+=" "),r+="* ")}return r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)},this.createWorker=function(e){var t=new a(["ace"],"ace/mode/javascript_worker","JavaScriptWorker");return t.attachToDocument(e.getDocument()),t.on("annotate",function(t){e.setAnnotations(t.data)}),t.on("terminate",function(){e.clearAnnotations()}),t},this.$id="ace/mode/javascript"}.call(c.prototype),t.Mode=c})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/mode-json.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/mode-json.js
new file mode 100644
index 0000000..f6226b8
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/mode-json.js
@@ -0,0 +1 @@
+ace.define("ace/mode/json_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(){this.$rules={start:[{token:"variable",regex:'["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]\\s*(?=:)'},{token:"string",regex:'"',next:"string"},{token:"constant.numeric",regex:"0[xX][0-9a-fA-F]+\\b"},{token:"constant.numeric",regex:"[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"},{token:"constant.language.boolean",regex:"(?:true|false)\\b"},{token:"invalid.illegal",regex:"['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']"},{token:"invalid.illegal",regex:"\\/\\/.*$"},{token:"paren.lparen",regex:"[[({]"},{token:"paren.rparen",regex:"[\\])}]"},{token:"text",regex:"\\s+"}],string:[{token:"constant.language.escape",regex:/\\(?:x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|["\\\/bfnrt])/},{token:"string",regex:'[^"\\\\]+'},{token:"string",regex:'"',next:"start"},{token:"string",regex:"",next:"start"}]}};r.inherits(s,i),t.JsonHighlightRules=s}),ace.define("ace/mode/matching_brace_outdent",["require","exports","module","ace/range"],function(e,t,n){"use strict";var r=e("../range").Range,i=function(){};(function(){this.checkOutdent=function(e,t){return/^\s+$/.test(e)?/^\s*\}/.test(t):!1},this.autoOutdent=function(e,t){var n=e.getLine(t),i=n.match(/^(\s*\})/);if(!i)return 0;var s=i[1].length,o=e.findMatchingBracket({row:t,column:s});if(!o||o.row==t)return 0;var u=this.$getIndent(e.getLine(o.row));e.replace(new r(t,0,t,s-1),u)},this.$getIndent=function(e){return e.match(/^\s*/)[0]}}).call(i.prototype),t.MatchingBraceOutdent=i}),ace.define("ace/mode/behaviour/cstyle",["require","exports","module","ace/lib/oop","ace/mode/behaviour","ace/token_iterator","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../behaviour").Behaviour,s=e("../../token_iterator").TokenIterator,o=e("../../lib/lang"),u=["text","paren.rparen","punctuation.operator"],a=["text","paren.rparen","punctuation.operator","comment"],f,l={},c=function(e){var t=-1;e.multiSelect&&(t=e.selection.index,l.rangeCount!=e.multiSelect.rangeCount&&(l={rangeCount:e.multiSelect.rangeCount}));if(l[t])return f=l[t];f=l[t]={autoInsertedBrackets:0,autoInsertedRow:-1,autoInsertedLineEnd:"",maybeInsertedBrackets:0,maybeInsertedRow:-1,maybeInsertedLineStart:"",maybeInsertedLineEnd:""}},h=function(e,t,n,r){var i=e.end.row-e.start.row;return{text:n+t+r,selection:[0,e.start.column+1,i,e.end.column+(i?0:1)]}},p=function(){this.add("braces","insertion",function(e,t,n,r,i){var s=n.getCursorPosition(),u=r.doc.getLine(s.row);if(i=="{"){c(n);var a=n.getSelectionRange(),l=r.doc.getTextRange(a);if(l!==""&&l!=="{"&&n.getWrapBehavioursEnabled())return h(a,l,"{","}");if(p.isSaneInsertion(n,r))return/[\]\}\)]/.test(u[s.column])||n.inMultiSelectMode?(p.recordAutoInsert(n,r,"}"),{text:"{}",selection:[1,1]}):(p.recordMaybeInsert(n,r,"{"),{text:"{",selection:[1,1]})}else if(i=="}"){c(n);var d=u.substring(s.column,s.column+1);if(d=="}"){var v=r.$findOpeningBracket("}",{column:s.column+1,row:s.row});if(v!==null&&p.isAutoInsertedClosing(s,u,i))return p.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}else{if(i=="\n"||i=="\r\n"){c(n);var m="";p.isMaybeInsertedClosing(s,u)&&(m=o.stringRepeat("}",f.maybeInsertedBrackets),p.clearMaybeInsertedClosing());var d=u.substring(s.column,s.column+1);if(d==="}"){var g=r.findMatchingBracket({row:s.row,column:s.column+1},"}");if(!g)return null;var y=this.$getIndent(r.getLine(g.row))}else{if(!m){p.clearMaybeInsertedClosing();return}var y=this.$getIndent(u)}var b=y+r.getTabString();return{text:"\n"+b+"\n"+y+m,selection:[1,b.length,1,b.length]}}p.clearMaybeInsertedClosing()}}),this.add("braces","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="{"){c(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.end.column,i.end.column+1);if(u=="}")return i.end.column++,i;f.maybeInsertedBrackets--}}),this.add("parens","insertion",function(e,t,n,r,i){if(i=="("){c(n);var s=n.getSelectionRange(),o=r.doc.getTextRange(s);if(o!==""&&n.getWrapBehavioursEnabled())return h(s,o,"(",")");if(p.isSaneInsertion(n,r))return p.recordAutoInsert(n,r,")"),{text:"()",selection:[1,1]}}else if(i==")"){c(n);var u=n.getCursorPosition(),a=r.doc.getLine(u.row),f=a.substring(u.column,u.column+1);if(f==")"){var l=r.$findOpeningBracket(")",{column:u.column+1,row:u.row});if(l!==null&&p.isAutoInsertedClosing(u,a,i))return p.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}}),this.add("parens","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="("){c(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u==")")return i.end.column++,i}}),this.add("brackets","insertion",function(e,t,n,r,i){if(i=="["){c(n);var s=n.getSelectionRange(),o=r.doc.getTextRange(s);if(o!==""&&n.getWrapBehavioursEnabled())return h(s,o,"[","]");if(p.isSaneInsertion(n,r))return p.recordAutoInsert(n,r,"]"),{text:"[]",selection:[1,1]}}else if(i=="]"){c(n);var u=n.getCursorPosition(),a=r.doc.getLine(u.row),f=a.substring(u.column,u.column+1);if(f=="]"){var l=r.$findOpeningBracket("]",{column:u.column+1,row:u.row});if(l!==null&&p.isAutoInsertedClosing(u,a,i))return p.popAutoInsertedClosing(),{text:"",selection:[1,1]}}}}),this.add("brackets","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&s=="["){c(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u=="]")return i.end.column++,i}}),this.add("string_dquotes","insertion",function(e,t,n,r,i){if(i=='"'||i=="'"){c(n);var s=i,o=n.getSelectionRange(),u=r.doc.getTextRange(o);if(u!==""&&u!=="'"&&u!='"'&&n.getWrapBehavioursEnabled())return h(o,u,s,s);if(!u){var a=n.getCursorPosition(),f=r.doc.getLine(a.row),l=f.substring(a.column-1,a.column),p=f.substring(a.column,a.column+1),d=r.getTokenAt(a.row,a.column),v=r.getTokenAt(a.row,a.column+1);if(l=="\\"&&d&&/escape/.test(d.type))return null;var m=d&&/string|escape/.test(d.type),g=!v||/string|escape/.test(v.type),y;if(p==s)y=m!==g;else{if(m&&!g)return null;if(m&&g)return null;var b=r.$mode.tokenRe;b.lastIndex=0;var w=b.test(l);b.lastIndex=0;var E=b.test(l);if(w||E)return null;if(p&&!/[\s;,.})\]\\]/.test(p))return null;y=!0}return{text:y?s+s:"",selection:[1,1]}}}}),this.add("string_dquotes","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&(s=='"'||s=="'")){c(n);var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u==s)return i.end.column++,i}})};p.isSaneInsertion=function(e,t){var n=e.getCursorPosition(),r=new s(t,n.row,n.column);if(!this.$matchTokenType(r.getCurrentToken()||"text",u)){var i=new s(t,n.row,n.column+1);if(!this.$matchTokenType(i.getCurrentToken()||"text",u))return!1}return r.stepForward(),r.getCurrentTokenRow()!==n.row||this.$matchTokenType(r.getCurrentToken()||"text",a)},p.$matchTokenType=function(e,t){return t.indexOf(e.type||e)>-1},p.recordAutoInsert=function(e,t,n){var r=e.getCursorPosition(),i=t.doc.getLine(r.row);this.isAutoInsertedClosing(r,i,f.autoInsertedLineEnd[0])||(f.autoInsertedBrackets=0),f.autoInsertedRow=r.row,f.autoInsertedLineEnd=n+i.substr(r.column),f.autoInsertedBrackets++},p.recordMaybeInsert=function(e,t,n){var r=e.getCursorPosition(),i=t.doc.getLine(r.row);this.isMaybeInsertedClosing(r,i)||(f.maybeInsertedBrackets=0),f.maybeInsertedRow=r.row,f.maybeInsertedLineStart=i.substr(0,r.column)+n,f.maybeInsertedLineEnd=i.substr(r.column),f.maybeInsertedBrackets++},p.isAutoInsertedClosing=function(e,t,n){return f.autoInsertedBrackets>0&&e.row===f.autoInsertedRow&&n===f.autoInsertedLineEnd[0]&&t.substr(e.column)===f.autoInsertedLineEnd},p.isMaybeInsertedClosing=function(e,t){return f.maybeInsertedBrackets>0&&e.row===f.maybeInsertedRow&&t.substr(e.column)===f.maybeInsertedLineEnd&&t.substr(0,e.column)==f.maybeInsertedLineStart},p.popAutoInsertedClosing=function(){f.autoInsertedLineEnd=f.autoInsertedLineEnd.substr(1),f.autoInsertedBrackets--},p.clearMaybeInsertedClosing=function(){f&&(f.maybeInsertedBrackets=0,f.maybeInsertedRow=-1)},r.inherits(p,i),t.CstyleBehaviour=p}),ace.define("ace/mode/folding/cstyle",["require","exports","module","ace/lib/oop","ace/range","ace/mode/folding/fold_mode"],function(e,t,n){"use strict";var r=e("../../lib/oop"),i=e("../../range").Range,s=e("./fold_mode").FoldMode,o=t.FoldMode=function(e){e&&(this.foldingStartMarker=new RegExp(this.foldingStartMarker.source.replace(/\|[^|]*?$/,"|"+e.start)),this.foldingStopMarker=new RegExp(this.foldingStopMarker.source.replace(/\|[^|]*?$/,"|"+e.end)))};r.inherits(o,s),function(){this.foldingStartMarker=/(\{|\[)[^\}\]]*$|^\s*(\/\*)/,this.foldingStopMarker=/^[^\[\{]*(\}|\])|^[\s\*]*(\*\/)/,this.singleLineBlockCommentRe=/^\s*(\/\*).*\*\/\s*$/,this.tripleStarBlockCommentRe=/^\s*(\/\*\*\*).*\*\/\s*$/,this.startRegionRe=/^\s*(\/\*|\/\/)#?region\b/,this._getFoldWidgetBase=this.getFoldWidget,this.getFoldWidget=function(e,t,n){var r=e.getLine(n);if(this.singleLineBlockCommentRe.test(r)&&!this.startRegionRe.test(r)&&!this.tripleStarBlockCommentRe.test(r))return"";var i=this._getFoldWidgetBase(e,t,n);return!i&&this.startRegionRe.test(r)?"start":i},this.getFoldWidgetRange=function(e,t,n,r){var i=e.getLine(n);if(this.startRegionRe.test(i))return this.getCommentRegionBlock(e,i,n);var s=i.match(this.foldingStartMarker);if(s){var o=s.index;if(s[1])return this.openingBracketBlock(e,s[1],n,o);var u=e.getCommentFoldRange(n,o+s[0].length,1);return u&&!u.isMultiLine()&&(r?u=this.getSectionRange(e,n):t!="all"&&(u=null)),u}if(t==="markbegin")return;var s=i.match(this.foldingStopMarker);if(s){var o=s.index+s[0].length;return s[1]?this.closingBracketBlock(e,s[1],n,o):e.getCommentFoldRange(n,o,-1)}},this.getSectionRange=function(e,t){var n=e.getLine(t),r=n.search(/\S/),s=t,o=n.length;t+=1;var u=t,a=e.getLength();while(++t<a){n=e.getLine(t);var f=n.search(/\S/);if(f===-1)continue;if(r>f)break;var l=this.getFoldWidgetRange(e,"all",t);if(l){if(l.start.row<=s)break;if(l.isMultiLine())t=l.end.row;else if(r==f)break}u=t}return new i(s,o,u,e.getLine(u).length)},this.getCommentRegionBlock=function(e,t,n){var r=t.search(/\s*$/),s=e.getLength(),o=n,u=/^\s*(?:\/\*|\/\/|--)#?(end)?region\b/,a=1;while(++n<s){t=e.getLine(n);var f=u.exec(t);if(!f)continue;f[1]?a--:a++;if(!a)break}var l=n;if(l>o)return new i(o,r,l,t.length)}}.call(o.prototype)}),ace.define("ace/mode/json",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/json_highlight_rules","ace/mode/matching_brace_outdent","ace/mode/behaviour/cstyle","ace/mode/folding/cstyle","ace/worker/worker_client"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./json_highlight_rules").JsonHighlightRules,o=e("./matching_brace_outdent").MatchingBraceOutdent,u=e("./behaviour/cstyle").CstyleBehaviour,a=e("./folding/cstyle").FoldMode,f=e("../worker/worker_client").WorkerClient,l=function(){this.HighlightRules=s,this.$outdent=new o,this.$behaviour=new u,this.foldingRules=new a};r.inherits(l,i),function(){this.getNextLineIndent=function(e,t,n){var r=this.$getIndent(t);if(e=="start"){var i=t.match(/^.*[\{\(\[]\s*$/);i&&(r+=n)}return r},this.checkOutdent=function(e,t,n){return this.$outdent.checkOutdent(t,n)},this.autoOutdent=function(e,t,n){this.$outdent.autoOutdent(t,n)},this.createWorker=function(e){var t=new f(["ace"],"ace/mode/json_worker","JsonWorker");return t.attachToDocument(e.getDocument()),t.on("annotate",function(t){e.setAnnotations(t.data)}),t.on("terminate",function(){e.clearAnnotations()}),t},this.$id="ace/mode/json"}.call(l.prototype),t.Mode=l})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/mode-plain_text.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/mode-plain_text.js
new file mode 100644
index 0000000..be72ab9
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/mode-plain_text.js
@@ -0,0 +1 @@
+ace.define("ace/mode/plain_text",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/text_highlight_rules","ace/mode/behaviour"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./text_highlight_rules").TextHighlightRules,o=e("./behaviour").Behaviour,u=function(){this.HighlightRules=s,this.$behaviour=new o};r.inherits(u,i),function(){this.type="text",this.getNextLineIndent=function(e,t,n){return""},this.$id="ace/mode/plain_text"}.call(u.prototype),t.Mode=u})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/mode-xml.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/mode-xml.js
new file mode 100644
index 0000000..3090bd0
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/mode-xml.js
@@ -0,0 +1 @@
+ace.define("ace/mode/xml_highlight_rules",["require","exports","module","ace/lib/oop","ace/mode/text_highlight_rules"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text_highlight_rules").TextHighlightRules,s=function(e){var t="[_:a-zA-Z\u00c0-\uffff][-_:.a-zA-Z0-9\u00c0-\uffff]*";this.$rules={start:[{token:"string.cdata.xml",regex:"<\\!\\[CDATA\\[",next:"cdata"},{token:["punctuation.xml-decl.xml","keyword.xml-decl.xml"],regex:"(<\\?)(xml)(?=[\\s])",next:"xml_decl",caseInsensitive:!0},{token:["punctuation.instruction.xml","keyword.instruction.xml"],regex:"(<\\?)("+t+")",next:"processing_instruction"},{token:"comment.xml",regex:"<\\!--",next:"comment"},{token:["xml-pe.doctype.xml","xml-pe.doctype.xml"],regex:"(<\\!)(DOCTYPE)(?=[\\s])",next:"doctype",caseInsensitive:!0},{include:"tag"},{token:"text.end-tag-open.xml",regex:"</"},{token:"text.tag-open.xml",regex:"<"},{include:"reference"},{defaultToken:"text.xml"}],xml_decl:[{token:"entity.other.attribute-name.decl-attribute-name.xml",regex:"(?:"+t+":)?"+t+""},{token:"keyword.operator.decl-attribute-equals.xml",regex:"="},{include:"whitespace"},{include:"string"},{token:"punctuation.xml-decl.xml",regex:"\\?>",next:"start"}],processing_instruction:[{token:"punctuation.instruction.xml",regex:"\\?>",next:"start"},{defaultToken:"instruction.xml"}],doctype:[{include:"whitespace"},{include:"string"},{token:"xml-pe.doctype.xml",regex:">",next:"start"},{token:"xml-pe.xml",regex:"[-_a-zA-Z0-9:]+"},{token:"punctuation.int-subset",regex:"\\[",push:"int_subset"}],int_subset:[{token:"text.xml",regex:"\\s+"},{token:"punctuation.int-subset.xml",regex:"]",next:"pop"},{token:["punctuation.markup-decl.xml","keyword.markup-decl.xml"],regex:"(<\\!)("+t+")",push:[{token:"text",regex:"\\s+"},{token:"punctuation.markup-decl.xml",regex:">",next:"pop"},{include:"string"}]}],cdata:[{token:"string.cdata.xml",regex:"\\]\\]>",next:"start"},{token:"text.xml",regex:"\\s+"},{token:"text.xml",regex:"(?:[^\\]]|\\](?!\\]>))+"}],comment:[{token:"comment.xml",regex:"-->",next:"start"},{defaultToken:"comment.xml"}],reference:[{token:"constant.language.escape.reference.xml",regex:"(?:&#[0-9]+;)|(?:&#x[0-9a-fA-F]+;)|(?:&[a-zA-Z0-9_:\\.-]+;)"}],attr_reference:[{token:"constant.language.escape.reference.attribute-value.xml",regex:"(?:&#[0-9]+;)|(?:&#x[0-9a-fA-F]+;)|(?:&[a-zA-Z0-9_:\\.-]+;)"}],tag:[{token:["meta.tag.punctuation.tag-open.xml","meta.tag.punctuation.end-tag-open.xml","meta.tag.tag-name.xml"],regex:"(?:(<)|(</))((?:"+t+":)?"+t+")",next:[{include:"attributes"},{token:"meta.tag.punctuation.tag-close.xml",regex:"/?>",next:"start"}]}],tag_whitespace:[{token:"text.tag-whitespace.xml",regex:"\\s+"}],whitespace:[{token:"text.whitespace.xml",regex:"\\s+"}],string:[{token:"string.xml",regex:"'",push:[{token:"string.xml",regex:"'",next:"pop"},{defaultToken:"string.xml"}]},{token:"string.xml",regex:'"',push:[{token:"string.xml",regex:'"',next:"pop"},{defaultToken:"string.xml"}]}],attributes:[{token:"entity.other.attribute-name.xml",regex:"(?:"+t+":)?"+t+""},{token:"keyword.operator.attribute-equals.xml",regex:"="},{include:"tag_whitespace"},{include:"attribute_value"}],attribute_value:[{token:"string.attribute-value.xml",regex:"'",push:[{token:"string.attribute-value.xml",regex:"'",next:"pop"},{include:"attr_reference"},{defaultToken:"string.attribute-value.xml"}]},{token:"string.attribute-value.xml",regex:'"',push:[{token:"string.attribute-value.xml",regex:'"',next:"pop"},{include:"attr_reference"},{defaultToken:"string.attribute-value.xml"}]}]},this.constructor===s&&this.normalizeRules()};(function(){this.embedTagRules=function(e,t,n){this.$rules.tag.unshift({token:["meta.tag.punctuation.tag-open.xml","meta.tag."+n+".tag-name.xml"],regex:"(<)("+n+"(?=\\s|>|$))",next:[{include:"attributes"},{token:"meta.tag.punctuation.tag-close.xml",regex:"/?>",next:t+"start"}]}),this.$rules[n+"-end"]=[{include:"attributes"},{token:"meta.tag.punctuation.tag-close.xml",regex:"/?>",next:"start",onMatch:function(e,t,n){return n.splice(0),this.token}}],this.embedRules(e,t,[{token:["meta.tag.punctuation.end-tag-open.xml","meta.tag."+n+".tag-name.xml"],regex:"(</)("+n+"(?=\\s|>|$))",next:n+"-end"},{token:"string.cdata.xml",regex:"<\\!\\[CDATA\\["},{token:"string.cdata.xml",regex:"\\]\\]>"}])}}).call(i.prototype),r.inherits(s,i),t.XmlHighlightRules=s}),ace.define("ace/mode/behaviour/xml",["require","exports","module","ace/lib/oop","ace/mode/behaviour","ace/token_iterator","ace/lib/lang"],function(e,t,n){"use strict";function u(e,t){return e.type.lastIndexOf(t+".xml")>-1}var r=e("../../lib/oop"),i=e("../behaviour").Behaviour,s=e("../../token_iterator").TokenIterator,o=e("../../lib/lang"),a=function(){this.add("string_dquotes","insertion",function(e,t,n,r,i){if(i=='"'||i=="'"){var o=i,a=r.doc.getTextRange(n.getSelectionRange());if(a!==""&&a!=="'"&&a!='"'&&n.getWrapBehavioursEnabled())return{text:o+a+o,selection:!1};var f=n.getCursorPosition(),l=r.doc.getLine(f.row),c=l.substring(f.column,f.column+1),h=new s(r,f.row,f.column),p=h.getCurrentToken();if(c==o&&(u(p,"attribute-value")||u(p,"string")))return{text:"",selection:[1,1]};p||(p=h.stepBackward());if(!p)return;while(u(p,"tag-whitespace")||u(p,"whitespace"))p=h.stepBackward();var d=!c||c.match(/\s/);if(u(p,"attribute-equals")&&(d||c==">")||u(p,"decl-attribute-equals")&&(d||c=="?"))return{text:o+o,selection:[1,1]}}}),this.add("string_dquotes","deletion",function(e,t,n,r,i){var s=r.doc.getTextRange(i);if(!i.isMultiLine()&&(s=='"'||s=="'")){var o=r.doc.getLine(i.start.row),u=o.substring(i.start.column+1,i.start.column+2);if(u==s)return i.end.column++,i}}),this.add("autoclosing","insertion",function(e,t,n,r,i){if(i==">"){var o=n.getCursorPosition(),a=new s(r,o.row,o.column),f=a.getCurrentToken()||a.stepBackward();if(!f||!(u(f,"tag-name")||u(f,"tag-whitespace")||u(f,"attribute-name")||u(f,"attribute-equals")||u(f,"attribute-value")))return;if(u(f,"reference.attribute-value"))return;if(u(f,"attribute-value")){var l=f.value.charAt(0);if(l=='"'||l=="'"){var c=f.value.charAt(f.value.length-1),h=a.getCurrentTokenColumn()+f.value.length;if(h>o.column||h==o.column&&l!=c)return}}while(!u(f,"tag-name"))f=a.stepBackward();var p=a.getCurrentTokenRow(),d=a.getCurrentTokenColumn();if(u(a.stepBackward(),"end-tag-open"))return;var v=f.value;p==o.row&&(v=v.substring(0,o.column-d));if(this.voidElements.hasOwnProperty(v.toLowerCase()))return;return{text:"></"+v+">",selection:[1,1]}}}),this.add("autoindent","insertion",function(e,t,n,r,i){if(i=="\n"){var o=n.getCursorPosition(),u=r.getLine(o.row),a=new s(r,o.row,o.column),f=a.getCurrentToken();if(f&&f.type.indexOf("tag-close")!==-1){if(f.value=="/>")return;while(f&&f.type.indexOf("tag-name")===-1)f=a.stepBackward();if(!f)return;var l=f.value,c=a.getCurrentTokenRow();f=a.stepBackward();if(!f||f.type.indexOf("end-tag")!==-1)return;if(this.voidElements&&!this.voidElements[l]){var h=r.getTokenAt(o.row,o.column+1),u=r.getLine(c),p=this.$getIndent(u),d=p+r.getTabString();return h&&h.value==="</"?{text:"\n"+d+"\n"+p,selection:[1,d.length,1,d.length]}:{text:"\n"+d}}}}})};r.inherits(a,i),t.XmlBehaviour=a}),ace.define("ace/mode/folding/xml",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/range","ace/mode/folding/fold_mode","ace/token_iterator"],function(e,t,n){"use strict";function l(e,t){return e.type.lastIndexOf(t+".xml")>-1}var r=e("../../lib/oop"),i=e("../../lib/lang"),s=e("../../range").Range,o=e("./fold_mode").FoldMode,u=e("../../token_iterator").TokenIterator,a=t.FoldMode=function(e,t){o.call(this),this.voidElements=e||{},this.optionalEndTags=r.mixin({},this.voidElements),t&&r.mixin(this.optionalEndTags,t)};r.inherits(a,o);var f=function(){this.tagName="",this.closing=!1,this.selfClosing=!1,this.start={row:0,column:0},this.end={row:0,column:0}};(function(){this.getFoldWidget=function(e,t,n){var r=this._getFirstTagInLine(e,n);return r?r.closing||!r.tagName&&r.selfClosing?t=="markbeginend"?"end":"":!r.tagName||r.selfClosing||this.voidElements.hasOwnProperty(r.tagName.toLowerCase())?"":this._findEndTagInLine(e,n,r.tagName,r.end.column)?"":"start":""},this._getFirstTagInLine=function(e,t){var n=e.getTokens(t),r=new f;for(var i=0;i<n.length;i++){var s=n[i];if(l(s,"tag-open")){r.end.column=r.start.column+s.value.length,r.closing=l(s,"end-tag-open"),s=n[++i];if(!s)return null;r.tagName=s.value,r.end.column+=s.value.length;for(i++;i<n.length;i++){s=n[i],r.end.column+=s.value.length;if(l(s,"tag-close")){r.selfClosing=s.value=="/>";break}}return r}if(l(s,"tag-close"))return r.selfClosing=s.value=="/>",r;r.start.column+=s.value.length}return null},this._findEndTagInLine=function(e,t,n,r){var i=e.getTokens(t),s=0;for(var o=0;o<i.length;o++){var u=i[o];s+=u.value.length;if(s<r)continue;if(l(u,"end-tag-open")){u=i[o+1];if(u&&u.value==n)return!0}}return!1},this._readTagForward=function(e){var t=e.getCurrentToken();if(!t)return null;var n=new f;do if(l(t,"tag-open"))n.closing=l(t,"end-tag-open"),n.start.row=e.getCurrentTokenRow(),n.start.column=e.getCurrentTokenColumn();else if(l(t,"tag-name"))n.tagName=t.value;else if(l(t,"tag-close"))return n.selfClosing=t.value=="/>",n.end.row=e.getCurrentTokenRow(),n.end.column=e.getCurrentTokenColumn()+t.value.length,e.stepForward(),n;while(t=e.stepForward());return null},this._readTagBackward=function(e){var t=e.getCurrentToken();if(!t)return null;var n=new f;do{if(l(t,"tag-open"))return n.closing=l(t,"end-tag-open"),n.start.row=e.getCurrentTokenRow(),n.start.column=e.getCurrentTokenColumn(),e.stepBackward(),n;l(t,"tag-name")?n.tagName=t.value:l(t,"tag-close")&&(n.selfClosing=t.value=="/>",n.end.row=e.getCurrentTokenRow(),n.end.column=e.getCurrentTokenColumn()+t.value.length)}while(t=e.stepBackward());return null},this._pop=function(e,t){while(e.length){var n=e[e.length-1];if(!t||n.tagName==t.tagName)return e.pop();if(this.optionalEndTags.hasOwnProperty(n.tagName)){e.pop();continue}return null}},this.getFoldWidgetRange=function(e,t,n){var r=this._getFirstTagInLine(e,n);if(!r)return null;var i=r.closing||r.selfClosing,o=[],a;if(!i){var f=new u(e,n,r.start.column),l={row:n,column:r.start.column+r.tagName.length+2};r.start.row==r.end.row&&(l.column=r.end.column);while(a=this._readTagForward(f)){if(a.selfClosing){if(!o.length)return a.start.column+=a.tagName.length+2,a.end.column-=2,s.fromPoints(a.start,a.end);continue}if(a.closing){this._pop(o,a);if(o.length==0)return s.fromPoints(l,a.start)}else o.push(a)}}else{var f=new u(e,n,r.end.column),c={row:n,column:r.start.column};while(a=this._readTagBackward(f)){if(a.selfClosing){if(!o.length)return a.start.column+=a.tagName.length+2,a.end.column-=2,s.fromPoints(a.start,a.end);continue}if(!a.closing){this._pop(o,a);if(o.length==0)return a.start.column+=a.tagName.length+2,a.start.row==a.end.row&&a.start.column<a.end.column&&(a.start.column=a.end.column),s.fromPoints(a.start,c)}else o.push(a)}}}}).call(a.prototype)}),ace.define("ace/mode/xml",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/mode/text","ace/mode/xml_highlight_rules","ace/mode/behaviour/xml","ace/mode/folding/xml","ace/worker/worker_client"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../lib/lang"),s=e("./text").Mode,o=e("./xml_highlight_rules").XmlHighlightRules,u=e("./behaviour/xml").XmlBehaviour,a=e("./folding/xml").FoldMode,f=e("../worker/worker_client").WorkerClient,l=function(){this.HighlightRules=o,this.$behaviour=new u,this.foldingRules=new a};r.inherits(l,s),function(){this.voidElements=i.arrayToMap([]),this.blockComment={start:"<!--",end:"-->"},this.createWorker=function(e){var t=new f(["ace"],"ace/mode/xml_worker","Worker");return t.attachToDocument(e.getDocument()),t.on("error",function(t){e.setAnnotations(t.data)}),t.on("terminate",function(){e.clearAnnotations()}),t},this.$id="ace/mode/xml"}.call(l.prototype),t.Mode=l})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/snippets/javascript.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/snippets/javascript.js
new file mode 100644
index 0000000..09f0fe0
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/snippets/javascript.js
@@ -0,0 +1 @@
+ace.define("ace/snippets/javascript",["require","exports","module"],function(e,t,n){"use strict";t.snippetText='# Prototype\nsnippet proto\n	${1:class_name}.prototype.${2:method_name} = function(${3:first_argument}) {\n		${4:// body...}\n	};\n# Function\nsnippet fun\n	function ${1?:function_name}(${2:argument}) {\n		${3:// body...}\n	}\n# Anonymous Function\nregex /((=)\\s*|(:)\\s*|(\\()|\\b)/f/(\\))?/\nsnippet f\n	function${M1?: ${1:functionName}}($2) {\n		${0:$TM_SELECTED_TEXT}\n	}${M2?;}${M3?,}${M4?)}\n# Immediate function\ntrigger \\(?f\\(\nendTrigger \\)?\nsnippet f(\n	(function(${1}) {\n		${0:${TM_SELECTED_TEXT:/* code */}}\n	}(${1}));\n# if\nsnippet if\n	if (${1:true}) {\n		${0}\n	}\n# if ... else\nsnippet ife\n	if (${1:true}) {\n		${2}\n	} else {\n		${0}\n	}\n# tertiary conditional\nsnippet ter\n	${1:/* condition */} ? ${2:a} : ${3:b}\n# switch\nsnippet switch\n	switch (${1:expression}) {\n		case \'${3:case}\':\n			${4:// code}\n			break;\n		${5}\n		default:\n			${2:// code}\n	}\n# case\nsnippet case\n	case \'${1:case}\':\n		${2:// code}\n		break;\n	${3}\n\n# while (...) {...}\nsnippet wh\n	while (${1:/* condition */}) {\n		${0:/* code */}\n	}\n# try\nsnippet try\n	try {\n		${0:/* code */}\n	} catch (e) {}\n# do...while\nsnippet do\n	do {\n		${2:/* code */}\n	} while (${1:/* condition */});\n# Object Method\nsnippet :f\nregex /([,{[])|^\\s*/:f/\n	${1:method_name}: function(${2:attribute}) {\n		${0}\n	}${3:,}\n# setTimeout function\nsnippet setTimeout\nregex /\\b/st|timeout|setTimeo?u?t?/\n	setTimeout(function() {${3:$TM_SELECTED_TEXT}}, ${1:10});\n# Get Elements\nsnippet gett\n	getElementsBy${1:TagName}(\'${2}\')${3}\n# Get Element\nsnippet get\n	getElementBy${1:Id}(\'${2}\')${3}\n# console.log (Firebug)\nsnippet cl\n	console.log(${1});\n# return\nsnippet ret\n	return ${1:result}\n# for (property in object ) { ... }\nsnippet fori\n	for (var ${1:prop} in ${2:Things}) {\n		${0:$2[$1]}\n	}\n# hasOwnProperty\nsnippet has\n	hasOwnProperty(${1})\n# docstring\nsnippet /**\n	/**\n	 * ${1:description}\n	 *\n	 */\nsnippet @par\nregex /^\\s*\\*\\s*/@(para?m?)?/\n	@param {${1:type}} ${2:name} ${3:description}\nsnippet @ret\n	@return {${1:type}} ${2:description}\n# JSON.parse\nsnippet jsonp\n	JSON.parse(${1:jstr});\n# JSON.stringify\nsnippet jsons\n	JSON.stringify(${1:object});\n# self-defining function\nsnippet sdf\n	var ${1:function_name} = function(${2:argument}) {\n		${3:// initial code ...}\n\n		$1 = function($2) {\n			${4:// main code}\n		};\n	}\n# singleton\nsnippet sing\n	function ${1:Singleton} (${2:argument}) {\n		// the cached instance\n		var instance;\n\n		// rewrite the constructor\n		$1 = function $1($2) {\n			return instance;\n		};\n		\n		// carry over the prototype properties\n		$1.prototype = this;\n\n		// the instance\n		instance = new $1();\n\n		// reset the constructor pointer\n		instance.constructor = $1;\n\n		${3:// code ...}\n\n		return instance;\n	}\n# class\nsnippet class\nregex /^\\s*/clas{0,2}/\n	var ${1:class} = function(${20}) {\n		$40$0\n	};\n	\n	(function() {\n		${60:this.prop = ""}\n	}).call(${1:class}.prototype);\n	\n	exports.${1:class} = ${1:class};\n# \nsnippet for-\n	for (var ${1:i} = ${2:Things}.length; ${1:i}--; ) {\n		${0:${2:Things}[${1:i}];}\n	}\n# for (...) {...}\nsnippet for\n	for (var ${1:i} = 0; $1 < ${2:Things}.length; $1++) {\n		${3:$2[$1]}$0\n	}\n# for (...) {...} (Improved Native For-Loop)\nsnippet forr\n	for (var ${1:i} = ${2:Things}.length - 1; $1 >= 0; $1--) {\n		${3:$2[$1]}$0\n	}\n\n\n#modules\nsnippet def\n	define(function(require, exports, module) {\n	"use strict";\n	var ${1/.*\\///} = require("${1}");\n	\n	$TM_SELECTED_TEXT\n	});\nsnippet req\nguard ^\\s*\n	var ${1/.*\\///} = require("${1}");\n	$0\nsnippet requ\nguard ^\\s*\n	var ${1/.*\\/(.)/\\u$1/} = require("${1}").${1/.*\\/(.)/\\u$1/};\n	$0\n',t.scope="javascript"})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/snippets/json.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/snippets/json.js
new file mode 100644
index 0000000..5e0e0ea
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/snippets/json.js
@@ -0,0 +1 @@
+ace.define("ace/snippets/json",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="json"})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/snippets/plain_text.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/snippets/plain_text.js
new file mode 100644
index 0000000..25ec4af
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/snippets/plain_text.js
@@ -0,0 +1 @@
+ace.define("ace/snippets/plain_text",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="plain_text"})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/snippets/xml.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/snippets/xml.js
new file mode 100644
index 0000000..e1c1b39
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/snippets/xml.js
@@ -0,0 +1 @@
+ace.define("ace/snippets/xml",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="xml"})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/theme-github.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/theme-github.js
new file mode 100644
index 0000000..2401002
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/theme-github.js
@@ -0,0 +1 @@
+ace.define("ace/theme/github",["require","exports","module","ace/lib/dom"],function(e,t,n){t.isDark=!1,t.cssClass="ace-github",t.cssText='.ace-github .ace_gutter {background: #e8e8e8;color: #AAA;}.ace-github  {background: #fff;color: #000;}.ace-github .ace_keyword {font-weight: bold;}.ace-github .ace_string {color: #D14;}.ace-github .ace_variable.ace_class {color: teal;}.ace-github .ace_constant.ace_numeric {color: #099;}.ace-github .ace_constant.ace_buildin {color: #0086B3;}.ace-github .ace_support.ace_function {color: #0086B3;}.ace-github .ace_comment {color: #998;font-style: italic;}.ace-github .ace_variable.ace_language  {color: #0086B3;}.ace-github .ace_paren {font-weight: bold;}.ace-github .ace_boolean {font-weight: bold;}.ace-github .ace_string.ace_regexp {color: #009926;font-weight: normal;}.ace-github .ace_variable.ace_instance {color: teal;}.ace-github .ace_constant.ace_language {font-weight: bold;}.ace-github .ace_cursor {color: black;}.ace-github.ace_focus .ace_marker-layer .ace_active-line {background: rgb(255, 255, 204);}.ace-github .ace_marker-layer .ace_active-line {background: rgb(245, 245, 245);}.ace-github .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-github.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px white;}.ace-github.ace_nobold .ace_line > span {font-weight: normal !important;}.ace-github .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-github .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-github .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-github .ace_gutter-active-line {background-color : rgba(0, 0, 0, 0.07);}.ace-github .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-github .ace_invisible {color: #BFBFBF}.ace-github .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-github .ace_indent-guide {background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y;}';var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-coffee.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-coffee.js
new file mode 100644
index 0000000..1be7db3
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-coffee.js
@@ -0,0 +1 @@
+"no use strict";(function(e){function t(e,t){var n=e,r="";while(n){var i=t[n];if(typeof i=="string")return i+r;if(i)return i.location.replace(/\/*$/,"/")+(r||i.main||i.name);if(i===!1)return"";var s=n.lastIndexOf("/");if(s===-1)break;r=n.substr(s)+r,n=n.slice(0,s)}return e}if(typeof e.window!="undefined"&&e.document)return;if(e.require&&e.define)return;e.console||(e.console=function(){var e=Array.prototype.slice.call(arguments,0);postMessage({type:"log",data:e})},e.console.error=e.console.warn=e.console.log=e.console.trace=e.console),e.window=e,e.ace=e,e.onerror=function(e,t,n,r,i){postMessage({type:"error",data:{message:e,data:i.data,file:t,line:n,col:r,stack:i.stack}})},e.normalizeModule=function(t,n){if(n.indexOf("!")!==-1){var r=n.split("!");return e.normalizeModule(t,r[0])+"!"+e.normalizeModule(t,r[1])}if(n.charAt(0)=="."){var i=t.split("/").slice(0,-1).join("/");n=(i?i+"/":"")+n;while(n.indexOf(".")!==-1&&s!=n){var s=n;n=n.replace(/^\.\//,"").replace(/\/\.\//,"/").replace(/[^\/]+\/\.\.\//,"")}}return n},e.require=function(r,i){i||(i=r,r=null);if(!i.charAt)throw new Error("worker.js require() accepts only (parentId, id) as arguments");i=e.normalizeModule(r,i);var s=e.require.modules[i];if(s)return s.initialized||(s.initialized=!0,s.exports=s.factory().exports),s.exports;if(!e.require.tlns)return console.log("unable to load "+i);var o=t(i,e.require.tlns);return o.slice(-3)!=".js"&&(o+=".js"),e.require.id=i,e.require.modules[i]={},importScripts(o),e.require(r,i)},e.require.modules={},e.require.tlns={},e.define=function(t,n,r){arguments.length==2?(r=n,typeof t!="string"&&(n=t,t=e.require.id)):arguments.length==1&&(r=t,n=[],t=e.require.id);if(typeof r!="function"){e.require.modules[t]={exports:r,initialized:!0};return}n.length||(n=["require","exports","module"]);var i=function(n){return e.require(t,n)};e.require.modules[t]={exports:{},factory:function(){var e=this,t=r.apply(this,n.map(function(t){switch(t){case"require":return i;case"exports":return e.exports;case"module":return e;default:return i(t)}}));return t&&(e.exports=t),e}}},e.define.amd={},require.tlns={},e.initBaseUrls=function(t){for(var n in t)require.tlns[n]=t[n]},e.initSender=function(){var n=e.require("ace/lib/event_emitter").EventEmitter,r=e.require("ace/lib/oop"),i=function(){};return function(){r.implement(this,n),this.callback=function(e,t){postMessage({type:"call",id:t,data:e})},this.emit=function(e,t){postMessage({type:"event",name:e,data:t})}}.call(i.prototype),new i};var n=e.main=null,r=e.sender=null;e.onmessage=function(t){var i=t.data;if(i.event&&r)r._signal(i.event,i.data);else if(i.command)if(n[i.command])n[i.command].apply(n,i.args);else{if(!e[i.command])throw new Error("Unknown command:"+i.command);e[i.command].apply(e,i.args)}else if(i.init){e.initBaseUrls(i.tlns),require("ace/lib/es5-shim"),r=e.sender=e.initSender();var s=require(i.module)[i.classname];n=e.main=new s(r)}}})(this),ace.define("ace/lib/oop",["require","exports","module"],function(e,t,n){"use strict";t.inherits=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})},t.mixin=function(e,t){for(var n in t)e[n]=t[n];return e},t.implement=function(e,n){t.mixin(e,n)}}),ace.define("ace/range",["require","exports","module"],function(e,t,n){"use strict";var r=function(e,t){return e.row-t.row||e.column-t.column},i=function(e,t,n,r){this.start={row:e,column:t},this.end={row:n,column:r}};(function(){this.isEqual=function(e){return this.start.row===e.start.row&&this.end.row===e.end.row&&this.start.column===e.start.column&&this.end.column===e.end.column},this.toString=function(){return"Range: ["+this.start.row+"/"+this.start.column+"] -> ["+this.end.row+"/"+this.end.column+"]"},this.contains=function(e,t){return this.compare(e,t)==0},this.compareRange=function(e){var t,n=e.end,r=e.start;return t=this.compare(n.row,n.column),t==1?(t=this.compare(r.row,r.column),t==1?2:t==0?1:0):t==-1?-2:(t=this.compare(r.row,r.column),t==-1?-1:t==1?42:0)},this.comparePoint=function(e){return this.compare(e.row,e.column)},this.containsRange=function(e){return this.comparePoint(e.start)==0&&this.comparePoint(e.end)==0},this.intersects=function(e){var t=this.compareRange(e);return t==-1||t==0||t==1},this.isEnd=function(e,t){return this.end.row==e&&this.end.column==t},this.isStart=function(e,t){return this.start.row==e&&this.start.column==t},this.setStart=function(e,t){typeof e=="object"?(this.start.column=e.column,this.start.row=e.row):(this.start.row=e,this.start.column=t)},this.setEnd=function(e,t){typeof e=="object"?(this.end.column=e.column,this.end.row=e.row):(this.end.row=e,this.end.column=t)},this.inside=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)||this.isStart(e,t)?!1:!0:!1},this.insideStart=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)?!1:!0:!1},this.insideEnd=function(e,t){return this.compare(e,t)==0?this.isStart(e,t)?!1:!0:!1},this.compare=function(e,t){return!this.isMultiLine()&&e===this.start.row?t<this.start.column?-1:t>this.end.column?1:0:e<this.start.row?-1:e>this.end.row?1:this.start.row===e?t>=this.start.column?0:-1:this.end.row===e?t<=this.end.column?0:1:0},this.compareStart=function(e,t){return this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.compareEnd=function(e,t){return this.end.row==e&&this.end.column==t?1:this.compare(e,t)},this.compareInside=function(e,t){return this.end.row==e&&this.end.column==t?1:this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.clipRows=function(e,t){if(this.end.row>t)var n={row:t+1,column:0};else if(this.end.row<e)var n={row:e,column:0};if(this.start.row>t)var r={row:t+1,column:0};else if(this.start.row<e)var r={row:e,column:0};return i.fromPoints(r||this.start,n||this.end)},this.extend=function(e,t){var n=this.compare(e,t);if(n==0)return this;if(n==-1)var r={row:e,column:t};else var s={row:e,column:t};return i.fromPoints(r||this.start,s||this.end)},this.isEmpty=function(){return this.start.row===this.end.row&&this.start.column===this.end.column},this.isMultiLine=function(){return this.start.row!==this.end.row},this.clone=function(){return i.fromPoints(this.start,this.end)},this.collapseRows=function(){return this.end.column==0?new i(this.start.row,0,Math.max(this.start.row,this.end.row-1),0):new i(this.start.row,0,this.end.row,0)},this.toScreenRange=function(e){var t=e.documentToScreenPosition(this.start),n=e.documentToScreenPosition(this.end);return new i(t.row,t.column,n.row,n.column)},this.moveBy=function(e,t){this.start.row+=e,this.start.column+=t,this.end.row+=e,this.end.column+=t}}).call(i.prototype),i.fromPoints=function(e,t){return new i(e.row,e.column,t.row,t.column)},i.comparePoints=r,i.comparePoints=function(e,t){return e.row-t.row||e.column-t.column},t.Range=i}),ace.define("ace/apply_delta",["require","exports","module"],function(e,t,n){"use strict";function r(e,t){throw console.log("Invalid Delta:",e),"Invalid Delta: "+t}function i(e,t){return t.row>=0&&t.row<e.length&&t.column>=0&&t.column<=e[t.row].length}function s(e,t){t.action!="insert"&&t.action!="remove"&&r(t,"delta.action must be 'insert' or 'remove'"),t.lines instanceof Array||r(t,"delta.lines must be an Array"),(!t.start||!t.end)&&r(t,"delta.start/end must be an present");var n=t.start;i(e,t.start)||r(t,"delta.start must be contained in document");var s=t.end;t.action=="remove"&&!i(e,s)&&r(t,"delta.end must contained in document for 'remove' actions");var o=s.row-n.row,u=s.column-(o==0?n.column:0);(o!=t.lines.length-1||t.lines[o].length!=u)&&r(t,"delta.range must match delta lines")}t.applyDelta=function(e,t,n){var r=t.start.row,i=t.start.column,s=e[r]||"";switch(t.action){case"insert":var o=t.lines;if(o.length===1)e[r]=s.substring(0,i)+t.lines[0]+s.substring(i);else{var u=[r,1].concat(t.lines);e.splice.apply(e,u),e[r]=s.substring(0,i)+e[r],e[r+t.lines.length-1]+=s.substring(i)}break;case"remove":var a=t.end.column,f=t.end.row;r===f?e[r]=s.substring(0,i)+s.substring(a):e.splice(r,f-r+1,s.substring(0,i)+e[f].substring(a))}}}),ace.define("ace/lib/event_emitter",["require","exports","module"],function(e,t,n){"use strict";var r={},i=function(){this.propagationStopped=!0},s=function(){this.defaultPrevented=!0};r._emit=r._dispatchEvent=function(e,t){this._eventRegistry||(this._eventRegistry={}),this._defaultHandlers||(this._defaultHandlers={});var n=this._eventRegistry[e]||[],r=this._defaultHandlers[e];if(!n.length&&!r)return;if(typeof t!="object"||!t)t={};t.type||(t.type=e),t.stopPropagation||(t.stopPropagation=i),t.preventDefault||(t.preventDefault=s),n=n.slice();for(var o=0;o<n.length;o++){n[o](t,this);if(t.propagationStopped)break}if(r&&!t.defaultPrevented)return r(t,this)},r._signal=function(e,t){var n=(this._eventRegistry||{})[e];if(!n)return;n=n.slice();for(var r=0;r<n.length;r++)n[r](t,this)},r.once=function(e,t){var n=this;t&&this.addEventListener(e,function r(){n.removeEventListener(e,r),t.apply(null,arguments)})},r.setDefaultHandler=function(e,t){var n=this._defaultHandlers;n||(n=this._defaultHandlers={_disabled_:{}});if(n[e]){var r=n[e],i=n._disabled_[e];i||(n._disabled_[e]=i=[]),i.push(r);var s=i.indexOf(t);s!=-1&&i.splice(s,1)}n[e]=t},r.removeDefaultHandler=function(e,t){var n=this._defaultHandlers;if(!n)return;var r=n._disabled_[e];if(n[e]==t){var i=n[e];r&&this.setDefaultHandler(e,r.pop())}else if(r){var s=r.indexOf(t);s!=-1&&r.splice(s,1)}},r.on=r.addEventListener=function(e,t,n){this._eventRegistry=this._eventRegistry||{};var r=this._eventRegistry[e];return r||(r=this._eventRegistry[e]=[]),r.indexOf(t)==-1&&r[n?"unshift":"push"](t),t},r.off=r.removeListener=r.removeEventListener=function(e,t){this._eventRegistry=this._eventRegistry||{};var n=this._eventRegistry[e];if(!n)return;var r=n.indexOf(t);r!==-1&&n.splice(r,1)},r.removeAllListeners=function(e){this._eventRegistry&&(this._eventRegistry[e]=[])},t.EventEmitter=r}),ace.define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=t.Anchor=function(e,t,n){this.$onChange=this.onChange.bind(this),this.attach(e),typeof n=="undefined"?this.setPosition(t.row,t.column):this.setPosition(t,n)};(function(){function e(e,t,n){var r=n?e.column<=t.column:e.column<t.column;return e.row<t.row||e.row==t.row&&r}function t(t,n,r){var i=t.action=="insert",s=(i?1:-1)*(t.end.row-t.start.row),o=(i?1:-1)*(t.end.column-t.start.column),u=t.start,a=i?u:t.end;return e(n,u,r)?{row:n.row,column:n.column}:e(a,n,!r)?{row:n.row+s,column:n.column+(n.row==a.row?o:0)}:{row:u.row,column:u.column}}r.implement(this,i),this.getPosition=function(){return this.$clipPositionToDocument(this.row,this.column)},this.getDocument=function(){return this.document},this.$insertRight=!1,this.onChange=function(e){if(e.start.row==e.end.row&&e.start.row!=this.row)return;if(e.start.row>this.row)return;var n=t(e,{row:this.row,column:this.column},this.$insertRight);this.setPosition(n.row,n.column,!0)},this.setPosition=function(e,t,n){var r;n?r={row:e,column:t}:r=this.$clipPositionToDocument(e,t);if(this.row==r.row&&this.column==r.column)return;var i={row:this.row,column:this.column};this.row=r.row,this.column=r.column,this._signal("change",{old:i,value:r})},this.detach=function(){this.document.removeEventListener("change",this.$onChange)},this.attach=function(e){this.document=e||this.document,this.document.on("change",this.$onChange)},this.$clipPositionToDocument=function(e,t){var n={};return e>=this.document.getLength()?(n.row=Math.max(0,this.document.getLength()-1),n.column=this.document.getLine(n.row).length):e<0?(n.row=0,n.column=0):(n.row=e,n.column=Math.min(this.document.getLine(n.row).length,Math.max(0,t))),t<0&&(n.column=0),n}}).call(s.prototype)}),ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./apply_delta").applyDelta,s=e("./lib/event_emitter").EventEmitter,o=e("./range").Range,u=e("./anchor").Anchor,a=function(e){this.$lines=[""],e.length===0?this.$lines=[""]:Array.isArray(e)?this.insertMergedLines({row:0,column:0},e):this.insert({row:0,column:0},e)};(function(){r.implement(this,s),this.setValue=function(e){var t=this.getLength()-1;this.remove(new o(0,0,t,this.getLine(t).length)),this.insert({row:0,column:0},e)},this.getValue=function(){return this.getAllLines().join(this.getNewLineCharacter())},this.createAnchor=function(e,t){return new u(this,e,t)},"aaa".split(/a/).length===0?this.$split=function(e){return e.replace(/\r\n|\r/g,"\n").split("\n")}:this.$split=function(e){return e.split(/\r\n|\r|\n/)},this.$detectNewLine=function(e){var t=e.match(/^.*?(\r\n|\r|\n)/m);this.$autoNewLine=t?t[1]:"\n",this._signal("changeNewLineMode")},this.getNewLineCharacter=function(){switch(this.$newLineMode){case"windows":return"\r\n";case"unix":return"\n";default:return this.$autoNewLine||"\n"}},this.$autoNewLine="",this.$newLineMode="auto",this.setNewLineMode=function(e){if(this.$newLineMode===e)return;this.$newLineMode=e,this._signal("changeNewLineMode")},this.getNewLineMode=function(){return this.$newLineMode},this.isNewLine=function(e){return e=="\r\n"||e=="\r"||e=="\n"},this.getLine=function(e){return this.$lines[e]||""},this.getLines=function(e,t){return this.$lines.slice(e,t+1)},this.getAllLines=function(){return this.getLines(0,this.getLength())},this.getLength=function(){return this.$lines.length},this.getTextRange=function(e){return this.getLinesForRange(e).join(this.getNewLineCharacter())},this.getLinesForRange=function(e){var t;if(e.start.row===e.end.row)t=[this.getLine(e.start.row).substring(e.start.column,e.end.column)];else{t=this.getLines(e.start.row,e.end.row),t[0]=(t[0]||"").substring(e.start.column);var n=t.length-1;e.end.row-e.start.row==n&&(t[n]=t[n].substring(0,e.end.column))}return t},this.insertLines=function(e,t){return console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."),this.insertFullLines(e,t)},this.removeLines=function(e,t){return console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."),this.removeFullLines(e,t)},this.insertNewLine=function(e){return console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead."),this.insertMergedLines(e,["",""])},this.insert=function(e,t){return this.getLength()<=1&&this.$detectNewLine(t),this.insertMergedLines(e,this.$split(t))},this.insertInLine=function(e,t){var n=this.clippedPos(e.row,e.column),r=this.pos(e.row,e.column+t.length);return this.applyDelta({start:n,end:r,action:"insert",lines:[t]},!0),this.clonePos(r)},this.clippedPos=function(e,t){var n=this.getLength();e===undefined?e=n:e<0?e=0:e>=n&&(e=n-1,t=undefined);var r=this.getLine(e);return t==undefined&&(t=r.length),t=Math.min(Math.max(t,0),r.length),{row:e,column:t}},this.clonePos=function(e){return{row:e.row,column:e.column}},this.pos=function(e,t){return{row:e,column:t}},this.$clipPosition=function(e){var t=this.getLength();return e.row>=t?(e.row=Math.max(0,t-1),e.column=this.getLine(t-1).length):(e.row=Math.max(0,e.row),e.column=Math.min(Math.max(e.column,0),this.getLine(e.row).length)),e},this.insertFullLines=function(e,t){e=Math.min(Math.max(e,0),this.getLength());var n=0;e<this.getLength()?(t=t.concat([""]),n=0):(t=[""].concat(t),e--,n=this.$lines[e].length),this.insertMergedLines({row:e,column:n},t)},this.insertMergedLines=function(e,t){var n=this.clippedPos(e.row,e.column),r={row:n.row+t.length-1,column:(t.length==1?n.column:0)+t[t.length-1].length};return this.applyDelta({start:n,end:r,action:"insert",lines:t}),this.clonePos(r)},this.remove=function(e){var t=this.clippedPos(e.start.row,e.start.column),n=this.clippedPos(e.end.row,e.end.column);return this.applyDelta({start:t,end:n,action:"remove",lines:this.getLinesForRange({start:t,end:n})}),this.clonePos(t)},this.removeInLine=function(e,t,n){var r=this.clippedPos(e,t),i=this.clippedPos(e,n);return this.applyDelta({start:r,end:i,action:"remove",lines:this.getLinesForRange({start:r,end:i})},!0),this.clonePos(r)},this.removeFullLines=function(e,t){e=Math.min(Math.max(0,e),this.getLength()-1),t=Math.min(Math.max(0,t),this.getLength()-1);var n=t==this.getLength()-1&&e>0,r=t<this.getLength()-1,i=n?e-1:e,s=n?this.getLine(i).length:0,u=r?t+1:t,a=r?0:this.getLine(u).length,f=new o(i,s,u,a),l=this.$lines.slice(e,t+1);return this.applyDelta({start:f.start,end:f.end,action:"remove",lines:this.getLinesForRange(f)}),l},this.removeNewLine=function(e){e<this.getLength()-1&&e>=0&&this.applyDelta({start:this.pos(e,this.getLine(e).length),end:this.pos(e+1,0),action:"remove",lines:["",""]})},this.replace=function(e,t){e instanceof o||(e=o.fromPoints(e.start,e.end));if(t.length===0&&e.isEmpty())return e.start;if(t==this.getTextRange(e))return e.end;this.remove(e);var n;return t?n=this.insert(e.start,t):n=e.start,n},this.applyDeltas=function(e){for(var t=0;t<e.length;t++)this.applyDelta(e[t])},this.revertDeltas=function(e){for(var t=e.length-1;t>=0;t--)this.revertDelta(e[t])},this.applyDelta=function(e,t){var n=e.action=="insert";if(n?e.lines.length<=1&&!e.lines[0]:!o.comparePoints(e.start,e.end))return;n&&e.lines.length>2e4&&this.$splitAndapplyLargeDelta(e,2e4),i(this.$lines,e,t),this._signal("change",e)},this.$splitAndapplyLargeDelta=function(e,t){var n=e.lines,r=n.length,i=e.start.row,s=e.start.column,o=0,u=0;do{o=u,u+=t-1;var a=n.slice(o,u);if(u>r){e.lines=a,e.start.row=i+o,e.start.column=s;break}a.push(""),this.applyDelta({start:this.pos(i+o,s),end:this.pos(i+u,s=0),action:e.action,lines:a},!0)}while(!0)},this.revertDelta=function(e){this.applyDelta({start:this.clonePos(e.start),end:this.clonePos(e.end),action:e.action=="insert"?"remove":"insert",lines:e.lines.slice()})},this.indexToPosition=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length;for(var i=t||0,s=n.length;i<s;i++){e-=n[i].length+r;if(e<0)return{row:i,column:e+n[i].length+r}}return{row:s-1,column:n[s-1].length}},this.positionToIndex=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length,i=0,s=Math.min(e.row,n.length);for(var o=t||0;o<s;++o)i+=n[o].length+r;return i+e.column}}).call(a.prototype),t.Document=a}),ace.define("ace/lib/lang",["require","exports","module"],function(e,t,n){"use strict";t.last=function(e){return e[e.length-1]},t.stringReverse=function(e){return e.split("").reverse().join("")},t.stringRepeat=function(e,t){var n="";while(t>0){t&1&&(n+=e);if(t>>=1)e+=e}return n};var r=/^\s\s*/,i=/\s\s*$/;t.stringTrimLeft=function(e){return e.replace(r,"")},t.stringTrimRight=function(e){return e.replace(i,"")},t.copyObject=function(e){var t={};for(var n in e)t[n]=e[n];return t},t.copyArray=function(e){var t=[];for(var n=0,r=e.length;n<r;n++)e[n]&&typeof e[n]=="object"?t[n]=this.copyObject(e[n]):t[n]=e[n];return t},t.deepCopy=function s(e){if(typeof e!="object"||!e)return e;var t;if(Array.isArray(e)){t=[];for(var n=0;n<e.length;n++)t[n]=s(e[n]);return t}var r=e.constructor;if(r===RegExp)return e;t=r();for(var n in e)t[n]=s(e[n]);return t},t.arrayToMap=function(e){var t={};for(var n=0;n<e.length;n++)t[e[n]]=1;return t},t.createMap=function(e){var t=Object.create(null);for(var n in e)t[n]=e[n];return t},t.arrayRemove=function(e,t){for(var n=0;n<=e.length;n++)t===e[n]&&e.splice(n,1)},t.escapeRegExp=function(e){return e.replace(/([.*+?^${}()|[\]\/\\])/g,"\\$1")},t.escapeHTML=function(e){return e.replace(/&/g,"&#38;").replace(/"/g,"&#34;").replace(/'/g,"&#39;").replace(/</g,"&#60;")},t.getMatchOffsets=function(e,t){var n=[];return e.replace(t,function(e){n.push({offset:arguments[arguments.length-2],length:e.length})}),n},t.deferredCall=function(e){var t=null,n=function(){t=null,e()},r=function(e){return r.cancel(),t=setTimeout(n,e||0),r};return r.schedule=r,r.call=function(){return this.cancel(),e(),r},r.cancel=function(){return clearTimeout(t),t=null,r},r.isPending=function(){return t},r},t.delayedCall=function(e,t){var n=null,r=function(){n=null,e()},i=function(e){n==null&&(n=setTimeout(r,e||t))};return i.delay=function(e){n&&clearTimeout(n),n=setTimeout(r,e||t)},i.schedule=i,i.call=function(){this.cancel(),e()},i.cancel=function(){n&&clearTimeout(n),n=null},i.isPending=function(){return n},i}}),ace.define("ace/worker/mirror",["require","exports","module","ace/range","ace/document","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../range").Range,i=e("../document").Document,s=e("../lib/lang"),o=t.Mirror=function(e){this.sender=e;var t=this.doc=new i(""),n=this.deferredUpdate=s.delayedCall(this.onUpdate.bind(this)),r=this;e.on("change",function(e){var i=e.data;if(i[0].start)t.applyDeltas(i);else for(var s=0;s<i.length;s+=2){if(Array.isArray(i[s+1]))var o={action:"insert",start:i[s],lines:i[s+1]};else var o={action:"remove",start:i[s],end:i[s+1]};t.applyDelta(o,!0)}if(r.$timeout)return n.schedule(r.$timeout);r.onUpdate()})};(function(){this.$timeout=500,this.setTimeout=function(e){this.$timeout=e},this.setValue=function(e){this.doc.setValue(e),this.deferredUpdate.schedule(this.$timeout)},this.getValue=function(e){this.sender.callback(this.doc.getValue(),e)},this.onUpdate=function(){},this.isPending=function(){return this.deferredUpdate.isPending()}}).call(o.prototype)}),ace.define("ace/mode/coffee/coffee",["require","exports","module"],function(require,exports,module){function define(e){module.exports=e()}define.amd={},function(root){var CoffeeScript=function(){function _dereq_(e){return _dereq_[e]}return _dereq_["./helpers"]=function(){var e={},t={exports:e};return function(){var t,n,r,i,s,o;e.starts=function(e,t,n){return t===e.substr(n,t.length)},e.ends=function(e,t,n){var r;return r=t.length,t===e.substr(e.length-r-(n||0),r)},e.repeat=s=function(e,t){var n;for(n="";t>0;)1&t&&(n+=e),t>>>=1,e+=e;return n},e.compact=function(e){var t,n,r,i;for(i=[],t=0,r=e.length;r>t;t++)n=e[t],n&&i.push(n);return i},e.count=function(e,t){var n,r;if(n=r=0,!t.length)return 1/0;for(;r=1+e.indexOf(t,r);)n++;return n},e.merge=function(e,t){return n(n({},e),t)},n=e.extend=function(e,t){var n,r;for(n in t)r=t[n],e[n]=r;return e},e.flatten=r=function(e){var t,n,i,s;for(n=[],i=0,s=e.length;s>i;i++)t=e[i],t instanceof Array?n=n.concat(r(t)):n.push(t);return n},e.del=function(e,t){var n;return n=e[t],delete e[t],n},e.some=null!=(i=Array.prototype.some)?i:function(e){var t,n,r;for(n=0,r=this.length;r>n;n++)if(t=this[n],e(t))return!0;return!1},e.invertLiterate=function(e){var t,n,r;return r=!0,n=function(){var n,i,s,o;for(s=e.split("\n"),o=[],n=0,i=s.length;i>n;n++)t=s[n],r&&/^([ ]{4}|[ ]{0,3}\t)/.test(t)?o.push(t):(r=/^\s*$/.test(t))?o.push(t):o.push("# "+t);return o}(),n.join("\n")},t=function(e,t){return t?{first_line:e.first_line,first_column:e.first_column,last_line:t.last_line,last_column:t.last_column}:e},e.addLocationDataFn=function(e,n){return function(r){return"object"==typeof r&&r.updateLocationDataIfMissing&&r.updateLocationDataIfMissing(t(e,n)),r}},e.locationDataToString=function(e){var t;return"2"in e&&"first_line"in e[2]?t=e[2]:"first_line"in e&&(t=e),t?t.first_line+1+":"+(t.first_column+1)+"-"+(t.last_line+1+":"+(t.last_column+1)):"No location data"},e.baseFileName=function(e,t,n){var r,i;return null==t&&(t=!1),null==n&&(n=!1),i=n?/\\|\//:/\//,r=e.split(i),e=r[r.length-1],t&&e.indexOf(".")>=0?(r=e.split("."),r.pop(),"coffee"===r[r.length-1]&&r.length>1&&r.pop(),r.join(".")):e},e.isCoffee=function(e){return/\.((lit)?coffee|coffee\.md)$/.test(e)},e.isLiterate=function(e){return/\.(litcoffee|coffee\.md)$/.test(e)},e.throwSyntaxError=function(e,t){var n;throw n=new SyntaxError(e),n.location=t,n.toString=o,n.stack=""+n,n},e.updateSyntaxError=function(e,t,n){return e.toString===o&&(e.code||(e.code=t),e.filename||(e.filename=n),e.stack=""+e),e},o=function(){var e,t,n,r,i,o,u,a,f,l,c,h,p,d,v;return this.code&&this.location?(c=this.location,u=c.first_line,o=c.first_column,f=c.last_line,a=c.last_column,null==f&&(f=u),null==a&&(a=o),i=this.filename||"[stdin]",e=this.code.split("\n")[u],v=o,r=u===f?a+1:e.length,l=e.slice(0,v).replace(/[^\s]/g," ")+s("^",r-v),"undefined"!=typeof process&&null!==process&&(n=(null!=(h=process.stdout)?h.isTTY:void 0)&&(null!=(p=process.env)?!p.NODE_DISABLE_COLORS:!void 0)),(null!=(d=this.colorful)?d:n)&&(t=function(e){return""+e+""},e=e.slice(0,v)+t(e.slice(v,r))+e.slice(r),l=t(l)),i+":"+(u+1)+":"+(o+1)+": error: "+this.message+"\n"+e+"\n"+l):Error.prototype.toString.call(this)},e.nameWhitespaceCharacter=function(e){switch(e){case" ":return"space";case"\n":return"newline";case"\r":return"carriage return";case"	":return"tab";default:return e}}}.call(this),t.exports}(),_dereq_["./rewriter"]=function(){var e={},t={exports:e};return function(){var t,n,r,i,s,o,u,a,f,l,c,h,p,d,v,m,g,y,b,w=[].indexOf||function(e){for(var t=0,n=this.length;n>t;t++)if(t in this&&this[t]===e)return t;return-1},E=[].slice;for(d=function(e,t,n){var r;return r=[e,t],r.generated=!0,n&&(r.origin=n),r},e.Rewriter=function(){function e(){}return e.prototype.rewrite=function(e){return this.tokens=e,this.removeLeadingNewlines(),this.closeOpenCalls(),this.closeOpenIndexes(),this.normalizeLines(),this.tagPostfixConditionals(),this.addImplicitBracesAndParens(),this.addLocationDataToGeneratedTokens(),this.tokens},e.prototype.scanTokens=function(e){var t,n,r;for(r=this.tokens,t=0;n=r[t];)t+=e.call(this,n,t,r);return!0},e.prototype.detectEnd=function(e,t,n){var r,o,u,a,f;for(f=this.tokens,r=0;a=f[e];){if(0===r&&t.call(this,a,e))return n.call(this,a,e);if(!a||0>r)return n.call(this,a,e-1);o=a[0],w.call(s,o)>=0?r+=1:(u=a[0],w.call(i,u)>=0&&(r-=1)),e+=1}return e-1},e.prototype.removeLeadingNewlines=function(){var e,t,n,r,i;for(r=this.tokens,e=t=0,n=r.length;n>t&&(i=r[e][0],"TERMINATOR"===i);e=++t);return e?this.tokens.splice(0,e):void 0},e.prototype.closeOpenCalls=function(){var e,t;return t=function(e,t){var n;return")"===(n=e[0])||"CALL_END"===n||"OUTDENT"===e[0]&&")"===this.tag(t-1)},e=function(e,t){return this.tokens["OUTDENT"===e[0]?t-1:t][0]="CALL_END"},this.scanTokens(function(n,r){return"CALL_START"===n[0]&&this.detectEnd(r+1,t,e),1})},e.prototype.closeOpenIndexes=function(){var e,t;return t=function(e){var t;return"]"===(t=e[0])||"INDEX_END"===t},e=function(e){return e[0]="INDEX_END"},this.scanTokens(function(n,r){return"INDEX_START"===n[0]&&this.detectEnd(r+1,t,e),1})},e.prototype.indexOfTag=function(){var e,t,n,r,i,s,o;for(t=arguments[0],i=arguments.length>=2?E.call(arguments,1):[],e=0,n=r=0,s=i.length;s>=0?s>r:r>s;n=s>=0?++r:--r){for(;"HERECOMMENT"===this.tag(t+n+e);)e+=2;if(null!=i[n]&&("string"==typeof i[n]&&(i[n]=[i[n]]),o=this.tag(t+n+e),0>w.call(i[n],o)))return-1}return t+n+e-1},e.prototype.looksObjectish=function(e){var t,n;return this.indexOfTag(e,"@",null,":")>-1||this.indexOfTag(e,null,":")>-1?!0:(n=this.indexOfTag(e,s),n>-1&&(t=null,this.detectEnd(n+1,function(e){var t;return t=e[0],w.call(i,t)>=0},function(e,n){return t=n}),":"===this.tag(t+1))?!0:!1)},e.prototype.findTagsBackwards=function(e,t){var n,r,o,u,a,f,l;for(n=[];e>=0&&(n.length||(u=this.tag(e),0>w.call(t,u)&&(a=this.tag(e),0>w.call(s,a)||this.tokens[e].generated)&&(f=this.tag(e),0>w.call(c,f))));)r=this.tag(e),w.call(i,r)>=0&&n.push(this.tag(e)),o=this.tag(e),w.call(s,o)>=0&&n.length&&n.pop(),e-=1;return l=this.tag(e),w.call(t,l)>=0},e.prototype.addImplicitBracesAndParens=function(){var e,t;return e=[],t=null,this.scanTokens(function(r,l,h){var p,v,m,g,y,b,E,S,x,T,N,C,L,A,O,M,_,D,P,H,B,j,F,I,q,R,U,z;if(z=r[0],N=(C=l>0?h[l-1]:[])[0],x=(h.length-1>l?h[l+1]:[])[0],F=function(){return e[e.length-1]},I=l,m=function(e){return l-I+e},g=function(){var e,t;return null!=(e=F())?null!=(t=e[2])?t.ours:void 0:void 0},y=function(){var e;return g()&&"("===(null!=(e=F())?e[0]:void 0)},E=function(){var e;return g()&&"{"===(null!=(e=F())?e[0]:void 0)},b=function(){var e;return g&&"CONTROL"===(null!=(e=F())?e[0]:void 0)},q=function(t){var n;return n=null!=t?t:l,e.push(["(",n,{ours:!0}]),h.splice(n,0,d("CALL_START","(")),null==t?l+=1:void 0},p=function(){return e.pop(),h.splice(l,0,d("CALL_END",")",["","end of input",r[2]])),l+=1},R=function(t,n){var i,s;return null==n&&(n=!0),i=null!=t?t:l,e.push(["{",i,{sameLine:!0,startsLine:n,ours:!0}]),s=new String("{"),s.generated=!0,h.splice(i,0,d("{",s,r)),null==t?l+=1:void 0},v=function(t){return t=null!=t?t:l,e.pop(),h.splice(t,0,d("}","}",r)),l+=1},!y()||"IF"!==z&&"TRY"!==z&&"FINALLY"!==z&&"CATCH"!==z&&"CLASS"!==z&&"SWITCH"!==z){if("INDENT"===z&&g()){if("=>"!==N&&"->"!==N&&"["!==N&&"("!==N&&","!==N&&"{"!==N&&"TRY"!==N&&"ELSE"!==N&&"="!==N)for(;y();)p();return b()&&e.pop(),e.push([z,l]),m(1)}if(w.call(s,z)>=0)return e.push([z,l]),m(1);if(w.call(i,z)>=0){for(;g();)y()?p():E()?v():e.pop();t=e.pop()}if((w.call(a,z)>=0&&r.spaced||"?"===z&&l>0&&!h[l-1].spaced)&&(w.call(o,x)>=0||w.call(f,x)>=0&&(null!=(L=h[l+1])?!L.spaced:!void 0)&&(null!=(A=h[l+1])?!A.newLine:!void 0)))return"?"===z&&(z=r[0]="FUNC_EXIST"),q(l+1),m(2);if(w.call(a,z)>=0&&this.indexOfTag(l+1,"INDENT")>-1&&this.looksObjectish(l+2)&&!this.findTagsBackwards(l,["CLASS","EXTENDS","IF","CATCH","SWITCH","LEADING_WHEN","FOR","WHILE","UNTIL"]))return q(l+1),e.push(["INDENT",l+2]),m(3);if(":"===z){for(P=function(){var e;switch(!1){case e=this.tag(l-1),0>w.call(i,e):return t[1];case"@"!==this.tag(l-2):return l-2;default:return l-1}}.call(this);"HERECOMMENT"===this.tag(P-2);)P-=2;return this.insideForDeclaration="FOR"===x,U=0===P||(O=this.tag(P-1),w.call(c,O)>=0)||h[P-1].newLine,F()&&(M=F(),j=M[0],B=M[1],("{"===j||"INDENT"===j&&"{"===this.tag(B-1))&&(U||","===this.tag(P-1)||"{"===this.tag(P-1)))?m(1):(R(P,!!U),m(2))}if(E()&&w.call(c,z)>=0&&(F()[2].sameLine=!1),S="OUTDENT"===N||C.newLine,w.call(u,z)>=0||w.call(n,z)>=0&&S)for(;g();)if(_=F(),j=_[0],B=_[1],D=_[2],H=D.sameLine,U=D.startsLine,y()&&","!==N)p();else if(E()&&!this.insideForDeclaration&&H&&"TERMINATOR"!==z&&":"!==N)v();else{if(!E()||"TERMINATOR"!==z||","===N||U&&this.looksObjectish(l+1))break;if("HERECOMMENT"===x)return m(1);v()}if(!(","!==z||this.looksObjectish(l+1)||!E()||this.insideForDeclaration||"TERMINATOR"===x&&this.looksObjectish(l+2)))for(T="OUTDENT"===x?1:0;E();)v(l+T);return m(1)}return e.push(["CONTROL",l,{ours:!0}]),m(1)})},e.prototype.addLocationDataToGeneratedTokens=function(){return this.scanTokens(function(e,t,n){var r,i,s,o,u,a;return e[2]?1:e.generated||e.explicit?("{"===e[0]&&(s=null!=(u=n[t+1])?u[2]:void 0)?(i=s.first_line,r=s.first_column):(o=null!=(a=n[t-1])?a[2]:void 0)?(i=o.last_line,r=o.last_column):i=r=0,e[2]={first_line:i,first_column:r,last_line:i,last_column:r},1):1})},e.prototype.normalizeLines=function(){var e,t,i,s,o;return o=i=s=null,t=function(e,t){var i,s,u,a;return";"!==e[1]&&(i=e[0],w.call(h,i)>=0)&&!("TERMINATOR"===e[0]&&(s=this.tag(t+1),w.call(r,s)>=0))&&("ELSE"!==e[0]||"THEN"===o)&&("CATCH"!==(u=e[0])&&"FINALLY"!==u||"->"!==o&&"=>"!==o)||(a=e[0],w.call(n,a)>=0&&this.tokens[t-1].newLine)},e=function(e,t){return this.tokens.splice(","===this.tag(t-1)?t-1:t,0,s)},this.scanTokens(function(n,u,a){var f,l,c,h,d,v;if(v=n[0],"TERMINATOR"===v){if("ELSE"===this.tag(u+1)&&"OUTDENT"!==this.tag(u-1))return a.splice.apply(a,[u,1].concat(E.call(this.indentation()))),1;if(c=this.tag(u+1),w.call(r,c)>=0)return a.splice(u,1),0}if("CATCH"===v)for(f=l=1;2>=l;f=++l)if("OUTDENT"===(h=this.tag(u+f))||"TERMINATOR"===h||"FINALLY"===h)return a.splice.apply(a,[u+f,0].concat(E.call(this.indentation()))),2+f;return w.call(p,v)>=0&&"INDENT"!==this.tag(u+1)&&("ELSE"!==v||"IF"!==this.tag(u+1))?(o=v,d=this.indentation(a[u]),i=d[0],s=d[1],"THEN"===o&&(i.fromThen=!0),a.splice(u+1,0,i),this.detectEnd(u+2,t,e),"THEN"===v&&a.splice(u,1),1):1})},e.prototype.tagPostfixConditionals=function(){var e,t,n;return n=null,t=function(e,t){var n,r;return r=e[0],n=this.tokens[t-1][0],"TERMINATOR"===r||"INDENT"===r&&0>w.call(p,n)},e=function(e){return"INDENT"!==e[0]||e.generated&&!e.fromThen?n[0]="POST_"+n[0]:void 0},this.scanTokens(function(r,i){return"IF"!==r[0]?1:(n=r,this.detectEnd(i+1,t,e),1)})},e.prototype.indentation=function(e){var t,n;return t=["INDENT",2],n=["OUTDENT",2],e?(t.generated=n.generated=!0,t.origin=n.origin=e):t.explicit=n.explicit=!0,[t,n]},e.prototype.generate=d,e.prototype.tag=function(e){var t;return null!=(t=this.tokens[e])?t[0]:void 0},e}(),t=[["(",")"],["[","]"],["{","}"],["INDENT","OUTDENT"],["CALL_START","CALL_END"],["PARAM_START","PARAM_END"],["INDEX_START","INDEX_END"],["STRING_START","STRING_END"],["REGEX_START","REGEX_END"]],e.INVERSES=l={},s=[],i=[],v=0,g=t.length;g>v;v++)y=t[v],m=y[0],b=y[1],s.push(l[b]=m),i.push(l[m]=b);r=["CATCH","THEN","ELSE","FINALLY"].concat(i),a=["IDENTIFIER","SUPER",")","CALL_END","]","INDEX_END","@","THIS"],o=["IDENTIFIER","NUMBER","STRING","STRING_START","JS","REGEX","REGEX_START","NEW","PARAM_START","CLASS","IF","TRY","SWITCH","THIS","BOOL","NULL","UNDEFINED","UNARY","YIELD","UNARY_MATH","SUPER","THROW","@","->","=>","[","(","{","--","++"],f=["+","-"],u=["POST_IF","FOR","WHILE","UNTIL","WHEN","BY","LOOP","TERMINATOR"],p=["ELSE","->","=>","TRY","FINALLY","THEN"],h=["TERMINATOR","CATCH","FINALLY","ELSE","OUTDENT","LEADING_WHEN"],c=["TERMINATOR","INDENT","OUTDENT"],n=[".","?.","::","?::"]}.call(this),t.exports}(),_dereq_["./lexer"]=function(){var e={},t={exports:e};return function(){var t,n,r,i,s,o,u,a,f,l,c,h,p,d,v,m,g,y,b,w,E,S,x,T,N,C,k,L,A,O,M,_,D,P,H,B,j,F,I,q,R,U,z,W,X,V,$,J,K,Q,G,Y,Z,et,tt,nt,rt,it,st,ot,ut,at,ft,lt,ct=[].indexOf||function(e){for(var t=0,n=this.length;n>t;t++)if(t in this&&this[t]===e)return t;return-1};ot=_dereq_("./rewriter"),R=ot.Rewriter,E=ot.INVERSES,ut=_dereq_("./helpers"),nt=ut.count,ft=ut.starts,tt=ut.compact,at=ut.repeat,rt=ut.invertLiterate,st=ut.locationDataToString,lt=ut.throwSyntaxError,e.Lexer=A=function(){function e(){}return e.prototype.tokenize=function(e,t){var n,r,i,s;for(null==t&&(t={}),this.literate=t.literate,this.indent=0,this.baseIndent=0,this.indebt=0,this.outdebt=0,this.indents=[],this.ends=[],this.tokens=[],this.chunkLine=t.line||0,this.chunkColumn=t.column||0,e=this.clean(e),i=0;this.chunk=e.slice(i);)if(n=this.identifierToken()||this.commentToken()||this.whitespaceToken()||this.lineToken()||this.stringToken()||this.numberToken()||this.regexToken()||this.jsToken()||this.literalToken(),s=this.getLineAndColumnFromChunk(n),this.chunkLine=s[0],this.chunkColumn=s[1],i+=n,t.untilBalanced&&0===this.ends.length)return{tokens:this.tokens,index:i};return this.closeIndentation(),(r=this.ends.pop())&&this.error("missing "+r.tag,r.origin[2]),t.rewrite===!1?this.tokens:(new R).rewrite(this.tokens)},e.prototype.clean=function(e){return e.charCodeAt(0)===t&&(e=e.slice(1)),e=e.replace(/\r/g,"").replace(Q,""),et.test(e)&&(e="\n"+e,this.chunkLine--),this.literate&&(e=rt(e)),e},e.prototype.identifierToken=function(){var e,t,n,r,i,a,f,l,c,h,p,d,v,m,y,b;return(l=g.exec(this.chunk))?(f=l[0],i=l[1],t=l[2],a=i.length,c=void 0,"own"===i&&"FOR"===this.tag()?(this.token("OWN",i),i.length):"from"===i&&"YIELD"===this.tag()?(this.token("FROM",i),i.length):(p=this.tokens,h=p[p.length-1],r=t||null!=h&&("."===(d=h[0])||"?."===d||"::"===d||"?::"===d||!h.spaced&&"@"===h[0]),y="IDENTIFIER",!r&&(ct.call(T,i)>=0||ct.call(u,i)>=0)&&(y=i.toUpperCase(),"WHEN"===y&&(v=this.tag(),ct.call(C,v)>=0)?y="LEADING_WHEN":"FOR"===y?this.seenFor=!0:"UNLESS"===y?y="IF":ct.call(G,y)>=0?y="UNARY":ct.call(I,y)>=0&&("INSTANCEOF"!==y&&this.seenFor?(y="FOR"+y,this.seenFor=!1):(y="RELATION","!"===this.value()&&(c=this.tokens.pop(),i="!"+i)))),ct.call(x,i)>=0&&(r?(y="IDENTIFIER",i=new String(i),i.reserved=!0):ct.call(q,i)>=0&&this.error("reserved word '"+i+"'",{length:i.length})),r||(ct.call(s,i)>=0&&(e=i,i=o[i]),y=function(){switch(i){case"!":return"UNARY";case"==":case"!=":return"COMPARE";case"&&":case"||":return"LOGIC";case"true":case"false":return"BOOL";case"break":case"continue":return"STATEMENT";default:return y}}()),b=this.token(y,i,0,a),e&&(b.origin=[y,e,b[2]]),b.variable=!r,c&&(m=[c[2].first_line,c[2].first_column],b[2].first_line=m[0],b[2].first_column=m[1]),t&&(n=f.lastIndexOf(":"),this.token(":",":",n,t.length)),f.length)):0},e.prototype.numberToken=function(){var e,t,n,r,i;return(n=D.exec(this.chunk))?(r=n[0],t=r.length,/^0[BOX]/.test(r)?this.error("radix prefix in '"+r+"' must be lowercase",{offset:1}):/E/.test(r)&&!/^0x/.test(r)?this.error("exponential notation in '"+r+"' must be indicated with a lowercase 'e'",{offset:r.indexOf("E")}):/^0\d*[89]/.test(r)?this.error("decimal literal '"+r+"' must not be prefixed with '0'",{length:t}):/^0\d+/.test(r)&&this.error("octal literal '"+r+"' must be prefixed with '0o'",{length:t}),(i=/^0o([0-7]+)/.exec(r))&&(r="0x"+parseInt(i[1],8).toString(16)),(e=/^0b([01]+)/.exec(r))&&(r="0x"+parseInt(e[1],2).toString(16)),this.token("NUMBER",r,0,t),t):0},e.prototype.stringToken=function(){var e,t,n,r,i,s,o,u,a,f,l,c,v,m,g,y;if(l=(J.exec(this.chunk)||[])[0],!l)return 0;if(m=function(){switch(l){case"'":return $;case'"':return X;case"'''":return d;case'"""':return h}}(),s=3===l.length,c=this.matchWithInterpolations(m,l),y=c.tokens,i=c.index,e=y.length-1,n=l.charAt(0),s){for(u=null,r=function(){var e,t,n;for(n=[],o=e=0,t=y.length;t>e;o=++e)g=y[o],"NEOSTRING"===g[0]&&n.push(g[1]);return n}().join("#{}");f=p.exec(r);)t=f[1],(null===u||(v=t.length)>0&&u.length>v)&&(u=t);u&&(a=RegExp("^"+u,"gm")),this.mergeInterpolationTokens(y,{delimiter:n},function(t){return function(n,r){return n=t.formatString(n),0===r&&(n=n.replace(N,"")),r===e&&(n=n.replace(K,"")),a&&(n=n.replace(a,"")),n}}(this))}else this.mergeInterpolationTokens(y,{delimiter:n},function(t){return function(n,r){return n=t.formatString(n),n=n.replace(z,function(t,i){return 0===r&&0===i||r===e&&i+t.length===n.length?"":" "})}}(this));return i},e.prototype.commentToken=function(){var e,t,n;return(n=this.chunk.match(a))?(e=n[0],t=n[1],t&&((n=c.exec(e))&&this.error("block comments cannot contain "+n[0],{offset:n.index,length:n[0].length}),t.indexOf("\n")>=0&&(t=t.replace(RegExp("\\n"+at(" ",this.indent),"g"),"\n")),this.token("HERECOMMENT",t,0,e.length)),e.length):0},e.prototype.jsToken=function(){var e,t;return"`"===this.chunk.charAt(0)&&(e=S.exec(this.chunk))?(this.token("JS",(t=e[0]).slice(1,-1),0,t.length),t.length):0},e.prototype.regexToken=function(){var e,t,n,i,s,o,u,a,f,l,c,h,p;switch(!1){case!(o=F.exec(this.chunk)):this.error("regular expressions cannot begin with "+o[2],{offset:o.index+o[1].length});break;case!(o=this.matchWithInterpolations(v,"///")):p=o.tokens,s=o.index;break;case!(o=B.exec(this.chunk)):if(h=o[0],e=o[1],t=o[2],this.validateEscapes(e,{isRegex:!0,offsetInChunk:1}),s=h.length,f=this.tokens,a=f[f.length-1],a)if(a.spaced&&(l=a[0],ct.call(r,l)>=0)){if(!t||H.test(h))return 0}else if(c=a[0],ct.call(_,c)>=0)return 0;t||this.error("missing / (unclosed regex)");break;default:return 0}switch(i=j.exec(this.chunk.slice(s))[0],n=s+i.length,u=this.makeToken("REGEX",null,0,n),!1){case!!Z.test(i):this.error("invalid regular expression flags "+i,{offset:s,length:i.length});break;case!h&&1!==p.length:null==e&&(e=this.formatHeregex(p[0][1])),this.token("REGEX",""+this.makeDelimitedLiteral(e,{delimiter:"/"})+i,0,n,u);break;default:this.token("REGEX_START","(",0,0,u),this.token("IDENTIFIER","RegExp",0,0),this.token("CALL_START","(",0,0),this.mergeInterpolationTokens(p,{delimiter:'"',"double":!0},this.formatHeregex),i&&(this.token(",",",",s,0),this.token("STRING",'"'+i+'"',s,i.length)),this.token(")",")",n,0),this.token("REGEX_END",")",n,0)}return n},e.prototype.lineToken=function(){var e,t,n,r,i;if(!(n=M.exec(this.chunk)))return 0;if(t=n[0],this.seenFor=!1,i=t.length-1-t.lastIndexOf("\n"),r=this.unfinished(),i-this.indebt===this.indent)return r?this.suppressNewlines():this.newlineToken(0),t.length;if(i>this.indent){if(r)return this.indebt=i-this.indent,this.suppressNewlines(),t.length;if(!this.tokens.length)return this.baseIndent=this.indent=i,t.length;e=i-this.indent+this.outdebt,this.token("INDENT",e,t.length-i,i),this.indents.push(e),this.ends.push({tag:"OUTDENT"}),this.outdebt=this.indebt=0,this.indent=i}else this.baseIndent>i?this.error("missing indentation",{offset:t.length}):(this.indebt=0,this.outdentToken(this.indent-i,r,t.length));return t.length},e.prototype.outdentToken=function(e,t,n){var r,i,s,o;for(r=this.indent-e;e>0;)s=this.indents[this.indents.length-1],s?s===this.outdebt?(e-=this.outdebt,this.outdebt=0):this.outdebt>s?(this.outdebt-=s,e-=s):(i=this.indents.pop()+this.outdebt,n&&(o=this.chunk[n],ct.call(y,o)>=0)&&(r-=i-e,e=i),this.outdebt=0,this.pair("OUTDENT"),this.token("OUTDENT",e,0,n),e-=i):e=0;for(i&&(this.outdebt-=e);";"===this.value();)this.tokens.pop();return"TERMINATOR"===this.tag()||t||this.token("TERMINATOR","\n",n,0),this.indent=r,this},e.prototype.whitespaceToken=function(){var e,t,n,r;return(e=et.exec(this.chunk))||(t="\n"===this.chunk.charAt(0))?(r=this.tokens,n=r[r.length-1],n&&(n[e?"spaced":"newLine"]=!0),e?e[0].length:0):0},e.prototype.newlineToken=function(e){for(;";"===this.value();)this.tokens.pop();return"TERMINATOR"!==this.tag()&&this.token("TERMINATOR","\n",e,0),this},e.prototype.suppressNewlines=function(){return"\\"===this.value()&&this.tokens.pop(),this},e.prototype.literalToken=function(){var e,t,n,s,o,u,a,c,h,p;if((e=P.exec(this.chunk))?(p=e[0],i.test(p)&&this.tagParameters()):p=this.chunk.charAt(0),c=p,n=this.tokens,t=n[n.length-1],"="===p&&t&&(!t[1].reserved&&(s=t[1],ct.call(x,s)>=0)&&(t.origin&&(t=t.origin),this.error("reserved word '"+t[1]+"' can't be assigned",t[2])),"||"===(o=t[1])||"&&"===o))return t[0]="COMPOUND_ASSIGN",t[1]+="=",p.length;if(";"===p)this.seenFor=!1,c="TERMINATOR";else if(ct.call(O,p)>=0)c="MATH";else if(ct.call(f,p)>=0)c="COMPARE";else if(ct.call(l,p)>=0)c="COMPOUND_ASSIGN";else if(ct.call(G,p)>=0)c="UNARY";else if(ct.call(Y,p)>=0)c="UNARY_MATH";else if(ct.call(U,p)>=0)c="SHIFT";else if(ct.call(L,p)>=0||"?"===p&&(null!=t?t.spaced:void 0))c="LOGIC";else if(t&&!t.spaced)if("("===p&&(u=t[0],ct.call(r,u)>=0))"?"===t[0]&&(t[0]="FUNC_EXIST"),c="CALL_START";else if("["===p&&(a=t[0],ct.call(b,a)>=0))switch(c="INDEX_START",t[0]){case"?":t[0]="INDEX_SOAK"}switch(h=this.makeToken(c,p),p){case"(":case"{":case"[":this.ends.push({tag:E[p],origin:h});break;case")":case"}":case"]":this.pair(p)}return this.tokens.push(h),p.length},e.prototype.tagParameters=function(){var e,t,n,r;if(")"!==this.tag())return this;for(t=[],r=this.tokens,e=r.length,r[--e][0]="PARAM_END";n=r[--e];)switch(n[0]){case")":t.push(n);break;case"(":case"CALL_START":if(!t.length)return"("===n[0]?(n[0]="PARAM_START",this):this;t.pop()}return this},e.prototype.closeIndentation=function(){return this.outdentToken(this.indent)},e.prototype.matchWithInterpolations=function(t,n){var r,i,s,o,u,a,f,l,c,h,p,d,v,m,g;if(g=[],l=n.length,this.chunk.slice(0,l)!==n)return null;for(v=this.chunk.slice(l);;){if(m=t.exec(v)[0],this.validateEscapes(m,{isRegex:"/"===n.charAt(0),offsetInChunk:l}),g.push(this.makeToken("NEOSTRING",m,l)),v=v.slice(m.length),l+=m.length,"#{"!==v.slice(0,2))break;h=this.getLineAndColumnFromChunk(l+1),a=h[0],i=h[1],p=(new e).tokenize(v.slice(1),{line:a,column:i,untilBalanced:!0}),f=p.tokens,o=p.index,o+=1,c=f[0],r=f[f.length-1],c[0]=c[1]="(",r[0]=r[1]=")",r.origin=["","end of interpolation",r[2]],"TERMINATOR"===(null!=(d=f[1])?d[0]:void 0)&&f.splice(1,1),g.push(["TOKENS",f]),v=v.slice(o),l+=o}return v.slice(0,n.length)!==n&&this.error("missing "+n,{length:n.length}),s=g[0],u=g[g.length-1],s[2].first_column-=n.length,u[2].last_column+=n.length,0===u[1].length&&(u[2].last_column-=1),{tokens:g,index:l+n.length}},e.prototype.mergeInterpolationTokens=function(e,t,n){var r,i,s,o,u,a,f,l,c,h,p,d,v,m,g,y;for(e.length>1&&(c=this.token("STRING_START","(",0,0)),s=this.tokens.length,o=u=0,f=e.length;f>u;o=++u){switch(m=e[o],v=m[0],y=m[1],v){case"TOKENS":if(2===y.length)continue;l=y[0],g=y;break;case"NEOSTRING":if(r=n(m[1],o),0===r.length){if(0!==o)continue;i=this.tokens.length}2===o&&null!=i&&this.tokens.splice(i,2),m[0]="STRING",m[1]=this.makeDelimitedLiteral(r,t),l=m,g=[m]}this.tokens.length>s&&(h=this.token("+","+"),h[2]={first_line:l[2].first_line,first_column:l[2].first_column,last_line:l[2].first_line,last_column:l[2].first_column}),(p=this.tokens).push.apply(p,g)}return c?(a=e[e.length-1],c.origin=["STRING",null,{first_line:c[2].first_line,first_column:c[2].first_column,last_line:a[2].last_line,last_column:a[2].last_column}],d=this.token("STRING_END",")"),d[2]={first_line:a[2].last_line,first_column:a[2].last_column,last_line:a[2].last_line,last_column:a[2].last_column}):void 0},e.prototype.pair=function(e){var t,n,r,i,s;return r=this.ends,n=r[r.length-1],e!==(s=null!=n?n.tag:void 0)?("OUTDENT"!==s&&this.error("unmatched "+e),i=this.indents,t=i[i.length-1],this.outdentToken(t,!0),this.pair(e)):this.ends.pop()},e.prototype.getLineAndColumnFromChunk=function(e){var t,n,r,i,s;return 0===e?[this.chunkLine,this.chunkColumn]:(s=e>=this.chunk.length?this.chunk:this.chunk.slice(0,+(e-1)+1||9e9),r=nt(s,"\n"),t=this.chunkColumn,r>0?(i=s.split("\n"),n=i[i.length-1],t=n.length):t+=s.length,[this.chunkLine+r,t])},e.prototype.makeToken=function(e,t,n,r){var i,s,o,u,a;return null==n&&(n=0),null==r&&(r=t.length),s={},o=this.getLineAndColumnFromChunk(n),s.first_line=o[0],s.first_column=o[1],i=Math.max(0,r-1),u=this.getLineAndColumnFromChunk(n+i),s.last_line=u[0],s.last_column=u[1],a=[e,t,s]},e.prototype.token=function(e,t,n,r,i){var s;return s=this.makeToken(e,t,n,r),i&&(s.origin=i),this.tokens.push(s),s},e.prototype.tag=function(){var e,t;return e=this.tokens,t=e[e.length-1],null!=t?t[0]:void 0},e.prototype.value=function(){var e,t;return e=this.tokens,t=e[e.length-1],null!=t?t[1]:void 0},e.prototype.unfinished=function(){var e;return k.test(this.chunk)||"\\"===(e=this.tag())||"."===e||"?."===e||"?::"===e||"UNARY"===e||"MATH"===e||"UNARY_MATH"===e||"+"===e||"-"===e||"YIELD"===e||"**"===e||"SHIFT"===e||"RELATION"===e||"COMPARE"===e||"LOGIC"===e||"THROW"===e||"EXTENDS"===e},e.prototype.formatString=function(e){return e.replace(V,"$1")},e.prototype.formatHeregex=function(e){return e.replace(m,"$1$2")},e.prototype.validateEscapes=function(e,t){var n,r,i,s,o,u,a,f;return null==t&&(t={}),s=w.exec(e),!s||(s[0],n=s[1],u=s[2],r=s[3],f=s[4],t.isRegex&&u&&"0"!==u.charAt(0))?void 0:(o=u?"octal escape sequences are not allowed":"invalid escape sequence",i="\\"+(u||r||f),this.error(o+" "+i,{offset:(null!=(a=t.offsetInChunk)?a:0)+s.index+n.length,length:i.length}))},e.prototype.makeDelimitedLiteral=function(e,t){var n;return null==t&&(t={}),""===e&&"/"===t.delimiter&&(e="(?:)"),n=RegExp("(\\\\\\\\)|(\\\\0(?=[1-7]))|\\\\?("+t.delimiter+")|\\\\?(?:(\\n)|(\\r)|(\\u2028)|(\\u2029))|(\\\\.)","g"),e=e.replace(n,function(e,n,r,i,s,o,u,a,f){switch(!1){case!n:return t.double?n+n:n;case!r:return"\\x00";case!i:return"\\"+i;case!s:return"\\n";case!o:return"\\r";case!u:return"\\u2028";case!a:return"\\u2029";case!f:return t.double?"\\"+f:f}}),""+t.delimiter+e+t.delimiter},e.prototype.error=function(e,t){var n,r,i,s,o,u;return null==t&&(t={}),i="first_line"in t?t:(o=this.getLineAndColumnFromChunk(null!=(s=t.offset)?s:0),r=o[0],n=o[1],o,{first_line:r,first_column:n,last_column:n+(null!=(u=t.length)?u:1)-1}),lt(e,i)},e}(),T=["true","false","null","this","new","delete","typeof","in","instanceof","return","throw","break","continue","debugger","yield","if","else","switch","for","while","do","try","catch","finally","class","extends","super"],u=["undefined","then","unless","until","loop","of","by","when"],o={and:"&&",or:"||",is:"==",isnt:"!=",not:"!",yes:"true",no:"false",on:"true",off:"false"},s=function(){var e;e=[];for(it in o)e.push(it);return e}(),u=u.concat(s),q=["case","default","function","var","void","with","const","let","enum","export","import","native","implements","interface","package","private","protected","public","static"],W=["arguments","eval","yield*"],x=T.concat(q).concat(W),e.RESERVED=q.concat(T).concat(u).concat(W),e.STRICT_PROSCRIBED=W,t=65279,g=/^(?!\d)((?:(?!\s)[$\w\x7f-\uffff])+)([^\n\S]*:(?!:))?/,D=/^0b[01]+|^0o[0-7]+|^0x[\da-f]+|^\d*\.?\d+(?:e[+-]?\d+)?/i,P=/^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>*\/%])\2=?|\?(\.|::)|\.{2,3})/,et=/^[^\n\S]+/,a=/^###([^#][\s\S]*?)(?:###[^\n\S]*|###$)|^(?:\s*#(?!##[^#]).*)+/,i=/^[-=]>/,M=/^(?:\n[^\n\S]*)+/,S=/^`[^\\`]*(?:\\.[^\\`]*)*`/,J=/^(?:'''|"""|'|")/,$=/^(?:[^\\']|\\[\s\S])*/,X=/^(?:[^\\"#]|\\[\s\S]|\#(?!\{))*/,d=/^(?:[^\\']|\\[\s\S]|'(?!''))*/,h=/^(?:[^\\"#]|\\[\s\S]|"(?!"")|\#(?!\{))*/,V=/((?:\\\\)+)|\\[^\S\n]*\n\s*/g,z=/\s*\n\s*/g,p=/\n+([^\n\S]*)(?=\S)/g,B=/^\/(?!\/)((?:[^[\/\n\\]|\\[^\n]|\[(?:\\[^\n]|[^\]\n\\])*\])*)(\/)?/,j=/^\w*/,Z=/^(?!.*(.).*\1)[imgy]*$/,v=/^(?:[^\\\/#]|\\[\s\S]|\/(?!\/\/)|\#(?!\{))*/,m=/((?:\\\\)+)|\\(\s)|\s+(?:#.*)?/g,F=/^(\/|\/{3}\s*)(\*)/,H=/^\/=?\s/,c=/\*\//,k=/^\s*(?:,|\??\.(?![.\d])|::)/,w=/((?:^|[^\\])(?:\\\\)*)\\(?:(0[0-7]|[1-7])|(x(?![\da-fA-F]{2}).{0,2})|(u(?![\da-fA-F]{4}).{0,4}))/,N=/^[^\n\S]*\n/,K=/\n[^\n\S]*$/,Q=/\s+$/,l=["-=","+=","/=","*=","%=","||=","&&=","?=","<<=",">>=",">>>=","&=","^=","|=","**=","//=","%%="],G=["NEW","TYPEOF","DELETE","DO"],Y=["!","~"],L=["&&","||","&","|","^"],U=["<<",">>",">>>"],f=["==","!=","<",">","<=",">="],O=["*","/","%","//","%%"],I=["IN","OF","INSTANCEOF"],n=["TRUE","FALSE"],r=["IDENTIFIER",")","]","?","@","THIS","SUPER"],b=r.concat(["NUMBER","STRING","STRING_END","REGEX","REGEX_END","BOOL","NULL","UNDEFINED","}","::"]),_=b.concat(["++","--"]),C=["INDENT","OUTDENT","TERMINATOR"],y=[")","}","]"]}.call(this),t.exports}(),_dereq_["./parser"]=function(){var e={},t={exports:e},n=function(){function e(){this.yy={}}var t=function(e,t,n,r){for(n=n||{},r=e.length;r--;n[e[r]]=t);return n},n=[1,20],r=[1,75],i=[1,71],s=[1,76],o=[1,77],u=[1,73],a=[1,74],f=[1,50],l=[1,52],c=[1,53],h=[1,54],p=[1,55],d=[1,45],v=[1,46],m=[1,27],g=[1,60],y=[1,61],b=[1,70],w=[1,43],E=[1,26],S=[1,58],x=[1,59],T=[1,57],N=[1,38],C=[1,44],k=[1,56],L=[1,65],A=[1,66],O=[1,67],M=[1,68],_=[1,42],D=[1,64],P=[1,29],H=[1,30],B=[1,31],j=[1,32],F=[1,33],I=[1,34],q=[1,35],R=[1,78],U=[1,6,26,34,108],z=[1,88],W=[1,81],X=[1,80],V=[1,79],$=[1,82],J=[1,83],K=[1,84],Q=[1,85],G=[1,86],Y=[1,87],Z=[1,91],et=[1,6,25,26,34,55,60,63,79,84,92,97,99,108,110,111,112,116,117,132,135,136,141,142,143,144,145,146,147],tt=[1,97],nt=[1,98],rt=[1,99],it=[1,100],st=[1,102],ot=[1,103],ut=[1,96],at=[2,112],ft=[1,6,25,26,34,55,60,63,72,73,74,75,77,79,80,84,90,91,92,97,99,108,110,111,112,116,117,132,135,136,141,142,143,144,145,146,147],lt=[2,79],ct=[1,108],ht=[2,58],pt=[1,112],dt=[1,117],vt=[1,118],mt=[1,120],gt=[1,6,25,26,34,46,55,60,63,72,73,74,75,77,79,80,84,90,91,92,97,99,108,110,111,112,116,117,132,135,136,141,142,143,144,145,146,147],yt=[2,76],bt=[1,6,26,34,55,60,63,79,84,92,97,99,108,110,111,112,116,117,132,135,136,141,142,143,144,145,146,147],wt=[1,155],Et=[1,157],St=[1,152],xt=[1,6,25,26,34,46,55,60,63,72,73,74,75,77,79,80,84,86,90,91,92,97,99,108,110,111,112,116,117,132,135,136,139,140,141,142,143,144,145,146,147,148],Tt=[2,95],Nt=[1,6,25,26,34,49,55,60,63,72,73,74,75,77,79,80,84,90,91,92,97,99,108,110,111,112,116,117,132,135,136,141,142,143,144,145,146,147],Ct=[1,6,25,26,34,46,49,55,60,63,72,73,74,75,77,79,80,84,86,90,91,92,97,99,108,110,111,112,116,117,123,124,132,135,136,139,140,141,142,143,144,145,146,147,148],kt=[1,206],Lt=[1,205],At=[1,6,25,26,34,38,55,60,63,72,73,74,75,77,79,80,84,90,91,92,97,99,108,110,111,112,116,117,132,135,136,141,142,143,144,145,146,147],Ot=[2,56],Mt=[1,216],_t=[6,25,26,55,60],Dt=[6,25,26,46,55,60,63],Pt=[1,6,25,26,34,55,60,63,79,84,92,97,99,108,110,111,112,116,117,132,135,136,142,144,145,146,147],Ht=[1,6,25,26,34,55,60,63,79,84,92,97,99,108,110,111,112,116,117,132],Bt=[72,73,74,75,77,80,90,91],jt=[1,235],Ft=[2,133],It=[1,6,25,26,34,46,55,60,63,72,73,74,75,77,79,80,84,90,91,92,97,99,108,110,111,112,116,117,123,124,132,135,136,141,142,143,144,145,146,147],qt=[1,244],Rt=[6,25,26,60,92,97],Ut=[1,6,25,26,34,55,60,63,79,84,92,97,99,108,117,132],zt=[1,6,25,26,34,55,60,63,79,84,92,97,99,108,111,117,132],Wt=[123,124],Xt=[60,123,124],Vt=[1,255],$t=[6,25,26,60,84],Jt=[6,25,26,49,60,84],Kt=[1,6,25,26,34,55,60,63,79,84,92,97,99,108,110,111,112,116,117,132,135,136,144,145,146,147],Qt=[11,28,30,32,33,36,37,40,41,42,43,44,51,52,53,57,58,79,82,85,89,94,95,96,102,106,107,110,112,114,116,125,131,133,134,135,136,137,139,140],Gt=[2,122],Yt=[6,25,26],Zt=[2,57],en=[1,268],tn=[1,269],nn=[1,6,25,26,34,55,60,63,79,84,92,97,99,104,105,108,110,111,112,116,117,127,129,132,135,136,141,142,143,144,145,146,147],rn=[26,127,129],sn=[1,6,26,34,55,60,63,79,84,92,97,99,108,111,117,132],on=[2,71],un=[1,291],an=[1,292],fn=[1,6,25,26,34,55,60,63,79,84,92,97,99,108,110,111,112,116,117,127,132,135,136,141,142,143,144,145,146,147],ln=[1,6,25,26,34,55,60,63,79,84,92,97,99,108,110,112,116,117,132],cn=[1,303],hn=[1,304],pn=[6,25,26,60],dn=[1,6,25,26,34,55,60,63,79,84,92,97,99,104,108,110,111,112,116,117,132,135,136,141,142,143,144,145,146,147],vn=[25,60],mn={trace:function(){},yy:{},symbols_:{error:2,Root:3,Body:4,Line:5,TERMINATOR:6,Expression:7,Statement:8,Return:9,Comment:10,STATEMENT:11,Value:12,Invocation:13,Code:14,Operation:15,Assign:16,If:17,Try:18,While:19,For:20,Switch:21,Class:22,Throw:23,Block:24,INDENT:25,OUTDENT:26,Identifier:27,IDENTIFIER:28,AlphaNumeric:29,NUMBER:30,String:31,STRING:32,STRING_START:33,STRING_END:34,Regex:35,REGEX:36,REGEX_START:37,REGEX_END:38,Literal:39,JS:40,DEBUGGER:41,UNDEFINED:42,NULL:43,BOOL:44,Assignable:45,"=":46,AssignObj:47,ObjAssignable:48,":":49,ThisProperty:50,RETURN:51,HERECOMMENT:52,PARAM_START:53,ParamList:54,PARAM_END:55,FuncGlyph:56,"->":57,"=>":58,OptComma:59,",":60,Param:61,ParamVar:62,"...":63,Array:64,Object:65,Splat:66,SimpleAssignable:67,Accessor:68,Parenthetical:69,Range:70,This:71,".":72,"?.":73,"::":74,"?::":75,Index:76,INDEX_START:77,IndexValue:78,INDEX_END:79,INDEX_SOAK:80,Slice:81,"{":82,AssignList:83,"}":84,CLASS:85,EXTENDS:86,OptFuncExist:87,Arguments:88,SUPER:89,FUNC_EXIST:90,CALL_START:91,CALL_END:92,ArgList:93,THIS:94,"@":95,"[":96,"]":97,RangeDots:98,"..":99,Arg:100,SimpleArgs:101,TRY:102,Catch:103,FINALLY:104,CATCH:105,THROW:106,"(":107,")":108,WhileSource:109,WHILE:110,WHEN:111,UNTIL:112,Loop:113,LOOP:114,ForBody:115,FOR:116,BY:117,ForStart:118,ForSource:119,ForVariables:120,OWN:121,ForValue:122,FORIN:123,FOROF:124,SWITCH:125,Whens:126,ELSE:127,When:128,LEADING_WHEN:129,IfBlock:130,IF:131,POST_IF:132,UNARY:133,UNARY_MATH:134,"-":135,"+":136,YIELD:137,FROM:138,"--":139,"++":140,"?":141,MATH:142,"**":143,SHIFT:144,COMPARE:145,LOGIC:146,RELATION:147,COMPOUND_ASSIGN:148,$accept:0,$end:1},terminals_:{2:"error",6:"TERMINATOR",11:"STATEMENT",25:"INDENT",26:"OUTDENT",28:"IDENTIFIER",30:"NUMBER",32:"STRING",33:"STRING_START",34:"STRING_END",36:"REGEX",37:"REGEX_START",38:"REGEX_END",40:"JS",41:"DEBUGGER",42:"UNDEFINED",43:"NULL",44:"BOOL",46:"=",49:":",51:"RETURN",52:"HERECOMMENT",53:"PARAM_START",55:"PARAM_END",57:"->",58:"=>",60:",",63:"...",72:".",73:"?.",74:"::",75:"?::",77:"INDEX_START",79:"INDEX_END",80:"INDEX_SOAK",82:"{",84:"}",85:"CLASS",86:"EXTENDS",89:"SUPER",90:"FUNC_EXIST",91:"CALL_START",92:"CALL_END",94:"THIS",95:"@",96:"[",97:"]",99:"..",102:"TRY",104:"FINALLY",105:"CATCH",106:"THROW",107:"(",108:")",110:"WHILE",111:"WHEN",112:"UNTIL",114:"LOOP",116:"FOR",117:"BY",121:"OWN",123:"FORIN",124:"FOROF",125:"SWITCH",127:"ELSE",129:"LEADING_WHEN",131:"IF",132:"POST_IF",133:"UNARY",134:"UNARY_MATH",135:"-",136:"+",137:"YIELD",138:"FROM",139:"--",140:"++",141:"?",142:"MATH",143:"**",144:"SHIFT",145:"COMPARE",146:"LOGIC",147:"RELATION",148:"COMPOUND_ASSIGN"},productions_:[0,[3,0],[3,1],[4,1],[4,3],[4,2],[5,1],[5,1],[8,1],[8,1],[8,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[24,2],[24,3],[27,1],[29,1],[29,1],[31,1],[31,3],[35,1],[35,3],[39,1],[39,1],[39,1],[39,1],[39,1],[39,1],[39,1],[16,3],[16,4],[16,5],[47,1],[47,3],[47,5],[47,1],[48,1],[48,1],[48,1],[9,2],[9,1],[10,1],[14,5],[14,2],[56,1],[56,1],[59,0],[59,1],[54,0],[54,1],[54,3],[54,4],[54,6],[61,1],[61,2],[61,3],[61,1],[62,1],[62,1],[62,1],[62,1],[66,2],[67,1],[67,2],[67,2],[67,1],[45,1],[45,1],[45,1],[12,1],[12,1],[12,1],[12,1],[12,1],[68,2],[68,2],[68,2],[68,2],[68,1],[68,1],[76,3],[76,2],[78,1],[78,1],[65,4],[83,0],[83,1],[83,3],[83,4],[83,6],[22,1],[22,2],[22,3],[22,4],[22,2],[22,3],[22,4],[22,5],[13,3],[13,3],[13,1],[13,2],[87,0],[87,1],[88,2],[88,4],[71,1],[71,1],[50,2],[64,2],[64,4],[98,1],[98,1],[70,5],[81,3],[81,2],[81,2],[81,1],[93,1],[93,3],[93,4],[93,4],[93,6],[100,1],[100,1],[100,1],[101,1],[101,3],[18,2],[18,3],[18,4],[18,5],[103,3],[103,3],[103,2],[23,2],[69,3],[69,5],[109,2],[109,4],[109,2],[109,4],[19,2],[19,2],[19,2],[19,1],[113,2],[113,2],[20,2],[20,2],[20,2],[115,2],[115,4],[115,2],[118,2],[118,3],[122,1],[122,1],[122,1],[122,1],[120,1],[120,3],[119,2],[119,2],[119,4],[119,4],[119,4],[119,6],[119,6],[21,5],[21,7],[21,4],[21,6],[126,1],[126,2],[128,3],[128,4],[130,3],[130,5],[17,1],[17,3],[17,3],[17,3],[15,2],[15,2],[15,2],[15,2],[15,2],[15,2],[15,3],[15,2],[15,2],[15,2],[15,2],[15,2],[15,3],[15,3],[15,3],[15,3],[15,3],[15,3],[15,3],[15,3],[15,3],[15,5],[15,4],[15,3]],performAction:function(e,t,n,r,i,s,o){var u=s.length-1;switch(i){case 1:return this.$=r.addLocationDataFn(o[u],o[u])(new r.Block);case 2:return this.$=s[u];case 3:this.$=r.addLocationDataFn(o[u],o[u])(r.Block.wrap([s[u]]));break;case 4:this.$=r.addLocationDataFn(o[u-2],o[u])(s[u-2].push(s[u]));break;case 5:this.$=s[u-1];break;case 6:case 7:case 8:case 9:case 11:case 12:case 13:case 14:case 15:case 16:case 17:case 18:case 19:case 20:case 21:case 22:case 27:case 32:case 34:case 45:case 46:case 47:case 48:case 56:case 57:case 67:case 68:case 69:case 70:case 75:case 76:case 79:case 83:case 89:case 133:case 134:case 136:case 166:case 167:case 183:case 189:this.$=s[u];break;case 10:case 25:case 26:case 28:case 30:case 33:case 35:this.$=r.addLocationDataFn(o[u],o[u])(new r.Literal(s[u]));break;case 23:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Block);break;case 24:case 31:case 90:this.$=r.addLocationDataFn(o[u-2],o[u])(s[u-1]);break;case 29:case 146:this.$=r.addLocationDataFn(o[u-2],o[u])(new r.Parens(s[u-1]));break;case 36:this.$=r.addLocationDataFn(o[u],o[u])(new r.Undefined);break;case 37:this.$=r.addLocationDataFn(o[u],o[u])(new r.Null);break;case 38:this.$=r.addLocationDataFn(o[u],o[u])(new r.Bool(s[u]));break;case 39:this.$=r.addLocationDataFn(o[u-2],o[u])(new r.Assign(s[u-2],s[u]));break;case 40:this.$=r.addLocationDataFn(o[u-3],o[u])(new r.Assign(s[u-3],s[u]));break;case 41:this.$=r.addLocationDataFn(o[u-4],o[u])(new r.Assign(s[u-4],s[u-1]));break;case 42:case 72:case 77:case 78:case 80:case 81:case 82:case 168:case 169:this.$=r.addLocationDataFn(o[u],o[u])(new r.Value(s[u]));break;case 43:this.$=r.addLocationDataFn(o[u-2],o[u])(new r.Assign(r.addLocationDataFn(o[u-2])(new r.Value(s[u-2])),s[u],"object"));break;case 44:this.$=r.addLocationDataFn(o[u-4],o[u])(new r.Assign(r.addLocationDataFn(o[u-4])(new r.Value(s[u-4])),s[u-1],"object"));break;case 49:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Return(s[u]));break;case 50:this.$=r.addLocationDataFn(o[u],o[u])(new r.Return);break;case 51:this.$=r.addLocationDataFn(o[u],o[u])(new r.Comment(s[u]));break;case 52:this.$=r.addLocationDataFn(o[u-4],o[u])(new r.Code(s[u-3],s[u],s[u-1]));break;case 53:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Code([],s[u],s[u-1]));break;case 54:this.$=r.addLocationDataFn(o[u],o[u])("func");break;case 55:this.$=r.addLocationDataFn(o[u],o[u])("boundfunc");break;case 58:case 95:this.$=r.addLocationDataFn(o[u],o[u])([]);break;case 59:case 96:case 128:case 170:this.$=r.addLocationDataFn(o[u],o[u])([s[u]]);break;case 60:case 97:case 129:this.$=r.addLocationDataFn(o[u-2],o[u])(s[u-2].concat(s[u]));break;case 61:case 98:case 130:this.$=r.addLocationDataFn(o[u-3],o[u])(s[u-3].concat(s[u]));break;case 62:case 99:case 132:this.$=r.addLocationDataFn(o[u-5],o[u])(s[u-5].concat(s[u-2]));break;case 63:this.$=r.addLocationDataFn(o[u],o[u])(new r.Param(s[u]));break;case 64:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Param(s[u-1],null,!0));break;case 65:this.$=r.addLocationDataFn(o[u-2],o[u])(new r.Param(s[u-2],s[u]));break;case 66:case 135:this.$=r.addLocationDataFn(o[u],o[u])(new r.Expansion);break;case 71:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Splat(s[u-1]));break;case 73:this.$=r.addLocationDataFn(o[u-1],o[u])(s[u-1].add(s[u]));break;case 74:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Value(s[u-1],[].concat(s[u])));break;case 84:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Access(s[u]));break;case 85:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Access(s[u],"soak"));break;case 86:this.$=r.addLocationDataFn(o[u-1],o[u])([r.addLocationDataFn(o[u-1])(new r.Access(new r.Literal("prototype"))),r.addLocationDataFn(o[u])(new r.Access(s[u]))]);break;case 87:this.$=r.addLocationDataFn(o[u-1],o[u])([r.addLocationDataFn(o[u-1])(new r.Access(new r.Literal("prototype"),"soak")),r.addLocationDataFn(o[u])(new r.Access(s[u]))]);break;case 88:this.$=r.addLocationDataFn(o[u],o[u])(new r.Access(new r.Literal("prototype")));break;case 91:this.$=r.addLocationDataFn(o[u-1],o[u])(r.extend(s[u],{soak:!0}));break;case 92:this.$=r.addLocationDataFn(o[u],o[u])(new r.Index(s[u]));break;case 93:this.$=r.addLocationDataFn(o[u],o[u])(new r.Slice(s[u]));break;case 94:this.$=r.addLocationDataFn(o[u-3],o[u])(new r.Obj(s[u-2],s[u-3].generated));break;case 100:this.$=r.addLocationDataFn(o[u],o[u])(new r.Class);break;case 101:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Class(null,null,s[u]));break;case 102:this.$=r.addLocationDataFn(o[u-2],o[u])(new r.Class(null,s[u]));break;case 103:this.$=r.addLocationDataFn(o[u-3],o[u])(new r.Class(null,s[u-1],s[u]));break;case 104:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Class(s[u]));break;case 105:this.$=r.addLocationDataFn(o[u-2],o[u])(new r.Class(s[u-1],null,s[u]));break;case 106:this.$=r.addLocationDataFn(o[u-3],o[u])(new r.Class(s[u-2],s[u]));break;case 107:this.$=r.addLocationDataFn(o[u-4],o[u])(new r.Class(s[u-3],s[u-1],s[u]));break;case 108:case 109:this.$=r.addLocationDataFn(o[u-2],o[u])(new r.Call(s[u-2],s[u],s[u-1]));break;case 110:this.$=r.addLocationDataFn(o[u],o[u])(new r.Call("super",[new r.Splat(new r.Literal("arguments"))]));break;case 111:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Call("super",s[u]));break;case 112:this.$=r.addLocationDataFn(o[u],o[u])(!1);break;case 113:this.$=r.addLocationDataFn(o[u],o[u])(!0);break;case 114:this.$=r.addLocationDataFn(o[u-1],o[u])([]);break;case 115:case 131:this.$=r.addLocationDataFn(o[u-3],o[u])(s[u-2]);break;case 116:case 117:this.$=r.addLocationDataFn(o[u],o[u])(new r.Value(new r.Literal("this")));break;case 118:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Value(r.addLocationDataFn(o[u-1])(new r.Literal("this")),[r.addLocationDataFn(o[u])(new r.Access(s[u]))],"this"));break;case 119:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Arr([]));break;case 120:this.$=r.addLocationDataFn(o[u-3],o[u])(new r.Arr(s[u-2]));break;case 121:this.$=r.addLocationDataFn(o[u],o[u])("inclusive");break;case 122:this.$=r.addLocationDataFn(o[u],o[u])("exclusive");break;case 123:this.$=r.addLocationDataFn(o[u-4],o[u])(new r.Range(s[u-3],s[u-1],s[u-2]));break;case 124:this.$=r.addLocationDataFn(o[u-2],o[u])(new r.Range(s[u-2],s[u],s[u-1]));break;case 125:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Range(s[u-1],null,s[u]));break;case 126:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Range(null,s[u],s[u-1]));break;case 127:this.$=r.addLocationDataFn(o[u],o[u])(new r.Range(null,null,s[u]));break;case 137:this.$=r.addLocationDataFn(o[u-2],o[u])([].concat(s[u-2],s[u]));break;case 138:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Try(s[u]));break;case 139:this.$=r.addLocationDataFn(o[u-2],o[u])(new r.Try(s[u-1],s[u][0],s[u][1]));break;case 140:this.$=r.addLocationDataFn(o[u-3],o[u])(new r.Try(s[u-2],null,null,s[u]));break;case 141:this.$=r.addLocationDataFn(o[u-4],o[u])(new r.Try(s[u-3],s[u-2][0],s[u-2][1],s[u]));break;case 142:this.$=r.addLocationDataFn(o[u-2],o[u])([s[u-1],s[u]]);break;case 143:this.$=r.addLocationDataFn(o[u-2],o[u])([r.addLocationDataFn(o[u-1])(new r.Value(s[u-1])),s[u]]);break;case 144:this.$=r.addLocationDataFn(o[u-1],o[u])([null,s[u]]);break;case 145:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Throw(s[u]));break;case 147:this.$=r.addLocationDataFn(o[u-4],o[u])(new r.Parens(s[u-2]));break;case 148:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.While(s[u]));break;case 149:this.$=r.addLocationDataFn(o[u-3],o[u])(new r.While(s[u-2],{guard:s[u]}));break;case 150:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.While(s[u],{invert:!0}));break;case 151:this.$=r.addLocationDataFn(o[u-3],o[u])(new r.While(s[u-2],{invert:!0,guard:s[u]}));break;case 152:this.$=r.addLocationDataFn(o[u-1],o[u])(s[u-1].addBody(s[u]));break;case 153:case 154:this.$=r.addLocationDataFn(o[u-1],o[u])(s[u].addBody(r.addLocationDataFn(o[u-1])(r.Block.wrap([s[u-1]]))));break;case 155:this.$=r.addLocationDataFn(o[u],o[u])(s[u]);break;case 156:this.$=r.addLocationDataFn(o[u-1],o[u])((new r.While(r.addLocationDataFn(o[u-1])(new r.Literal("true")))).addBody(s[u]));break;case 157:this.$=r.addLocationDataFn(o[u-1],o[u])((new r.While(r.addLocationDataFn(o[u-1])(new r.Literal("true")))).addBody(r.addLocationDataFn(o[u])(r.Block.wrap([s[u]]))));break;case 158:case 159:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.For(s[u-1],s[u]));break;case 160:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.For(s[u],s[u-1]));break;case 161:this.$=r.addLocationDataFn(o[u-1],o[u])({source:r.addLocationDataFn(o[u])(new r.Value(s[u]))});break;case 162:this.$=r.addLocationDataFn(o[u-3],o[u])({source:r.addLocationDataFn(o[u-2])(new r.Value(s[u-2])),step:s[u]});break;case 163:this.$=r.addLocationDataFn(o[u-1],o[u])(function(){return s[u].own=s[u-1].own,s[u].name=s[u-1][0],s[u].index=s[u-1][1],s[u]}());break;case 164:this.$=r.addLocationDataFn(o[u-1],o[u])(s[u]);break;case 165:this.$=r.addLocationDataFn(o[u-2],o[u])(function(){return s[u].own=!0,s[u]}());break;case 171:this.$=r.addLocationDataFn(o[u-2],o[u])([s[u-2],s[u]]);break;case 172:this.$=r.addLocationDataFn(o[u-1],o[u])({source:s[u]});break;case 173:this.$=r.addLocationDataFn(o[u-1],o[u])({source:s[u],object:!0});break;case 174:this.$=r.addLocationDataFn(o[u-3],o[u])({source:s[u-2],guard:s[u]});break;case 175:this.$=r.addLocationDataFn(o[u-3],o[u])({source:s[u-2],guard:s[u],object:!0});break;case 176:this.$=r.addLocationDataFn(o[u-3],o[u])({source:s[u-2],step:s[u]});break;case 177:this.$=r.addLocationDataFn(o[u-5],o[u])({source:s[u-4],guard:s[u-2],step:s[u]});break;case 178:this.$=r.addLocationDataFn(o[u-5],o[u])({source:s[u-4],step:s[u-2],guard:s[u]});break;case 179:this.$=r.addLocationDataFn(o[u-4],o[u])(new r.Switch(s[u-3],s[u-1]));break;case 180:this.$=r.addLocationDataFn(o[u-6],o[u])(new r.Switch(s[u-5],s[u-3],s[u-1]));break;case 181:this.$=r.addLocationDataFn(o[u-3],o[u])(new r.Switch(null,s[u-1]));break;case 182:this.$=r.addLocationDataFn(o[u-5],o[u])(new r.Switch(null,s[u-3],s[u-1]));break;case 184:this.$=r.addLocationDataFn(o[u-1],o[u])(s[u-1].concat(s[u]));break;case 185:this.$=r.addLocationDataFn(o[u-2],o[u])([[s[u-1],s[u]]]);break;case 186:this.$=r.addLocationDataFn(o[u-3],o[u])([[s[u-2],s[u-1]]]);break;case 187:this.$=r.addLocationDataFn(o[u-2],o[u])(new r.If(s[u-1],s[u],{type:s[u-2]}));break;case 188:this.$=r.addLocationDataFn(o[u-4],o[u])(s[u-4].addElse(r.addLocationDataFn(o[u-2],o[u])(new r.If(s[u-1],s[u],{type:s[u-2]}))));break;case 190:this.$=r.addLocationDataFn(o[u-2],o[u])(s[u-2].addElse(s[u]));break;case 191:case 192:this.$=r.addLocationDataFn(o[u-2],o[u])(new r.If(s[u],r.addLocationDataFn(o[u-2])(r.Block.wrap([s[u-2]])),{type:s[u-1],statement:!0}));break;case 193:case 194:case 197:case 198:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Op(s[u-1],s[u]));break;case 195:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Op("-",s[u]));break;case 196:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Op("+",s[u]));break;case 199:this.$=r.addLocationDataFn(o[u-2],o[u])(new r.Op(s[u-2].concat(s[u-1]),s[u]));break;case 200:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Op("--",s[u]));break;case 201:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Op("++",s[u]));break;case 202:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Op("--",s[u-1],null,!0));break;case 203:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Op("++",s[u-1],null,!0));break;case 204:this.$=r.addLocationDataFn(o[u-1],o[u])(new r.Existence(s[u-1]));break;case 205:this.$=r.addLocationDataFn(o[u-2],o[u])(new r.Op("+",s[u-2],s[u]));break;case 206:this.$=r.addLocationDataFn(o[u-2],o[u])(new r.Op("-",s[u-2],s[u]));break;case 207:case 208:case 209:case 210:case 211:this.$=r.addLocationDataFn(o[u-2],o[u])(new r.Op(s[u-1],s[u-2],s[u]));break;case 212:this.$=r.addLocationDataFn(o[u-2],o[u])(function(){return"!"===s[u-1].charAt(0)?(new r.Op(s[u-1].slice(1),s[u-2],s[u])).invert():new r.Op(s[u-1],s[u-2],s[u])}());break;case 213:this.$=r.addLocationDataFn(o[u-2],o[u])(new r.Assign(s[u-2],s[u],s[u-1]));break;case 214:this.$=r.addLocationDataFn(o[u-4],o[u])(new r.Assign(s[u-4],s[u-1],s[u-3]));break;case 215:this.$=r.addLocationDataFn(o[u-3],o[u])(new r.Assign(s[u-3],s[u],s[u-2]));break;case 216:this.$=r.addLocationDataFn(o[u-2],o[u])(new r.Extends(s[u-2],s[u]))}},table:[{1:[2,1],3:1,4:2,5:3,7:4,8:5,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{1:[3]},{1:[2,2],6:R},t(U,[2,3]),t(U,[2,6],{118:69,109:89,115:90,110:L,112:A,116:M,132:z,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t(U,[2,7],{118:69,109:92,115:93,110:L,112:A,116:M,132:Z}),t(et,[2,11],{87:94,68:95,76:101,72:tt,73:nt,74:rt,75:it,77:st,80:ot,90:ut,91:at}),t(et,[2,12],{76:101,87:104,68:105,72:tt,73:nt,74:rt,75:it,77:st,80:ot,90:ut,91:at}),t(et,[2,13]),t(et,[2,14]),t(et,[2,15]),t(et,[2,16]),t(et,[2,17]),t(et,[2,18]),t(et,[2,19]),t(et,[2,20]),t(et,[2,21]),t(et,[2,22]),t(et,[2,8]),t(et,[2,9]),t(et,[2,10]),t(ft,lt,{46:[1,106]}),t(ft,[2,80]),t(ft,[2,81]),t(ft,[2,82]),t(ft,[2,83]),t([1,6,25,26,34,38,55,60,63,72,73,74,75,77,79,80,84,90,92,97,99,108,110,111,112,116,117,132,135,136,141,142,143,144,145,146,147],[2,110],{88:107,91:ct}),t([6,25,55,60],ht,{54:109,61:110,62:111,27:113,50:114,64:115,65:116,28:r,63:pt,82:b,95:dt,96:vt}),{24:119,25:mt},{7:121,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:123,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:124,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:125,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:127,8:126,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,138:[1,128],139:I,140:q},{12:130,13:131,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:132,50:63,64:47,65:48,67:129,69:23,70:24,71:25,82:b,89:E,94:S,95:x,96:T,107:k},{12:130,13:131,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:132,50:63,64:47,65:48,67:133,69:23,70:24,71:25,82:b,89:E,94:S,95:x,96:T,107:k},t(gt,yt,{86:[1,137],139:[1,134],140:[1,135],148:[1,136]}),t(et,[2,189],{127:[1,138]}),{24:139,25:mt},{24:140,25:mt},t(et,[2,155]),{24:141,25:mt},{7:142,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,25:[1,143],27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(bt,[2,100],{39:22,69:23,70:24,71:25,64:47,65:48,29:49,35:51,27:62,50:63,31:72,12:130,13:131,45:132,24:144,67:146,25:mt,28:r,30:i,32:s,33:o,36:u,37:a,40:f,41:l,42:c,43:h,44:p,82:b,86:[1,145],89:E,94:S,95:x,96:T,107:k}),{7:147,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t([1,6,25,26,34,55,60,63,79,84,92,97,99,108,110,111,112,116,117,132,141,142,143,144,145,146,147],[2,50],{12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,9:18,10:19,45:21,39:22,69:23,70:24,71:25,56:28,67:36,130:37,109:39,113:40,115:41,64:47,65:48,29:49,35:51,27:62,50:63,118:69,31:72,8:122,7:148,11:n,28:r,30:i,32:s,33:o,36:u,37:a,40:f,41:l,42:c,43:h,44:p,51:d,52:v,53:m,57:g,58:y,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,114:O,125:_,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q}),t(et,[2,51]),t(gt,[2,77]),t(gt,[2,78]),t(ft,[2,32]),t(ft,[2,33]),t(ft,[2,34]),t(ft,[2,35]),t(ft,[2,36]),t(ft,[2,37]),t(ft,[2,38]),{4:149,5:3,7:4,8:5,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,25:[1,150],27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:151,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,25:wt,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,63:Et,64:47,65:48,66:156,67:36,69:23,70:24,71:25,82:b,85:w,89:E,93:153,94:S,95:x,96:T,97:St,100:154,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(ft,[2,116]),t(ft,[2,117],{27:158,28:r}),{25:[2,54]},{25:[2,55]},t(xt,[2,72]),t(xt,[2,75]),{7:159,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:160,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:161,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:163,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,24:162,25:mt,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{27:168,28:r,50:169,64:170,65:171,70:164,82:b,95:dt,96:T,120:165,121:[1,166],122:167},{119:172,123:[1,173],124:[1,174]},t([6,25,60,84],Tt,{31:72,83:175,47:176,48:177,10:178,27:179,29:180,50:181,28:r,30:i,32:s,33:o,52:v,95:dt}),t(Nt,[2,26]),t(Nt,[2,27]),t(ft,[2,30]),{12:130,13:182,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:132,50:63,64:47,65:48,67:183,69:23,70:24,71:25,82:b,89:E,94:S,95:x,96:T,107:k},t(Ct,[2,25]),t(Nt,[2,28]),{4:184,5:3,7:4,8:5,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(U,[2,5],{7:4,8:5,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,9:18,10:19,45:21,39:22,69:23,70:24,71:25,56:28,67:36,130:37,109:39,113:40,115:41,64:47,65:48,29:49,35:51,27:62,50:63,118:69,31:72,5:185,11:n,28:r,30:i,32:s,33:o,36:u,37:a,40:f,41:l,42:c,43:h,44:p,51:d,52:v,53:m,57:g,58:y,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,110:L,112:A,114:O,116:M,125:_,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q}),t(et,[2,204]),{7:186,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:187,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:188,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:189,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:190,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:191,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:192,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:193,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:194,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(et,[2,154]),t(et,[2,159]),{7:195,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(et,[2,153]),t(et,[2,158]),{88:196,91:ct},t(xt,[2,73]),{91:[2,113]},{27:197,28:r},{27:198,28:r},t(xt,[2,88],{27:199,28:r}),{27:200,28:r},t(xt,[2,89]),{7:202,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,63:kt,64:47,65:48,67:36,69:23,70:24,71:25,78:201,81:203,82:b,85:w,89:E,94:S,95:x,96:T,98:204,99:Lt,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{76:207,77:st,80:ot},{88:208,91:ct},t(xt,[2,74]),{6:[1,210],7:209,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,25:[1,211],27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(At,[2,111]),{7:214,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,25:wt,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,63:Et,64:47,65:48,66:156,67:36,69:23,70:24,71:25,82:b,85:w,89:E,92:[1,212],93:213,94:S,95:x,96:T,100:154,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t([6,25],Ot,{59:217,55:[1,215],60:Mt}),t(_t,[2,59]),t(_t,[2,63],{46:[1,219],63:[1,218]}),t(_t,[2,66]),t(Dt,[2,67]),t(Dt,[2,68]),t(Dt,[2,69]),t(Dt,[2,70]),{27:158,28:r},{7:214,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,25:wt,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,63:Et,64:47,65:48,66:156,67:36,69:23,70:24,71:25,82:b,85:w,89:E,93:153,94:S,95:x,96:T,97:St,100:154,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(et,[2,53]),{4:221,5:3,7:4,8:5,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,26:[1,220],27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t([1,6,25,26,34,55,60,63,79,84,92,97,99,108,110,111,112,116,117,132,135,136,142,143,144,145,146,147],[2,193],{118:69,109:89,115:90,141:V}),{109:92,110:L,112:A,115:93,116:M,118:69,132:Z},t(Pt,[2,194],{118:69,109:89,115:90,141:V,143:J}),t(Pt,[2,195],{118:69,109:89,115:90,141:V,143:J}),t(Pt,[2,196],{118:69,109:89,115:90,141:V,143:J}),t(et,[2,197],{118:69,109:92,115:93}),t(Ht,[2,198],{118:69,109:89,115:90,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),{7:222,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(et,[2,200],{72:yt,73:yt,74:yt,75:yt,77:yt,80:yt,90:yt,91:yt}),{68:95,72:tt,73:nt,74:rt,75:it,76:101,77:st,80:ot,87:94,90:ut,91:at},{68:105,72:tt,73:nt,74:rt,75:it,76:101,77:st,80:ot,87:104,90:ut,91:at},t(Bt,lt),t(et,[2,201],{72:yt,73:yt,74:yt,75:yt,77:yt,80:yt,90:yt,91:yt}),t(et,[2,202]),t(et,[2,203]),{6:[1,225],7:223,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,25:[1,224],27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:226,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{24:227,25:mt,131:[1,228]},t(et,[2,138],{103:229,104:[1,230],105:[1,231]}),t(et,[2,152]),t(et,[2,160]),{25:[1,232],109:89,110:L,112:A,115:90,116:M,118:69,132:z,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y},{126:233,128:234,129:jt},t(et,[2,101]),{7:236,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(bt,[2,104],{24:237,25:mt,72:yt,73:yt,74:yt,75:yt,77:yt,80:yt,90:yt,91:yt,86:[1,238]}),t(Ht,[2,145],{118:69,109:89,115:90,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t(Ht,[2,49],{118:69,109:89,115:90,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),{6:R,108:[1,239]},{4:240,5:3,7:4,8:5,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t([6,25,60,97],Ft,{118:69,109:89,115:90,98:241,63:[1,242],99:Lt,110:L,112:A,116:M,132:z,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t(It,[2,119]),t([6,25,97],Ot,{59:243,60:qt}),t(Rt,[2,128]),{7:214,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,25:wt,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,63:Et,64:47,65:48,66:156,67:36,69:23,70:24,71:25,82:b,85:w,89:E,93:245,94:S,95:x,96:T,100:154,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(Rt,[2,134]),t(Rt,[2,135]),t(Ct,[2,118]),{24:246,25:mt,109:89,110:L,112:A,115:90,116:M,118:69,132:z,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y},t(Ut,[2,148],{118:69,109:89,115:90,110:L,111:[1,247],112:A,116:M,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t(Ut,[2,150],{118:69,109:89,115:90,110:L,111:[1,248],112:A,116:M,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t(et,[2,156]),t(zt,[2,157],{118:69,109:89,115:90,110:L,112:A,116:M,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t([1,6,25,26,34,55,60,63,79,84,92,97,99,108,110,111,112,116,132,135,136,141,142,143,144,145,146,147],[2,161],{117:[1,249]}),t(Wt,[2,164]),{27:168,28:r,50:169,64:170,65:171,82:b,95:dt,96:vt,120:250,122:167},t(Wt,[2,170],{60:[1,251]}),t(Xt,[2,166]),t(Xt,[2,167]),t(Xt,[2,168]),t(Xt,[2,169]),t(et,[2,163]),{7:252,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:253,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t([6,25,84],Ot,{59:254,60:Vt}),t($t,[2,96]),t($t,[2,42],{49:[1,256]}),t($t,[2,45]),t(Jt,[2,46]),t(Jt,[2,47]),t(Jt,[2,48]),{38:[1,257],68:105,72:tt,73:nt,74:rt,75:it,76:101,77:st,80:ot,87:104,90:ut,91:at},t(Bt,yt),{6:R,34:[1,258]},t(U,[2,4]),t(Kt,[2,205],{118:69,109:89,115:90,141:V,142:$,143:J}),t(Kt,[2,206],{118:69,109:89,115:90,141:V,142:$,143:J}),t(Pt,[2,207],{118:69,109:89,115:90,141:V,143:J}),t(Pt,[2,208],{118:69,109:89,115:90,141:V,143:J}),t([1,6,25,26,34,55,60,63,79,84,92,97,99,108,110,111,112,116,117,132,144,145,146,147],[2,209],{118:69,109:89,115:90,135:W,136:X,141:V,142:$,143:J}),t([1,6,25,26,34,55,60,63,79,84,92,97,99,108,110,111,112,116,117,132,145,146],[2,210],{118:69,109:89,115:90,135:W,136:X,141:V,142:$,143:J,144:K,147:Y}),t([1,6,25,26,34,55,60,63,79,84,92,97,99,108,110,111,112,116,117,132,146],[2,211],{118:69,109:89,115:90,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,147:Y}),t([1,6,25,26,34,55,60,63,79,84,92,97,99,108,110,111,112,116,117,132,145,146,147],[2,212],{118:69,109:89,115:90,135:W,136:X,141:V,142:$,143:J,144:K}),t(zt,[2,192],{118:69,109:89,115:90,110:L,112:A,116:M,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t(zt,[2,191],{118:69,109:89,115:90,110:L,112:A,116:M,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t(At,[2,108]),t(xt,[2,84]),t(xt,[2,85]),t(xt,[2,86]),t(xt,[2,87]),{79:[1,259]},{63:kt,79:[2,92],98:260,99:Lt,109:89,110:L,112:A,115:90,116:M,118:69,132:z,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y},{79:[2,93]},{7:261,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,79:[2,127],82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(Qt,[2,121]),t(Qt,Gt),t(xt,[2,91]),t(At,[2,109]),t(Ht,[2,39],{118:69,109:89,115:90,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),{7:262,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:263,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(At,[2,114]),t([6,25,92],Ot,{59:264,60:qt}),t(Rt,Ft,{118:69,109:89,115:90,63:[1,265],110:L,112:A,116:M,132:z,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),{56:266,57:g,58:y},t(Yt,Zt,{62:111,27:113,50:114,64:115,65:116,61:267,28:r,63:pt,82:b,95:dt,96:vt}),{6:en,25:tn},t(_t,[2,64]),{7:270,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(nn,[2,23]),{6:R,26:[1,271]},t(Ht,[2,199],{118:69,109:89,115:90,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t(Ht,[2,213],{118:69,109:89,115:90,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),{7:272,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:273,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(Ht,[2,216],{118:69,109:89,115:90,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t(et,[2,190]),{7:274,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(et,[2,139],{104:[1,275]}),{24:276,25:mt},{24:279,25:mt,27:277,28:r,65:278,82:b},{126:280,128:234,129:jt},{26:[1,281],127:[1,282],128:283,129:jt},t(rn,[2,183]),{7:285,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,101:284,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(sn,[2,102],{118:69,109:89,115:90,24:286,25:mt,110:L,112:A,116:M,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t(et,[2,105]),{7:287,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(ft,[2,146]),{6:R,26:[1,288]},{7:289,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t([11,28,30,32,33,36,37,40,41,42,43,44,51,52,53,57,58,82,85,89,94,95,96,102,106,107,110,112,114,116,125,131,133,134,135,136,137,139,140],Gt,{6:on,25:on,60:on,97:on}),{6:un,25:an,97:[1,290]},t([6,25,26,92,97],Zt,{12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,9:18,10:19,45:21,39:22,69:23,70:24,71:25,56:28,67:36,130:37,109:39,113:40,115:41,64:47,65:48,29:49,35:51,27:62,50:63,118:69,31:72,8:122,66:156,7:214,100:293,11:n,28:r,30:i,32:s,33:o,36:u,37:a,40:f,41:l,42:c,43:h,44:p,51:d,52:v,53:m,57:g,58:y,63:Et,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,110:L,112:A,114:O,116:M,125:_,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q}),t(Yt,Ot,{59:294,60:qt}),t(fn,[2,187]),{7:295,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:296,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:297,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(Wt,[2,165]),{27:168,28:r,50:169,64:170,65:171,82:b,95:dt,96:vt,122:298},t([1,6,25,26,34,55,60,63,79,84,92,97,99,108,110,112,116,132],[2,172],{118:69,109:89,115:90,111:[1,299],117:[1,300],135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t(ln,[2,173],{118:69,109:89,115:90,111:[1,301],135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),{6:cn,25:hn,84:[1,302]},t([6,25,26,84],Zt,{31:72,48:177,10:178,27:179,29:180,50:181,47:305,28:r,30:i,32:s,33:o,52:v,95:dt}),{7:306,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,25:[1,307],27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(ft,[2,31]),t(Nt,[2,29]),t(xt,[2,90]),{7:308,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,79:[2,125],82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{79:[2,126],109:89,110:L,112:A,115:90,116:M,118:69,132:z,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y},t(Ht,[2,40],{118:69,109:89,115:90,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),{26:[1,309],109:89,110:L,112:A,115:90,116:M,118:69,132:z,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y},{6:un,25:an,92:[1,310]},t(Rt,on),{24:311,25:mt},t(_t,[2,60]),{27:113,28:r,50:114,61:312,62:111,63:pt,64:115,65:116,82:b,95:dt,96:vt},t(pn,ht,{61:110,62:111,27:113,50:114,64:115,65:116,54:313,28:r,63:pt,82:b,95:dt,96:vt}),t(_t,[2,65],{118:69,109:89,115:90,110:L,112:A,116:M,132:z,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t(nn,[2,24]),{26:[1,314],109:89,110:L,112:A,115:90,116:M,118:69,132:z,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y},t(Ht,[2,215],{118:69,109:89,115:90,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),{24:315,25:mt,109:89,110:L,112:A,115:90,116:M,118:69,132:z,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y},{24:316,25:mt},t(et,[2,140]),{24:317,25:mt},{24:318,25:mt},t(dn,[2,144]),{26:[1,319],127:[1,320],128:283,129:jt},t(et,[2,181]),{24:321,25:mt},t(rn,[2,184]),{24:322,25:mt,60:[1,323]},t(vn,[2,136],{118:69,109:89,115:90,110:L,112:A,116:M,132:z,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t(et,[2,103]),t(sn,[2,106],{118:69,109:89,115:90,24:324,25:mt,110:L,112:A,116:M,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),{108:[1,325]},{97:[1,326],109:89,110:L,112:A,115:90,116:M,118:69,132:z,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y},t(It,[2,120]),{7:214,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,63:Et,64:47,65:48,66:156,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,100:327,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:214,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,25:wt,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,63:Et,64:47,65:48,66:156,67:36,69:23,70:24,71:25,82:b,85:w,89:E,93:328,94:S,95:x,96:T,100:154,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(Rt,[2,129]),{6:un,25:an,26:[1,329]},t(zt,[2,149],{118:69,109:89,115:90,110:L,112:A,116:M,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t(zt,[2,151],{118:69,109:89,115:90,110:L,112:A,116:M,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t(zt,[2,162],{118:69,109:89,115:90,110:L,112:A,116:M,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t(Wt,[2,171]),{7:330,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:331,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:332,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(It,[2,94]),{10:178,27:179,28:r,29:180,30:i,31:72,32:s,33:o,47:333,48:177,50:181,52:v,95:dt},t(pn,Tt,{31:72,47:176,48:177,10:178,27:179,29:180,50:181,83:334,28:r,30:i,32:s,33:o,52:v,95:dt}),t($t,[2,97]),t($t,[2,43],{118:69,109:89,115:90,110:L,112:A,116:M,132:z,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),{7:335,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{79:[2,124],109:89,110:L,112:A,115:90,116:M,118:69,132:z,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y},t(et,[2,41]),t(At,[2,115]),t(et,[2,52]),t(_t,[2,61]),t(Yt,Ot,{59:336,60:Mt}),t(et,[2,214]),t(fn,[2,188]),t(et,[2,141]),t(dn,[2,142]),t(dn,[2,143]),t(et,[2,179]),{24:337,25:mt},{26:[1,338]},t(rn,[2,185],{6:[1,339]}),{7:340,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},t(et,[2,107]),t(ft,[2,147]),t(ft,[2,123]),t(Rt,[2,130]),t(Yt,Ot,{59:341,60:qt}),t(Rt,[2,131]),t([1,6,25,26,34,55,60,63,79,84,92,97,99,108,110,111,112,116,132],[2,174],{118:69,109:89,115:90,117:[1,342],135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t(ln,[2,176],{118:69,109:89,115:90,111:[1,343],135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t(Ht,[2,175],{118:69,109:89,115:90,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t($t,[2,98]),t(Yt,Ot,{59:344,60:Vt}),{26:[1,345],109:89,110:L,112:A,115:90,116:M,118:69,132:z,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y},{6:en,25:tn,26:[1,346]},{26:[1,347]},t(et,[2,182]),t(rn,[2,186]),t(vn,[2,137],{118:69,109:89,115:90,110:L,112:A,116:M,132:z,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),{6:un,25:an,26:[1,348]},{7:349,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{7:350,8:122,9:18,10:19,11:n,12:6,13:7,14:8,15:9,16:10,17:11,18:12,19:13,20:14,21:15,22:16,23:17,27:62,28:r,29:49,30:i,31:72,32:s,33:o,35:51,36:u,37:a,39:22,40:f,41:l,42:c,43:h,44:p,45:21,50:63,51:d,52:v,53:m,56:28,57:g,58:y,64:47,65:48,67:36,69:23,70:24,71:25,82:b,85:w,89:E,94:S,95:x,96:T,102:N,106:C,107:k,109:39,110:L,112:A,113:40,114:O,115:41,116:M,118:69,125:_,130:37,131:D,133:P,134:H,135:B,136:j,137:F,139:I,140:q},{6:cn,25:hn,26:[1,351]},t($t,[2,44]),t(_t,[2,62]),t(et,[2,180]),t(Rt,[2,132]),t(Ht,[2,177],{118:69,109:89,115:90,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t(Ht,[2,178],{118:69,109:89,115:90,135:W,136:X,141:V,142:$,143:J,144:K,145:Q,146:G,147:Y}),t($t,[2,99])],defaultActions:{60:[2,54],61:[2,55],96:[2,113],203:[2,93]},parseError:function(e,t){if(!t.recoverable)throw Error(e);this.trace(e)},parse:function(e){function t(){var e;return e=d.lex()||h,"number"!=typeof e&&(e=n.symbols_[e]||e),e}var n=this,r=[0],i=[null],s=[],o=this.table,u="",a=0,f=0,l=0,c=2,h=1,p=s.slice.call(arguments,1),d=Object.create(this.lexer),v={yy:{}};for(var m in this.yy)Object.prototype.hasOwnProperty.call(this.yy,m)&&(v.yy[m]=this.yy[m]);d.setInput(e,v.yy),v.yy.lexer=d,v.yy.parser=this,d.yylloc===void 0&&(d.yylloc={});var g=d.yylloc;s.push(g);var y=d.options&&d.options.ranges;this.parseError="function"==typeof v.yy.parseError?v.yy.parseError:Object.getPrototypeOf(this).parseError;for(var b,w,E,S,x,T,N,C,k,L={};;){if(E=r[r.length-1],this.defaultActions[E]?S=this.defaultActions[E]:((null===b||b===void 0)&&(b=t()),S=o[E]&&o[E][b]),S===void 0||!S.length||!S[0]){var A="";k=[];for(T in o[E])this.terminals_[T]&&T>c&&k.push("'"+this.terminals_[T]+"'");A=d.showPosition?"Parse error on line "+(a+1)+":\n"+d.showPosition()+"\nExpecting "+k.join(", ")+", got '"+(this.terminals_[b]||b)+"'":"Parse error on line "+(a+1)+": Unexpected "+(b==h?"end of input":"'"+(this.terminals_[b]||b)+"'"),this.parseError(A,{text:d.match,token:this.terminals_[b]||b,line:d.yylineno,loc:g,expected:k})}if(S[0]instanceof Array&&S.length>1)throw Error("Parse Error: multiple actions possible at state: "+E+", token: "+b);switch(S[0]){case 1:r.push(b),i.push(d.yytext),s.push(d.yylloc),r.push(S[1]),b=null,w?(b=w,w=null):(f=d.yyleng,u=d.yytext,a=d.yylineno,g=d.yylloc,l>0&&l--);break;case 2:if(N=this.productions_[S[1]][1],L.$=i[i.length-N],L._$={first_line:s[s.length-(N||1)].first_line,last_line:s[s.length-1].last_line,first_column:s[s.length-(N||1)].first_column,last_column:s[s.length-1].last_column},y&&(L._$.range=[s[s.length-(N||1)].range[0],s[s.length-1].range[1]]),x=this.performAction.apply(L,[u,f,a,v.yy,S[1],i,s].concat(p)),x!==void 0)return x;N&&(r=r.slice(0,-2*N),i=i.slice(0,-1*N),s=s.slice(0,-1*N)),r.push(this.productions_[S[1]][0]),i.push(L.$),s.push(L._$),C=o[r[r.length-2]][r[r.length-1]],r.push(C);break;case 3:return!0}}return!0}};return e.prototype=mn,mn.Parser=e,new e}();return _dereq_!==void 0&&e!==void 0&&(e.parser=n,e.Parser=n.Parser,e.parse=function(){return n.parse.apply(n,arguments)},e.main=function(t){t[1]||(console.log("Usage: "+t[0]+" FILE"),process.exit(1));var n=_dereq_("fs").readFileSync(_dereq_("path").normalize(t[1]),"utf8");return e.parser.parse(n)},t!==void 0&&_dereq_.main===t&&e.main(process.argv.slice(1))),t.exports}(),_dereq_["./scope"]=function(){var e={},t={exports:e};return function(){var t,n=[].indexOf||function(e){for(var t=0,n=this.length;n>t;t++)if(t in this&&this[t]===e)return t;return-1};e.Scope=t=function(){function e(e,t,n,r){var i,s;this.parent=e,this.expressions=t,this.method=n,this.referencedVars=r,this.variables=[{name:"arguments",type:"arguments"}],this.positions={},this.parent||(this.utilities={}),this.root=null!=(i=null!=(s=this.parent)?s.root:void 0)?i:this}return e.prototype.add=function(e,t,n){return this.shared&&!n?this.parent.add(e,t,n):Object.prototype.hasOwnProperty.call(this.positions,e)?this.variables[this.positions[e]].type=t:this.positions[e]=this.variables.push({name:e,type:t})-1},e.prototype.namedMethod=function(){var e;return(null!=(e=this.method)?e.name:void 0)||!this.parent?this.method:this.parent.namedMethod()},e.prototype.find=function(e){return this.check(e)?!0:(this.add(e,"var"),!1)},e.prototype.parameter=function(e){return this.shared&&this.parent.check(e,!0)?void 0:this.add(e,"param")},e.prototype.check=function(e){var t;return!!(this.type(e)||(null!=(t=this.parent)?t.check(e):void 0))},e.prototype.temporary=function(e,t,n){return null==n&&(n=!1),n?(t+parseInt(e,36)).toString(36).replace(/\d/g,"a"):e+(t||"")},e.prototype.type=function(e){var t,n,r,i;for(r=this.variables,t=0,n=r.length;n>t;t++)if(i=r[t],i.name===e)return i.type;return null},e.prototype.freeVariable=function(e,t){var r,i,s;for(null==t&&(t={}),r=0;;){if(s=this.temporary(e,r,t.single),!(this.check(s)||n.call(this.root.referencedVars,s)>=0))break;r++}return(null!=(i=t.reserve)?i:!0)&&this.add(s,"var",!0),s},e.prototype.assign=function(e,t){return this.add(e,{value:t,assigned:!0},!0),this.hasAssignments=!0},e.prototype.hasDeclarations=function(){return!!this.declaredVariables().length},e.prototype.declaredVariables=function(){var e;return function(){var t,n,r,i;for(r=this.variables,i=[],t=0,n=r.length;n>t;t++)e=r[t],"var"===e.type&&i.push(e.name);return i}.call(this).sort()},e.prototype.assignedVariables=function(){var e,t,n,r,i;for(n=this.variables,r=[],e=0,t=n.length;t>e;e++)i=n[e],i.type.assigned&&r.push(i.name+" = "+i.type.value);return r},e}()}.call(this),t.exports}(),_dereq_["./nodes"]=function(){var e={},t={exports:e};return function(){var t,n,r,i,s,o,u,a,f,l,c,h,p,d,v,m,g,y,b,w,E,S,x,T,N,C,k,L,A,O,M,_,D,P,H,B,j,F,I,q,R,U,z,W,X,V,$,J,K,Q,G,Y,Z,et,tt,nt,rt,it,st,ot,ut,at,ft,lt,ct,ht,pt,dt,vt,mt,gt,yt,bt,wt=function(e,t){function n(){this.constructor=e}for(var r in t)Et.call(t,r)&&(e[r]=t[r]);return n.prototype=t.prototype,e.prototype=new n,e.__super__=t.prototype,e},Et={}.hasOwnProperty,St=[].indexOf||function(e){for(var t=0,n=this.length;n>t;t++)if(t in this&&this[t]===e)return t;return-1},xt=[].slice;Error.stackTraceLimit=1/0,R=_dereq_("./scope").Scope,pt=_dereq_("./lexer"),B=pt.RESERVED,q=pt.STRICT_PROSCRIBED,dt=_dereq_("./helpers"),et=dt.compact,it=dt.flatten,rt=dt.extend,lt=dt.merge,tt=dt.del,mt=dt.starts,nt=dt.ends,vt=dt.some,Z=dt.addLocationDataFn,ft=dt.locationDataToString,gt=dt.throwSyntaxError,e.extend=rt,e.addLocationDataFn=Z,Y=function(){return!0},O=function(){return!1},V=function(){return this},A=function(){return this.negated=!this.negated,this},e.CodeFragment=f=function(){function e(e,t){var n;this.code=""+t,this.locationData=null!=e?e.locationData:void 0,this.type=(null!=e?null!=(n=e.constructor)?n.name:void 0:void 0)||"unknown"}return e.prototype.toString=function(){return""+this.code+(this.locationData?": "+ft(this.locationData):"")},e}(),st=function(e){var t;return function(){var n,r,i;for(i=[],n=0,r=e.length;r>n;n++)t=e[n],i.push(t.code);return i}().join("")},e.Base=i=function(){function e(){}return e.prototype.compile=function(e,t){return st(this.compileToFragments(e,t))},e.prototype.compileToFragments=function(e,t){var n;return e=rt({},e),t&&(e.level=t),n=this.unfoldSoak(e)||this,n.tab=e.indent,e.level!==k&&n.isStatement(e)?n.compileClosure(e):n.compileNode(e)},e.prototype.compileClosure=function(e){var n,r,i,u,f,l,c;return(u=this.jumps())&&u.error("cannot use a pure statement in an expression"),e.sharedScope=!0,i=new a([],s.wrap([this])),n=[],((r=this.contains(ut))||this.contains(at))&&(n=[new L("this")],r?(f="apply",n.push(new L("arguments"))):f="call",i=new Q(i,[new t(new L(f))])),l=(new o(i,n)).compileNode(e),(i.isGenerator||(null!=(c=i.base)?c.isGenerator:void 0))&&(l.unshift(this.makeCode("(yield* ")),l.push(this.makeCode(")"))),l},e.prototype.cache=function(e,t,n){var i,s,o;return i=null!=n?n(this):this.isComplex(),i?(s=new L(e.scope.freeVariable("ref")),o=new r(s,this),t?[o.compileToFragments(e,t),[this.makeCode(s.value)]]:[o,s]):(s=t?this.compileToFragments(e,t):this,[s,s])},e.prototype.cacheToCodeFragments=function(e){return[st(e[0]),st(e[1])]},e.prototype.makeReturn=function(e){var t;return t=this.unwrapAll(),e?new o(new L(e+".push"),[t]):new F(t)},e.prototype.contains=function(e){var t;return t=void 0,this.traverseChildren(!1,function(n){return e(n)?(t=n,!1):void 0}),t},e.prototype.lastNonComment=function(e){var t;for(t=e.length;t--;)if(!(e[t]instanceof l))return e[t];return null},e.prototype.toString=function(e,t){var n;return null==e&&(e=""),null==t&&(t=this.constructor.name),n="\n"+e+t,this.soak&&(n+="?"),this.eachChild(function(t){return n+=t.toString(e+X)}),n},e.prototype.eachChild=function(e){var t,n,r,i,s,o,u,a;if(!this.children)return this;for(u=this.children,r=0,s=u.length;s>r;r++)if(t=u[r],this[t])for(a=it([this[t]]),i=0,o=a.length;o>i;i++)if(n=a[i],e(n)===!1)return this;return this},e.prototype.traverseChildren=function(e,t){return this.eachChild(function(n){var r;return r=t(n),r!==!1?n.traverseChildren(e,t):void 0})},e.prototype.invert=function(){return new D("!",this)},e.prototype.unwrapAll=function(){var e;for(e=this;e!==(e=e.unwrap()););return e},e.prototype.children=[],e.prototype.isStatement=O,e.prototype.jumps=O,e.prototype.isComplex=Y,e.prototype.isChainable=O,e.prototype.isAssignable=O,e.prototype.unwrap=V,e.prototype.unfoldSoak=O,e.prototype.assigns=O,e.prototype.updateLocationDataIfMissing=function(e){return this.locationData?this:(this.locationData=e,this.eachChild(function(t){return t.updateLocationDataIfMissing(e)}))},e.prototype.error=function(e){return gt(e,this.locationData)},e.prototype.makeCode=function(e){return new f(this,e)},e.prototype.wrapInBraces=function(e){return[].concat(this.makeCode("("),e,this.makeCode(")"))},e.prototype.joinFragmentArrays=function(e,t){var n,r,i,s,o;for(n=[],i=s=0,o=e.length;o>s;i=++s)r=e[i],i&&n.push(this.makeCode(t)),n=n.concat(r);return n},e}(),e.Block=s=function(e){function t(e){this.expressions=et(it(e||[]))}return wt(t,e),t.prototype.children=["expressions"],t.prototype.push=function(e){return this.expressions.push(e),this},t.prototype.pop=function(){return this.expressions.pop()},t.prototype.unshift=function(e){return this.expressions.unshift(e),this},t.prototype.unwrap=function(){return 1===this.expressions.length?this.expressions[0]:this},t.prototype.isEmpty=function(){return!this.expressions.length},t.prototype.isStatement=function(e){var t,n,r,i;for(i=this.expressions,n=0,r=i.length;r>n;n++)if(t=i[n],t.isStatement(e))return!0;return!1},t.prototype.jumps=function(e){var t,n,r,i,s;for(s=this.expressions,n=0,i=s.length;i>n;n++)if(t=s[n],r=t.jumps(e))return r},t.prototype.makeReturn=function(e){var t,n;for(n=this.expressions.length;n--;)if(t=this.expressions[n],!(t instanceof l)){this.expressions[n]=t.makeReturn(e),t instanceof F&&!t.expression&&this.expressions.splice(n,1);break}return this},t.prototype.compileToFragments=function(e,n){return null==e&&(e={}),e.scope?t.__super__.compileToFragments.call(this,e,n):this.compileRoot(e)},t.prototype.compileNode=function(e){var n,r,i,s,o,u,a,f,l;for(this.tab=e.indent,l=e.level===k,r=[],f=this.expressions,s=o=0,u=f.length;u>o;s=++o)a=f[s],a=a.unwrapAll(),a=a.unfoldSoak(e)||a,a instanceof t?r.push(a.compileNode(e)):l?(a.front=!0,i=a.compileToFragments(e),a.isStatement(e)||(i.unshift(this.makeCode(""+this.tab)),i.push(this.makeCode(";"))),r.push(i)):r.push(a.compileToFragments(e,T));return l?this.spaced?[].concat(this.joinFragmentArrays(r,"\n\n"),this.makeCode("\n")):this.joinFragmentArrays(r,"\n"):(n=r.length?this.joinFragmentArrays(r,", "):[this.makeCode("void 0")],r.length>1&&e.level>=T?this.wrapInBraces(n):n)},t.prototype.compileRoot=function(e){var t,n,r,i,s,o,u,a,f,c,h;for(e.indent=e.bare?"":X,e.level=k,this.spaced=!0,e.scope=new R(null,this,null,null!=(f=e.referencedVars)?f:[]),c=e.locals||[],i=0,s=c.length;s>i;i++)o=c[i],e.scope.parameter(o);return u=[],e.bare||(a=function(){var e,n,i,s;for(i=this.expressions,s=[],r=e=0,n=i.length;n>e&&(t=i[r],t.unwrap()instanceof l);r=++e)s.push(t);return s}.call(this),h=this.expressions.slice(a.length),this.expressions=a,a.length&&(u=this.compileNode(lt(e,{indent:""})),u.push(this.makeCode("\n"))),this.expressions=h),n=this.compileWithDeclarations(e),e.bare?n:[].concat(u,this.makeCode("(function() {\n"),n,this.makeCode("\n}).call(this);\n"))},t.prototype.compileWithDeclarations=function(e){var t,n,r,i,s,o,u,a,f,c,h,p,d,v;for(i=[],a=[],f=this.expressions,s=o=0,u=f.length;u>o&&(r=f[s],r=r.unwrap(),r instanceof l||r instanceof L);s=++o);return e=lt(e,{level:k}),s&&(p=this.expressions.splice(s,9e9),c=[this.spaced,!1],v=c[0],this.spaced=c[1],h=[this.compileNode(e),v],i=h[0],this.spaced=h[1],this.expressions=p),a=this.compileNode(e),d=e.scope,d.expressions===this&&(n=e.scope.hasDeclarations(),t=d.hasAssignments,n||t?(s&&i.push(this.makeCode("\n")),i.push(this.makeCode(this.tab+"var ")),n&&i.push(this.makeCode(d.declaredVariables().join(", "))),t&&(n&&i.push(this.makeCode(",\n"+(this.tab+X))),i.push(this.makeCode(d.assignedVariables().join(",\n"+(this.tab+X))))),i.push(this.makeCode(";\n"+(this.spaced?"\n":"")))):i.length&&a.length&&i.push(this.makeCode("\n"))),i.concat(a)},t.wrap=function(e){return 1===e.length&&e[0]instanceof t?e[0]:new t(e)},t}(i),e.Literal=L=function(e){function t(e){this.value=e}return wt(t,e),t.prototype.makeReturn=function(){return this.isStatement()?this:t.__super__.makeReturn.apply(this,arguments)},t.prototype.isAssignable=function(){return m.test(this.value)},t.prototype.isStatement=function(){var e;return"break"===(e=this.value)||"continue"===e||"debugger"===e},t.prototype.isComplex=O,t.prototype.assigns=function(e){return e===this.value},t.prototype.jumps=function(e){return"break"!==this.value||(null!=e?e.loop:void 0)||(null!=e?e.block:void 0)?"continue"!==this.value||(null!=e?e.loop:void 0)?void 0:this:this},t.prototype.compileNode=function(e){var t,n,r;return n="this"===this.value?(null!=(r=e.scope.method)?r.bound:void 0)?e.scope.method.context:this.value:this.value.reserved?'"'+this.value+'"':this.value,t=this.isStatement()?""+this.tab+n+";":n,[this.makeCode(t)]},t.prototype.toString=function(){return' "'+this.value+'"'},t}(i),e.Undefined=function(e){function t(){return t.__super__.constructor.apply(this,arguments)}return wt(t,e),t.prototype.isAssignable=O,t.prototype.isComplex=O,t.prototype.compileNode=function(e){return[this.makeCode(e.level>=S?"(void 0)":"void 0")]},t}(i),e.Null=function(e){function t(){return t.__super__.constructor.apply(this,arguments)}return wt(t,e),t.prototype.isAssignable=O,t.prototype.isComplex=O,t.prototype.compileNode=function(){return[this.makeCode("null")]},t}(i),e.Bool=function(e){function t(e){this.val=e}return wt(t,e),t.prototype.isAssignable=O,t.prototype.isComplex=O,t.prototype.compileNode=function(){return[this.makeCode(this.val)]},t}(i),e.Return=F=function(e){function t(e){this.expression=e}return wt(t,e),t.prototype.children=["expression"],t.prototype.isStatement=Y,t.prototype.makeReturn=V,t.prototype.jumps=V,t.prototype.compileToFragments=function(e,n){var r,i;return r=null!=(i=this.expression)?i.makeReturn():void 0,!r||r instanceof t?t.__super__.compileToFragments.call(this,e,n):r.compileToFragments(e,n)},t.prototype.compileNode=function(e){var t,n,r;return t=[],n=null!=(r=this.expression)?"function"==typeof r.isYieldReturn?r.isYieldReturn():void 0:void 0,n||t.push(this.makeCode(this.tab+("return"+(this.expression?" ":"")))),this.expression&&(t=t.concat(this.expression.compileToFragments(e,C))),n||t.push(this.makeCode(";")),t},t}(i),e.Value=Q=function(e){function t(e,n,r){return!n&&e instanceof t?e:(this.base=e,this.properties=n||[],r&&(this[r]=!0),this)}return wt(t,e),t.prototype.children=["base","properties"],t.prototype.add=function(e){return this.properties=this.properties.concat(e),this},t.prototype.hasProperties=function(){return!!this.properties.length},t.prototype.bareLiteral=function(e){return!this.properties.length&&this.base instanceof e},t.prototype.isArray=function(){return this.bareLiteral(n)},t.prototype.isRange=function(){return this.bareLiteral(j)},t.prototype.isComplex=function(){return this.hasProperties()||this.base.isComplex()},t.prototype.isAssignable=function(){return this.hasProperties()||this.base.isAssignable()},t.prototype.isSimpleNumber=function(){return this.bareLiteral(L)&&I.test(this.base.value)},t.prototype.isString=function(){return this.bareLiteral(L)&&y.test(this.base.value)},t.prototype.isRegex=function(){return this.bareLiteral(L)&&g.test(this.base.value)},t.prototype.isAtomic=function(){var e,t,n,r;for(r=this.properties.concat(this.base),e=0,t=r.length;t>e;e++)if(n=r[e],n.soak||n instanceof o)return!1;return!0},t.prototype.isNotCallable=function(){return this.isSimpleNumber()||this.isString()||this.isRegex()||this.isArray()||this.isRange()||this.isSplice()||this.isObject()},t.prototype.isStatement=function(e){return!this.properties.length&&this.base.isStatement(e)},t.prototype.assigns=function(e){return!this.properties.length&&this.base.assigns(e)},t.prototype.jumps=function(e){return!this.properties.length&&this.base.jumps(e)},t.prototype.isObject=function(e){return this.properties.length?!1:this.base instanceof _&&(!e||this.base.generated)},t.prototype.isSplice=function(){var e,t;return t=this.properties,e=t[t.length-1],e instanceof U},t.prototype.looksStatic=function(e){var t;return this.base.value===e&&1===this.properties.length&&"prototype"!==(null!=(t=this.properties[0].name)?t.value:void 0)},t.prototype.unwrap=function(){return this.properties.length?this:this.base},t.prototype.cacheReference=function(e){var n,i,s,o,u;return u=this.properties,s=u[u.length-1],2>this.properties.length&&!this.base.isComplex()&&(null!=s?!s.isComplex():!void 0)?[this,this]:(n=new t(this.base,this.properties.slice(0,-1)),n.isComplex()&&(i=new L(e.scope.freeVariable("base")),n=new t(new H(new r(i,n)))),s?(s.isComplex()&&(o=new L(e.scope.freeVariable("name")),s=new E(new r(o,s.index)),o=new E(o)),[n.add(s),new t(i||n.base,[o||s])]):[n,i])},t.prototype.compileNode=function(e){var t,n,r,i,s;for(this.base.front=this.front,s=this.properties,t=this.base.compileToFragments(e,s.length?S:null),(this.base instanceof H||s.length)&&I.test(st(t))&&t.push(this.makeCode(".")),n=0,r=s.length;r>n;n++)i=s[n],t.push.apply(t,i.compileToFragments(e));return t},t.prototype.unfoldSoak=function(e){return null!=this.unfoldedSoak?this.unfoldedSoak:this.unfoldedSoak=function(n){return function(){var i,s,o,u,a,f,l,h,p,d;if(o=n.base.unfoldSoak(e))return(h=o.body.properties).push.apply(h,n.properties),o;for(p=n.properties,s=u=0,a=p.length;a>u;s=++u)if(f=p[s],f.soak)return f.soak=!1,i=new t(n.base,n.properties.slice(0,s)),d=new t(n.base,n.properties.slice(s)),i.isComplex()&&(l=new L(e.scope.freeVariable("ref")),i=new H(new r(l,i)),d.base=l),new b(new c(i),d,{soak:!0});return!1}}(this)()},t}(i),e.Comment=l=function(e){function t(e){this.comment=e}return wt(t,e),t.prototype.isStatement=Y,t.prototype.makeReturn=V,t.prototype.compileNode=function(e,t){var n,r;return r=this.comment.replace(/^(\s*)#(?=\s)/gm,"$1 *"),n="/*"+ct(r,this.tab)+(St.call(r,"\n")>=0?"\n"+this.tab:"")+" */",(t||e.level)===k&&(n=e.indent+n),[this.makeCode("\n"),this.makeCode(n)]},t}(i),e.Call=o=function(e){function n(e,t,n){this.args=null!=t?t:[],this.soak=n,this.isNew=!1,this.isSuper="super"===e,this.variable=this.isSuper?null:e,e instanceof Q&&e.isNotCallable()&&e.error("literal is not a function")}return wt(n,e),n.prototype.children=["variable","args"],n.prototype.newInstance=function(){var e,t;return e=(null!=(t=this.variable)?t.base:void 0)||this.variable,e instanceof n&&!e.isNew?e.newInstance():this.isNew=!0,this},n.prototype.superReference=function(e){var n,i,s,o,u,a,f,l;return u=e.scope.namedMethod(),(null!=u?u.klass:void 0)?(o=u.klass,a=u.name,l=u.variable,o.isComplex()&&(s=new L(e.scope.parent.freeVariable("base")),i=new Q(new H(new r(s,o))),l.base=i,l.properties.splice(0,o.properties.length)),(a.isComplex()||a instanceof E&&a.index.isAssignable())&&(f=new L(e.scope.parent.freeVariable("name")),a=new E(new r(f,a.index)),l.properties.pop(),l.properties.push(a)),n=[new t(new L("__super__"))],u["static"]&&n.push(new t(new L("constructor"))),n.push(null!=f?new E(f):a),(new Q(null!=s?s:o,n)).compile(e)):(null!=u?u.ctor:void 0)?u.name+".__super__.constructor":this.error("cannot call super outside of an instance method.")},n.prototype.superThis=function(e){var t;return t=e.scope.method,t&&!t.klass&&t.context||"this"},n.prototype.unfoldSoak=function(e){var t,r,i,s,o,u,a,f,l;if(this.soak){if(this.variable){if(r=yt(e,this,"variable"))return r;a=(new Q(this.variable)).cacheReference(e),s=a[0],l=a[1]}else s=new L(this.superReference(e)),l=new Q(s);return l=new n(l,this.args),l.isNew=this.isNew,s=new L("typeof "+s.compile(e)+' === "function"'),new b(s,new Q(l),{soak:!0})}for(t=this,u=[];;)if(t.variable instanceof n)u.push(t),t=t.variable;else{if(!(t.variable instanceof Q))break;if(u.push(t),!((t=t.variable.base)instanceof n))break}for(f=u.reverse(),i=0,o=f.length;o>i;i++)t=f[i],r&&(t.variable instanceof n?t.variable=r:t.variable.base=r),r=yt(e,t,"variable");return r},n.prototype.compileNode=function(e){var t,n,r,i,s,o,u,a,f,l;if(null!=(f=this.variable)&&(f.front=this.front),i=z.compileSplattedArray(e,this.args,!0),i.length)return this.compileSplat(e,i);for(r=[],l=this.args,n=o=0,u=l.length;u>o;n=++o)t=l[n],n&&r.push(this.makeCode(", ")),r.push.apply(r,t.compileToFragments(e,T));return s=[],this.isSuper?(a=this.superReference(e)+(".call("+this.superThis(e)),r.length&&(a+=", "),s.push(this.makeCode(a))):(this.isNew&&s.push(this.makeCode("new ")),s.push.apply(s,this.variable.compileToFragments(e,S)),s.push(this.makeCode("("))),s.push.apply(s,r),s.push(this.makeCode(")")),s},n.prototype.compileSplat=function(e,t){var n,r,i,s,o,u;return this.isSuper?[].concat(this.makeCode(this.superReference(e)+".apply("+this.superThis(e)+", "),t,this.makeCode(")")):this.isNew?(s=this.tab+X,[].concat(this.makeCode("(function(func, args, ctor) {\n"+s+"ctor.prototype = func.prototype;\n"+s+"var child = new ctor, result = func.apply(child, args);\n"+s+"return Object(result) === result ? result : child;\n"+this.tab+"})("),this.variable.compileToFragments(e,T),this.makeCode(", "),t,this.makeCode(", function(){})"))):(n=[],r=new Q(this.variable),(o=r.properties.pop())&&r.isComplex()?(u=e.scope.freeVariable("ref"),n=n.concat(this.makeCode("("+u+" = "),r.compileToFragments(e,T),this.makeCode(")"),o.compileToFragments(e))):(i=r.compileToFragments(e,S),I.test(st(i))&&(i=this.wrapInBraces(i)),o?(u=st(i),i.push.apply(i,o.compileToFragments(e))):u="null",n=n.concat(i)),n=n.concat(this.makeCode(".apply("+u+", "),t,this.makeCode(")")))},n}(i),e.Extends=p=function(e){function t(e,t){this.child=e,this.parent=t}return wt(t,e),t.prototype.children=["child","parent"],t.prototype.compileToFragments=function(e){return(new o(new Q(new L(bt("extend",e))),[this.child,this.parent])).compileToFragments(e)},t}(i),e.Access=t=function(e){function t(e,t){this.name=e,this.name.asKey=!0,this.soak="soak"===t}return wt(t,e),t.prototype.children=["name"],t.prototype.compileToFragments=function(e){var t;return t=this.name.compileToFragments(e),m.test(st(t))?t.unshift(this.makeCode(".")):(t.unshift(this.makeCode("[")),t.push(this.makeCode("]"))),t},t.prototype.isComplex=O,t}(i),e.Index=E=function(e){function t(e){this.index=e}return wt(t,e),t.prototype.children=["index"],t.prototype.compileToFragments=function(e){return[].concat(this.makeCode("["),this.index.compileToFragments(e,C),this.makeCode("]"))},t.prototype.isComplex=function(){return this.index.isComplex()},t}(i),e.Range=j=function(e){function t(e,t,n){this.from=e,this.to=t,this.exclusive="exclusive"===n,this.equals=this.exclusive?"":"="}return wt(t,e),t.prototype.children=["from","to"],t.prototype.compileVariables=function(e){var t,n,r,i,s,o;return e=lt(e,{top:!0}),t=tt(e,"isComplex"),n=this.cacheToCodeFragments(this.from.cache(e,T,t)),this.fromC=n[0],this.fromVar=n[1],r=this.cacheToCodeFragments(this.to.cache(e,T,t)),this.toC=r[0],this.toVar=r[1],(o=tt(e,"step"))&&(i=this.cacheToCodeFragments(o.cache(e,T,t)),this.step=i[0],this.stepVar=i[1]),s=[this.fromVar.match(M),this.toVar.match(M)],this.fromNum=s[0],this.toNum=s[1],this.stepVar?this.stepNum=this.stepVar.match(M):void 0},t.prototype.compileNode=function(e){var t,n,r,i,s,o,u,a,f,l,c,h,p,d;return this.fromVar||this.compileVariables(e),e.index?(u=this.fromNum&&this.toNum,s=tt(e,"index"),o=tt(e,"name"),f=o&&o!==s,d=s+" = "+this.fromC,this.toC!==this.toVar&&(d+=", "+this.toC),this.step!==this.stepVar&&(d+=", "+this.step),l=[s+" <"+this.equals,s+" >"+this.equals],a=l[0],i=l[1],n=this.stepNum?ht(this.stepNum[0])>0?a+" "+this.toVar:i+" "+this.toVar:u?(c=[ht(this.fromNum[0]),ht(this.toNum[0])],r=c[0],p=c[1],c,p>=r?a+" "+p:i+" "+p):(t=this.stepVar?this.stepVar+" > 0":this.fromVar+" <= "+this.toVar,t+" ? "+a+" "+this.toVar+" : "+i+" "+this.toVar),h=this.stepVar?s+" += "+this.stepVar:u?f?p>=r?"++"+s:"--"+s:p>=r?s+"++":s+"--":f?t+" ? ++"+s+" : --"+s:t+" ? "+s+"++ : "+s+"--",f&&(d=o+" = "+d),f&&(h=o+" = "+h),[this.makeCode(d+"; "+n+"; "+h)]):this.compileArray(e)},t.prototype.compileArray=function(e){var t,n,r,i,s,o,u,a,f,l,c,h,p;return this.fromNum&&this.toNum&&20>=Math.abs(this.fromNum-this.toNum)?(f=function(){h=[];for(var e=l=+this.fromNum,t=+this.toNum;t>=l?t>=e:e>=t;t>=l?e++:e--)h.push(e);return h}.apply(this),this.exclusive&&f.pop(),[this.makeCode("["+f.join(", ")+"]")]):(o=this.tab+X,s=e.scope.freeVariable("i",{single:!0}),c=e.scope.freeVariable("results"),a="\n"+o+c+" = [];",this.fromNum&&this.toNum?(e.index=s,n=st(this.compileNode(e))):(p=s+" = "+this.fromC+(this.toC!==this.toVar?", "+this.toC:""),r=this.fromVar+" <= "+this.toVar,n="var "+p+"; "+r+" ? "+s+" <"+this.equals+" "+this.toVar+" : "+s+" >"+this.equals+" "+this.toVar+"; "+r+" ? "+s+"++ : "+s+"--"),u="{ "+c+".push("+s+"); }\n"+o+"return "+c+";\n"+e.indent,i=function(e){return null!=e?e.contains(ut):void 0},(i(this.from)||i(this.to))&&(t=", arguments"),[this.makeCode("(function() {"+a+"\n"+o+"for ("+n+")"+u+"}).apply(this"+(null!=t?t:"")+")")])},t}(i),e.Slice=U=function(e){function t(e){this.range=e,t.__super__.constructor.call(this)}return wt(t,e),t.prototype.children=["range"],t.prototype.compileNode=function(e){var t,n,r,i,s,o,u;return s=this.range,o=s.to,r=s.from,i=r&&r.compileToFragments(e,C)||[this.makeCode("0")],o&&(t=o.compileToFragments(e,C),n=st(t),(this.range.exclusive||-1!==+n)&&(u=", "+(this.range.exclusive?n:I.test(n)?""+(+n+1):(t=o.compileToFragments(e,S),"+"+st(t)+" + 1 || 9e9")))),[this.makeCode(".slice("+st(i)+(u||"")+")")]},t}(i),e.Obj=_=function(e){function n(e,t){this.generated=null!=t?t:!1,this.objects=this.properties=e||[]}return wt(n,e),n.prototype.children=["properties"],n.prototype.compileNode=function(e){var n,i,s,o,u,a,f,c,h,p,d,v,m,g,y,b,w,E,S,x,T;if(S=this.properties,this.generated)for(f=0,m=S.length;m>f;f++)b=S[f],b instanceof Q&&b.error("cannot have an implicit value in an implicit object");for(i=h=0,g=S.length;g>h&&(E=S[i],!((E.variable||E).base instanceof H));i=++h);for(s=S.length>i,u=e.indent+=X,v=this.lastNonComment(this.properties),n=[],s&&(w=e.scope.freeVariable("obj"),n.push(this.makeCode("(\n"+u+w+" = "))),n.push(this.makeCode("{"+(0===S.length||0===i?"}":"\n"))),o=d=0,y=S.length;y>d;o=++d)E=S[o],o===i&&(0!==o&&n.push(this.makeCode("\n"+u+"}")),n.push(this.makeCode(",\n"))),c=o===S.length-1||o===i-1?"":E===v||E instanceof l?"\n":",\n",a=E instanceof l?"":u,s&&i>o&&(a+=X),E instanceof r&&E.variable instanceof Q&&E.variable.hasProperties()&&E.variable.error("invalid object key"),E instanceof Q&&E["this"]&&(E=new r(E.properties[0].name,E,"object")),E instanceof l||(i>o?(E instanceof r||(E=new r(E,E,"object")),(E.variable.base||E.variable).asKey=!0):(E instanceof r?(p=E.variable,T=E.value):(x=E.base.cache(e),p=x[0],T=x[1]),E=new r(new Q(new L(w),[new t(p)]),T))),a&&n.push(this.makeCode(a)),n.push.apply(n,E.compileToFragments(e,k)),c&&n.push(this.makeCode(c));return s?n.push(this.makeCode(",\n"+u+w+"\n"+this.tab+")")):0!==S.length&&n.push(this.makeCode("\n"+this.tab+"}")),this.front&&!s?this.wrapInBraces(n):n},n.prototype.assigns=function(e){var t,n,r,i;for(i=this.properties,t=0,n=i.length;n>t;t++)if(r=i[t],r.assigns(e))return!0;return!1},n}(i),e.Arr=n=function(e){function t(e){this.objects=e||[]}return wt(t,e),t.prototype.children=["objects"],t.prototype.compileNode=function(e){var t,n,r,i,s,o,u;if(!this.objects.length)return[this.makeCode("[]")];if(e.indent+=X,t=z.compileSplattedArray(e,this.objects),t.length)return t;for(t=[],n=function(){var t,n,r,i;for(r=this.objects,i=[],t=0,n=r.length;n>t;t++)u=r[t],i.push(u.compileToFragments(e,T));return i}.call(this),i=s=0,o=n.length;o>s;i=++s)r=n[i],i&&t.push(this.makeCode(", ")),t.push.apply(t,r);return st(t).indexOf("\n")>=0?(t.unshift(this.makeCode("[\n"+e.indent)),t.push(this.makeCode("\n"+this.tab+"]"))):(t.unshift(this.makeCode("[")),t.push(this.makeCode("]"))),t},t.prototype.assigns=function(e){var t,n,r,i;for(i=this.objects,t=0,n=i.length;n>t;t++)if(r=i[t],r.assigns(e))return!0;return!1},t}(i),e.Class=u=function(e){function n(e,t,n){this.variable=e,this.parent=t,this.body=null!=n?n:new s,this.boundFuncs=[],this.body.classBody=!0}return wt(n,e),n.prototype.children=["variable","parent","body"],n.prototype.determineName=function(){var e,n,r;return this.variable?(n=this.variable.properties,r=n[n.length-1],e=r?r instanceof t&&r.name.value:this.variable.base.value,St.call(q,e)>=0&&this.variable.error("class variable name may not be "+e),e&&(e=m.test(e)&&e)):null},n.prototype.setContext=function(e){return this.body.traverseChildren(!1,function(t){return t.classBody?!1:t instanceof L&&"this"===t.value?t.value=e:t instanceof a&&t.bound?t.context=e:void 0})},n.prototype.addBoundFunctions=function(e){var n,r,i,s,o;for(o=this.boundFuncs,r=0,i=o.length;i>r;r++)n=o[r],s=(new Q(new L("this"),[new t(n)])).compile(e),this.ctor.body.unshift(new L(s+" = "+bt("bind",e)+"("+s+", this)"))},n.prototype.addProperties=function(e,n,i){var s,o,u,f,l,c;return c=e.base.properties.slice(0),f=function(){var e;for(e=[];o=c.shift();)o instanceof r&&(u=o.variable.base,delete o.context,l=o.value,"constructor"===u.value?(this.ctor&&o.error("cannot define more than one constructor in a class"),l.bound&&o.error("cannot define a constructor as a bound function"),l instanceof a?o=this.ctor=l:(this.externalCtor=i.classScope.freeVariable("class"),o=new r(new L(this.externalCtor),l))):o.variable["this"]?l["static"]=!0:(s=u.isComplex()?new E(u):new t(u),o.variable=new Q(new L(n),[new t(new L("prototype")),s]),l instanceof a&&l.bound&&(this.boundFuncs.push(u),l.bound=!1))),e.push(o);return e}.call(this),et(f)},n.prototype.walkBody=function(e,t){return this.traverseChildren(!1,function(i){return function(o){var u,a,f,l,c,h,p;if(u=!0,o instanceof n)return!1;if(o instanceof s){for(p=a=o.expressions,f=l=0,c=p.length;c>l;f=++l)h=p[f],h instanceof r&&h.variable.looksStatic(e)?h.value["static"]=!0:h instanceof Q&&h.isObject(!0)&&(u=!1,a[f]=i.addProperties(h,e,t));o.expressions=a=it(a)}return u&&!(o instanceof n)}}(this))},n.prototype.hoistDirectivePrologue=function(){var e,t,n;for(t=0,e=this.body.expressions;(n=e[t])&&n instanceof l||n instanceof Q&&n.isString();)++t;return this.directives=e.splice(0,t)},n.prototype.ensureConstructor=function(e){return this.ctor||(this.ctor=new a,this.externalCtor?this.ctor.body.push(new L(this.externalCtor+".apply(this, arguments)")):this.parent&&this.ctor.body.push(new L(e+".__super__.constructor.apply(this, arguments)")),this.ctor.body.makeReturn(),this.body.expressions.unshift(this.ctor)),this.ctor.ctor=this.ctor.name=e,this.ctor.klass=null,this.ctor.noReturn=!0},n.prototype.compileNode=function(e){var t,n,i,u,f,l,c,h,d;return(u=this.body.jumps())&&u.error("Class bodies cannot contain pure statements"),(n=this.body.contains(ut))&&n.error("Class bodies shouldn't reference arguments"),c=this.determineName()||"_Class",c.reserved&&(c="_"+c),l=new L(c),i=new a([],s.wrap([this.body])),t=[],e.classScope=i.makeScope(e.scope),this.hoistDirectivePrologue(),this.setContext(c),this.walkBody(c,e),this.ensureConstructor(c),this.addBoundFunctions(e),this.body.spaced=!0,this.body.expressions.push(l),this.parent&&(d=new L(e.classScope.freeVariable("superClass",{reserve:!1})),this.body.expressions.unshift(new p(l,d)),i.params.push(new P(d)),t.push(this.parent)),(h=this.body.expressions).unshift.apply(h,this.directives),f=new H(new o(i,t)),this.variable&&(f=new r(this.variable,f)),f.compileToFragments(e)},n}(i),e.Assign=r=function(e){function n(e,t,n,r){var i,s,o;this.variable=e,this.value=t,this.context=n,this.param=r&&r.param,this.subpattern=r&&r.subpattern,o=s=this.variable.unwrapAll().value,i=St.call(q,o)>=0,i&&"object"!==this.context&&this.variable.error('variable name may not be "'+s+'"')}return wt(n,e),n.prototype.children=["variable","value"],n.prototype.isStatement=function(e){return(null!=e?e.level:void 0)===k&&null!=this.context&&St.call(this.context,"?")>=0},n.prototype.assigns=function(e){return this["object"===this.context?"value":"variable"].assigns(e)},n.prototype.unfoldSoak=function(e){return yt(e,this,"variable")},n.prototype.compileNode=function(e){var t,n,r,i,s,o,u,f,l,c,h,p,d,v;if(r=this.variable instanceof Q){if(this.variable.isArray()||this.variable.isObject())return this.compilePatternMatch(e);if(this.variable.isSplice())return this.compileSplice(e);if("||="===(f=this.context)||"&&="===f||"?="===f)return this.compileConditional(e);if("**="===(l=this.context)||"//="===l||"%%="===l)return this.compileSpecialMath(e)}return this.value instanceof a&&(this.value["static"]?(this.value.klass=this.variable.base,this.value.name=this.variable.properties[0],this.value.variable=this.variable):(null!=(c=this.variable.properties)?c.length:void 0)>=2&&(h=this.variable.properties,o=h.length>=3?xt.call(h,0,i=h.length-2):(i=0,[]),u=h[i++],s=h[i++],"prototype"===(null!=(p=u.name)?p.value:void 0)&&(this.value.klass=new Q(this.variable.base,o),this.value.name=s,this.value.variable=this.variable))),this.context||(v=this.variable.unwrapAll(),v.isAssignable()||this.variable.error('"'+this.variable.compile(e)+'" cannot be assigned'),("function"==typeof v.hasProperties?v.hasProperties():void 0)||(this.param?e.scope.add(v.value,"var"):e.scope.find(v.value))),d=this.value.compileToFragments(e,T),n=this.variable.compileToFragments(e,T),"object"===this.context?n.concat(this.makeCode(": "),d):(t=n.concat(this.makeCode(" "+(this.context||"=")+" "),d),T>=e.level?t:this.wrapInBraces(t))},n.prototype.compilePatternMatch=function(e){var r,i,s,o,u,a,f,l,c,p,d,v,g,y,b,w,S,x,C,A,O,M,_,D,P,j,F,I;if(D=e.level===k,j=this.value,y=this.variable.base.objects,!(b=y.length))return s=j.compileToFragments(e),e.level>=N?this.wrapInBraces(s):s;if(l=this.variable.isObject(),!D||1!==b||(g=y[0])instanceof z){for(F=j.compileToFragments(e,T),I=st(F),i=[],o=!1,(!m.test(I)||this.variable.assigns(I))&&(i.push([this.makeCode((w=e.scope.freeVariable("ref"))+" = ")].concat(xt.call(F))),F=[this.makeCode(w)],I=w),a=p=0,d=y.length;d>p;a=++p){if(g=y[a],f=a,l&&(g instanceof n?(A=g,O=A.variable,f=O.base,g=A.value):g.base instanceof H?(M=(new Q(g.unwrapAll())).cacheReference(e),g=M[0],f=M[1]):f=g["this"]?g.properties[0].name:g),!o&&g instanceof z)v=g.name.unwrap().value,g=g.unwrap(),P=b+" <= "+I+".length ? "+bt("slice",e)+".call("+I+", "+a,(_=b-a-1)?(c=e.scope.freeVariable("i",{single:!0}),P+=", "+c+" = "+I+".length - "+_+") : ("+c+" = "+a+", [])"):P+=") : []",P=new L(P),o=c+"++";else{if(!o&&g instanceof h){(_=b-a-1)&&(1===_?o=I+".length - 1":(c=e.scope.freeVariable("i",{single:!0}),P=new L(c+" = "+I+".length - "+_),o=c+"++",i.push(P.compileToFragments(e,T))));continue}v=g.unwrap().value,(g instanceof z||g instanceof h)&&g.error("multiple splats/expansions are disallowed in an assignment"),"number"==typeof f?(f=new L(o||f),r=!1):r=l&&m.test(f.unwrap().value||0),P=new Q(new L(I),[new(r?t:E)(f)])}null!=v&&St.call(B,v)>=0&&g.error("assignment to a reserved word: "+g.compile(e)),i.push((new n(g,P,null,{param:this.param,subpattern:!0})).compileToFragments(e,T))}return D||this.subpattern||i.push(F),u=this.joinFragmentArrays(i,", "),T>e.level?u:this.wrapInBraces(u)}return g instanceof n?(S=g,x=S.variable,f=x.base,g=S.value):f=l?g["this"]?g.properties[0].name:g:new L(0),r=m.test(f.unwrap().value||0),j=new Q(j),j.properties.push(new(r?t:E)(f)),C=g.unwrap().value,St.call(B,C)>=0&&g.error("assignment to a reserved word: "+g.compile(e)),(new n(g,j,null,{param:this.param})).compileToFragments(e,k)},n.prototype.compileConditional=function(e){var t,r,i,s;return i=this.variable.cacheReference(e),r=i[0],s=i[1],!r.properties.length&&r.base instanceof L&&"this"!==r.base.value&&!e.scope.check(r.base.value)&&this.variable.error('the variable "'+r.base.value+"\" can't be assigned with "+this.context+" because it has not been declared before"),St.call(this.context,"?")>=0?(e.isExistentialEquals=!0,(new b(new c(r),s,{type:"if"})).addElse(new n(s,this.value,"=")).compileToFragments(e)):(t=(new D(this.context.slice(0,-1),r,new n(s,this.value,"="))).compileToFragments(e),T>=e.level?t:this.wrapInBraces(t))},n.prototype.compileSpecialMath=function(e){var t,r,i;return r=this.variable.cacheReference(e),t=r[0],i=r[1],(new n(t,new D(this.context.slice(0,-1),i,this.value))).compileToFragments(e)},n.prototype.compileSplice=function(e){var t,n,r,i,s,o,u,a,f,l,c,h;return u=this.variable.properties.pop().range,r=u.from,l=u.to,n=u.exclusive,o=this.variable.compile(e),r?(a=this.cacheToCodeFragments(r.cache(e,N)),i=a[0],s=a[1]):i=s="0",l?r instanceof Q&&r.isSimpleNumber()&&l instanceof Q&&l.isSimpleNumber()?(l=l.compile(e)-s,n||(l+=1)):(l=l.compile(e,S)+" - "+s,n||(l+=" + 1")):l="9e9",f=this.value.cache(e,T),c=f[0],h=f[1],t=[].concat(this.makeCode("[].splice.apply("+o+", ["+i+", "+l+"].concat("),c,this.makeCode(")), "),h),e.level>k?this.wrapInBraces(t):t},n}(i),e.Code=a=function(e){function t(e,t,n){this.params=e||[],this.body=t||new s,this.bound="boundfunc"===n,this.isGenerator=!!this.body.contains(function(e){var t;return e instanceof D&&("yield"===(t=e.operator)||"yield*"===t)})}return wt(t,e),t.prototype.children=["params","body"],t.prototype.isStatement=function(){return!!this.ctor},t.prototype.jumps=O,t.prototype.makeScope=function(e){return new R(e,this.body,this)},t.prototype.compileNode=function(e){var i,u,a,f,l,c,p,d,v,m,g,y,w,E,x,T,N,C,k,A,O,M,_,H,B,j,F,I,q,R,U,z,W;if(this.bound&&(null!=(_=e.scope.method)?_.bound:void 0)&&(this.context=e.scope.method.context),this.bound&&!this.context)return this.context="_this",W=new t([new P(new L(this.context))],new s([this])),u=new o(W,[new L("this")]),u.updateLocationDataIfMissing(this.locationData),u.compileNode(e);for(e.scope=tt(e,"classScope")||this.makeScope(e.scope),e.scope.shared=tt(e,"sharedScope"),e.indent+=X,delete e.bare,delete e.isExistentialEquals,k=[],f=[],H=this.params,c=0,v=H.length;v>c;c++)C=H[c],C instanceof h||e.scope.parameter(C.asReference(e));for(B=this.params,p=0,m=B.length;m>p;p++)if(C=B[p],C.splat||C instanceof h){for(j=this.params,d=0,g=j.length;g>d;d++)N=j[d],N instanceof h||!N.name.value||e.scope.add(N.name.value,"var",!0);q=new r(new Q(new n(function(){var t,n,r,i;for(r=this.params,i=[],n=0,t=r.length;t>n;n++)N=r[n],i.push(N.asReference(e));return i}.call(this))),new Q(new L("arguments")));break}for(F=this.params,T=0,y=F.length;y>T;T++)C=F[T],C.isComplex()?(U=M=C.asReference(e),C.value&&(U=new D("?",M,C.value)),f.push(new r(new Q(C.name),U,"=",{param:!0}))):(M=C,C.value&&(x=new L(M.name.value+" == null"),U=new r(new Q(C.name),C.value,"="),f.push(new b(x,U)))),q||k.push(M);for(z=this.body.isEmpty(),q&&f.unshift(q),f.length&&(I=this.body.expressions).unshift.apply(I,f),l=A=0,w=k.length;w>A;l=++A)N=k[l],k[l]=N.compileToFragments(e),e.scope.parameter(st(k[l]));for(R=[],this.eachParamName(function(e,t){return St.call(R,e)>=0&&t.error("multiple parameters named "+e),R.push(e)}),z||this.noReturn||this.body.makeReturn(),a="function",this.isGenerator&&(a+="*"),this.ctor&&(a+=" "+this.name),a+="(",i=[this.makeCode(a)],l=O=0,E=k.length;E>O;l=++O)N=k[l],l&&i.push(this.makeCode(", ")),i.push.apply(i,N);return i.push(this.makeCode(") {")),this.body.isEmpty()||(i=i.concat(this.makeCode("\n"),this.body.compileWithDeclarations(e),this.makeCode("\n"+this.tab))),i.push(this.makeCode("}")),this.ctor?[this.makeCode(this.tab)].concat(xt.call(i)):this.front||e.level>=S?this.wrapInBraces(i):i},t.prototype.eachParamName=function(e){var t,n,r,i,s;for(i=this.params,s=[],t=0,n=i.length;n>t;t++)r=i[t],s.push(r.eachName(e));return s},t.prototype.traverseChildren=function(e,n){return e?t.__super__.traverseChildren.call(this,e,n):void 0},t}(i),e.Param=P=function(e){function t(e,t,n){var r,i;this.name=e,this.value=t,this.splat=n,i=r=this.name.unwrapAll().value,St.call(q,i)>=0&&this.name.error('parameter name "'+r+'" is not allowed')}return wt(t,e),t.prototype.children=["name","value"],t.prototype.compileToFragments=function(e){return this.name.compileToFragments(e,T)},t.prototype.asReference=function(e){var t,n;return this.reference?this.reference:(n=this.name,n["this"]?(t=n.properties[0].name.value,t.reserved&&(t="_"+t),n=new L(e.scope.freeVariable(t))):n.isComplex()&&(n=new L(e.scope.freeVariable("arg"))),n=new Q(n),this.splat&&(n=new z(n)),n.updateLocationDataIfMissing(this.locationData),this.reference=n)},t.prototype.isComplex=function(){return this.name.isComplex()},t.prototype.eachName=function(e,t){var n,i,s,o,u,a;if(null==t&&(t=this.name),n=function(t){return e("@"+t.properties[0].name.value,t)},t instanceof L)return e(t.value,t);if(t instanceof Q)return n(t);for(a=t.objects,i=0,s=a.length;s>i;i++)u=a[i],u instanceof r?this.eachName(e,u.value.unwrap()):u instanceof z?(o=u.name.unwrap(),e(o.value,o)):u instanceof Q?u.isArray()||u.isObject()?this.eachName(e,u.base):u["this"]?n(u):e(u.base.value,u.base):u instanceof h||u.error("illegal parameter "+u.compile())},t}(i),e.Splat=z=function(e){function t(e){this.name=e.compile?e:new L(e)}return wt(t,e),t.prototype.children=["name"],t.prototype.isAssignable=Y,t.prototype.assigns=function(e){return this.name.assigns(e)},t.prototype.compileToFragments=function(e){return this.name.compileToFragments(e)},t.prototype.unwrap=function(){return this.name},t.compileSplattedArray=function(e,n,r){var i,s,o,u,a,f,l,c,h,p,d;for(l=-1;(d=n[++l])&&!(d instanceof t););if(l>=n.length)return[];if(1===n.length)return d=n[0],a=d.compileToFragments(e,T),r?a:[].concat(d.makeCode(bt("slice",e)+".call("),a,d.makeCode(")"));for(i=n.slice(l),f=c=0,p=i.length;p>c;f=++c)d=i[f],o=d.compileToFragments(e,T),i[f]=d instanceof t?[].concat(d.makeCode(bt("slice",e)+".call("),o,d.makeCode(")")):[].concat(d.makeCode("["),o,d.makeCode("]"));return 0===l?(d=n[0],u=d.joinFragmentArrays(i.slice(1),", "),i[0].concat(d.makeCode(".concat("),u,d.makeCode(")"))):(s=function(){var t,r,i,s;for(i=n.slice(0,l),s=[],t=0,r=i.length;r>t;t++)d=i[t],s.push(d.compileToFragments(e,T));return s}(),s=n[0].joinFragmentArrays(s,", "),u=n[l].joinFragmentArrays(i,", "),h=n[n.length-1],[].concat(n[0].makeCode("["),s,n[l].makeCode("].concat("),u,h.makeCode(")")))},t}(i),e.Expansion=h=function(e){function t(){return t.__super__.constructor.apply(this,arguments)}return wt(t,e),t.prototype.isComplex=O,t.prototype.compileNode=function(){return this.error("Expansion must be used inside a destructuring assignment or parameter list")},t.prototype.asReference=function(){return this},t.prototype.eachName=function(){},t}(i),e.While=G=function(e){function t(e,t){this.condition=(null!=t?t.invert:void 0)?e.invert():e,this.guard=null!=t?t.guard:void 0}return wt(t,e),t.prototype.children=["condition","guard","body"],t.prototype.isStatement=Y,t.prototype.makeReturn=function(e){return e?t.__super__.makeReturn.apply(this,arguments):(this.returns=!this.jumps({loop:!0}),this)},t.prototype.addBody=function(e){return this.body=e,this},t.prototype.jumps=function(){var e,t,n,r,i;if(e=this.body.expressions,!e.length)return!1;for(t=0,r=e.length;r>t;t++)if(i=e[t],n=i.jumps({loop:!0}))return n;return!1},t.prototype.compileNode=function(e){var t,n,r,i;return e.indent+=X,i="",n=this.body,n.isEmpty()?n=this.makeCode(""):(this.returns&&(n.makeReturn(r=e.scope.freeVariable("results")),i=""+this.tab+r+" = [];\n"),this.guard&&(n.expressions.length>1?n.expressions.unshift(new b((new H(this.guard)).invert(),new L("continue"))):this.guard&&(n=s.wrap([new b(this.guard,n)]))),n=[].concat(this.makeCode("\n"),n.compileToFragments(e,k),this.makeCode("\n"+this.tab))),t=[].concat(this.makeCode(i+this.tab+"while ("),this.condition.compileToFragments(e,C),this.makeCode(") {"),n,this.makeCode("}")),this.returns&&t.push(this.makeCode("\n"+this.tab+"return "+r+";")),t},t}(i),e.Op=D=function(e){function n(e,t,n,r){if("in"===e)return new w(t,n);if("do"===e)return this.generateDo(t);if("new"===e){if(t instanceof o&&!t["do"]&&!t.isNew)return t.newInstance();(t instanceof a&&t.bound||t["do"])&&(t=new H(t))}return this.operator=i[e]||e,this.first=t,this.second=n,this.flip=!!r,this}var i,s;return wt(n,e),i={"==":"===","!=":"!==",of:"in",yieldfrom:"yield*"},s={"!==":"===","===":"!=="},n.prototype.children=["first","second"],n.prototype.isSimpleNumber=O,n.prototype.isYield=function(){var e;return"yield"===(e=this.operator)||"yield*"===e},n.prototype.isYieldReturn=function(){return this.isYield()&&this.first instanceof F},n.prototype.isUnary=function(){return!this.second},n.prototype.isComplex=function(){var e;return!(this.isUnary()&&("+"===(e=this.operator)||"-"===e)&&this.first instanceof Q&&this.first.isSimpleNumber())},n.prototype.isChainable=function(){var e;return"<"===(e=this.operator)||">"===e||">="===e||"<="===e||"==="===e||"!=="===e},n.prototype.invert=function(){var e,t,r,i,o;if(this.isChainable()&&this.first.isChainable()){for(e=!0,t=this;t&&t.operator;)e&&(e=t.operator in s),t=t.first;if(!e)return(new H(this)).invert();for(t=this;t&&t.operator;)t.invert=!t.invert,t.operator=s[t.operator],t=t.first;return this}return(i=s[this.operator])?(this.operator=i,this.first.unwrap()instanceof n&&this.first.invert(),this):this.second?(new H(this)).invert():"!"===this.operator&&(r=this.first.unwrap())instanceof n&&("!"===(o=r.operator)||"in"===o||"instanceof"===o)?r:new n("!",this)},n.prototype.unfoldSoak=function(e){var t;return("++"===(t=this.operator)||"--"===t||"delete"===t)&&yt(e,this,"first")},n.prototype.generateDo=function(e){var t,n,i,s,u,f,l,c;for(f=[],n=e instanceof r&&(l=e.value.unwrap())instanceof a?l:e,c=n.params||[],i=0,s=c.length;s>i;i++)u=c[i],u.value?(f.push(u.value),delete u.value):f.push(u);return t=new o(e,f),t["do"]=!0,t},n.prototype.compileNode=function(e){var t,n,r,i,s,o;if(n=this.isChainable()&&this.first.isChainable(),n||(this.first.front=this.front),"delete"===this.operator&&e.scope.check(this.first.unwrapAll().value)&&this.error("delete operand may not be argument or var"),("--"===(i=this.operator)||"++"===i)&&(s=this.first.unwrapAll().value,St.call(q,s)>=0)&&this.error('cannot increment/decrement "'+this.first.unwrapAll().value+'"'),this.isYield())return this.compileYield(e);if(this.isUnary())return this.compileUnary(e);if(n)return this.compileChain(e);switch(this.operator){case"?":return this.compileExistence(e);case"**":return this.compilePower(e);case"//":return this.compileFloorDivision(e);case"%%":return this.compileModulo(e);default:return r=this.first.compileToFragments(e,N),o=this.second.compileToFragments(e,N),t=[].concat(r,this.makeCode(" "+this.operator+" "),o),N>=e.level?t:this.wrapInBraces(t)}},n.prototype.compileChain=function(e){var t,n,r,i;return r=this.first.second.cache(e),this.first.second=r[0],i=r[1],n=this.first.compileToFragments(e,N),t=n.concat(this.makeCode(" "+(this.invert?"&&":"||")+" "),i.compileToFragments(e),this.makeCode(" "+this.operator+" "),this.second.compileToFragments(e,N)),this.wrapInBraces(t)},n.prototype.compileExistence=function(e){var t,n;return this.first.isComplex()?(n=new L(e.scope.freeVariable("ref")),t=new H(new r(n,this.first))):(t=this.first,n=t),(new b(new c(t),n,{type:"if"})).addElse(this.second).compileToFragments(e)},n.prototype.compileUnary=function(e){var t,r,i;return r=[],t=this.operator,r.push([this.makeCode(t)]),"!"===t&&this.first instanceof c?(this.first.negated=!this.first.negated,this.first.compileToFragments(e)):e.level>=S?(new H(this)).compileToFragments(e):(i="+"===t||"-"===t,("new"===t||"typeof"===t||"delete"===t||i&&this.first instanceof n&&this.first.operator===t)&&r.push([this.makeCode(" ")]),(i&&this.first instanceof n||"new"===t&&this.first.isStatement(e))&&(this.first=new H(this.first)),r.push(this.first.compileToFragments(e,N)),this.flip&&r.reverse(),this.joinFragmentArrays(r,""))},n.prototype.compileYield=function(e){var t,n;return n=[],t=this.operator,null==e.scope.parent&&this.error("yield statements must occur within a function generator."),St.call(Object.keys(this.first),"expression")>=0&&!(this.first instanceof $)?this.isYieldReturn()?n.push(this.first.compileToFragments(e,k)):null!=this.first.expression&&n.push(this.first.expression.compileToFragments(e,N)):(n.push([this.makeCode("("+t+" ")]),n.push(this.first.compileToFragments(e,N)),n.push([this.makeCode(")")])),this.joinFragmentArrays(n,"")},n.prototype.compilePower=function(e){var n;return n=new Q(new L("Math"),[new t(new L("pow"))]),(new o(n,[this.first,this.second])).compileToFragments(e)},n.prototype.compileFloorDivision=function(e){var r,i;return i=new Q(new L("Math"),[new t(new L("floor"))]),r=new n("/",this.first,this.second),(new o(i,[r])).compileToFragments(e)},n.prototype.compileModulo=function(e){var t;return t=new Q(new L(bt("modulo",e))),(new o(t,[this.first,this.second])).compileToFragments(e)},n.prototype.toString=function(e){return n.__super__.toString.call(this,e,this.constructor.name+" "+this.operator)},n}(i),e.In=w=function(e){function t(e,t){this.object=e,this.array=t}return wt(t,e),t.prototype.children=["object","array"],t.prototype.invert=A,t.prototype.compileNode=function(e){var t,n,r,i,s;if(this.array instanceof Q&&this.array.isArray()&&this.array.base.objects.length){for(s=this.array.base.objects,n=0,r=s.length;r>n;n++)if(i=s[n],i instanceof z){t=!0;break}if(!t)return this.compileOrTest(e)}return this.compileLoopTest(e)},t.prototype.compileOrTest=function(e){var t,n,r,i,s,o,u,a,f,l,c,h;for(a=this.object.cache(e,N),c=a[0],u=a[1],f=this.negated?[" !== "," && "]:[" === "," || "],t=f[0],n=f[1],h=[],l=this.array.base.objects,r=s=0,o=l.length;o>s;r=++s)i=l[r],r&&h.push(this.makeCode(n)),h=h.concat(r?u:c,this.makeCode(t),i.compileToFragments(e,S));return N>e.level?h:this.wrapInBraces(h)},t.prototype.compileLoopTest=function(e){var t,n,r,i;return r=this.object.cache(e,T),i=r[0],n=r[1],t=[].concat(this.makeCode(bt("indexOf",e)+".call("),this.array.compileToFragments(e,T),this.makeCode(", "),n,this.makeCode(") "+(this.negated?"< 0":">= 0"))),st(i)===st(n)?t:(t=i.concat(this.makeCode(", "),t),T>e.level?t:this.wrapInBraces(t))},t.prototype.toString=function(e){return t.__super__.toString.call(this,e,this.constructor.name+(this.negated?"!":""))},t}(i),e.Try=J=function(e){function t(e,t,n,r){this.attempt=e,this.errorVariable=t,this.recovery=n,this.ensure=r}return wt(t,e),t.prototype.children=["attempt","recovery","ensure"],t.prototype.isStatement=Y,t.prototype.jumps=function(e){var t;return this.attempt.jumps(e)||(null!=(t=this.recovery)?t.jumps(e):void 0)},t.prototype.makeReturn=function(e){return this.attempt&&(this.attempt=this.attempt.makeReturn(e)),this.recovery&&(this.recovery=this.recovery.makeReturn(e)),this},t.prototype.compileNode=function(e){var t,n,i,s;return e.indent+=X,s=this.attempt.compileToFragments(e,k),t=this.recovery?(i=new L("_error"),this.errorVariable?this.recovery.unshift(new r(this.errorVariable,i)):void 0,[].concat(this.makeCode(" catch ("),i.compileToFragments(e),this.makeCode(") {\n"),this.recovery.compileToFragments(e,k),this.makeCode("\n"+this.tab+"}"))):this.ensure||this.recovery?[]:[this.makeCode(" catch (_error) {}")],n=this.ensure?[].concat(this.makeCode(" finally {\n"),this.ensure.compileToFragments(e,k),this.makeCode("\n"+this.tab+"}")):[],[].concat(this.makeCode(this.tab+"try {\n"),s,this.makeCode("\n"+this.tab+"}"),t,n)},t}(i),e.Throw=$=function(e){function t(e){this.expression=e}return wt(t,e),t.prototype.children=["expression"],t.prototype.isStatement=Y,t.prototype.jumps=O,t.prototype.makeReturn=V,t.prototype.compileNode=function(e){return[].concat(this.makeCode(this.tab+"throw "),this.expression.compileToFragments(e),this.makeCode(";"))},t}(i),e.Existence=c=function(e){function t(e){this.expression=e}return wt(t,e),t.prototype.children=["expression"],t.prototype.invert=A,t.prototype.compileNode=function(e){var t,n,r,i;return this.expression.front=this.front,r=this.expression.compile(e,N),m.test(r)&&!e.scope.check(r)?(i=this.negated?["===","||"]:["!==","&&"],t=i[0],n=i[1],r="typeof "+r+" "+t+' "undefined" '+n+" "+r+" "+t+" null"):r=r+" "+(this.negated?"==":"!=")+" null",[this.makeCode(x>=e.level?r:"("+r+")")]},t}(i),e.Parens=H=function(e){function t(e){this.body=e}return wt(t,e),t.prototype.children=["body"],t.prototype.unwrap=function(){return this.body},t.prototype.isComplex=function(){return this.body.isComplex()},t.prototype.compileNode=function(e){var t,n,r;return n=this.body.unwrap(),n instanceof Q&&n.isAtomic()?(n.front=this.front,n.compileToFragments(e)):(r=n.compileToFragments(e,C),t=N>e.level&&(n instanceof D||n instanceof o||n instanceof d&&n.returns),t?r:this.wrapInBraces(r))},t}(i),e.For=d=function(e){function t(e,t){var n;this.source=t.source,this.guard=t.guard,this.step=t.step,this.name=t.name,this.index=t.index,this.body=s.wrap([e]),this.own=!!t.own,this.object=!!t.object,this.object&&(n=[this.index,this.name],this.name=n[0],this.index=n[1]),this.index instanceof Q&&this.index.error("index cannot be a pattern matching expression"),this.range=this.source instanceof Q&&this.source.base instanceof j&&!this.source.properties.length,this.pattern=this.name instanceof Q,this.range&&this.index&&this.index.error("indexes do not apply to range loops"),this.range&&this.pattern&&this.name.error("cannot pattern match over range loops"),this.own&&!this.object&&this.name.error("cannot use own with for-in"),this.returns=!1}return wt(t,e),t.prototype.children=["body","source","guard","step"],t.prototype.compileNode=function(e){var t,n,i,o,u,a,f,l,c,h,p,d,v,g,y,w,E,S,x,N,C,A,O,_,D,P,B,j,I,q,R,U,z,W;return t=s.wrap([this.body]),O=t.expressions,S=O[O.length-1],(null!=S?S.jumps():void 0)instanceof F&&(this.returns=!1),I=this.range?this.source.base:this.source,j=e.scope,this.pattern||(N=this.name&&this.name.compile(e,T)),g=this.index&&this.index.compile(e,T),N&&!this.pattern&&j.find(N),g&&j.find(g),this.returns&&(B=j.freeVariable("results")),y=this.object&&g||j.freeVariable("i",{single:!0}),w=this.range&&N||g||y,E=w!==y?w+" = ":"",this.step&&!this.range&&(_=this.cacheToCodeFragments(this.step.cache(e,T,ot)),q=_[0],U=_[1],R=U.match(M)),this.pattern&&(N=y),W="",p="",f="",d=this.tab+X,this.range?h=I.compileToFragments(lt(e,{index:y,name:N,step:this.step,isComplex:ot})):(z=this.source.compile(e,T),!N&&!this.own||m.test(z)||(f+=""+this.tab+(A=j.freeVariable("ref"))+" = "+z+";\n",z=A),N&&!this.pattern&&(C=N+" = "+z+"["+w+"]"),this.object||(q!==U&&(f+=""+this.tab+q+";\n"),this.step&&R&&(c=0>ht(R[0]))||(x=j.freeVariable("len")),u=""+E+y+" = 0, "+x+" = "+z+".length",a=""+E+y+" = "+z+".length - 1",i=y+" < "+x,o=y+" >= 0",this.step?(R?c&&(i=o,u=a):(i=U+" > 0 ? "+i+" : "+o,u="("+U+" > 0 ? ("+u+") : "+a+")"),v=y+" += "+U):v=""+(w!==y?"++"+y:y+"++"),h=[this.makeCode(u+"; "+i+"; "+E+v)])),this.returns&&(D=""+this.tab+B+" = [];\n",P="\n"+this.tab+"return "+B+";",t.makeReturn(B)),this.guard&&(t.expressions.length>1?t.expressions.unshift(new b((new H(this.guard)).invert(),new L("continue"))):this.guard&&(t=s.wrap([new b(this.guard,t)]))),this.pattern&&t.expressions.unshift(new r(this.name,new L(z+"["+w+"]"))),l=[].concat(this.makeCode(f),this.pluckDirectCall(e,t)),C&&(W="\n"+d+C+";"),this.object&&(h=[this.makeCode(w+" in "+z)],this.own&&(p="\n"+d+"if (!"+bt("hasProp",e)+".call("+z+", "+w+")) continue;")),n=t.compileToFragments(lt(e,{indent:d}),k),n&&n.length>0&&(n=[].concat(this.makeCode("\n"),n,this.makeCode("\n"))),[].concat(l,this.makeCode(""+(D||"")+this.tab+"for ("),h,this.makeCode(") {"+p+W),n,this.makeCode(this.tab+"}"+(P||"")))},t.prototype.pluckDirectCall=function(e,t){var n,i,s,u,f,l,c,h,p,d,v,m,g,y,b,w;for(i=[],p=t.expressions,f=l=0,c=p.length;c>l;f=++l)s=p[f],s=s.unwrapAll(),s instanceof o&&(w=null!=(d=s.variable)?d.unwrapAll():void 0,(w instanceof a||w instanceof Q&&(null!=(v=w.base)?v.unwrapAll():void 0)instanceof a&&1===w.properties.length&&("call"===(m=null!=(g=w.properties[0].name)?g.value:void 0)||"apply"===m))&&(u=(null!=(y=w.base)?y.unwrapAll():void 0)||w,h=new L(e.scope.freeVariable("fn")),n=new Q(h),w.base&&(b=[n,w],w.base=b[0],n=b[1]),t.expressions[f]=new o(n,s.args),i=i.concat(this.makeCode(this.tab),(new r(h,u)).compileToFragments(e,k),this.makeCode(";\n"))));return i},t}(G),e.Switch=W=function(e){function t(e,t,n){this.subject=e,this.cases=t,this.otherwise=n}return wt(t,e),t.prototype.children=["subject","cases","otherwise"],t.prototype.isStatement=Y,t.prototype.jumps=function(e){var t,n,r,i,s,o,u,a;for(null==e&&(e={block:!0}),o=this.cases,r=0,s=o.length;s>r;r++)if(u=o[r],n=u[0],t=u[1],i=t.jumps(e))return i;return null!=(a=this.otherwise)?a.jumps(e):void 0},t.prototype.makeReturn=function(e){var t,n,r,i,o;for(i=this.cases,t=0,n=i.length;n>t;t++)r=i[t],r[1].makeReturn(e);return e&&(this.otherwise||(this.otherwise=new s([new L("void 0")]))),null!=(o=this.otherwise)&&o.makeReturn(e),this},t.prototype.compileNode=function(e){var t,n,r,i,s,o,u,a,f,l,c,h,p,d,v,m;for(a=e.indent+X,f=e.indent=a+X,o=[].concat(this.makeCode(this.tab+"switch ("),this.subject?this.subject.compileToFragments(e,C):this.makeCode("false"),this.makeCode(") {\n")),d=this.cases,u=l=0,h=d.length;h>l;u=++l){for(v=d[u],i=v[0],t=v[1],m=it([i]),c=0,p=m.length;p>c;c++)r=m[c],this.subject||(r=r.invert()),o=o.concat(this.makeCode(a+"case "),r.compileToFragments(e,C),this.makeCode(":\n"));if((n=t.compileToFragments(e,k)).length>0&&(o=o.concat(n,this.makeCode("\n"))),u===this.cases.length-1&&!this.otherwise)break;s=this.lastNonComment(t.expressions),s instanceof F||s instanceof L&&s.jumps()&&"debugger"!==s.value||o.push(r.makeCode(f+"break;\n"))}return this.otherwise&&this.otherwise.expressions.length&&o.push.apply(o,[this.makeCode(a+"default:\n")].concat(xt.call(this.otherwise.compileToFragments(e,k)),[this.makeCode("\n")])),o.push(this.makeCode(this.tab+"}")),o},t}(i),e.If=b=function(e){function t(e,t,n){this.body=t,null==n&&(n={}),this.condition="unless"===n.type?e.invert():e,this.elseBody=null,this.isChain=!1,this.soak=n.soak}return wt(t,e),t.prototype.children=["condition","body","elseBody"],t.prototype.bodyNode=function(){var e;return null!=(e=this.body)?e.unwrap():void 0},t.prototype.elseBodyNode=function(){var e;return null!=(e=this.elseBody)?e.unwrap():void 0},t.prototype.addElse=function(e){return this.isChain?this.elseBodyNode().addElse(e):(this.isChain=e instanceof t,this.elseBody=this.ensureBlock(e),this.elseBody.updateLocationDataIfMissing(e.locationData)),this},t.prototype.isStatement=function(e){var t;return(null!=e?e.level:void 0)===k||this.bodyNode().isStatement(e)||(null!=(t=this.elseBodyNode())?t.isStatement(e):void 0)},t.prototype.jumps=function(e){var t;return this.body.jumps(e)||(null!=(t=this.elseBody)?t.jumps(e):void 0)},t.prototype.compileNode=function(e){return this.isStatement(e)?this.compileStatement(e):this.compileExpression(e)},t.prototype.makeReturn=function(e){return e&&(this.elseBody||(this.elseBody=new s([new L("void 0")]))),this.body&&(this.body=new s([this.body.makeReturn(e)])),this.elseBody&&(this.elseBody=new s([this.elseBody.makeReturn(e)])),this},t.prototype.ensureBlock=function(e){return e instanceof s?e:new s([e])},t.prototype.compileStatement=function(e){var n,r,i,s,o,u,a;return i=tt(e,"chainChild"),(o=tt(e,"isExistentialEquals"))?(new t(this.condition.invert(),this.elseBodyNode(),{type:"if"})).compileToFragments(e):(a=e.indent+X,s=this.condition.compileToFragments(e,C),r=this.ensureBlock(this.body).compileToFragments(lt(e,{indent:a})),u=[].concat(this.makeCode("if ("),s,this.makeCode(") {\n"),r,this.makeCode("\n"+this.tab+"}")),i||u.unshift(this.makeCode(this.tab)),this.elseBody?(n=u.concat(this.makeCode(" else ")),this.isChain?(e.chainChild=!0,n=n.concat(this.elseBody.unwrap().compileToFragments(e,k))):n=n.concat(this.makeCode("{\n"),this.elseBody.compileToFragments(lt(e,{indent:a}),k),this.makeCode("\n"+this.tab+"}")),n):u)},t.prototype.compileExpression=function(e){var t,n,r,i;return r=this.condition.compileToFragments(e,x),n=this.bodyNode().compileToFragments(e,T),t=this.elseBodyNode()?this.elseBodyNode().compileToFragments(e,T):[this.makeCode("void 0")],i=r.concat(this.makeCode(" ? "),n,this.makeCode(" : "),t),e.level>=x?this.wrapInBraces(i):i},t.prototype.unfoldSoak=function(){return this.soak&&this},t}(i),K={extend:function(e){return"function(child, parent) { for (var key in parent) { if ("+bt("hasProp",e)+".call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }"},bind:function(){return"function(fn, me){ return function(){ return fn.apply(me, arguments); }; }"},indexOf:function(){return"[].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }"},modulo:function(){return"function(a, b) { return (+a % (b = +b) + b) % b; }"},hasProp:function(){return"{}.hasOwnProperty"},slice:function(){return"[].slice"}},k=1,C=2,T=3,x=4,N=5,S=6,X="  ",m=/^(?!\d)[$\w\x7f-\uffff]+$/,I=/^[+-]?\d+$/,v=/^[+-]?0x[\da-f]+/i,M=/^[+-]?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)$/i,y=/^['"]/,g=/^\//,bt=function(e,t){var n,r;return r=t.scope.root,e in r.utilities?r.utilities[e]:(n=r.freeVariable(e),r.assign(n,K[e](t)),r.utilities[e]=n)},ct=function(e,t){return e=e.replace(/\n/g,"$&"+t),e.replace(/\s+$/,"")},ht=function(e){return null==e?0:e.match(v)?parseInt(e,16):parseFloat(e)},ut=function(e){return e instanceof L&&"arguments"===e.value&&!e.asKey},at=function(e){return e instanceof L&&"this"===e.value&&!e.asKey||e instanceof a&&e.bound||e instanceof o&&e.isSuper},ot=function(e){return e.isComplex()||("function"==typeof e.isAssignable?e.isAssignable():void 0)},yt=function(e,t,n){var r;if(r=t[n].unfoldSoak(e))return t[n]=r.body,r.body=new Q(t),r}}.call(this),t.exports}(),_dereq_["./sourcemap"]=function(){var e={},t={exports:e};return function(){var e,n;e=function(){function e(e){this.line=e,this.columns=[]}return e.prototype.add=function(e,t,n){var r,i;return i=t[0],r=t[1],null==n&&(n={}),this.columns[e]&&n.noReplace?void 0:this.columns[e]={line:this.line,column:e,sourceLine:i,sourceColumn:r}},e.prototype.sourceLocation=function(e){for(var t;!((t=this.columns[e])||0>=e);)e--;return t&&[t.sourceLine,t.sourceColumn]},e}(),n=function(){function t(){this.lines=[]}var n,r,i,s;return t.prototype.add=function(t,n,r){var i,s,o,u;return null==r&&(r={}),o=n[0],s=n[1],u=(i=this.lines)[o]||(i[o]=new e(o)),u.add(s,t,r)},t.prototype.sourceLocation=function(e){var t,n,r;for(n=e[0],t=e[1];!((r=this.lines[n])||0>=n);)n--;return r&&r.sourceLocation(t)},t.prototype.generate=function(e,t){var n,r,i,s,o,u,a,f,l,c,h,p,d,v,m,g;for(null==e&&(e={}),null==t&&(t=null),g=0,s=0,u=0,o=0,p=!1,n="",d=this.lines,c=r=0,a=d.length;a>r;c=++r)if(l=d[c])for(v=l.columns,i=0,f=v.length;f>i;i++)if(h=v[i]){for(;h.line>g;)s=0,p=!1,n+=";",g++;p&&(n+=",",p=!1),n+=this.encodeVlq(h.column-s),s=h.column,n+=this.encodeVlq(0),n+=this.encodeVlq(h.sourceLine-u),u=h.sourceLine,n+=this.encodeVlq(h.sourceColumn-o),o=h.sourceColumn,p=!0}return m={version:3,file:e.generatedFile||"",sourceRoot:e.sourceRoot||"",sources:e.sourceFiles||[""],names:[],mappings:n},e.inline&&(m.sourcesContent=[t]),JSON.stringify(m,null,2)},i=5,r=1<<i,s=r-1,t.prototype.encodeVlq=function(e){var t,n,o,u;for(t="",o=0>e?1:0,u=(Math.abs(e)<<1)+o;u||!t;)n=u&s,u>>=i,u&&(n|=r),t+=this.encodeBase64(n);return t},n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",t.prototype.encodeBase64=function(e){return n[e]||function(){throw Error("Cannot Base64 encode value: "+e)}()},t}(),t.exports=n}.call(this),t.exports}(),_dereq_["./coffee-script"]=function(){var e={},t={exports:e};return function(){var t,n,r,i,s,o,u,a,f,l,c,h,p,d,v,m,g,y,b={}.hasOwnProperty,w=[].indexOf||function(e){for(var t=0,n=this.length;n>t;t++)if(t in this&&this[t]===e)return t;return-1};if(u=_dereq_("fs"),g=_dereq_("vm"),d=_dereq_("path"),t=_dereq_("./lexer").Lexer,p=_dereq_("./parser").parser,f=_dereq_("./helpers"),n=_dereq_("./sourcemap"),e.VERSION="1.9.3",e.FILE_EXTENSIONS=[".coffee",".litcoffee",".coffee.md"],e.helpers=f,y=function(e){return function(t,n){var r;null==n&&(n={});try{return e.call(this,t,n)}catch(i){throw(r=i,"string"!=typeof t)?r:f.updateSyntaxError(r,t,n.filename)}}},e.compile=i=y(function(e,t){var r,i,s,o,u,a,l,c,d,v,m,g,y,b,w;for(g=f.merge,o=f.extend,t=o({},t),t.sourceMap&&(m=new n),w=h.tokenize(e,t),t.referencedVars=function(){var e,t,n;for(n=[],e=0,t=w.length;t>e;e++)b=w[e],b.variable&&n.push(b[1]);return n}(),a=p.parse(w).compileToFragments(t),s=0,t.header&&(s+=1),t.shiftLine&&(s+=1),i=0,d="",c=0,v=a.length;v>c;c++)u=a[c],t.sourceMap&&(u.locationData&&!/^[;\s]*$/.test(u.code)&&m.add([u.locationData.first_line,u.locationData.first_column],[s,i],{noReplace:!0}),y=f.count(u.code,"\n"),s+=y,y?i=u.code.length-(u.code.lastIndexOf("\n")+1):i+=u.code.length),d+=u.code;return t.header&&(l="Generated by CoffeeScript "+this.VERSION,d="// "+l+"\n"+d),t.sourceMap?(r={js:d},r.sourceMap=m,r.v3SourceMap=m.generate(t,e),r):d}),e.tokens=y(function(e,t){return h.tokenize(e,t)}),e.nodes=y(function(e,t){return"string"==typeof e?p.parse(h.tokenize(e,t)):p.parse(e)}),e.run=function(e,t){var n,r,s,o;return null==t&&(t={}),s=_dereq_.main,s.filename=process.argv[1]=t.filename?u.realpathSync(t.filename):".",s.moduleCache&&(s.moduleCache={}),r=t.filename?d.dirname(u.realpathSync(t.filename)):u.realpathSync("."),s.paths=_dereq_("module")._nodeModulePaths(r),(!f.isCoffee(s.filename)||_dereq_.extensions)&&(n=i(e,t),e=null!=(o=n.js)?o:n),s._compile(e,s.filename)},e.eval=function(e,t){var n,r,s,o,u,a,f,l,c,h,p,v,m,y,w,E,S;if(null==t&&(t={}),e=e.trim()){if(o=null!=(v=g.Script.createContext)?v:g.createContext,a=null!=(m=g.isContext)?m:function(){return t.sandbox instanceof o().constructor},o){if(null!=t.sandbox){if(a(t.sandbox))E=t.sandbox;else{E=o(),y=t.sandbox;for(l in y)b.call(y,l)&&(S=y[l],E[l]=S)}E.global=E.root=E.GLOBAL=E}else E=global;if(E.__filename=t.filename||"eval",E.__dirname=d.dirname(E.__filename),E===global&&!E.module&&!E.require){for(n=_dereq_("module"),E.module=r=new n(t.modulename||"eval"),E.require=s=function(e){return n._load(e,r,!0)},r.filename=E.__filename,w=Object.getOwnPropertyNames(_dereq_),u=0,c=w.length;c>u;u++)p=w[u],"paths"!==p&&(s[p]=_dereq_[p]);s.paths=r.paths=n._nodeModulePaths(process.cwd()),s.resolve=function(e){return n._resolveFilename(e,r)}}}h={};for(l in t)b.call(t,l)&&(S=t[l],h[l]=S);return h.bare=!0,f=i(e,h),E===global?g.runInThisContext(f):g.runInContext(f,E)}},e.register=function(){return _dereq_("./register")},_dereq_.extensions)for(v=this.FILE_EXTENSIONS,l=0,c=v.length;c>l;l++)s=v[l],null==(r=_dereq_.extensions)[s]&&(r[s]=function(){throw Error("Use CoffeeScript.register() or require the coffee-script/register module to require "+s+" files.")});e._compileFile=function(e,t){var n,r,s,o;null==t&&(t=!1),s=u.readFileSync(e,"utf8"),o=65279===s.charCodeAt(0)?s.substring(1):s;try{n=i(o,{filename:e,sourceMap:t,literate:f.isLiterate(e)})}catch(a){throw r=a,f.updateSyntaxError(r,o,e)}return n},h=new t,p.lexer={lex:function(){var e,t;return t=p.tokens[this.pos++],t?(e=t[0],this.yytext=t[1],this.yylloc=t[2],p.errorToken=t.origin||t,this.yylineno=this.yylloc.first_line):e="",e},setInput:function(e){return p.tokens=e,this.pos=0},upcomingInput:function(){return""}},p.yy=_dereq_("./nodes"),p.yy.parseError=function(e,t){var n,r,i,s,o,u;return o=t.token,s=p.errorToken,u=p.tokens,r=s[0],i=s[1],n=s[2],i=function(){switch(!1){case s!==u[u.length-1]:return"end of input";case"INDENT"!==r&&"OUTDENT"!==r:return"indentation";case"IDENTIFIER"!==r&&"NUMBER"!==r&&"STRING"!==r&&"STRING_START"!==r&&"REGEX"!==r&&"REGEX_START"!==r:return r.replace(/_START$/,"").toLowerCase();default:return f.nameWhitespaceCharacter(i)}}(),f.throwSyntaxError("unexpected "+i,n)},o=function(e,t){var n,r,i,s,o,u,a,f,l,c,h,p;return s=void 0,i="",e.isNative()?i="native":(e.isEval()?(s=e.getScriptNameOrSourceURL(),s||(i=e.getEvalOrigin()+", ")):s=e.getFileName(),s||(s="<anonymous>"),f=e.getLineNumber(),r=e.getColumnNumber(),c=t(s,f,r),i=c?s+":"+c[0]+":"+c[1]:s+":"+f+":"+r),o=e.getFunctionName(),u=e.isConstructor(),a=!e.isToplevel()&&!u,a?(l=e.getMethodName(),p=e.getTypeName(),o?(h=n="",p&&o.indexOf(p)&&(h=p+"."),l&&o.indexOf("."+l)!==o.length-l.length-1&&(n=" [as "+l+"]"),""+h+o+n+" ("+i+")"):p+"."+(l||"<anonymous>")+" ("+i+")"):u?"new "+(o||"<anonymous>")+" ("+i+")":o?o+" ("+i+")":i},m={},a=function(t){var n,r;if(m[t])return m[t];if(r=null!=d?d.extname(t):void 0,!(0>w.call(e.FILE_EXTENSIONS,r)))return n=e._compileFile(t,!0),m[t]=n.sourceMap},Error.prepareStackTrace=function(t,n){var r,i,s;return s=function(e,t,n){var r,i;return i=a(e),i&&(r=i.sourceLocation([t-1,n-1])),r?[r[0]+1,r[1]+1]:null},i=function(){var t,i,u;for(u=[],t=0,i=n.length;i>t&&(r=n[t],r.getFunction()!==e.run);t++)u.push("  at "+o(r,s));return u}(),""+t+"\n"+i.join("\n")+"\n"}}.call(this),t.exports}(),_dereq_["./browser"]=function(){var exports={},module={exports:exports};return function(){var CoffeeScript,compile,runScripts,indexOf=[].indexOf||function(e){for(var t=0,n=this.length;n>t;t++)if(t in this&&this[t]===e)return t;return-1};CoffeeScript=_dereq_("./coffee-script"),CoffeeScript.require=_dereq_,compile=CoffeeScript.compile,CoffeeScript.eval=function(code,options){return null==options&&(options={}),null==options.bare&&(options.bare=!0),eval(compile(code,options))},CoffeeScript.run=function(e,t){return null==t&&(t={}),t.bare=!0,t.shiftLine=!0,Function(compile(e,t))()},"undefined"!=typeof window&&null!==window&&("undefined"!=typeof btoa&&null!==btoa&&"undefined"!=typeof JSON&&null!==JSON&&"undefined"!=typeof unescape&&null!==unescape&&"undefined"!=typeof encodeURIComponent&&null!==encodeURIComponent&&(compile=function(e,t){var n,r,i;return null==t&&(t={}),t.sourceMap=!0,t.inline=!0,r=CoffeeScript.compile(e,t),n=r.js,i=r.v3SourceMap,n+"\n//# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(i)))+"\n//# sourceURL=coffeescript"}),CoffeeScript.load=function(e,t,n,r){var i;return null==n&&(n={}),null==r&&(r=!1),n.sourceFiles=[e],i=window.ActiveXObject?new window.ActiveXObject("Microsoft.XMLHTTP"):new window.XMLHttpRequest,i.open("GET",e,!0),"overrideMimeType"in i&&i.overrideMimeType("text/plain"),i.onreadystatechange=function(){var s,o;if(4===i.readyState){if(0!==(o=i.status)&&200!==o)throw Error("Could not load "+e);if(s=[i.responseText,n],r||CoffeeScript.run.apply(CoffeeScript,s),t)return t(s)}},i.send(null)},runScripts=function(){var e,t,n,r,i,s,o,u,a,f,l;for(l=window.document.getElementsByTagName("script"),t=["text/coffeescript","text/literate-coffeescript"],e=function(){var e,n,r,i;for(i=[],e=0,n=l.length;n>e;e++)a=l[e],r=a.type,indexOf.call(t,r)>=0&&i.push(a);return i}(),s=0,n=function(){var t;return t=e[s],t instanceof Array?(CoffeeScript.run.apply(CoffeeScript,t),s++,n()):void 0},r=function(r,i){var s,o;return s={literate:r.type===t[1]},o=r.src||r.getAttribute("data-src"),o?CoffeeScript.load(o,function(t){return e[i]=t,n()},s,!0):(s.sourceFiles=["embedded"],e[i]=[r.innerHTML,s])},i=o=0,u=e.length;u>o;i=++o)f=e[i],r(f,i);return n()},window.addEventListener?window.addEventListener("DOMContentLoaded",runScripts,!1):window.attachEvent("onload",runScripts))}.call(this),module.exports}(),_dereq_["./coffee-script"]}();"function"==typeof define&&define.amd?define(function(){return CoffeeScript}):root.CoffeeScript=CoffeeScript}(this)}),ace.define("ace/mode/coffee_worker",["require","exports","module","ace/lib/oop","ace/worker/mirror","ace/mode/coffee/coffee"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../worker/mirror").Mirror,s=e("../mode/coffee/coffee");window.addEventListener=function(){};var o=t.Worker=function(e){i.call(this,e),this.setTimeout(250)};r.inherits(o,i),function(){this.onUpdate=function(){var e=this.doc.getValue(),t=[];try{s.compile(e)}catch(n){var r=n.location;r&&t.push({row:r.first_line,column:r.first_column,endRow:r.last_line,endColumn:r.last_column,text:n.message,type:"error"})}this.sender.emit("annotate",t)}}.call(o.prototype)}),ace.define("ace/lib/es5-shim",["require","exports","module"],function(e,t,n){function r(){}function w(e){try{return Object.defineProperty(e,"sentinel",{}),"sentinel"in e}catch(t){}}function H(e){return e=+e,e!==e?e=0:e!==0&&e!==1/0&&e!==-1/0&&(e=(e>0||-1)*Math.floor(Math.abs(e))),e}function B(e){var t=typeof e;return e===null||t==="undefined"||t==="boolean"||t==="number"||t==="string"}function j(e){var t,n,r;if(B(e))return e;n=e.valueOf;if(typeof n=="function"){t=n.call(e);if(B(t))return t}r=e.toString;if(typeof r=="function"){t=r.call(e);if(B(t))return t}throw new TypeError}Function.prototype.bind||(Function.prototype.bind=function(t){var n=this;if(typeof n!="function")throw new TypeError("Function.prototype.bind called on incompatible "+n);var i=u.call(arguments,1),s=function(){if(this instanceof s){var e=n.apply(this,i.concat(u.call(arguments)));return Object(e)===e?e:this}return n.apply(t,i.concat(u.call(arguments)))};return n.prototype&&(r.prototype=n.prototype,s.prototype=new r,r.prototype=null),s});var i=Function.prototype.call,s=Array.prototype,o=Object.prototype,u=s.slice,a=i.bind(o.toString),f=i.bind(o.hasOwnProperty),l,c,h,p,d;if(d=f(o,"__defineGetter__"))l=i.bind(o.__defineGetter__),c=i.bind(o.__defineSetter__),h=i.bind(o.__lookupGetter__),p=i.bind(o.__lookupSetter__);if([1,2].splice(0).length!=2)if(!function(){function e(e){var t=new Array(e+2);return t[0]=t[1]=0,t}var t=[],n;t.splice.apply(t,e(20)),t.splice.apply(t,e(26)),n=t.length,t.splice(5,0,"XXX"),n+1==t.length;if(n+1==t.length)return!0}())Array.prototype.splice=function(e,t){var n=this.length;e>0?e>n&&(e=n):e==void 0?e=0:e<0&&(e=Math.max(n+e,0)),e+t<n||(t=n-e);var r=this.slice(e,e+t),i=u.call(arguments,2),s=i.length;if(e===n)s&&this.push.apply(this,i);else{var o=Math.min(t,n-e),a=e+o,f=a+s-o,l=n-a,c=n-o;if(f<a)for(var h=0;h<l;++h)this[f+h]=this[a+h];else if(f>a)for(h=l;h--;)this[f+h]=this[a+h];if(s&&e===c)this.length=c,this.push.apply(this,i);else{this.length=c+s;for(h=0;h<s;++h)this[e+h]=i[h]}}return r};else{var v=Array.prototype.splice;Array.prototype.splice=function(e,t){return arguments.length?v.apply(this,[e===void 0?0:e,t===void 0?this.length-e:t].concat(u.call(arguments,2))):[]}}Array.isArray||(Array.isArray=function(t){return a(t)=="[object Array]"});var m=Object("a"),g=m[0]!="a"||!(0 in m);Array.prototype.forEach||(Array.prototype.forEach=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=arguments[1],s=-1,o=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError;while(++s<o)s in r&&t.call(i,r[s],s,n)}),Array.prototype.map||(Array.prototype.map=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=Array(i),o=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var u=0;u<i;u++)u in r&&(s[u]=t.call(o,r[u],u,n));return s}),Array.prototype.filter||(Array.prototype.filter=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=[],o,u=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var f=0;f<i;f++)f in r&&(o=r[f],t.call(u,o,f,n)&&s.push(o));return s}),Array.prototype.every||(Array.prototype.every=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&!t.call(s,r[o],o,n))return!1;return!0}),Array.prototype.some||(Array.prototype.some=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&t.call(s,r[o],o,n))return!0;return!1}),Array.prototype.reduce||(Array.prototype.reduce=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduce of empty array with no initial value");var s=0,o;if(arguments.length>=2)o=arguments[1];else do{if(s in r){o=r[s++];break}if(++s>=i)throw new TypeError("reduce of empty array with no initial value")}while(!0);for(;s<i;s++)s in r&&(o=t.call(void 0,o,r[s],s,n));return o}),Array.prototype.reduceRight||(Array.prototype.reduceRight=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduceRight of empty array with no initial value");var s,o=i-1;if(arguments.length>=2)s=arguments[1];else do{if(o in r){s=r[o--];break}if(--o<0)throw new TypeError("reduceRight of empty array with no initial value")}while(!0);do o in this&&(s=t.call(void 0,s,r[o],o,n));while(o--);return s});if(!Array.prototype.indexOf||[0,1].indexOf(1,2)!=-1)Array.prototype.indexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=0;arguments.length>1&&(i=H(arguments[1])),i=i>=0?i:Math.max(0,r+i);for(;i<r;i++)if(i in n&&n[i]===t)return i;return-1};if(!Array.prototype.lastIndexOf||[0,1].lastIndexOf(0,-3)!=-1)Array.prototype.lastIndexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=r-1;arguments.length>1&&(i=Math.min(i,H(arguments[1]))),i=i>=0?i:r-Math.abs(i);for(;i>=0;i--)if(i in n&&t===n[i])return i;return-1};Object.getPrototypeOf||(Object.getPrototypeOf=function(t){return t.__proto__||(t.constructor?t.constructor.prototype:o)});if(!Object.getOwnPropertyDescriptor){var y="Object.getOwnPropertyDescriptor called on a non-object: ";Object.getOwnPropertyDescriptor=function(t,n){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(y+t);if(!f(t,n))return;var r,i,s;r={enumerable:!0,configurable:!0};if(d){var u=t.__proto__;t.__proto__=o;var i=h(t,n),s=p(t,n);t.__proto__=u;if(i||s)return i&&(r.get=i),s&&(r.set=s),r}return r.value=t[n],r}}Object.getOwnPropertyNames||(Object.getOwnPropertyNames=function(t){return Object.keys(t)});if(!Object.create){var b;Object.prototype.__proto__===null?b=function(){return{__proto__:null}}:b=function(){var e={};for(var t in e)e[t]=null;return e.constructor=e.hasOwnProperty=e.propertyIsEnumerable=e.isPrototypeOf=e.toLocaleString=e.toString=e.valueOf=e.__proto__=null,e},Object.create=function(t,n){var r;if(t===null)r=b();else{if(typeof t!="object")throw new TypeError("typeof prototype["+typeof t+"] != 'object'");var i=function(){};i.prototype=t,r=new i,r.__proto__=t}return n!==void 0&&Object.defineProperties(r,n),r}}if(Object.defineProperty){var E=w({}),S=typeof document=="undefined"||w(document.createElement("div"));if(!E||!S)var x=Object.defineProperty}if(!Object.defineProperty||x){var T="Property description must be an object: ",N="Object.defineProperty called on non-object: ",C="getters & setters can not be defined on this javascript engine";Object.defineProperty=function(t,n,r){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(N+t);if(typeof r!="object"&&typeof r!="function"||r===null)throw new TypeError(T+r);if(x)try{return x.call(Object,t,n,r)}catch(i){}if(f(r,"value"))if(d&&(h(t,n)||p(t,n))){var s=t.__proto__;t.__proto__=o,delete t[n],t[n]=r.value,t.__proto__=s}else t[n]=r.value;else{if(!d)throw new TypeError(C);f(r,"get")&&l(t,n,r.get),f(r,"set")&&c(t,n,r.set)}return t}}Object.defineProperties||(Object.defineProperties=function(t,n){for(var r in n)f(n,r)&&Object.defineProperty(t,r,n[r]);return t}),Object.seal||(Object.seal=function(t){return t}),Object.freeze||(Object.freeze=function(t){return t});try{Object.freeze(function(){})}catch(k){Object.freeze=function(t){return function(n){return typeof n=="function"?n:t(n)}}(Object.freeze)}Object.preventExtensions||(Object.preventExtensions=function(t){return t}),Object.isSealed||(Object.isSealed=function(t){return!1}),Object.isFrozen||(Object.isFrozen=function(t){return!1}),Object.isExtensible||(Object.isExtensible=function(t){if(Object(t)===t)throw new TypeError;var n="";while(f(t,n))n+="?";t[n]=!0;var r=f(t,n);return delete t[n],r});if(!Object.keys){var L=!0,A=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],O=A.length;for(var M in{toString:null})L=!1;Object.keys=function I(e){if(typeof e!="object"&&typeof e!="function"||e===null)throw new TypeError("Object.keys called on a non-object");var I=[];for(var t in e)f(e,t)&&I.push(t);if(L)for(var n=0,r=O;n<r;n++){var i=A[n];f(e,i)&&I.push(i)}return I}}Date.now||(Date.now=function(){return(new Date).getTime()});var _="	\n\f\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\ufeff";if(!String.prototype.trim||_.trim()){_="["+_+"]";var D=new RegExp("^"+_+_+"*"),P=new RegExp(_+_+"*$");String.prototype.trim=function(){return String(this).replace(D,"").replace(P,"")}}var F=function(e){if(e==null)throw new TypeError("can't convert "+e+" to object");return Object(e)}})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-css.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-css.js
new file mode 100644
index 0000000..408c6bd
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-css.js
@@ -0,0 +1 @@
+"no use strict";(function(e){function t(e,t){var n=e,r="";while(n){var i=t[n];if(typeof i=="string")return i+r;if(i)return i.location.replace(/\/*$/,"/")+(r||i.main||i.name);if(i===!1)return"";var s=n.lastIndexOf("/");if(s===-1)break;r=n.substr(s)+r,n=n.slice(0,s)}return e}if(typeof e.window!="undefined"&&e.document)return;if(e.require&&e.define)return;e.console||(e.console=function(){var e=Array.prototype.slice.call(arguments,0);postMessage({type:"log",data:e})},e.console.error=e.console.warn=e.console.log=e.console.trace=e.console),e.window=e,e.ace=e,e.onerror=function(e,t,n,r,i){postMessage({type:"error",data:{message:e,data:i.data,file:t,line:n,col:r,stack:i.stack}})},e.normalizeModule=function(t,n){if(n.indexOf("!")!==-1){var r=n.split("!");return e.normalizeModule(t,r[0])+"!"+e.normalizeModule(t,r[1])}if(n.charAt(0)=="."){var i=t.split("/").slice(0,-1).join("/");n=(i?i+"/":"")+n;while(n.indexOf(".")!==-1&&s!=n){var s=n;n=n.replace(/^\.\//,"").replace(/\/\.\//,"/").replace(/[^\/]+\/\.\.\//,"")}}return n},e.require=function(r,i){i||(i=r,r=null);if(!i.charAt)throw new Error("worker.js require() accepts only (parentId, id) as arguments");i=e.normalizeModule(r,i);var s=e.require.modules[i];if(s)return s.initialized||(s.initialized=!0,s.exports=s.factory().exports),s.exports;if(!e.require.tlns)return console.log("unable to load "+i);var o=t(i,e.require.tlns);return o.slice(-3)!=".js"&&(o+=".js"),e.require.id=i,e.require.modules[i]={},importScripts(o),e.require(r,i)},e.require.modules={},e.require.tlns={},e.define=function(t,n,r){arguments.length==2?(r=n,typeof t!="string"&&(n=t,t=e.require.id)):arguments.length==1&&(r=t,n=[],t=e.require.id);if(typeof r!="function"){e.require.modules[t]={exports:r,initialized:!0};return}n.length||(n=["require","exports","module"]);var i=function(n){return e.require(t,n)};e.require.modules[t]={exports:{},factory:function(){var e=this,t=r.apply(this,n.map(function(t){switch(t){case"require":return i;case"exports":return e.exports;case"module":return e;default:return i(t)}}));return t&&(e.exports=t),e}}},e.define.amd={},require.tlns={},e.initBaseUrls=function(t){for(var n in t)require.tlns[n]=t[n]},e.initSender=function(){var n=e.require("ace/lib/event_emitter").EventEmitter,r=e.require("ace/lib/oop"),i=function(){};return function(){r.implement(this,n),this.callback=function(e,t){postMessage({type:"call",id:t,data:e})},this.emit=function(e,t){postMessage({type:"event",name:e,data:t})}}.call(i.prototype),new i};var n=e.main=null,r=e.sender=null;e.onmessage=function(t){var i=t.data;if(i.event&&r)r._signal(i.event,i.data);else if(i.command)if(n[i.command])n[i.command].apply(n,i.args);else{if(!e[i.command])throw new Error("Unknown command:"+i.command);e[i.command].apply(e,i.args)}else if(i.init){e.initBaseUrls(i.tlns),require("ace/lib/es5-shim"),r=e.sender=e.initSender();var s=require(i.module)[i.classname];n=e.main=new s(r)}}})(this),ace.define("ace/lib/oop",["require","exports","module"],function(e,t,n){"use strict";t.inherits=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})},t.mixin=function(e,t){for(var n in t)e[n]=t[n];return e},t.implement=function(e,n){t.mixin(e,n)}}),ace.define("ace/lib/lang",["require","exports","module"],function(e,t,n){"use strict";t.last=function(e){return e[e.length-1]},t.stringReverse=function(e){return e.split("").reverse().join("")},t.stringRepeat=function(e,t){var n="";while(t>0){t&1&&(n+=e);if(t>>=1)e+=e}return n};var r=/^\s\s*/,i=/\s\s*$/;t.stringTrimLeft=function(e){return e.replace(r,"")},t.stringTrimRight=function(e){return e.replace(i,"")},t.copyObject=function(e){var t={};for(var n in e)t[n]=e[n];return t},t.copyArray=function(e){var t=[];for(var n=0,r=e.length;n<r;n++)e[n]&&typeof e[n]=="object"?t[n]=this.copyObject(e[n]):t[n]=e[n];return t},t.deepCopy=function s(e){if(typeof e!="object"||!e)return e;var t;if(Array.isArray(e)){t=[];for(var n=0;n<e.length;n++)t[n]=s(e[n]);return t}var r=e.constructor;if(r===RegExp)return e;t=r();for(var n in e)t[n]=s(e[n]);return t},t.arrayToMap=function(e){var t={};for(var n=0;n<e.length;n++)t[e[n]]=1;return t},t.createMap=function(e){var t=Object.create(null);for(var n in e)t[n]=e[n];return t},t.arrayRemove=function(e,t){for(var n=0;n<=e.length;n++)t===e[n]&&e.splice(n,1)},t.escapeRegExp=function(e){return e.replace(/([.*+?^${}()|[\]\/\\])/g,"\\$1")},t.escapeHTML=function(e){return e.replace(/&/g,"&#38;").replace(/"/g,"&#34;").replace(/'/g,"&#39;").replace(/</g,"&#60;")},t.getMatchOffsets=function(e,t){var n=[];return e.replace(t,function(e){n.push({offset:arguments[arguments.length-2],length:e.length})}),n},t.deferredCall=function(e){var t=null,n=function(){t=null,e()},r=function(e){return r.cancel(),t=setTimeout(n,e||0),r};return r.schedule=r,r.call=function(){return this.cancel(),e(),r},r.cancel=function(){return clearTimeout(t),t=null,r},r.isPending=function(){return t},r},t.delayedCall=function(e,t){var n=null,r=function(){n=null,e()},i=function(e){n==null&&(n=setTimeout(r,e||t))};return i.delay=function(e){n&&clearTimeout(n),n=setTimeout(r,e||t)},i.schedule=i,i.call=function(){this.cancel(),e()},i.cancel=function(){n&&clearTimeout(n),n=null},i.isPending=function(){return n},i}}),ace.define("ace/range",["require","exports","module"],function(e,t,n){"use strict";var r=function(e,t){return e.row-t.row||e.column-t.column},i=function(e,t,n,r){this.start={row:e,column:t},this.end={row:n,column:r}};(function(){this.isEqual=function(e){return this.start.row===e.start.row&&this.end.row===e.end.row&&this.start.column===e.start.column&&this.end.column===e.end.column},this.toString=function(){return"Range: ["+this.start.row+"/"+this.start.column+"] -> ["+this.end.row+"/"+this.end.column+"]"},this.contains=function(e,t){return this.compare(e,t)==0},this.compareRange=function(e){var t,n=e.end,r=e.start;return t=this.compare(n.row,n.column),t==1?(t=this.compare(r.row,r.column),t==1?2:t==0?1:0):t==-1?-2:(t=this.compare(r.row,r.column),t==-1?-1:t==1?42:0)},this.comparePoint=function(e){return this.compare(e.row,e.column)},this.containsRange=function(e){return this.comparePoint(e.start)==0&&this.comparePoint(e.end)==0},this.intersects=function(e){var t=this.compareRange(e);return t==-1||t==0||t==1},this.isEnd=function(e,t){return this.end.row==e&&this.end.column==t},this.isStart=function(e,t){return this.start.row==e&&this.start.column==t},this.setStart=function(e,t){typeof e=="object"?(this.start.column=e.column,this.start.row=e.row):(this.start.row=e,this.start.column=t)},this.setEnd=function(e,t){typeof e=="object"?(this.end.column=e.column,this.end.row=e.row):(this.end.row=e,this.end.column=t)},this.inside=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)||this.isStart(e,t)?!1:!0:!1},this.insideStart=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)?!1:!0:!1},this.insideEnd=function(e,t){return this.compare(e,t)==0?this.isStart(e,t)?!1:!0:!1},this.compare=function(e,t){return!this.isMultiLine()&&e===this.start.row?t<this.start.column?-1:t>this.end.column?1:0:e<this.start.row?-1:e>this.end.row?1:this.start.row===e?t>=this.start.column?0:-1:this.end.row===e?t<=this.end.column?0:1:0},this.compareStart=function(e,t){return this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.compareEnd=function(e,t){return this.end.row==e&&this.end.column==t?1:this.compare(e,t)},this.compareInside=function(e,t){return this.end.row==e&&this.end.column==t?1:this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.clipRows=function(e,t){if(this.end.row>t)var n={row:t+1,column:0};else if(this.end.row<e)var n={row:e,column:0};if(this.start.row>t)var r={row:t+1,column:0};else if(this.start.row<e)var r={row:e,column:0};return i.fromPoints(r||this.start,n||this.end)},this.extend=function(e,t){var n=this.compare(e,t);if(n==0)return this;if(n==-1)var r={row:e,column:t};else var s={row:e,column:t};return i.fromPoints(r||this.start,s||this.end)},this.isEmpty=function(){return this.start.row===this.end.row&&this.start.column===this.end.column},this.isMultiLine=function(){return this.start.row!==this.end.row},this.clone=function(){return i.fromPoints(this.start,this.end)},this.collapseRows=function(){return this.end.column==0?new i(this.start.row,0,Math.max(this.start.row,this.end.row-1),0):new i(this.start.row,0,this.end.row,0)},this.toScreenRange=function(e){var t=e.documentToScreenPosition(this.start),n=e.documentToScreenPosition(this.end);return new i(t.row,t.column,n.row,n.column)},this.moveBy=function(e,t){this.start.row+=e,this.start.column+=t,this.end.row+=e,this.end.column+=t}}).call(i.prototype),i.fromPoints=function(e,t){return new i(e.row,e.column,t.row,t.column)},i.comparePoints=r,i.comparePoints=function(e,t){return e.row-t.row||e.column-t.column},t.Range=i}),ace.define("ace/apply_delta",["require","exports","module"],function(e,t,n){"use strict";function r(e,t){throw console.log("Invalid Delta:",e),"Invalid Delta: "+t}function i(e,t){return t.row>=0&&t.row<e.length&&t.column>=0&&t.column<=e[t.row].length}function s(e,t){t.action!="insert"&&t.action!="remove"&&r(t,"delta.action must be 'insert' or 'remove'"),t.lines instanceof Array||r(t,"delta.lines must be an Array"),(!t.start||!t.end)&&r(t,"delta.start/end must be an present");var n=t.start;i(e,t.start)||r(t,"delta.start must be contained in document");var s=t.end;t.action=="remove"&&!i(e,s)&&r(t,"delta.end must contained in document for 'remove' actions");var o=s.row-n.row,u=s.column-(o==0?n.column:0);(o!=t.lines.length-1||t.lines[o].length!=u)&&r(t,"delta.range must match delta lines")}t.applyDelta=function(e,t,n){var r=t.start.row,i=t.start.column,s=e[r]||"";switch(t.action){case"insert":var o=t.lines;if(o.length===1)e[r]=s.substring(0,i)+t.lines[0]+s.substring(i);else{var u=[r,1].concat(t.lines);e.splice.apply(e,u),e[r]=s.substring(0,i)+e[r],e[r+t.lines.length-1]+=s.substring(i)}break;case"remove":var a=t.end.column,f=t.end.row;r===f?e[r]=s.substring(0,i)+s.substring(a):e.splice(r,f-r+1,s.substring(0,i)+e[f].substring(a))}}}),ace.define("ace/lib/event_emitter",["require","exports","module"],function(e,t,n){"use strict";var r={},i=function(){this.propagationStopped=!0},s=function(){this.defaultPrevented=!0};r._emit=r._dispatchEvent=function(e,t){this._eventRegistry||(this._eventRegistry={}),this._defaultHandlers||(this._defaultHandlers={});var n=this._eventRegistry[e]||[],r=this._defaultHandlers[e];if(!n.length&&!r)return;if(typeof t!="object"||!t)t={};t.type||(t.type=e),t.stopPropagation||(t.stopPropagation=i),t.preventDefault||(t.preventDefault=s),n=n.slice();for(var o=0;o<n.length;o++){n[o](t,this);if(t.propagationStopped)break}if(r&&!t.defaultPrevented)return r(t,this)},r._signal=function(e,t){var n=(this._eventRegistry||{})[e];if(!n)return;n=n.slice();for(var r=0;r<n.length;r++)n[r](t,this)},r.once=function(e,t){var n=this;t&&this.addEventListener(e,function r(){n.removeEventListener(e,r),t.apply(null,arguments)})},r.setDefaultHandler=function(e,t){var n=this._defaultHandlers;n||(n=this._defaultHandlers={_disabled_:{}});if(n[e]){var r=n[e],i=n._disabled_[e];i||(n._disabled_[e]=i=[]),i.push(r);var s=i.indexOf(t);s!=-1&&i.splice(s,1)}n[e]=t},r.removeDefaultHandler=function(e,t){var n=this._defaultHandlers;if(!n)return;var r=n._disabled_[e];if(n[e]==t){var i=n[e];r&&this.setDefaultHandler(e,r.pop())}else if(r){var s=r.indexOf(t);s!=-1&&r.splice(s,1)}},r.on=r.addEventListener=function(e,t,n){this._eventRegistry=this._eventRegistry||{};var r=this._eventRegistry[e];return r||(r=this._eventRegistry[e]=[]),r.indexOf(t)==-1&&r[n?"unshift":"push"](t),t},r.off=r.removeListener=r.removeEventListener=function(e,t){this._eventRegistry=this._eventRegistry||{};var n=this._eventRegistry[e];if(!n)return;var r=n.indexOf(t);r!==-1&&n.splice(r,1)},r.removeAllListeners=function(e){this._eventRegistry&&(this._eventRegistry[e]=[])},t.EventEmitter=r}),ace.define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=t.Anchor=function(e,t,n){this.$onChange=this.onChange.bind(this),this.attach(e),typeof n=="undefined"?this.setPosition(t.row,t.column):this.setPosition(t,n)};(function(){function e(e,t,n){var r=n?e.column<=t.column:e.column<t.column;return e.row<t.row||e.row==t.row&&r}function t(t,n,r){var i=t.action=="insert",s=(i?1:-1)*(t.end.row-t.start.row),o=(i?1:-1)*(t.end.column-t.start.column),u=t.start,a=i?u:t.end;return e(n,u,r)?{row:n.row,column:n.column}:e(a,n,!r)?{row:n.row+s,column:n.column+(n.row==a.row?o:0)}:{row:u.row,column:u.column}}r.implement(this,i),this.getPosition=function(){return this.$clipPositionToDocument(this.row,this.column)},this.getDocument=function(){return this.document},this.$insertRight=!1,this.onChange=function(e){if(e.start.row==e.end.row&&e.start.row!=this.row)return;if(e.start.row>this.row)return;var n=t(e,{row:this.row,column:this.column},this.$insertRight);this.setPosition(n.row,n.column,!0)},this.setPosition=function(e,t,n){var r;n?r={row:e,column:t}:r=this.$clipPositionToDocument(e,t);if(this.row==r.row&&this.column==r.column)return;var i={row:this.row,column:this.column};this.row=r.row,this.column=r.column,this._signal("change",{old:i,value:r})},this.detach=function(){this.document.removeEventListener("change",this.$onChange)},this.attach=function(e){this.document=e||this.document,this.document.on("change",this.$onChange)},this.$clipPositionToDocument=function(e,t){var n={};return e>=this.document.getLength()?(n.row=Math.max(0,this.document.getLength()-1),n.column=this.document.getLine(n.row).length):e<0?(n.row=0,n.column=0):(n.row=e,n.column=Math.min(this.document.getLine(n.row).length,Math.max(0,t))),t<0&&(n.column=0),n}}).call(s.prototype)}),ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./apply_delta").applyDelta,s=e("./lib/event_emitter").EventEmitter,o=e("./range").Range,u=e("./anchor").Anchor,a=function(e){this.$lines=[""],e.length===0?this.$lines=[""]:Array.isArray(e)?this.insertMergedLines({row:0,column:0},e):this.insert({row:0,column:0},e)};(function(){r.implement(this,s),this.setValue=function(e){var t=this.getLength()-1;this.remove(new o(0,0,t,this.getLine(t).length)),this.insert({row:0,column:0},e)},this.getValue=function(){return this.getAllLines().join(this.getNewLineCharacter())},this.createAnchor=function(e,t){return new u(this,e,t)},"aaa".split(/a/).length===0?this.$split=function(e){return e.replace(/\r\n|\r/g,"\n").split("\n")}:this.$split=function(e){return e.split(/\r\n|\r|\n/)},this.$detectNewLine=function(e){var t=e.match(/^.*?(\r\n|\r|\n)/m);this.$autoNewLine=t?t[1]:"\n",this._signal("changeNewLineMode")},this.getNewLineCharacter=function(){switch(this.$newLineMode){case"windows":return"\r\n";case"unix":return"\n";default:return this.$autoNewLine||"\n"}},this.$autoNewLine="",this.$newLineMode="auto",this.setNewLineMode=function(e){if(this.$newLineMode===e)return;this.$newLineMode=e,this._signal("changeNewLineMode")},this.getNewLineMode=function(){return this.$newLineMode},this.isNewLine=function(e){return e=="\r\n"||e=="\r"||e=="\n"},this.getLine=function(e){return this.$lines[e]||""},this.getLines=function(e,t){return this.$lines.slice(e,t+1)},this.getAllLines=function(){return this.getLines(0,this.getLength())},this.getLength=function(){return this.$lines.length},this.getTextRange=function(e){return this.getLinesForRange(e).join(this.getNewLineCharacter())},this.getLinesForRange=function(e){var t;if(e.start.row===e.end.row)t=[this.getLine(e.start.row).substring(e.start.column,e.end.column)];else{t=this.getLines(e.start.row,e.end.row),t[0]=(t[0]||"").substring(e.start.column);var n=t.length-1;e.end.row-e.start.row==n&&(t[n]=t[n].substring(0,e.end.column))}return t},this.insertLines=function(e,t){return console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."),this.insertFullLines(e,t)},this.removeLines=function(e,t){return console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."),this.removeFullLines(e,t)},this.insertNewLine=function(e){return console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead."),this.insertMergedLines(e,["",""])},this.insert=function(e,t){return this.getLength()<=1&&this.$detectNewLine(t),this.insertMergedLines(e,this.$split(t))},this.insertInLine=function(e,t){var n=this.clippedPos(e.row,e.column),r=this.pos(e.row,e.column+t.length);return this.applyDelta({start:n,end:r,action:"insert",lines:[t]},!0),this.clonePos(r)},this.clippedPos=function(e,t){var n=this.getLength();e===undefined?e=n:e<0?e=0:e>=n&&(e=n-1,t=undefined);var r=this.getLine(e);return t==undefined&&(t=r.length),t=Math.min(Math.max(t,0),r.length),{row:e,column:t}},this.clonePos=function(e){return{row:e.row,column:e.column}},this.pos=function(e,t){return{row:e,column:t}},this.$clipPosition=function(e){var t=this.getLength();return e.row>=t?(e.row=Math.max(0,t-1),e.column=this.getLine(t-1).length):(e.row=Math.max(0,e.row),e.column=Math.min(Math.max(e.column,0),this.getLine(e.row).length)),e},this.insertFullLines=function(e,t){e=Math.min(Math.max(e,0),this.getLength());var n=0;e<this.getLength()?(t=t.concat([""]),n=0):(t=[""].concat(t),e--,n=this.$lines[e].length),this.insertMergedLines({row:e,column:n},t)},this.insertMergedLines=function(e,t){var n=this.clippedPos(e.row,e.column),r={row:n.row+t.length-1,column:(t.length==1?n.column:0)+t[t.length-1].length};return this.applyDelta({start:n,end:r,action:"insert",lines:t}),this.clonePos(r)},this.remove=function(e){var t=this.clippedPos(e.start.row,e.start.column),n=this.clippedPos(e.end.row,e.end.column);return this.applyDelta({start:t,end:n,action:"remove",lines:this.getLinesForRange({start:t,end:n})}),this.clonePos(t)},this.removeInLine=function(e,t,n){var r=this.clippedPos(e,t),i=this.clippedPos(e,n);return this.applyDelta({start:r,end:i,action:"remove",lines:this.getLinesForRange({start:r,end:i})},!0),this.clonePos(r)},this.removeFullLines=function(e,t){e=Math.min(Math.max(0,e),this.getLength()-1),t=Math.min(Math.max(0,t),this.getLength()-1);var n=t==this.getLength()-1&&e>0,r=t<this.getLength()-1,i=n?e-1:e,s=n?this.getLine(i).length:0,u=r?t+1:t,a=r?0:this.getLine(u).length,f=new o(i,s,u,a),l=this.$lines.slice(e,t+1);return this.applyDelta({start:f.start,end:f.end,action:"remove",lines:this.getLinesForRange(f)}),l},this.removeNewLine=function(e){e<this.getLength()-1&&e>=0&&this.applyDelta({start:this.pos(e,this.getLine(e).length),end:this.pos(e+1,0),action:"remove",lines:["",""]})},this.replace=function(e,t){e instanceof o||(e=o.fromPoints(e.start,e.end));if(t.length===0&&e.isEmpty())return e.start;if(t==this.getTextRange(e))return e.end;this.remove(e);var n;return t?n=this.insert(e.start,t):n=e.start,n},this.applyDeltas=function(e){for(var t=0;t<e.length;t++)this.applyDelta(e[t])},this.revertDeltas=function(e){for(var t=e.length-1;t>=0;t--)this.revertDelta(e[t])},this.applyDelta=function(e,t){var n=e.action=="insert";if(n?e.lines.length<=1&&!e.lines[0]:!o.comparePoints(e.start,e.end))return;n&&e.lines.length>2e4&&this.$splitAndapplyLargeDelta(e,2e4),i(this.$lines,e,t),this._signal("change",e)},this.$splitAndapplyLargeDelta=function(e,t){var n=e.lines,r=n.length,i=e.start.row,s=e.start.column,o=0,u=0;do{o=u,u+=t-1;var a=n.slice(o,u);if(u>r){e.lines=a,e.start.row=i+o,e.start.column=s;break}a.push(""),this.applyDelta({start:this.pos(i+o,s),end:this.pos(i+u,s=0),action:e.action,lines:a},!0)}while(!0)},this.revertDelta=function(e){this.applyDelta({start:this.clonePos(e.start),end:this.clonePos(e.end),action:e.action=="insert"?"remove":"insert",lines:e.lines.slice()})},this.indexToPosition=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length;for(var i=t||0,s=n.length;i<s;i++){e-=n[i].length+r;if(e<0)return{row:i,column:e+n[i].length+r}}return{row:s-1,column:n[s-1].length}},this.positionToIndex=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length,i=0,s=Math.min(e.row,n.length);for(var o=t||0;o<s;++o)i+=n[o].length+r;return i+e.column}}).call(a.prototype),t.Document=a}),ace.define("ace/worker/mirror",["require","exports","module","ace/range","ace/document","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../range").Range,i=e("../document").Document,s=e("../lib/lang"),o=t.Mirror=function(e){this.sender=e;var t=this.doc=new i(""),n=this.deferredUpdate=s.delayedCall(this.onUpdate.bind(this)),r=this;e.on("change",function(e){var i=e.data;if(i[0].start)t.applyDeltas(i);else for(var s=0;s<i.length;s+=2){if(Array.isArray(i[s+1]))var o={action:"insert",start:i[s],lines:i[s+1]};else var o={action:"remove",start:i[s],end:i[s+1]};t.applyDelta(o,!0)}if(r.$timeout)return n.schedule(r.$timeout);r.onUpdate()})};(function(){this.$timeout=500,this.setTimeout=function(e){this.$timeout=e},this.setValue=function(e){this.doc.setValue(e),this.deferredUpdate.schedule(this.$timeout)},this.getValue=function(e){this.sender.callback(this.doc.getValue(),e)},this.onUpdate=function(){},this.isPending=function(){return this.deferredUpdate.isPending()}}).call(o.prototype)}),ace.define("ace/mode/css/csslint",["require","exports","module"],function(require,exports,module){function objectToString(e){return Object.prototype.toString.call(e)}function clone(e,t,n,r){function u(e,n){if(e===null)return null;if(n==0)return e;var a;if(typeof e!="object")return e;if(util.isArray(e))a=[];else if(util.isRegExp(e))a=new RegExp(e.source,util.getRegExpFlags(e)),e.lastIndex&&(a.lastIndex=e.lastIndex);else if(util.isDate(e))a=new Date(e.getTime());else{if(o&&Buffer.isBuffer(e))return a=new Buffer(e.length),e.copy(a),a;typeof r=="undefined"?a=Object.create(Object.getPrototypeOf(e)):a=Object.create(r)}if(t){var f=i.indexOf(e);if(f!=-1)return s[f];i.push(e),s.push(a)}for(var l in e)a[l]=u(e[l],n-1);return a}var i=[],s=[],o=typeof Buffer!="undefined";return typeof t=="undefined"&&(t=!0),typeof n=="undefined"&&(n=Infinity),u(e,n)}function Reporter(e,t){this.messages=[],this.stats=[],this.lines=e,this.ruleset=t}var parserlib={};(function(){function e(){this._listeners={}}function t(e){this._input=e.replace(/\n\r?/g,"\n"),this._line=1,this._col=1,this._cursor=0}function n(e,t,n){this.col=n,this.line=t,this.message=e}function r(e,t,n,r){this.col=n,this.line=t,this.text=e,this.type=r}function i(e,n){this._reader=e?new t(e.toString()):null,this._token=null,this._tokenData=n,this._lt=[],this._ltIndex=0,this._ltIndexCache=[]}e.prototype={constructor:e,addListener:function(e,t){this._listeners[e]||(this._listeners[e]=[]),this._listeners[e].push(t)},fire:function(e){typeof e=="string"&&(e={type:e}),typeof e.target!="undefined"&&(e.target=this);if(typeof e.type=="undefined")throw new Error("Event object missing 'type' property.");if(this._listeners[e.type]){var t=this._listeners[e.type].concat();for(var n=0,r=t.length;n<r;n++)t[n].call(this,e)}},removeListener:function(e,t){if(this._listeners[e]){var n=this._listeners[e];for(var r=0,i=n.length;r<i;r++)if(n[r]===t){n.splice(r,1);break}}}},t.prototype={constructor:t,getCol:function(){return this._col},getLine:function(){return this._line},eof:function(){return this._cursor==this._input.length},peek:function(e){var t=null;return e=typeof e=="undefined"?1:e,this._cursor<this._input.length&&(t=this._input.charAt(this._cursor+e-1)),t},read:function(){var e=null;return this._cursor<this._input.length&&(this._input.charAt(this._cursor)=="\n"?(this._line++,this._col=1):this._col++,e=this._input.charAt(this._cursor++)),e},mark:function(){this._bookmark={cursor:this._cursor,line:this._line,col:this._col}},reset:function(){this._bookmark&&(this._cursor=this._bookmark.cursor,this._line=this._bookmark.line,this._col=this._bookmark.col,delete this._bookmark)},readTo:function(e){var t="",n;while(t.length<e.length||t.lastIndexOf(e)!=t.length-e.length){n=this.read();if(!n)throw new Error('Expected "'+e+'" at line '+this._line+", col "+this._col+".");t+=n}return t},readWhile:function(e){var t="",n=this.read();while(n!==null&&e(n))t+=n,n=this.read();return t},readMatch:function(e){var t=this._input.substring(this._cursor),n=null;return typeof e=="string"?t.indexOf(e)===0&&(n=this.readCount(e.length)):e instanceof RegExp&&e.test(t)&&(n=this.readCount(RegExp.lastMatch.length)),n},readCount:function(e){var t="";while(e--)t+=this.read();return t}},n.prototype=new Error,r.fromToken=function(e){return new r(e.value,e.startLine,e.startCol)},r.prototype={constructor:r,valueOf:function(){return this.text},toString:function(){return this.text}},i.createTokenData=function(e){var t=[],n={},r=e.concat([]),i=0,s=r.length+1;r.UNKNOWN=-1,r.unshift({name:"EOF"});for(;i<s;i++)t.push(r[i].name),r[r[i].name]=i,r[i].text&&(n[r[i].text]=i);return r.name=function(e){return t[e]},r.type=function(e){return n[e]},r},i.prototype={constructor:i,match:function(e,t){e instanceof Array||(e=[e]);var n=this.get(t),r=0,i=e.length;while(r<i)if(n==e[r++])return!0;return this.unget(),!1},mustMatch:function(e,t){var r;e instanceof Array||(e=[e]);if(!this.match.apply(this,arguments))throw r=this.LT(1),new n("Expected "+this._tokenData[e[0]].name+" at line "+r.startLine+", col "+r.startCol+".",r.startLine,r.startCol)},advance:function(e,t){while(this.LA(0)!==0&&!this.match(e,t))this.get();return this.LA(0)},get:function(e){var t=this._tokenData,n=this._reader,r,i=0,s=t.length,o=!1,u,a;if(this._lt.length&&this._ltIndex>=0&&this._ltIndex<this._lt.length){i++,this._token=this._lt[this._ltIndex++],a=t[this._token.type];while(a.channel!==undefined&&e!==a.channel&&this._ltIndex<this._lt.length)this._token=this._lt[this._ltIndex++],a=t[this._token.type],i++;if((a.channel===undefined||e===a.channel)&&this._ltIndex<=this._lt.length)return this._ltIndexCache.push(i),this._token.type}return u=this._getToken(),u.type>-1&&!t[u.type].hide&&(u.channel=t[u.type].channel,this._token=u,this._lt.push(u),this._ltIndexCache.push(this._lt.length-this._ltIndex+i),this._lt.length>5&&this._lt.shift(),this._ltIndexCache.length>5&&this._ltIndexCache.shift(),this._ltIndex=this._lt.length),a=t[u.type],a&&(a.hide||a.channel!==undefined&&e!==a.channel)?this.get(e):u.type},LA:function(e){var t=e,n;if(e>0){if(e>5)throw new Error("Too much lookahead.");while(t)n=this.get(),t--;while(t<e)this.unget(),t++}else if(e<0){if(!this._lt[this._ltIndex+e])throw new Error("Too much lookbehind.");n=this._lt[this._ltIndex+e].type}else n=this._token.type;return n},LT:function(e){return this.LA(e),this._lt[this._ltIndex+e-1]},peek:function(){return this.LA(1)},token:function(){return this._token},tokenName:function(e){return e<0||e>this._tokenData.length?"UNKNOWN_TOKEN":this._tokenData[e].name},tokenType:function(e){return this._tokenData[e]||-1},unget:function(){if(!this._ltIndexCache.length)throw new Error("Too much lookahead.");this._ltIndex-=this._ltIndexCache.pop(),this._token=this._lt[this._ltIndex-1]}},parserlib.util={StringReader:t,SyntaxError:n,SyntaxUnit:r,EventTarget:e,TokenStreamBase:i}})(),function(){function Combinator(e,t,n){SyntaxUnit.call(this,e,t,n,Parser.COMBINATOR_TYPE),this.type="unknown",/^\s+$/.test(e)?this.type="descendant":e==">"?this.type="child":e=="+"?this.type="adjacent-sibling":e=="~"&&(this.type="sibling")}function MediaFeature(e,t){SyntaxUnit.call(this,"("+e+(t!==null?":"+t:"")+")",e.startLine,e.startCol,Parser.MEDIA_FEATURE_TYPE),this.name=e,this.value=t}function MediaQuery(e,t,n,r,i){SyntaxUnit.call(this,(e?e+" ":"")+(t?t:"")+(t&&n.length>0?" and ":"")+n.join(" and "),r,i,Parser.MEDIA_QUERY_TYPE),this.modifier=e,this.mediaType=t,this.features=n}function Parser(e){EventTarget.call(this),this.options=e||{},this._tokenStream=null}function PropertyName(e,t,n,r){SyntaxUnit.call(this,e,n,r,Parser.PROPERTY_NAME_TYPE),this.hack=t}function PropertyValue(e,t,n){SyntaxUnit.call(this,e.join(" "),t,n,Parser.PROPERTY_VALUE_TYPE),this.parts=e}function PropertyValueIterator(e){this._i=0,this._parts=e.parts,this._marks=[],this.value=e}function PropertyValuePart(text,line,col){SyntaxUnit.call(this,text,line,col,Parser.PROPERTY_VALUE_PART_TYPE),this.type="unknown";var temp;if(/^([+\-]?[\d\.]+)([a-z]+)$/i.test(text)){this.type="dimension",this.value=+RegExp.$1,this.units=RegExp.$2;switch(this.units.toLowerCase()){case"em":case"rem":case"ex":case"px":case"cm":case"mm":case"in":case"pt":case"pc":case"ch":case"vh":case"vw":case"vmax":case"vmin":this.type="length";break;case"deg":case"rad":case"grad":this.type="angle";break;case"ms":case"s":this.type="time";break;case"hz":case"khz":this.type="frequency";break;case"dpi":case"dpcm":this.type="resolution"}}else/^([+\-]?[\d\.]+)%$/i.test(text)?(this.type="percentage",this.value=+RegExp.$1):/^([+\-]?\d+)$/i.test(text)?(this.type="integer",this.value=+RegExp.$1):/^([+\-]?[\d\.]+)$/i.test(text)?(this.type="number",this.value=+RegExp.$1):/^#([a-f0-9]{3,6})/i.test(text)?(this.type="color",temp=RegExp.$1,temp.length==3?(this.red=parseInt(temp.charAt(0)+temp.charAt(0),16),this.green=parseInt(temp.charAt(1)+temp.charAt(1),16),this.blue=parseInt(temp.charAt(2)+temp.charAt(2),16)):(this.red=parseInt(temp.substring(0,2),16),this.green=parseInt(temp.substring(2,4),16),this.blue=parseInt(temp.substring(4,6),16))):/^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/i.test(text)?(this.type="color",this.red=+RegExp.$1,this.green=+RegExp.$2,this.blue=+RegExp.$3):/^rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)?(this.type="color",this.red=+RegExp.$1*255/100,this.green=+RegExp.$2*255/100,this.blue=+RegExp.$3*255/100):/^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d\.]+)\s*\)/i.test(text)?(this.type="color",this.red=+RegExp.$1,this.green=+RegExp.$2,this.blue=+RegExp.$3,this.alpha=+RegExp.$4):/^rgba\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)?(this.type="color",this.red=+RegExp.$1*255/100,this.green=+RegExp.$2*255/100,this.blue=+RegExp.$3*255/100,this.alpha=+RegExp.$4):/^hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/i.test(text)?(this.type="color",this.hue=+RegExp.$1,this.saturation=+RegExp.$2/100,this.lightness=+RegExp.$3/100):/^hsla\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*([\d\.]+)\s*\)/i.test(text)?(this.type="color",this.hue=+RegExp.$1,this.saturation=+RegExp.$2/100,this.lightness=+RegExp.$3/100,this.alpha=+RegExp.$4):/^url\(["']?([^\)"']+)["']?\)/i.test(text)?(this.type="uri",this.uri=RegExp.$1):/^([^\(]+)\(/i.test(text)?(this.type="function",this.name=RegExp.$1,this.value=text):/^["'][^"']*["']/.test(text)?(this.type="string",this.value=eval(text)):Colors[text.toLowerCase()]?(this.type="color",temp=Colors[text.toLowerCase()].substring(1),this.red=parseInt(temp.substring(0,2),16),this.green=parseInt(temp.substring(2,4),16),this.blue=parseInt(temp.substring(4,6),16)):/^[\,\/]$/.test(text)?(this.type="operator",this.value=text):/^[a-z\-_\u0080-\uFFFF][a-z0-9\-_\u0080-\uFFFF]*$/i.test(text)&&(this.type="identifier",this.value=text)}function Selector(e,t,n){SyntaxUnit.call(this,e.join(" "),t,n,Parser.SELECTOR_TYPE),this.parts=e,this.specificity=Specificity.calculate(this)}function SelectorPart(e,t,n,r,i){SyntaxUnit.call(this,n,r,i,Parser.SELECTOR_PART_TYPE),this.elementName=e,this.modifiers=t}function SelectorSubPart(e,t,n,r){SyntaxUnit.call(this,e,n,r,Parser.SELECTOR_SUB_PART_TYPE),this.type=t,this.args=[]}function Specificity(e,t,n,r){this.a=e,this.b=t,this.c=n,this.d=r}function isHexDigit(e){return e!==null&&h.test(e)}function isDigit(e){return e!==null&&/\d/.test(e)}function isWhitespace(e){return e!==null&&/\s/.test(e)}function isNewLine(e){return e!==null&&nl.test(e)}function isNameStart(e){return e!==null&&/[a-z_\u0080-\uFFFF\\]/i.test(e)}function isNameChar(e){return e!==null&&(isNameStart(e)||/[0-9\-\\]/.test(e))}function isIdentStart(e){return e!==null&&(isNameStart(e)||/\-\\/.test(e))}function mix(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e}function TokenStream(e){TokenStreamBase.call(this,e,Tokens)}function ValidationError(e,t,n){this.col=n,this.line=t,this.message=e}var EventTarget=parserlib.util.EventTarget,TokenStreamBase=parserlib.util.TokenStreamBase,StringReader=parserlib.util.StringReader,SyntaxError=parserlib.util.SyntaxError,SyntaxUnit=parserlib.util.SyntaxUnit,Colors={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgrey:"#a9a9a9",darkgreen:"#006400",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",grey:"#808080",green:"#008000",greenyellow:"#adff2f",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgrey:"#d3d3d3",lightgreen:"#90ee90",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370d8",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#d87093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32",activeBorder:"Active window border.",activecaption:"Active window caption.",appworkspace:"Background color of multiple document interface.",background:"Desktop background.",buttonface:"The face background color for 3-D elements that appear 3-D due to one layer of surrounding border.",buttonhighlight:"The color of the border facing the light source for 3-D elements that appear 3-D due to one layer of surrounding border.",buttonshadow:"The color of the border away from the light source for 3-D elements that appear 3-D due to one layer of surrounding border.",buttontext:"Text on push buttons.",captiontext:"Text in caption, size box, and scrollbar arrow box.",graytext:"Grayed (disabled) text. This color is set to #000 if the current display driver does not support a solid gray color.",greytext:"Greyed (disabled) text. This color is set to #000 if the current display driver does not support a solid grey color.",highlight:"Item(s) selected in a control.",highlighttext:"Text of item(s) selected in a control.",inactiveborder:"Inactive window border.",inactivecaption:"Inactive window caption.",inactivecaptiontext:"Color of text in an inactive caption.",infobackground:"Background color for tooltip controls.",infotext:"Text color for tooltip controls.",menu:"Menu background.",menutext:"Text in menus.",scrollbar:"Scroll bar gray area.",threeddarkshadow:"The color of the darker (generally outer) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",threedface:"The face background color for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",threedhighlight:"The color of the lighter (generally outer) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",threedlightshadow:"The color of the darker (generally inner) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",threedshadow:"The color of the lighter (generally inner) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border.",window:"Window background.",windowframe:"Window frame.",windowtext:"Text in windows."};Combinator.prototype=new SyntaxUnit,Combinator.prototype.constructor=Combinator,MediaFeature.prototype=new SyntaxUnit,MediaFeature.prototype.constructor=MediaFeature,MediaQuery.prototype=new SyntaxUnit,MediaQuery.prototype.constructor=MediaQuery,Parser.DEFAULT_TYPE=0,Parser.COMBINATOR_TYPE=1,Parser.MEDIA_FEATURE_TYPE=2,Parser.MEDIA_QUERY_TYPE=3,Parser.PROPERTY_NAME_TYPE=4,Parser.PROPERTY_VALUE_TYPE=5,Parser.PROPERTY_VALUE_PART_TYPE=6,Parser.SELECTOR_TYPE=7,Parser.SELECTOR_PART_TYPE=8,Parser.SELECTOR_SUB_PART_TYPE=9,Parser.prototype=function(){var e=new EventTarget,t,n={constructor:Parser,DEFAULT_TYPE:0,COMBINATOR_TYPE:1,MEDIA_FEATURE_TYPE:2,MEDIA_QUERY_TYPE:3,PROPERTY_NAME_TYPE:4,PROPERTY_VALUE_TYPE:5,PROPERTY_VALUE_PART_TYPE:6,SELECTOR_TYPE:7,SELECTOR_PART_TYPE:8,SELECTOR_SUB_PART_TYPE:9,_stylesheet:function(){var e=this._tokenStream,t=null,n,r,i;this.fire("startstylesheet"),this._charset(),this._skipCruft();while(e.peek()==Tokens.IMPORT_SYM)this._import(),this._skipCruft();while(e.peek()==Tokens.NAMESPACE_SYM)this._namespace(),this._skipCruft();i=e.peek();while(i>Tokens.EOF){try{switch(i){case Tokens.MEDIA_SYM:this._media(),this._skipCruft();break;case Tokens.PAGE_SYM:this._page(),this._skipCruft();break;case Tokens.FONT_FACE_SYM:this._font_face(),this._skipCruft();break;case Tokens.KEYFRAMES_SYM:this._keyframes(),this._skipCruft();break;case Tokens.VIEWPORT_SYM:this._viewport(),this._skipCruft();break;case Tokens.UNKNOWN_SYM:e.get();if(!!this.options.strict)throw new SyntaxError("Unknown @ rule.",e.LT(0).startLine,e.LT(0).startCol);this.fire({type:"error",error:null,message:"Unknown @ rule: "+e.LT(0).value+".",line:e.LT(0).startLine,col:e.LT(0).startCol}),n=0;while(e.advance([Tokens.LBRACE,Tokens.RBRACE])==Tokens.LBRACE)n++;while(n)e.advance([Tokens.RBRACE]),n--;break;case Tokens.S:this._readWhitespace();break;default:if(!this._ruleset())switch(i){case Tokens.CHARSET_SYM:throw r=e.LT(1),this._charset(!1),new SyntaxError("@charset not allowed here.",r.startLine,r.startCol);case Tokens.IMPORT_SYM:throw r=e.LT(1),this._import(!1),new SyntaxError("@import not allowed here.",r.startLine,r.startCol);case Tokens.NAMESPACE_SYM:throw r=e.LT(1),this._namespace(!1),new SyntaxError("@namespace not allowed here.",r.startLine,r.startCol);default:e.get(),this._unexpectedToken(e.token())}}}catch(s){if(!(s instanceof SyntaxError&&!this.options.strict))throw s;this.fire({type:"error",error:s,message:s.message,line:s.line,col:s.col})}i=e.peek()}i!=Tokens.EOF&&this._unexpectedToken(e.token()),this.fire("endstylesheet")},_charset:function(e){var t=this._tokenStream,n,r,i,s;t.match(Tokens.CHARSET_SYM)&&(i=t.token().startLine,s=t.token().startCol,this._readWhitespace(),t.mustMatch(Tokens.STRING),r=t.token(),n=r.value,this._readWhitespace(),t.mustMatch(Tokens.SEMICOLON),e!==!1&&this.fire({type:"charset",charset:n,line:i,col:s}))},_import:function(e){var t=this._tokenStream,n,r,i,s=[];t.mustMatch(Tokens.IMPORT_SYM),i=t.token(),this._readWhitespace(),t.mustMatch([Tokens.STRING,Tokens.URI]),r=t.token().value.replace(/^(?:url\()?["']?([^"']+?)["']?\)?$/,"$1"),this._readWhitespace(),s=this._media_query_list(),t.mustMatch(Tokens.SEMICOLON),this._readWhitespace(),e!==!1&&this.fire({type:"import",uri:r,media:s,line:i.startLine,col:i.startCol})},_namespace:function(e){var t=this._tokenStream,n,r,i,s;t.mustMatch(Tokens.NAMESPACE_SYM),n=t.token().startLine,r=t.token().startCol,this._readWhitespace(),t.match(Tokens.IDENT)&&(i=t.token().value,this._readWhitespace()),t.mustMatch([Tokens.STRING,Tokens.URI]),s=t.token().value.replace(/(?:url\()?["']([^"']+)["']\)?/,"$1"),this._readWhitespace(),t.mustMatch(Tokens.SEMICOLON),this._readWhitespace(),e!==!1&&this.fire({type:"namespace",prefix:i,uri:s,line:n,col:r})},_media:function(){var e=this._tokenStream,t,n,r;e.mustMatch(Tokens.MEDIA_SYM),t=e.token().startLine,n=e.token().startCol,this._readWhitespace(),r=this._media_query_list(),e.mustMatch(Tokens.LBRACE),this._readWhitespace(),this.fire({type:"startmedia",media:r,line:t,col:n});for(;;)if(e.peek()==Tokens.PAGE_SYM)this._page();else if(e.peek()==Tokens.FONT_FACE_SYM)this._font_face();else if(e.peek()==Tokens.VIEWPORT_SYM)this._viewport();else if(!this._ruleset())break;e.mustMatch(Tokens.RBRACE),this._readWhitespace(),this.fire({type:"endmedia",media:r,line:t,col:n})},_media_query_list:function(){var e=this._tokenStream,t=[];this._readWhitespace(),(e.peek()==Tokens.IDENT||e.peek()==Tokens.LPAREN)&&t.push(this._media_query());while(e.match(Tokens.COMMA))this._readWhitespace(),t.push(this._media_query());return t},_media_query:function(){var e=this._tokenStream,t=null,n=null,r=null,i=[];e.match(Tokens.IDENT)&&(n=e.token().value.toLowerCase(),n!="only"&&n!="not"?(e.unget(),n=null):r=e.token()),this._readWhitespace(),e.peek()==Tokens.IDENT?(t=this._media_type(),r===null&&(r=e.token())):e.peek()==Tokens.LPAREN&&(r===null&&(r=e.LT(1)),i.push(this._media_expression()));if(t===null&&i.length===0)return null;this._readWhitespace();while(e.match(Tokens.IDENT))e.token().value.toLowerCase()!="and"&&this._unexpectedToken(e.token()),this._readWhitespace(),i.push(this._media_expression());return new MediaQuery(n,t,i,r.startLine,r.startCol)},_media_type:function(){return this._media_feature()},_media_expression:function(){var e=this._tokenStream,t=null,n,r=null;return e.mustMatch(Tokens.LPAREN),t=this._media_feature(),this._readWhitespace(),e.match(Tokens.COLON)&&(this._readWhitespace(),n=e.LT(1),r=this._expression()),e.mustMatch(Tokens.RPAREN),this._readWhitespace(),new MediaFeature(t,r?new SyntaxUnit(r,n.startLine,n.startCol):null)},_media_feature:function(){var e=this._tokenStream;return e.mustMatch(Tokens.IDENT),SyntaxUnit.fromToken(e.token())},_page:function(){var e=this._tokenStream,t,n,r=null,i=null;e.mustMatch(Tokens.PAGE_SYM),t=e.token().startLine,n=e.token().startCol,this._readWhitespace(),e.match(Tokens.IDENT)&&(r=e.token().value,r.toLowerCase()==="auto"&&this._unexpectedToken(e.token())),e.peek()==Tokens.COLON&&(i=this._pseudo_page()),this._readWhitespace(),this.fire({type:"startpage",id:r,pseudo:i,line:t,col:n}),this._readDeclarations(!0,!0),this.fire({type:"endpage",id:r,pseudo:i,line:t,col:n})},_margin:function(){var e=this._tokenStream,t,n,r=this._margin_sym();return r?(t=e.token().startLine,n=e.token().startCol,this.fire({type:"startpagemargin",margin:r,line:t,col:n}),this._readDeclarations(!0),this.fire({type:"endpagemargin",margin:r,line:t,col:n}),!0):!1},_margin_sym:function(){var e=this._tokenStream;return e.match([Tokens.TOPLEFTCORNER_SYM,Tokens.TOPLEFT_SYM,Tokens.TOPCENTER_SYM,Tokens.TOPRIGHT_SYM,Tokens.TOPRIGHTCORNER_SYM,Tokens.BOTTOMLEFTCORNER_SYM,Tokens.BOTTOMLEFT_SYM,Tokens.BOTTOMCENTER_SYM,Tokens.BOTTOMRIGHT_SYM,Tokens.BOTTOMRIGHTCORNER_SYM,Tokens.LEFTTOP_SYM,Tokens.LEFTMIDDLE_SYM,Tokens.LEFTBOTTOM_SYM,Tokens.RIGHTTOP_SYM,Tokens.RIGHTMIDDLE_SYM,Tokens.RIGHTBOTTOM_SYM])?SyntaxUnit.fromToken(e.token()):null},_pseudo_page:function(){var e=this._tokenStream;return e.mustMatch(Tokens.COLON),e.mustMatch(Tokens.IDENT),e.token().value},_font_face:function(){var e=this._tokenStream,t,n;e.mustMatch(Tokens.FONT_FACE_SYM),t=e.token().startLine,n=e.token().startCol,this._readWhitespace(),this.fire({type:"startfontface",line:t,col:n}),this._readDeclarations(!0),this.fire({type:"endfontface",line:t,col:n})},_viewport:function(){var e=this._tokenStream,t,n;e.mustMatch(Tokens.VIEWPORT_SYM),t=e.token().startLine,n=e.token().startCol,this._readWhitespace(),this.fire({type:"startviewport",line:t,col:n}),this._readDeclarations(!0),this.fire({type:"endviewport",line:t,col:n})},_operator:function(e){var t=this._tokenStream,n=null;if(t.match([Tokens.SLASH,Tokens.COMMA])||e&&t.match([Tokens.PLUS,Tokens.STAR,Tokens.MINUS]))n=t.token(),this._readWhitespace();return n?PropertyValuePart.fromToken(n):null},_combinator:function(){var e=this._tokenStream,t=null,n;return e.match([Tokens.PLUS,Tokens.GREATER,Tokens.TILDE])&&(n=e.token(),t=new Combinator(n.value,n.startLine,n.startCol),this._readWhitespace()),t},_unary_operator:function(){var e=this._tokenStream;return e.match([Tokens.MINUS,Tokens.PLUS])?e.token().value:null},_property:function(){var e=this._tokenStream,t=null,n=null,r,i,s,o;return e.peek()==Tokens.STAR&&this.options.starHack&&(e.get(),i=e.token(),n=i.value,s=i.startLine,o=i.startCol),e.match(Tokens.IDENT)&&(i=e.token(),r=i.value,r.charAt(0)=="_"&&this.options.underscoreHack&&(n="_",r=r.substring(1)),t=new PropertyName(r,n,s||i.startLine,o||i.startCol),this._readWhitespace()),t},_ruleset:function(){var e=this._tokenStream,t,n;try{n=this._selectors_group()}catch(r){if(r instanceof SyntaxError&&!this.options.strict){this.fire({type:"error",error:r,message:r.message,line:r.line,col:r.col}),t=e.advance([Tokens.RBRACE]);if(t!=Tokens.RBRACE)throw r;return!0}throw r}return n&&(this.fire({type:"startrule",selectors:n,line:n[0].line,col:n[0].col}),this._readDeclarations(!0),this.fire({type:"endrule",selectors:n,line:n[0].line,col:n[0].col})),n},_selectors_group:function(){var e=this._tokenStream,t=[],n;n=this._selector();if(n!==null){t.push(n);while(e.match(Tokens.COMMA))this._readWhitespace(),n=this._selector(),n!==null?t.push(n):this._unexpectedToken(e.LT(1))}return t.length?t:null},_selector:function(){var e=this._tokenStream,t=[],n=null,r=null,i=null;n=this._simple_selector_sequence();if(n===null)return null;t.push(n);do{r=this._combinator();if(r!==null)t.push(r),n=this._simple_selector_sequence(),n===null?this._unexpectedToken(e.LT(1)):t.push(n);else{if(!this._readWhitespace())break;i=new Combinator(e.token().value,e.token().startLine,e.token().startCol),r=this._combinator(),n=this._simple_selector_sequence(),n===null?r!==null&&this._unexpectedToken(e.LT(1)):(r!==null?t.push(r):t.push(i),t.push(n))}}while(!0);return new Selector(t,t[0].line,t[0].col)},_simple_selector_sequence:function(){var e=this._tokenStream,t=null,n=[],r="",i=[function(){return e.match(Tokens.HASH)?new SelectorSubPart(e.token().value,"id",e.token().startLine,e.token().startCol):null},this._class,this._attrib,this._pseudo,this._negation],s=0,o=i.length,u=null,a=!1,f,l;f=e.LT(1).startLine,l=e.LT(1).startCol,t=this._type_selector(),t||(t=this._universal()),t!==null&&(r+=t);for(;;){if(e.peek()===Tokens.S)break;while(s<o&&u===null)u=i[s++].call(this);if(u===null){if(r==="")return null;break}s=0,n.push(u),r+=u.toString(),u=null}return r!==""?new SelectorPart(t,n,r,f,l):null},_type_selector:function(){var e=this._tokenStream,t=this._namespace_prefix(),n=this._element_name();return n?(t&&(n.text=t+n.text,n.col-=t.length),n):(t&&(e.unget(),t.length>1&&e.unget()),null)},_class:function(){var e=this._tokenStream,t;return e.match(Tokens.DOT)?(e.mustMatch(Tokens.IDENT),t=e.token(),new SelectorSubPart("."+t.value,"class",t.startLine,t.startCol-1)):null},_element_name:function(){var e=this._tokenStream,t;return e.match(Tokens.IDENT)?(t=e.token(),new SelectorSubPart(t.value,"elementName",t.startLine,t.startCol)):null},_namespace_prefix:function(){var e=this._tokenStream,t="";if(e.LA(1)===Tokens.PIPE||e.LA(2)===Tokens.PIPE)e.match([Tokens.IDENT,Tokens.STAR])&&(t+=e.token().value),e.mustMatch(Tokens.PIPE),t+="|";return t.length?t:null},_universal:function(){var e=this._tokenStream,t="",n;return n=this._namespace_prefix(),n&&(t+=n),e.match(Tokens.STAR)&&(t+="*"),t.length?t:null},_attrib:function(){var e=this._tokenStream,t=null,n,r;return e.match(Tokens.LBRACKET)?(r=e.token(),t=r.value,t+=this._readWhitespace(),n=this._namespace_prefix(),n&&(t+=n),e.mustMatch(Tokens.IDENT),t+=e.token().value,t+=this._readWhitespace(),e.match([Tokens.PREFIXMATCH,Tokens.SUFFIXMATCH,Tokens.SUBSTRINGMATCH,Tokens.EQUALS,Tokens.INCLUDES,Tokens.DASHMATCH])&&(t+=e.token().value,t+=this._readWhitespace(),e.mustMatch([Tokens.IDENT,Tokens.STRING]),t+=e.token().value,t+=this._readWhitespace()),e.mustMatch(Tokens.RBRACKET),new SelectorSubPart(t+"]","attribute",r.startLine,r.startCol)):null},_pseudo:function(){var e=this._tokenStream,t=null,n=":",r,i;return e.match(Tokens.COLON)&&(e.match(Tokens.COLON)&&(n+=":"),e.match(Tokens.IDENT)?(t=e.token().value,r=e.token().startLine,i=e.token().startCol-n.length):e.peek()==Tokens.FUNCTION&&(r=e.LT(1).startLine,i=e.LT(1).startCol-n.length,t=this._functional_pseudo()),t&&(t=new SelectorSubPart(n+t,"pseudo",r,i))),t},_functional_pseudo:function(){var e=this._tokenStream,t=null;return e.match(Tokens.FUNCTION)&&(t=e.token().value,t+=this._readWhitespace(),t+=this._expression(),e.mustMatch(Tokens.RPAREN),t+=")"),t},_expression:function(){var e=this._tokenStream,t="";while(e.match([Tokens.PLUS,Tokens.MINUS,Tokens.DIMENSION,Tokens.NUMBER,Tokens.STRING,Tokens.IDENT,Tokens.LENGTH,Tokens.FREQ,Tokens.ANGLE,Tokens.TIME,Tokens.RESOLUTION,Tokens.SLASH]))t+=e.token().value,t+=this._readWhitespace();return t.length?t:null},_negation:function(){var e=this._tokenStream,t,n,r="",i,s=null;return e.match(Tokens.NOT)&&(r=e.token().value,t=e.token().startLine,n=e.token().startCol,r+=this._readWhitespace(),i=this._negation_arg(),r+=i,r+=this._readWhitespace(),e.match(Tokens.RPAREN),r+=e.token().value,s=new SelectorSubPart(r,"not",t,n),s.args.push(i)),s},_negation_arg:function(){var e=this._tokenStream,t=[this._type_selector,this._universal,function(){return e.match(Tokens.HASH)?new SelectorSubPart(e.token().value,"id",e.token().startLine,e.token().startCol):null},this._class,this._attrib,this._pseudo],n=null,r=0,i=t.length,s,o,u,a;o=e.LT(1).startLine,u=e.LT(1).startCol;while(r<i&&n===null)n=t[r].call(this),r++;return n===null&&this._unexpectedToken(e.LT(1)),n.type=="elementName"?a=new SelectorPart(n,[],n.toString(),o,u):a=new SelectorPart(null,[n],n.toString(),o,u),a},_declaration:function(){var e=this._tokenStream,t=null,n=null,r=null,i=null,s=null,o="";t=this._property();if(t!==null){e.mustMatch(Tokens.COLON),this._readWhitespace(),n=this._expr(),(!n||n.length===0)&&this._unexpectedToken(e.LT(1)),r=this._prio(),o=t.toString();if(this.options.starHack&&t.hack=="*"||this.options.underscoreHack&&t.hack=="_")o=t.text;try{this._validateProperty(o,n)}catch(u){s=u}return this.fire({type:"property",property:t,value:n,important:r,line:t.line,col:t.col,invalid:s}),!0}return!1},_prio:function(){var e=this._tokenStream,t=e.match(Tokens.IMPORTANT_SYM);return this._readWhitespace(),t},_expr:function(e){var t=this._tokenStream,n=[],r=null,i=null;r=this._term(e);if(r!==null){n.push(r);do{i=this._operator(e),i&&n.push(i),r=this._term(e);if(r===null)break;n.push(r)}while(!0)}return n.length>0?new PropertyValue(n,n[0].line,n[0].col):null},_term:function(e){var t=this._tokenStream,n=null,r=null,i=null,s,o,u;return n=this._unary_operator(),n!==null&&(o=t.token().startLine,u=t.token().startCol),t.peek()==Tokens.IE_FUNCTION&&this.options.ieFilters?(r=this._ie_function(),n===null&&(o=t.token().startLine,u=t.token().startCol)):e&&t.match([Tokens.LPAREN,Tokens.LBRACE,Tokens.LBRACKET])?(s=t.token(),i=s.endChar,r=s.value+this._expr(e).text,n===null&&(o=t.token().startLine,u=t.token().startCol),t.mustMatch(Tokens.type(i)),r+=i,this._readWhitespace()):t.match([Tokens.NUMBER,Tokens.PERCENTAGE,Tokens.LENGTH,Tokens.ANGLE,Tokens.TIME,Tokens.FREQ,Tokens.STRING,Tokens.IDENT,Tokens.URI,Tokens.UNICODE_RANGE])?(r=t.token().value,n===null&&(o=t.token().startLine,u=t.token().startCol),this._readWhitespace()):(s=this._hexcolor(),s===null?(n===null&&(o=t.LT(1).startLine,u=t.LT(1).startCol),r===null&&(t.LA(3)==Tokens.EQUALS&&this.options.ieFilters?r=this._ie_function():r=this._function())):(r=s.value,n===null&&(o=s.startLine,u=s.startCol))),r!==null?new PropertyValuePart(n!==null?n+r:r,o,u):null},_function:function(){var e=this._tokenStream,t=null,n=null,r;if(e.match(Tokens.FUNCTION)){t=e.token().value,this._readWhitespace(),n=this._expr(!0),t+=n;if(this.options.ieFilters&&e.peek()==Tokens.EQUALS)do{this._readWhitespace()&&(t+=e.token().value),e.LA(0)==Tokens.COMMA&&(t+=e.token().value),e.match(Tokens.IDENT),t+=e.token().value,e.match(Tokens.EQUALS),t+=e.token().value,r=e.peek();while(r!=Tokens.COMMA&&r!=Tokens.S&&r!=Tokens.RPAREN)e.get(),t+=e.token().value,r=e.peek()}while(e.match([Tokens.COMMA,Tokens.S]));e.match(Tokens.RPAREN),t+=")",this._readWhitespace()}return t},_ie_function:function(){var e=this._tokenStream,t=null,n=null,r;if(e.match([Tokens.IE_FUNCTION,Tokens.FUNCTION])){t=e.token().value;do{this._readWhitespace()&&(t+=e.token().value),e.LA(0)==Tokens.COMMA&&(t+=e.token().value),e.match(Tokens.IDENT),t+=e.token().value,e.match(Tokens.EQUALS),t+=e.token().value,r=e.peek();while(r!=Tokens.COMMA&&r!=Tokens.S&&r!=Tokens.RPAREN)e.get(),t+=e.token().value,r=e.peek()}while(e.match([Tokens.COMMA,Tokens.S]));e.match(Tokens.RPAREN),t+=")",this._readWhitespace()}return t},_hexcolor:function(){var e=this._tokenStream,t=null,n;if(e.match(Tokens.HASH)){t=e.token(),n=t.value;if(!/#[a-f0-9]{3,6}/i.test(n))throw new SyntaxError("Expected a hex color but found '"+n+"' at line "+t.startLine+", col "+t.startCol+".",t.startLine,t.startCol);this._readWhitespace()}return t},_keyframes:function(){var e=this._tokenStream,t,n,r,i="";e.mustMatch(Tokens.KEYFRAMES_SYM),t=e.token(),/^@\-([^\-]+)\-/.test(t.value)&&(i=RegExp.$1),this._readWhitespace(),r=this._keyframe_name(),this._readWhitespace(),e.mustMatch(Tokens.LBRACE),this.fire({type:"startkeyframes",name:r,prefix:i,line:t.startLine,col:t.startCol}),this._readWhitespace(),n=e.peek();while(n==Tokens.IDENT||n==Tokens.PERCENTAGE)this._keyframe_rule(),this._readWhitespace(),n=e.peek();this.fire({type:"endkeyframes",name:r,prefix:i,line:t.startLine,col:t.startCol}),this._readWhitespace(),e.mustMatch(Tokens.RBRACE)},_keyframe_name:function(){var e=this._tokenStream,t;return e.mustMatch([Tokens.IDENT,Tokens.STRING]),SyntaxUnit.fromToken(e.token())},_keyframe_rule:function(){var e=this._tokenStream,t,n=this._key_list();this.fire({type:"startkeyframerule",keys:n,line:n[0].line,col:n[0].col}),this._readDeclarations(!0),this.fire({type:"endkeyframerule",keys:n,line:n[0].line,col:n[0].col})},_key_list:function(){var e=this._tokenStream,t,n,r=[];r.push(this._key()),this._readWhitespace();while(e.match(Tokens.COMMA))this._readWhitespace(),r.push(this._key()),this._readWhitespace();return r},_key:function(){var e=this._tokenStream,t;if(e.match(Tokens.PERCENTAGE))return SyntaxUnit.fromToken(e.token());if(e.match(Tokens.IDENT)){t=e.token();if(/from|to/i.test(t.value))return SyntaxUnit.fromToken(t);e.unget()}this._unexpectedToken(e.LT(1))},_skipCruft:function(){while(this._tokenStream.match([Tokens.S,Tokens.CDO,Tokens.CDC]));},_readDeclarations:function(e,t){var n=this._tokenStream,r;this._readWhitespace(),e&&n.mustMatch(Tokens.LBRACE),this._readWhitespace();try{for(;;){if(!(n.match(Tokens.SEMICOLON)||t&&this._margin())){if(!this._declaration())break;if(!n.match(Tokens.SEMICOLON))break}this._readWhitespace()}n.mustMatch(Tokens.RBRACE),this._readWhitespace()}catch(i){if(!(i instanceof SyntaxError&&!this.options.strict))throw i;this.fire({type:"error",error:i,message:i.message,line:i.line,col:i.col}),r=n.advance([Tokens.SEMICOLON,Tokens.RBRACE]);if(r==Tokens.SEMICOLON)this._readDeclarations(!1,t);else if(r!=Tokens.RBRACE)throw i}},_readWhitespace:function(){var e=this._tokenStream,t="";while(e.match(Tokens.S))t+=e.token().value;return t},_unexpectedToken:function(e){throw new SyntaxError("Unexpected token '"+e.value+"' at line "+e.startLine+", col "+e.startCol+".",e.startLine,e.startCol)},_verifyEnd:function(){this._tokenStream.LA(1)!=Tokens.EOF&&this._unexpectedToken(this._tokenStream.LT(1))},_validateProperty:function(e,t){Validation.validate(e,t)},parse:function(e){this._tokenStream=new TokenStream(e,Tokens),this._stylesheet()},parseStyleSheet:function(e){return this.parse(e)},parseMediaQuery:function(e){this._tokenStream=new TokenStream(e,Tokens);var t=this._media_query();return this._verifyEnd(),t},parsePropertyValue:function(e){this._tokenStream=new TokenStream(e,Tokens),this._readWhitespace();var t=this._expr();return this._readWhitespace(),this._verifyEnd(),t},parseRule:function(e){this._tokenStream=new TokenStream(e,Tokens),this._readWhitespace();var t=this._ruleset();return this._readWhitespace(),this._verifyEnd(),t},parseSelector:function(e){this._tokenStream=new TokenStream(e,Tokens),this._readWhitespace();var t=this._selector();return this._readWhitespace(),this._verifyEnd(),t},parseStyleAttribute:function(e){e+="}",this._tokenStream=new TokenStream(e,Tokens),this._readDeclarations()}};for(t in n)n.hasOwnProperty(t)&&(e[t]=n[t]);return e}();var Properties={"align-items":"flex-start | flex-end | center | baseline | stretch","align-content":"flex-start | flex-end | center | space-between | space-around | stretch","align-self":"auto | flex-start | flex-end | center | baseline | stretch","-webkit-align-items":"flex-start | flex-end | center | baseline | stretch","-webkit-align-content":"flex-start | flex-end | center | space-between | space-around | stretch","-webkit-align-self":"auto | flex-start | flex-end | center | baseline | stretch","alignment-adjust":"auto | baseline | before-edge | text-before-edge | middle | central | after-edge | text-after-edge | ideographic | alphabetic | hanging | mathematical | <percentage> | <length>","alignment-baseline":"baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical",animation:1,"animation-delay":{multi:"<time>",comma:!0},"animation-direction":{multi:"normal | alternate",comma:!0},"animation-duration":{multi:"<time>",comma:!0},"animation-fill-mode":{multi:"none | forwards | backwards | both",comma:!0},"animation-iteration-count":{multi:"<number> | infinite",comma:!0},"animation-name":{multi:"none | <ident>",comma:!0},"animation-play-state":{multi:"running | paused",comma:!0},"animation-timing-function":1,"-moz-animation-delay":{multi:"<time>",comma:!0},"-moz-animation-direction":{multi:"normal | alternate",comma:!0},"-moz-animation-duration":{multi:"<time>",comma:!0},"-moz-animation-iteration-count":{multi:"<number> | infinite",comma:!0},"-moz-animation-name":{multi:"none | <ident>",comma:!0},"-moz-animation-play-state":{multi:"running | paused",comma:!0},"-ms-animation-delay":{multi:"<time>",comma:!0},"-ms-animation-direction":{multi:"normal | alternate",comma:!0},"-ms-animation-duration":{multi:"<time>",comma:!0},"-ms-animation-iteration-count":{multi:"<number> | infinite",comma:!0},"-ms-animation-name":{multi:"none | <ident>",comma:!0},"-ms-animation-play-state":{multi:"running | paused",comma:!0},"-webkit-animation-delay":{multi:"<time>",comma:!0},"-webkit-animation-direction":{multi:"normal | alternate",comma:!0},"-webkit-animation-duration":{multi:"<time>",comma:!0},"-webkit-animation-fill-mode":{multi:"none | forwards | backwards | both",comma:!0},"-webkit-animation-iteration-count":{multi:"<number> | infinite",comma:!0},"-webkit-animation-name":{multi:"none | <ident>",comma:!0},"-webkit-animation-play-state":{multi:"running | paused",comma:!0},"-o-animation-delay":{multi:"<time>",comma:!0},"-o-animation-direction":{multi:"normal | alternate",comma:!0},"-o-animation-duration":{multi:"<time>",comma:!0},"-o-animation-iteration-count":{multi:"<number> | infinite",comma:!0},"-o-animation-name":{multi:"none | <ident>",comma:!0},"-o-animation-play-state":{multi:"running | paused",comma:!0},appearance:"icon | window | desktop | workspace | document | tooltip | dialog | button | push-button | hyperlink | radio-button | checkbox | menu-item | tab | menu | menubar | pull-down-menu | pop-up-menu | list-menu | radio-group | checkbox-group | outline-tree | range | field | combo-box | signature | password | normal | none | inherit",azimuth:function(e){var t="<angle> | leftwards | rightwards | inherit",n="left-side | far-left | left | center-left | center | center-right | right | far-right | right-side",r=!1,i=!1,s;ValidationTypes.isAny(e,t)||(ValidationTypes.isAny(e,"behind")&&(r=!0,i=!0),ValidationTypes.isAny(e,n)&&(i=!0,r||ValidationTypes.isAny(e,"behind")));if(e.hasNext())throw s=e.next(),i?new ValidationError("Expected end of value but found '"+s+"'.",s.line,s.col):new ValidationError("Expected (<'azimuth'>) but found '"+s+"'.",s.line,s.col)},"backface-visibility":"visible | hidden",background:1,"background-attachment":{multi:"<attachment>",comma:!0},"background-clip":{multi:"<box>",comma:!0},"background-color":"<color> | inherit","background-image":{multi:"<bg-image>",comma:!0},"background-origin":{multi:"<box>",comma:!0},"background-position":{multi:"<bg-position>",comma:!0},"background-repeat":{multi:"<repeat-style>"},"background-size":{multi:"<bg-size>",comma:!0},"baseline-shift":"baseline | sub | super | <percentage> | <length>",behavior:1,binding:1,bleed:"<length>","bookmark-label":"<content> | <attr> | <string>","bookmark-level":"none | <integer>","bookmark-state":"open | closed","bookmark-target":"none | <uri> | <attr>",border:"<border-width> || <border-style> || <color>","border-bottom":"<border-width> || <border-style> || <color>","border-bottom-color":"<color> | inherit","border-bottom-left-radius":"<x-one-radius>","border-bottom-right-radius":"<x-one-radius>","border-bottom-style":"<border-style>","border-bottom-width":"<border-width>","border-collapse":"collapse | separate | inherit","border-color":{multi:"<color> | inherit",max:4},"border-image":1,"border-image-outset":{multi:"<length> | <number>",max:4},"border-image-repeat":{multi:"stretch | repeat | round",max:2},"border-image-slice":function(e){var t=!1,n="<number> | <percentage>",r=!1,i=0,s=4,o;ValidationTypes.isAny(e,"fill")&&(r=!0,t=!0);while(e.hasNext()&&i<s){t=ValidationTypes.isAny(e,n);if(!t)break;i++}r?t=!0:ValidationTypes.isAny(e,"fill");if(e.hasNext())throw o=e.next(),t?new ValidationError("Expected end of value but found '"+o+"'.",o.line,o.col):new ValidationError("Expected ([<number> | <percentage>]{1,4} && fill?) but found '"+o+"'.",o.line,o.col)},"border-image-source":"<image> | none","border-image-width":{multi:"<length> | <percentage> | <number> | auto",max:4},"border-left":"<border-width> || <border-style> || <color>","border-left-color":"<color> | inherit","border-left-style":"<border-style>","border-left-width":"<border-width>","border-radius":function(e){var t=!1,n="<length> | <percentage> | inherit",r=!1,i=!1,s=0,o=8,u;while(e.hasNext()&&s<o){t=ValidationTypes.isAny(e,n);if(!t){if(!(e.peek()=="/"&&s>0&&!r))break;r=!0,o=s+5,e.next()}s++}if(e.hasNext())throw u=e.next(),t?new ValidationError("Expected end of value but found '"+u+"'.",u.line,u.col):new ValidationError("Expected (<'border-radius'>) but found '"+u+"'.",u.line,u.col)},"border-right":"<border-width> || <border-style> || <color>","border-right-color":"<color> | inherit","border-right-style":"<border-style>","border-right-width":"<border-width>","border-spacing":{multi:"<length> | inherit",max:2},"border-style":{multi:"<border-style>",max:4},"border-top":"<border-width> || <border-style> || <color>","border-top-color":"<color> | inherit","border-top-left-radius":"<x-one-radius>","border-top-right-radius":"<x-one-radius>","border-top-style":"<border-style>","border-top-width":"<border-width>","border-width":{multi:"<border-width>",max:4},bottom:"<margin-width> | inherit","-moz-box-align":"start | end | center | baseline | stretch","-moz-box-decoration-break":"slice |clone","-moz-box-direction":"normal | reverse | inherit","-moz-box-flex":"<number>","-moz-box-flex-group":"<integer>","-moz-box-lines":"single | multiple","-moz-box-ordinal-group":"<integer>","-moz-box-orient":"horizontal | vertical | inline-axis | block-axis | inherit","-moz-box-pack":"start | end | center | justify","-webkit-box-align":"start | end | center | baseline | stretch","-webkit-box-decoration-break":"slice |clone","-webkit-box-direction":"normal | reverse | inherit","-webkit-box-flex":"<number>","-webkit-box-flex-group":"<integer>","-webkit-box-lines":"single | multiple","-webkit-box-ordinal-group":"<integer>","-webkit-box-orient":"horizontal | vertical | inline-axis | block-axis | inherit","-webkit-box-pack":"start | end | center | justify","box-shadow":function(e){var t=!1,n;if(!ValidationTypes.isAny(e,"none"))Validation.multiProperty("<shadow>",e,!0,Infinity);else if(e.hasNext())throw n=e.next(),new ValidationError("Expected end of value but found '"+n+"'.",n.line,n.col)},"box-sizing":"content-box | border-box | inherit","break-after":"auto | always | avoid | left | right | page | column | avoid-page | avoid-column","break-before":"auto | always | avoid | left | right | page | column | avoid-page | avoid-column","break-inside":"auto | avoid | avoid-page | avoid-column","caption-side":"top | bottom | inherit",clear:"none | right | left | both | inherit",clip:1,color:"<color> | inherit","color-profile":1,"column-count":"<integer> | auto","column-fill":"auto | balance","column-gap":"<length> | normal","column-rule":"<border-width> || <border-style> || <color>","column-rule-color":"<color>","column-rule-style":"<border-style>","column-rule-width":"<border-width>","column-span":"none | all","column-width":"<length> | auto",columns:1,content:1,"counter-increment":1,"counter-reset":1,crop:"<shape> | auto",cue:"cue-after | cue-before | inherit","cue-after":1,"cue-before":1,cursor:1,direction:"ltr | rtl | inherit",display:"inline | block | list-item | inline-block | table | inline-table | table-row-group | table-header-group | table-footer-group | table-row | table-column-group | table-column | table-cell | table-caption | grid | inline-grid | none | inherit | -moz-box | -moz-inline-block | -moz-inline-box | -moz-inline-grid | -moz-inline-stack | -moz-inline-table | -moz-grid | -moz-grid-group | -moz-grid-line | -moz-groupbox | -moz-deck | -moz-popup | -moz-stack | -moz-marker | -webkit-box | -webkit-inline-box | -ms-flexbox | -ms-inline-flexbox | flex | -webkit-flex | inline-flex | -webkit-inline-flex","dominant-baseline":1,"drop-initial-after-adjust":"central | middle | after-edge | text-after-edge | ideographic | alphabetic | mathematical | <percentage> | <length>","drop-initial-after-align":"baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical","drop-initial-before-adjust":"before-edge | text-before-edge | central | middle | hanging | mathematical | <percentage> | <length>","drop-initial-before-align":"caps-height | baseline | use-script | before-edge | text-before-edge | after-edge | text-after-edge | central | middle | ideographic | alphabetic | hanging | mathematical","drop-initial-size":"auto | line | <length> | <percentage>","drop-initial-value":"initial | <integer>",elevation:"<angle> | below | level | above | higher | lower | inherit","empty-cells":"show | hide | inherit",filter:1,fit:"fill | hidden | meet | slice","fit-position":1,flex:"<flex>","flex-basis":"<width>","flex-direction":"row | row-reverse | column | column-reverse","flex-flow":"<flex-direction> || <flex-wrap>","flex-grow":"<number>","flex-shrink":"<number>","flex-wrap":"nowrap | wrap | wrap-reverse","-webkit-flex":"<flex>","-webkit-flex-basis":"<width>","-webkit-flex-direction":"row | row-reverse | column | column-reverse","-webkit-flex-flow":"<flex-direction> || <flex-wrap>","-webkit-flex-grow":"<number>","-webkit-flex-shrink":"<number>","-webkit-flex-wrap":"nowrap | wrap | wrap-reverse","-ms-flex":"<flex>","-ms-flex-align":"start | end | center | stretch | baseline","-ms-flex-direction":"row | row-reverse | column | column-reverse | inherit","-ms-flex-order":"<number>","-ms-flex-pack":"start | end | center | justify","-ms-flex-wrap":"nowrap | wrap | wrap-reverse","float":"left | right | none | inherit","float-offset":1,font:1,"font-family":1,"font-size":"<absolute-size> | <relative-size> | <length> | <percentage> | inherit","font-size-adjust":"<number> | none | inherit","font-stretch":"normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded | inherit","font-style":"normal | italic | oblique | inherit","font-variant":"normal | small-caps | inherit","font-weight":"normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | inherit","grid-cell-stacking":"columns | rows | layer","grid-column":1,"grid-columns":1,"grid-column-align":"start | end | center | stretch","grid-column-sizing":1,"grid-column-span":"<integer>","grid-flow":"none | rows | columns","grid-layer":"<integer>","grid-row":1,"grid-rows":1,"grid-row-align":"start | end | center | stretch","grid-row-span":"<integer>","grid-row-sizing":1,"hanging-punctuation":1,height:"<margin-width> | <content-sizing> | inherit","hyphenate-after":"<integer> | auto","hyphenate-before":"<integer> | auto","hyphenate-character":"<string> | auto","hyphenate-lines":"no-limit | <integer>","hyphenate-resource":1,hyphens:"none | manual | auto",icon:1,"image-orientation":"angle | auto","image-rendering":1,"image-resolution":1,"inline-box-align":"initial | last | <integer>","justify-content":"flex-start | flex-end | center | space-between | space-around","-webkit-justify-content":"flex-start | flex-end | center | space-between | space-around",left:"<margin-width> | inherit","letter-spacing":"<length> | normal | inherit","line-height":"<number> | <length> | <percentage> | normal | inherit","line-break":"auto | loose | normal | strict","line-stacking":1,"line-stacking-ruby":"exclude-ruby | include-ruby","line-stacking-shift":"consider-shifts | disregard-shifts","line-stacking-strategy":"inline-line-height | block-line-height | max-height | grid-height","list-style":1,"list-style-image":"<uri> | none | inherit","list-style-position":"inside | outside | inherit","list-style-type":"disc | circle | square | decimal | decimal-leading-zero | lower-roman | upper-roman | lower-greek | lower-latin | upper-latin | armenian | georgian | lower-alpha | upper-alpha | none | inherit",margin:{multi:"<margin-width> | inherit",max:4},"margin-bottom":"<margin-width> | inherit","margin-left":"<margin-width> | inherit","margin-right":"<margin-width> | inherit","margin-top":"<margin-width> | inherit",mark:1,"mark-after":1,"mark-before":1,marks:1,"marquee-direction":1,"marquee-play-count":1,"marquee-speed":1,"marquee-style":1,"max-height":"<length> | <percentage> | <content-sizing> | none | inherit","max-width":"<length> | <percentage> | <content-sizing> | none | inherit","min-height":"<length> | <percentage> | <content-sizing> | contain-floats | -moz-contain-floats | -webkit-contain-floats | inherit","min-width":"<length> | <percentage> | <content-sizing> | contain-floats | -moz-contain-floats | -webkit-contain-floats | inherit","move-to":1,"nav-down":1,"nav-index":1,"nav-left":1,"nav-right":1,"nav-up":1,opacity:"<number> | inherit",order:"<integer>","-webkit-order":"<integer>",orphans:"<integer> | inherit",outline:1,"outline-color":"<color> | invert | inherit","outline-offset":1,"outline-style":"<border-style> | inherit","outline-width":"<border-width> | inherit",overflow:"visible | hidden | scroll | auto | inherit","overflow-style":1,"overflow-wrap":"normal | break-word","overflow-x":1,"overflow-y":1,padding:{multi:"<padding-width> | inherit",max:4},"padding-bottom":"<padding-width> | inherit","padding-left":"<padding-width> | inherit","padding-right":"<padding-width> | inherit","padding-top":"<padding-width> | inherit",page:1,"page-break-after":"auto | always | avoid | left | right | inherit","page-break-before":"auto | always | avoid | left | right | inherit","page-break-inside":"auto | avoid | inherit","page-policy":1,pause:1,"pause-after":1,"pause-before":1,perspective:1,"perspective-origin":1,phonemes:1,pitch:1,"pitch-range":1,"play-during":1,"pointer-events":"auto | none | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | inherit",position:"static | relative | absolute | fixed | inherit","presentation-level":1,"punctuation-trim":1,quotes:1,"rendering-intent":1,resize:1,rest:1,"rest-after":1,"rest-before":1,richness:1,right:"<margin-width> | inherit",rotation:1,"rotation-point":1,"ruby-align":1,"ruby-overhang":1,"ruby-position":1,"ruby-span":1,size:1,speak:"normal | none | spell-out | inherit","speak-header":"once | always | inherit","speak-numeral":"digits | continuous | inherit","speak-punctuation":"code | none | inherit","speech-rate":1,src:1,stress:1,"string-set":1,"table-layout":"auto | fixed | inherit","tab-size":"<integer> | <length>",target:1,"target-name":1,"target-new":1,"target-position":1,"text-align":"left | right | center | justify | inherit","text-align-last":1,"text-decoration":1,"text-emphasis":1,"text-height":1,"text-indent":"<length> | <percentage> | inherit","text-justify":"auto | none | inter-word | inter-ideograph | inter-cluster | distribute | kashida","text-outline":1,"text-overflow":1,"text-rendering":"auto | optimizeSpeed | optimizeLegibility | geometricPrecision | inherit","text-shadow":1,"text-transform":"capitalize | uppercase | lowercase | none | inherit","text-wrap":"normal | none | avoid",top:"<margin-width> | inherit","-ms-touch-action":"auto | none | pan-x | pan-y","touch-action":"auto | none | pan-x | pan-y",transform:1,"transform-origin":1,"transform-style":1,transition:1,"transition-delay":1,"transition-duration":1,"transition-property":1,"transition-timing-function":1,"unicode-bidi":"normal | embed | isolate | bidi-override | isolate-override | plaintext | inherit","user-modify":"read-only | read-write | write-only | inherit","user-select":"none | text | toggle | element | elements | all | inherit","vertical-align":"auto | use-script | baseline | sub | super | top | text-top | central | middle | bottom | text-bottom | <percentage> | <length>",visibility:"visible | hidden | collapse | inherit","voice-balance":1,"voice-duration":1,"voice-family":1,"voice-pitch":1,"voice-pitch-range":1,"voice-rate":1,"voice-stress":1,"voice-volume":1,volume:1,"white-space":"normal | pre | nowrap | pre-wrap | pre-line | inherit | -pre-wrap | -o-pre-wrap | -moz-pre-wrap | -hp-pre-wrap","white-space-collapse":1,widows:"<integer> | inherit",width:"<length> | <percentage> | <content-sizing> | auto | inherit","word-break":"normal | keep-all | break-all","word-spacing":"<length> | normal | inherit","word-wrap":"normal | break-word","writing-mode":"horizontal-tb | vertical-rl | vertical-lr | lr-tb | rl-tb | tb-rl | bt-rl | tb-lr | bt-lr | lr-bt | rl-bt | lr | rl | tb | inherit","z-index":"<integer> | auto | inherit",zoom:"<number> | <percentage> | normal"};PropertyName.prototype=new SyntaxUnit,PropertyName.prototype.constructor=PropertyName,PropertyName.prototype.toString=function(){return(this.hack?this.hack:"")+this.text},PropertyValue.prototype=new SyntaxUnit,PropertyValue.prototype.constructor=PropertyValue,PropertyValueIterator.prototype.count=function(){return this._parts.length},PropertyValueIterator.prototype.isFirst=function(){return this._i===0},PropertyValueIterator.prototype.hasNext=function(){return this._i<this._parts.length},PropertyValueIterator.prototype.mark=function(){this._marks.push(this._i)},PropertyValueIterator.prototype.peek=function(e){return this.hasNext()?this._parts[this._i+(e||0)]:null},PropertyValueIterator.prototype.next=function(){return this.hasNext()?this._parts[this._i++]:null},PropertyValueIterator.prototype.previous=function(){return this._i>0?this._parts[--this._i]:null},PropertyValueIterator.prototype.restore=function(){this._marks.length&&(this._i=this._marks.pop())},PropertyValuePart.prototype=new SyntaxUnit,PropertyValuePart.prototype.constructor=PropertyValuePart,PropertyValuePart.fromToken=function(e){return new PropertyValuePart(e.value,e.startLine,e.startCol)};var Pseudos={":first-letter":1,":first-line":1,":before":1,":after":1};Pseudos.ELEMENT=1,Pseudos.CLASS=2,Pseudos.isElement=function(e){return e.indexOf("::")===0||Pseudos[e.toLowerCase()]==Pseudos.ELEMENT},Selector.prototype=new SyntaxUnit,Selector.prototype.constructor=Selector,SelectorPart.prototype=new SyntaxUnit,SelectorPart.prototype.constructor=SelectorPart,SelectorSubPart.prototype=new SyntaxUnit,SelectorSubPart.prototype.constructor=SelectorSubPart,Specificity.prototype={constructor:Specificity,compare:function(e){var t=["a","b","c","d"],n,r;for(n=0,r=t.length;n<r;n++){if(this[t[n]]<e[t[n]])return-1;if(this[t[n]]>e[t[n]])return 1}return 0},valueOf:function(){return this.a*1e3+this.b*100+this.c*10+this.d},toString:function(){return this.a+","+this.b+","+this.c+","+this.d}},Specificity.calculate=function(e){function u(e){var t,n,r,a,f=e.elementName?e.elementName.text:"",l;f&&f.charAt(f.length-1)!="*"&&o++;for(t=0,r=e.modifiers.length;t<r;t++){l=e.modifiers[t];switch(l.type){case"class":case"attribute":s++;break;case"id":i++;break;case"pseudo":Pseudos.isElement(l.text)?o++:s++;break;case"not":for(n=0,a=l.args.length;n<a;n++)u(l.args[n])}}}var t,n,r,i=0,s=0,o=0;for(t=0,n=e.parts.length;t<n;t++)r=e.parts[t],r instanceof SelectorPart&&u(r);return new Specificity(0,i,s,o)};var h=/^[0-9a-fA-F]$/,nonascii=/^[\u0080-\uFFFF]$/,nl=/\n|\r\n|\r|\f/;TokenStream.prototype=mix(new TokenStreamBase,{_getToken:function(e){var t,n=this._reader,r=null,i=n.getLine(),s=n.getCol();t=n.read();while(t){switch(t){case"/":n.peek()=="*"?r=this.commentToken(t,i,s):r=this.charToken(t,i,s);break;case"|":case"~":case"^":case"$":case"*":n.peek()=="="?r=this.comparisonToken(t,i,s):r=this.charToken(t,i,s);break;case'"':case"'":r=this.stringToken(t,i,s);break;case"#":isNameChar(n.peek())?r=this.hashToken(t,i,s):r=this.charToken(t,i,s);break;case".":isDigit(n.peek())?r=this.numberToken(t,i,s):r=this.charToken(t,i,s);break;case"-":n.peek()=="-"?r=this.htmlCommentEndToken(t,i,s):isNameStart(n.peek())?r=this.identOrFunctionToken(t,i,s):r=this.charToken(t,i,s);break;case"!":r=this.importantToken(t,i,s);break;case"@":r=this.atRuleToken(t,i,s);break;case":":r=this.notToken(t,i,s);break;case"<":r=this.htmlCommentStartToken(t,i,s);break;case"U":case"u":if(n.peek()=="+"){r=this.unicodeRangeToken(t,i,s);break};default:isDigit(t)?r=this.numberToken(t,i,s):isWhitespace(t)?r=this.whitespaceToken(t,i,s):isIdentStart(t)?r=this.identOrFunctionToken(t,i,s):r=this.charToken(t,i,s)}break}return!r&&t===null&&(r=this.createToken(Tokens.EOF,null,i,s)),r},createToken:function(e,t,n,r,i){var s=this._reader;return i=i||{},{value:t,type:e,channel:i.channel,endChar:i.endChar,hide:i.hide||!1,startLine:n,startCol:r,endLine:s.getLine(),endCol:s.getCol()}},atRuleToken:function(e,t,n){var r=e,i=this._reader,s=Tokens.CHAR,o=!1,u,a;i.mark(),u=this.readName(),r=e+u,s=Tokens.type(r.toLowerCase());if(s==Tokens.CHAR||s==Tokens.UNKNOWN)r.length>1?s=Tokens.UNKNOWN_SYM:(s=Tokens.CHAR,r=e,i.reset());return this.createToken(s,r,t,n)},charToken:function(e,t,n){var r=Tokens.type(e),i={};return r==-1?r=Tokens.CHAR:i.endChar=Tokens[r].endChar,this.createToken(r,e,t,n,i)},commentToken:function(e,t,n){var r=this._reader,i=this.readComment(e);return this.createToken(Tokens.COMMENT,i,t,n)},comparisonToken:function(e,t,n){var r=this._reader,i=e+r.read(),s=Tokens.type(i)||Tokens.CHAR;return this.createToken(s,i,t,n)},hashToken:function(e,t,n){var r=this._reader,i=this.readName(e);return this.createToken(Tokens.HASH,i,t,n)},htmlCommentStartToken:function(e,t,n){var r=this._reader,i=e;return r.mark(),i+=r.readCount(3),i=="<!--"?this.createToken(Tokens.CDO,i,t,n):(r.reset(),this.charToken(e,t,n))},htmlCommentEndToken:function(e,t,n){var r=this._reader,i=e;return r.mark(),i+=r.readCount(2),i=="-->"?this.createToken(Tokens.CDC,i,t,n):(r.reset(),this.charToken(e,t,n))},identOrFunctionToken:function(e,t,n){var r=this._reader,i=this.readName(e),s=Tokens.IDENT;return r.peek()=="("?(i+=r.read(),i.toLowerCase()=="url("?(s=Tokens.URI,i=this.readURI(i),i.toLowerCase()=="url("&&(s=Tokens.FUNCTION)):s=Tokens.FUNCTION):r.peek()==":"&&i.toLowerCase()=="progid"&&(i+=r.readTo("("),s=Tokens.IE_FUNCTION),this.createToken(s,i,t,n)},importantToken:function(e,t,n){var r=this._reader,i=e,s=Tokens.CHAR,o,u;r.mark(),u=r.read();while(u){if(u=="/"){if(r.peek()!="*")break;o=this.readComment(u);if(o==="")break}else{if(!isWhitespace(u)){if(/i/i.test(u)){o=r.readCount(8),/mportant/i.test(o)&&(i+=u+o,s=Tokens.IMPORTANT_SYM);break}break}i+=u+this.readWhitespace()}u=r.read()}return s==Tokens.CHAR?(r.reset(),this.charToken(e,t,n)):this.createToken(s,i,t,n)},notToken:function(e,t,n){var r=this._reader,i=e;return r.mark(),i+=r.readCount(4),i.toLowerCase()==":not("?this.createToken(Tokens.NOT,i,t,n):(r.reset(),this.charToken(e,t,n))},numberToken:function(e,t,n){var r=this._reader,i=this.readNumber(e),s,o=Tokens.NUMBER,u=r.peek();return isIdentStart(u)?(s=this.readName(r.read()),i+=s,/^em$|^ex$|^px$|^gd$|^rem$|^vw$|^vh$|^vmax$|^vmin$|^ch$|^cm$|^mm$|^in$|^pt$|^pc$/i.test(s)?o=Tokens.LENGTH:/^deg|^rad$|^grad$/i.test(s)?o=Tokens.ANGLE:/^ms$|^s$/i.test(s)?o=Tokens.TIME:/^hz$|^khz$/i.test(s)?o=Tokens.FREQ:/^dpi$|^dpcm$/i.test(s)?o=Tokens.RESOLUTION:o=Tokens.DIMENSION):u=="%"&&(i+=r.read(),o=Tokens.PERCENTAGE),this.createToken(o,i,t,n)},stringToken:function(e,t,n){var r=e,i=e,s=this._reader,o=e,u=Tokens.STRING,a=s.read();while(a){i+=a;if(a==r&&o!="\\")break;if(isNewLine(s.peek())&&a!="\\"){u=Tokens.INVALID;break}o=a,a=s.read()}return a===null&&(u=Tokens.INVALID),this.createToken(u,i,t,n)},unicodeRangeToken:function(e,t,n){var r=this._reader,i=e,s,o=Tokens.CHAR;return r.peek()=="+"&&(r.mark(),i+=r.read(),i+=this.readUnicodeRangePart(!0),i.length==2?r.reset():(o=Tokens.UNICODE_RANGE,i.indexOf("?")==-1&&r.peek()=="-"&&(r.mark(),s=r.read(),s+=this.readUnicodeRangePart(!1),s.length==1?r.reset():i+=s))),this.createToken(o,i,t,n)},whitespaceToken:function(e,t,n){var r=this._reader,i=e+this.readWhitespace();return this.createToken(Tokens.S,i,t,n)},readUnicodeRangePart:function(e){var t=this._reader,n="",r=t.peek();while(isHexDigit(r)&&n.length<6)t.read(),n+=r,r=t.peek();if(e)while(r=="?"&&n.length<6)t.read(),n+=r,r=t.peek();return n},readWhitespace:function(){var e=this._reader,t="",n=e.peek();while(isWhitespace(n))e.read(),t+=n,n=e.peek();return t},readNumber:function(e){var t=this._reader,n=e,r=e==".",i=t.peek();while(i){if(isDigit(i))n+=t.read();else{if(i!=".")break;if(r)break;r=!0,n+=t.read()}i=t.peek()}return n},readString:function(){var e=this._reader,t=e.read(),n=t,r=t,i=e.peek();while(i){i=e.read(),n+=i;if(i==t&&r!="\\")break;if(isNewLine(e.peek())&&i!="\\"){n="";break}r=i,i=e.peek()}return i===null&&(n=""),n},readURI:function(e){var t=this._reader,n=e,r="",i=t.peek();t.mark();while(i&&isWhitespace(i))t.read(),i=t.peek();i=="'"||i=='"'?r=this.readString():r=this.readURL(),i=t.peek();while(i&&isWhitespace(i))t.read(),i=t.peek();return r===""||i!=")"?(n=e,t.reset()):n+=r+t.read(),n},readURL:function(){var e=this._reader,t="",n=e.peek();while(/^[!#$%&\\*-~]$/.test(n))t+=e.read(),n=e.peek();return t},readName:function(e){var t=this._reader,n=e||"",r=t.peek();for(;;)if(r=="\\")n+=this.readEscape(t.read()),r=t.peek();else{if(!r||!isNameChar(r))break;n+=t.read(),r=t.peek()}return n},readEscape:function(e){var t=this._reader,n=e||"",r=0,i=t.peek();if(isHexDigit(i))do n+=t.read(),i=t.peek();while(i&&isHexDigit(i)&&++r<6);return n.length==3&&/\s/.test(i)||n.length==7||n.length==1?t.read():i="",n+i},readComment:function(e){var t=this._reader,n=e||"",r=t.read();if(r=="*"){while(r){n+=r;if(n.length>2&&r=="*"&&t.peek()=="/"){n+=t.read();break}r=t.read()}return n}return""}});var Tokens=[{name:"CDO"},{name:"CDC"},{name:"S",whitespace:!0},{name:"COMMENT",comment:!0,hide:!0,channel:"comment"},{name:"INCLUDES",text:"~="},{name:"DASHMATCH",text:"|="},{name:"PREFIXMATCH",text:"^="},{name:"SUFFIXMATCH",text:"$="},{name:"SUBSTRINGMATCH",text:"*="},{name:"STRING"},{name:"IDENT"},{name:"HASH"},{name:"IMPORT_SYM",text:"@import"},{name:"PAGE_SYM",text:"@page"},{name:"MEDIA_SYM",text:"@media"},{name:"FONT_FACE_SYM",text:"@font-face"},{name:"CHARSET_SYM",text:"@charset"},{name:"NAMESPACE_SYM",text:"@namespace"},{name:"VIEWPORT_SYM",text:["@viewport","@-ms-viewport"]},{name:"UNKNOWN_SYM"},{name:"KEYFRAMES_SYM",text:["@keyframes","@-webkit-keyframes","@-moz-keyframes","@-o-keyframes"]},{name:"IMPORTANT_SYM"},{name:"LENGTH"},{name:"ANGLE"},{name:"TIME"},{name:"FREQ"},{name:"DIMENSION"},{name:"PERCENTAGE"},{name:"NUMBER"},{name:"URI"},{name:"FUNCTION"},{name:"UNICODE_RANGE"},{name:"INVALID"},{name:"PLUS",text:"+"},{name:"GREATER",text:">"},{name:"COMMA",text:","},{name:"TILDE",text:"~"},{name:"NOT"},{name:"TOPLEFTCORNER_SYM",text:"@top-left-corner"},{name:"TOPLEFT_SYM",text:"@top-left"},{name:"TOPCENTER_SYM",text:"@top-center"},{name:"TOPRIGHT_SYM",text:"@top-right"},{name:"TOPRIGHTCORNER_SYM",text:"@top-right-corner"},{name:"BOTTOMLEFTCORNER_SYM",text:"@bottom-left-corner"},{name:"BOTTOMLEFT_SYM",text:"@bottom-left"},{name:"BOTTOMCENTER_SYM",text:"@bottom-center"},{name:"BOTTOMRIGHT_SYM",text:"@bottom-right"},{name:"BOTTOMRIGHTCORNER_SYM",text:"@bottom-right-corner"},{name:"LEFTTOP_SYM",text:"@left-top"},{name:"LEFTMIDDLE_SYM",text:"@left-middle"},{name:"LEFTBOTTOM_SYM",text:"@left-bottom"},{name:"RIGHTTOP_SYM",text:"@right-top"},{name:"RIGHTMIDDLE_SYM",text:"@right-middle"},{name:"RIGHTBOTTOM_SYM",text:"@right-bottom"},{name:"RESOLUTION",state:"media"},{name:"IE_FUNCTION"},{name:"CHAR"},{name:"PIPE",text:"|"},{name:"SLASH",text:"/"},{name:"MINUS",text:"-"},{name:"STAR",text:"*"},{name:"LBRACE",endChar:"}",text:"{"},{name:"RBRACE",text:"}"},{name:"LBRACKET",endChar:"]",text:"["},{name:"RBRACKET",text:"]"},{name:"EQUALS",text:"="},{name:"COLON",text:":"},{name:"SEMICOLON",text:";"},{name:"LPAREN",endChar:")",text:"("},{name:"RPAREN",text:")"},{name:"DOT",text:"."}];(function(){var e=[],t={};Tokens.UNKNOWN=-1,Tokens.unshift({name:"EOF"});for(var n=0,r=Tokens.length;n<r;n++){e.push(Tokens[n].name),Tokens[Tokens[n].name]=n;if(Tokens[n].text)if(Tokens[n].text instanceof Array)for(var i=0;i<Tokens[n].text.length;i++)t[Tokens[n].text[i]]=n;else t[Tokens[n].text]=n}Tokens.name=function(t){return e[t]},Tokens.type=function(e){return t[e]||-1}})();var Validation={validate:function(e,t){var n=e.toString().toLowerCase(),r=t.parts,i=new PropertyValueIterator(t),s=Properties[n],o,u,a,f,l,c,h,p,d,v,m;if(!s){if(n.indexOf("-")!==0)throw new ValidationError("Unknown property '"+e+"'.",e.line,e.col)}else typeof s!="number"&&(typeof s=="string"?s.indexOf("||")>-1?this.groupProperty(s,i):this.singleProperty(s,i,1):s.multi?this.multiProperty(s.multi,i,s.comma,s.max||Infinity):typeof s=="function"&&s(i))},singleProperty:function(e,t,n,r){var i=!1,s=t.value,o=0,u;while(t.hasNext()&&o<n){i=ValidationTypes.isAny(t,e);if(!i)break;o++}if(!i)throw t.hasNext()&&!t.isFirst()?(u=t.peek(),new ValidationError("Expected end of value but found '"+u+"'.",u.line,u.col)):new ValidationError("Expected ("+e+") but found '"+s+"'.",s.line,s.col);if(t.hasNext())throw u=t.next(),new ValidationError("Expected end of value but found '"+u+"'.",u.line,u.col)},multiProperty:function(e,t,n,r){var i=!1,s=t.value,o=0,u=!1,a;while(t.hasNext()&&!i&&o<r){if(!ValidationTypes.isAny(t,e))break;o++;if(!t.hasNext())i=!0;else if(n){if(t.peek()!=",")break;a=t.next()}}if(!i)throw t.hasNext()&&!t.isFirst()?(a=t.peek(),new ValidationError("Expected end of value but found '"+a+"'.",a.line,a.col)):(a=t.previous(),n&&a==","?new ValidationError("Expected end of value but found '"+a+"'.",a.line,a.col):new ValidationError("Expected ("+e+") but found '"+s+"'.",s.line,s.col));if(t.hasNext())throw a=t.next(),new ValidationError("Expected end of value but found '"+a+"'.",a.line,a.col)},groupProperty:function(e,t,n){var r=!1,i=t.value,s=e.split("||").length,o={count:0},u=!1,a,f;while(t.hasNext()&&!r){a=ValidationTypes.isAnyOfGroup(t,e);if(!a)break;if(o[a])break;o[a]=1,o.count++,u=!0;if(o.count==s||!t.hasNext())r=!0}if(!r)throw u&&t.hasNext()?(f=t.peek(),new ValidationError("Expected end of value but found '"+f+"'.",f.line,f.col)):new ValidationError("Expected ("+e+") but found '"+i+"'.",i.line,i.col);if(t.hasNext())throw f=t.next(),new ValidationError("Expected end of value but found '"+f+"'.",f.line,f.col)}};ValidationError.prototype=new Error;var ValidationTypes={isLiteral:function(e,t){var n=e.text.toString().toLowerCase(),r=t.split(" | "),i,s,o=!1;for(i=0,s=r.length;i<s&&!o;i++)n==r[i].toLowerCase()&&(o=!0);return o},isSimple:function(e){return!!this.simple[e]},isComplex:function(e){return!!this.complex[e]},isAny:function(e,t){var n=t.split(" | "),r,i,s=!1;for(r=0,i=n.length;r<i&&!s&&e.hasNext();r++)s=this.isType(e,n[r]);return s},isAnyOfGroup:function(e,t){var n=t.split(" || "),r,i,s=!1;for(r=0,i=n.length;r<i&&!s;r++)s=this.isType(e,n[r]);return s?n[r-1]:!1},isType:function(e,t){var n=e.peek(),r=!1;return t.charAt(0)!="<"?(r=this.isLiteral(n,t),r&&e.next()):this.simple[t]?(r=this.simple[t](n),r&&e.next()):r=this.complex[t](e),r},simple:{"<absolute-size>":function(e){return ValidationTypes.isLiteral(e,"xx-small | x-small | small | medium | large | x-large | xx-large")},"<attachment>":function(e){return ValidationTypes.isLiteral(e,"scroll | fixed | local")},"<attr>":function(e){return e.type=="function"&&e.name=="attr"},"<bg-image>":function(e){return this["<image>"](e)||this["<gradient>"](e)||e=="none"},"<gradient>":function(e){return e.type=="function"&&/^(?:\-(?:ms|moz|o|webkit)\-)?(?:repeating\-)?(?:radial\-|linear\-)?gradient/i.test(e)},"<box>":function(e){return ValidationTypes.isLiteral(e,"padding-box | border-box | content-box")},"<content>":function(e){return e.type=="function"&&e.name=="content"},"<relative-size>":function(e){return ValidationTypes.isLiteral(e,"smaller | larger")},"<ident>":function(e){return e.type=="identifier"},"<length>":function(e){return e.type=="function"&&/^(?:\-(?:ms|moz|o|webkit)\-)?calc/i.test(e)?!0:e.type=="length"||e.type=="number"||e.type=="integer"||e=="0"},"<color>":function(e){return e.type=="color"||e=="transparent"},"<number>":function(e){return e.type=="number"||this["<integer>"](e)},"<integer>":function(e){return e.type=="integer"},"<line>":function(e){return e.type=="integer"},"<angle>":function(e){return e.type=="angle"},"<uri>":function(e){return e.type=="uri"},"<image>":function(e){return this["<uri>"](e)},"<percentage>":function(e){return e.type=="percentage"||e=="0"},"<border-width>":function(e){return this["<length>"](e)||ValidationTypes.isLiteral(e,"thin | medium | thick")},"<border-style>":function(e){return ValidationTypes.isLiteral(e,"none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset")},"<content-sizing>":function(e){return ValidationTypes.isLiteral(e,"fill-available | -moz-available | -webkit-fill-available | max-content | -moz-max-content | -webkit-max-content | min-content | -moz-min-content | -webkit-min-content | fit-content | -moz-fit-content | -webkit-fit-content")},"<margin-width>":function(e){return this["<length>"](e)||this["<percentage>"](e)||ValidationTypes.isLiteral(e,"auto")},"<padding-width>":function(e){return this["<length>"](e)||this["<percentage>"](e)},"<shape>":function(e){return e.type=="function"&&(e.name=="rect"||e.name=="inset-rect")},"<time>":function(e){return e.type=="time"},"<flex-grow>":function(e){return this["<number>"](e)},"<flex-shrink>":function(e){return this["<number>"](e)},"<width>":function(e){return this["<margin-width>"](e)},"<flex-basis>":function(e){return this["<width>"](e)},"<flex-direction>":function(e){return ValidationTypes.isLiteral(e,"row | row-reverse | column | column-reverse")},"<flex-wrap>":function(e){return ValidationTypes.isLiteral(e,"nowrap | wrap | wrap-reverse")}},complex:{"<bg-position>":function(e){var t=this,n=!1,r="<percentage> | <length>",i="left | right",s="top | bottom",o=0,u=function(){return e.hasNext()&&e.peek()!=","};while(e.peek(o)&&e.peek(o)!=",")o++;return o<3?ValidationTypes.isAny(e,i+" | center | "+r)?(n=!0,ValidationTypes.isAny(e,s+" | center | "+r)):ValidationTypes.isAny(e,s)&&(n=!0,ValidationTypes.isAny(e,i+" | center")):ValidationTypes.isAny(e,i)?ValidationTypes.isAny(e,s)?(n=!0,ValidationTypes.isAny(e,r)):ValidationTypes.isAny(e,r)&&(ValidationTypes.isAny(e,s)?(n=!0,ValidationTypes.isAny(e,r)):ValidationTypes.isAny(e,"center")&&(n=!0)):ValidationTypes.isAny(e,s)?ValidationTypes.isAny(e,i)?(n=!0,ValidationTypes.isAny(e,r)):ValidationTypes.isAny(e,r)&&(ValidationTypes.isAny(e,i)?(n=!0,ValidationTypes.isAny(e,r)):ValidationTypes.isAny(e,"center")&&(n=!0)):ValidationTypes.isAny(e,"center")&&ValidationTypes.isAny(e,i+" | "+s)&&(n=!0,ValidationTypes.isAny(e,r)),n},"<bg-size>":function(e){var t=this,n=!1,r="<percentage> | <length> | auto",i,s,o;return ValidationTypes.isAny(e,"cover | contain")?n=!0:ValidationTypes.isAny(e,r)&&(n=!0,ValidationTypes.isAny(e,r)),n},"<repeat-style>":function(e){var t=!1,n="repeat | space | round | no-repeat",r;return e.hasNext()&&(r=e.next(),ValidationTypes.isLiteral(r,"repeat-x | repeat-y")?t=!0:ValidationTypes.isLiteral(r,n)&&(t=!0,e.hasNext()&&ValidationTypes.isLiteral(e.peek(),n)&&e.next())),t},"<shadow>":function(e){var t=!1,n=0,r=!1,i=!1,s;if(e.hasNext()){ValidationTypes.isAny(e,"inset")&&(r=!0),ValidationTypes.isAny(e,"<color>")&&(i=!0);while(ValidationTypes.isAny(e,"<length>")&&n<4)n++;e.hasNext()&&(i||ValidationTypes.isAny(e,"<color>"),r||ValidationTypes.isAny(e,"inset")),t=n>=2&&n<=4}return t},"<x-one-radius>":function(e){var t=!1,n="<length> | <percentage> | inherit";return ValidationTypes.isAny(e,n)&&(t=!0,ValidationTypes.isAny(e,n)),t},"<flex>":function(e){var t,n=!1;ValidationTypes.isAny(e,"none | inherit")?n=!0:ValidationTypes.isType(e,"<flex-grow>")?e.peek()?ValidationTypes.isType(e,"<flex-shrink>")?e.peek()?n=ValidationTypes.isType(e,"<flex-basis>"):n=!0:ValidationTypes.isType(e,"<flex-basis>")&&(n=e.peek()===null):n=!0:ValidationTypes.isType(e,"<flex-basis>")&&(n=!0);if(!n)throw t=e.peek(),new ValidationError("Expected (none | [ <flex-grow> <flex-shrink>? || <flex-basis> ]) but found '"+e.value.text+"'.",t.line,t.col);return n}}};parserlib.css={Colors:Colors,Combinator:Combinator,Parser:Parser,PropertyName:PropertyName,PropertyValue:PropertyValue,PropertyValuePart:PropertyValuePart,MediaFeature:MediaFeature,MediaQuery:MediaQuery,Selector:Selector,SelectorPart:SelectorPart,SelectorSubPart:SelectorSubPart,Specificity:Specificity,TokenStream:TokenStream,Tokens:Tokens,ValidationError:ValidationError}}(),function(){for(var e in parserlib)exports[e]=parserlib[e]}();var util={isArray:function(e){return Array.isArray(e)||typeof e=="object"&&objectToString(e)==="[object Array]"},isDate:function(e){return typeof e=="object"&&objectToString(e)==="[object Date]"},isRegExp:function(e){return typeof e=="object"&&objectToString(e)==="[object RegExp]"},getRegExpFlags:function(e){var t="";return e.global&&(t+="g"),e.ignoreCase&&(t+="i"),e.multiline&&(t+="m"),t}};typeof module=="object"&&(module.exports=clone),clone.clonePrototype=function(e){if(e===null)return null;var t=function(){};return t.prototype=e,new t};var CSSLint=function(){function i(e,t){var r,i=e&&e.match(n),s=i&&i[1];return s&&(r={"true":2,"":1,"false":0,2:2,1:1,0:0},s.toLowerCase().split(",").forEach(function(e){var n=e.split(":"),i=n[0]||"",s=n[1]||"";t[i.trim()]=r[s.trim()]})),t}var e=[],t=[],n=/\/\*csslint([^\*]*)\*\//,r=new parserlib.util.EventTarget;return r.version="@VERSION@",r.addRule=function(t){e.push(t),e[t.id]=t},r.clearRules=function(){e=[]},r.getRules=function(){return[].concat(e).sort(function(e,t){return e.id>t.id?1:0})},r.getRuleset=function(){var t={},n=0,r=e.length;while(n<r)t[e[n++].id]=1;return t},r.addFormatter=function(e){t[e.id]=e},r.getFormatter=function(e){return t[e]},r.format=function(e,t,n,r){var i=this.getFormatter(n),s=null;return i&&(s=i.startFormat(),s+=i.formatResults(e,t,r||{}),s+=i.endFormat()),s},r.hasFormat=function(e){return t.hasOwnProperty(e)},r.verify=function(t,r){var s=0,o,u,a,f=new parserlib.css.Parser({starHack:!0,ieFilters:!0,underscoreHack:!0,strict:!1});u=t.replace(/\n\r?/g,"$split$").split("$split$"),r||(r=this.getRuleset()),n.test(t)&&(r=clone(r),r=i(t,r)),o=new Reporter(u,r),r.errors=2;for(s in r)r.hasOwnProperty(s)&&r[s]&&e[s]&&e[s].init(f,o);try{f.parse(t)}catch(l){o.error("Fatal error, cannot continue: "+l.message,l.line,l.col,{})}return a={messages:o.messages,stats:o.stats,ruleset:o.ruleset},a.messages.sort(function(e,t){return e.rollup&&!t.rollup?1:!e.rollup&&t.rollup?-1:e.line-t.line}),a},r}();Reporter.prototype={constructor:Reporter,error:function(e,t,n,r){this.messages.push({type:"error",line:t,col:n,message:e,evidence:this.lines[t-1],rule:r||{}})},warn:function(e,t,n,r){this.report(e,t,n,r)},report:function(e,t,n,r){this.messages.push({type:this.ruleset[r.id]===2?"error":"warning",line:t,col:n,message:e,evidence:this.lines[t-1],rule:r})},info:function(e,t,n,r){this.messages.push({type:"info",line:t,col:n,message:e,evidence:this.lines[t-1],rule:r})},rollupError:function(e,t){this.messages.push({type:"error",rollup:!0,message:e,rule:t})},rollupWarn:function(e,t){this.messages.push({type:"warning",rollup:!0,message:e,rule:t})},stat:function(e,t){this.stats[e]=t}},CSSLint._Reporter=Reporter,CSSLint.Util={mix:function(e,t){var n;for(n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return n},indexOf:function(e,t){if(e.indexOf)return e.indexOf(t);for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},forEach:function(e,t){if(e.forEach)return e.forEach(t);for(var n=0,r=e.length;n<r;n++)t(e[n],n,e)}},CSSLint.addRule({id:"adjoining-classes",name:"Disallow adjoining classes",desc:"Don't use adjoining classes.",browsers:"IE6",init:function(e,t){var n=this;e.addListener("startrule",function(r){var i=r.selectors,s,o,u,a,f,l,c;for(f=0;f<i.length;f++){s=i[f];for(l=0;l<s.parts.length;l++){o=s.parts[l];if(o.type===e.SELECTOR_PART_TYPE){a=0;for(c=0;c<o.modifiers.length;c++)u=o.modifiers[c],u.type==="class"&&a++,a>1&&t.report("Don't use adjoining classes.",o.line,o.col,n)}}}})}}),CSSLint.addRule({id:"box-model",name:"Beware of broken box size",desc:"Don't use width or height when using padding or border.",browsers:"All",init:function(e,t){function u(){s={},o=!1}function a(){var e,u;if(!o){if(s.height)for(e in i)i.hasOwnProperty(e)&&s[e]&&(u=s[e].value,(e!=="padding"||u.parts.length!==2||u.parts[0].value!==0)&&t.report("Using height with "+e+" can sometimes make elements larger than you expect.",s[e].line,s[e].col,n));if(s.width)for(e in r)r.hasOwnProperty(e)&&s[e]&&(u=s[e].value,(e!=="padding"||u.parts.length!==2||u.parts[1].value!==0)&&t.report("Using width with "+e+" can sometimes make elements larger than you expect.",s[e].line,s[e].col,n))}}var n=this,r={border:1,"border-left":1,"border-right":1,padding:1,"padding-left":1,"padding-right":1},i={border:1,"border-bottom":1,"border-top":1,padding:1,"padding-bottom":1,"padding-top":1},s,o=!1;e.addListener("startrule",u),e.addListener("startfontface",u),e.addListener("startpage",u),e.addListener("startpagemargin",u),e.addListener("startkeyframerule",u),e.addListener("property",function(e){var t=e.property.text.toLowerCase();i[t]||r[t]?!/^0\S*$/.test(e.value)&&(t!=="border"||e.value.toString()!=="none")&&(s[t]={line:e.property.line,col:e.property.col,value:e.value}):/^(width|height)/i.test(t)&&/^(length|percentage)/.test(e.value.parts[0].type)?s[t]=1:t==="box-sizing"&&(o=!0)}),e.addListener("endrule",a),e.addListener("endfontface",a),e.addListener("endpage",a),e.addListener("endpagemargin",a),e.addListener("endkeyframerule",a)}}),CSSLint.addRule({id:"box-sizing",name:"Disallow use of box-sizing",desc:"The box-sizing properties isn't supported in IE6 and IE7.",browsers:"IE6, IE7",tags:["Compatibility"],init:function(e,t){var n=this;e.addListener("property",function(e){var r=e.property.text.toLowerCase();r==="box-sizing"&&t.report("The box-sizing property isn't supported in IE6 and IE7.",e.line,e.col,n)})}}),CSSLint.addRule({id:"bulletproof-font-face",name:"Use the bulletproof @font-face syntax",desc:"Use the bulletproof @font-face syntax to avoid 404's in old IE (http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax).",browsers:"All",init:function(e,t){var n=this,r=!1,i=!0,s=!1,o,u;e.addListener("startfontface",function(){r=!0}),e.addListener("property",function(e){if(!r)return;var t=e.property.toString().toLowerCase(),n=e.value.toString();o=e.line,u=e.col;if(t==="src"){var a=/^\s?url\(['"].+\.eot\?.*['"]\)\s*format\(['"]embedded-opentype['"]\).*$/i;!n.match(a)&&i?(s=!0,i=!1):n.match(a)&&!i&&(s=!1)}}),e.addListener("endfontface",function(){r=!1,s&&t.report("@font-face declaration doesn't follow the fontspring bulletproof syntax.",o,u,n)})}}),CSSLint.addRule({id:"compatible-vendor-prefixes",name:"Require compatible vendor prefixes",desc:"Include all compatible vendor prefixes to reach a wider range of users.",browsers:"All",init:function(e,t){var n=this,r,i,s,o,u,a,f,l=!1,c=Array.prototype.push,h=[];r={animation:"webkit moz","animation-delay":"webkit moz","animation-direction":"webkit moz","animation-duration":"webkit moz","animation-fill-mode":"webkit moz","animation-iteration-count":"webkit moz","animation-name":"webkit moz","animation-play-state":"webkit moz","animation-timing-function":"webkit moz",appearance:"webkit moz","border-end":"webkit moz","border-end-color":"webkit moz","border-end-style":"webkit moz","border-end-width":"webkit moz","border-image":"webkit moz o","border-radius":"webkit","border-start":"webkit moz","border-start-color":"webkit moz","border-start-style":"webkit moz","border-start-width":"webkit moz","box-align":"webkit moz ms","box-direction":"webkit moz ms","box-flex":"webkit moz ms","box-lines":"webkit ms","box-ordinal-group":"webkit moz ms","box-orient":"webkit moz ms","box-pack":"webkit moz ms","box-sizing":"webkit moz","box-shadow":"webkit moz","column-count":"webkit moz ms","column-gap":"webkit moz ms","column-rule":"webkit moz ms","column-rule-color":"webkit moz ms","column-rule-style":"webkit moz ms","column-rule-width":"webkit moz ms","column-width":"webkit moz ms",hyphens:"epub moz","line-break":"webkit ms","margin-end":"webkit moz","margin-start":"webkit moz","marquee-speed":"webkit wap","marquee-style":"webkit wap","padding-end":"webkit moz","padding-start":"webkit moz","tab-size":"moz o","text-size-adjust":"webkit ms",transform:"webkit moz ms o","transform-origin":"webkit moz ms o",transition:"webkit moz o","transition-delay":"webkit moz o","transition-duration":"webkit moz o","transition-property":"webkit moz o","transition-timing-function":"webkit moz o","user-modify":"webkit moz","user-select":"webkit moz ms","word-break":"epub ms","writing-mode":"epub ms"};for(s in r)if(r.hasOwnProperty(s)){o=[],u=r[s].split(" ");for(a=0,f=u.length;a<f;a++)o.push("-"+u[a]+"-"+s);r[s]=o,c.apply(h,o)}e.addListener("startrule",function(){i=[]}),e.addListener("startkeyframes",function(e){l=e.prefix||!0}),e.addListener("endkeyframes",function(){l=!1}),e.addListener("property",function(e){var t=e.property;CSSLint.Util.indexOf(h,t.text)>-1&&(!l||typeof l!="string"||t.text.indexOf("-"+l+"-")!==0)&&i.push(t)}),e.addListener("endrule",function(){if(!i.length)return;var e={},s,o,u,a,f,l,c,h,p,d;for(s=0,o=i.length;s<o;s++){u=i[s];for(a in r)r.hasOwnProperty(a)&&(f=r[a],CSSLint.Util.indexOf(f,u.text)>-1&&(e[a]||(e[a]={full:f.slice(0),actual:[],actualNodes:[]}),CSSLint.Util.indexOf(e[a].actual,u.text)===-1&&(e[a].actual.push(u.text),e[a].actualNodes.push(u))))}for(a in e)if(e.hasOwnProperty(a)){l=e[a],c=l.full,h=l.actual;if(c.length>h.length)for(s=0,o=c.length;s<o;s++)p=c[s],CSSLint.Util.indexOf(h,p)===-1&&(d=h.length===1?h[0]:h.length===2?h.join(" and "):h.join(", "),t.report("The property "+p+" is compatible with "+d+" and should be included as well.",l.actualNodes[0].line,l.actualNodes[0].col,n))}})}}),CSSLint.addRule({id:"display-property-grouping",name:"Require properties appropriate for display",desc:"Certain properties shouldn't be used with certain display property values.",browsers:"All",init:function(e,t){function s(e,s,o){i[e]&&(typeof r[e]!="string"||i[e].value.toLowerCase()!==r[e])&&t.report(o||e+" can't be used with display: "+s+".",i[e].line,i[e].col,n)}function o(){i={}}function u(){var e=i.display?i.display.value:null;if(e)switch(e){case"inline":s("height",e),s("width",e),s("margin",e),s("margin-top",e),s("margin-bottom",e),s("float",e,"display:inline has no effect on floated elements (but may be used to fix the IE6 double-margin bug).");break;case"block":s("vertical-align",e);break;case"inline-block":s("float",e);break;default:e.indexOf("table-")===0&&(s("margin",e),s("margin-left",e),s("margin-right",e),s("margin-top",e),s("margin-bottom",e),s("float",e))}}var n=this,r={display:1,"float":"none",height:1,width:1,margin:1,"margin-left":1,"margin-right":1,"margin-bottom":1,"margin-top":1,padding:1,"padding-left":1,"padding-right":1,"padding-bottom":1,"padding-top":1,"vertical-align":1},i;e.addListener("startrule",o),e.addListener("startfontface",o),e.addListener("startkeyframerule",o),e.addListener("startpagemargin",o),e.addListener("startpage",o),e.addListener("property",function(e){var t=e.property.text.toLowerCase();r[t]&&(i[t]={value:e.value.text,line:e.property.line,col:e.property.col})}),e.addListener("endrule",u),e.addListener("endfontface",u),e.addListener("endkeyframerule",u),e.addListener("endpagemargin",u),e.addListener("endpage",u)}}),CSSLint.addRule({id:"duplicate-background-images",name:"Disallow duplicate background images",desc:"Every background-image should be unique. Use a common class for e.g. sprites.",browsers:"All",init:function(e,t){var n=this,r={};e.addListener("property",function(e){var i=e.property.text,s=e.value,o,u;if(i.match(/background/i))for(o=0,u=s.parts.length;o<u;o++)s.parts[o].type==="uri"&&(typeof r[s.parts[o].uri]=="undefined"?r[s.parts[o].uri]=e:t.report("Background image '"+s.parts[o].uri+"' was used multiple times, first declared at line "+r[s.parts[o].uri].line+", col "+r[s.parts[o].uri].col+".",e.line,e.col,n))})}}),CSSLint.addRule({id:"duplicate-properties",name:"Disallow duplicate properties",desc:"Duplicate properties must appear one after the other.",browsers:"All",init:function(e,t){function s(){r={}}var n=this,r,i;e.addListener("startrule",s),e.addListener("startfontface",s),e.addListener("startpage",s),e.addListener("startpagemargin",s),e.addListener("startkeyframerule",s),e.addListener("property",function(e){var s=e.property,o=s.text.toLowerCase();r[o]&&(i!==o||r[o]===e.value.text)&&t.report("Duplicate property '"+e.property+"' found.",e.line,e.col,n),r[o]=e.value.text,i=o})}}),CSSLint.addRule({id:"empty-rules",name:"Disallow empty rules",desc:"Rules without any properties specified should be removed.",browsers:"All",init:function(e,t){var n=this,r=0;e.addListener("startrule",function(){r=0}),e.addListener("property",function(){r++}),e.addListener("endrule",function(e){var i=e.selectors;r===0&&t.report("Rule is empty.",i[0].line,i[0].col,n)})}}),CSSLint.addRule({id:"errors",name:"Parsing Errors",desc:"This rule looks for recoverable syntax errors.",browsers:"All",init:function(e,t){var n=this;e.addListener("error",function(e){t.error(e.message,e.line,e.col,n)})}}),CSSLint.addRule({id:"fallback-colors",name:"Require fallback colors",desc:"For older browsers that don't support RGBA, HSL, or HSLA, provide a fallback color.",browsers:"IE6,IE7,IE8",init:function(e,t){function o(){s={},r=null}var n=this,r,i={color:1,background:1,"border-color":1,"border-top-color":1,"border-right-color":1,"border-bottom-color":1,"border-left-color":1,border:1,"border-top":1,"border-right":1,"border-bottom":1,"border-left":1,"background-color":1},s;e.addListener("startrule",o),e.addListener("startfontface",o),e.addListener("startpage",o),e.addListener("startpagemargin",o),e.addListener("startkeyframerule",o),e.addListener("property",function(e){var s=e.property,o=s.text.toLowerCase(),u=e.value.parts,a=0,f="",l=u.length;if(i[o])while(a<l)u[a].type==="color"&&("alpha"in u[a]||"hue"in u[a]?(/([^\)]+)\(/.test(u[a])&&(f=RegExp.$1.toUpperCase()),(!r||r.property.text.toLowerCase()!==o||r.colorType!=="compat")&&t.report("Fallback "+o+" (hex or RGB) should precede "+f+" "+o+".",e.line,e.col,n)):e.colorType="compat"),a++;r=e})}}),CSSLint.addRule({id:"floats",name:"Disallow too many floats",desc:"This rule tests if the float property is used too many times",browsers:"All",init:function(e,t){var n=this,r=0;e.addListener("property",function(e){e.property.text.toLowerCase()==="float"&&e.value.text.toLowerCase()!=="none"&&r++}),e.addListener("endstylesheet",function(){t.stat("floats",r),r>=10&&t.rollupWarn("Too many floats ("+r+"), you're probably using them for layout. Consider using a grid system instead.",n)})}}),CSSLint.addRule({id:"font-faces",name:"Don't use too many web fonts",desc:"Too many different web fonts in the same stylesheet.",browsers:"All",init:function(e,t){var n=this,r=0;e.addListener("startfontface",function(){r++}),e.addListener("endstylesheet",function(){r>5&&t.rollupWarn("Too many @font-face declarations ("+r+").",n)})}}),CSSLint.addRule({id:"font-sizes",name:"Disallow too many font sizes",desc:"Checks the number of font-size declarations.",browsers:"All",init:function(e,t){var n=this,r=0;e.addListener("property",function(e){e.property.toString()==="font-size"&&r++}),e.addListener("endstylesheet",function(){t.stat("font-sizes",r),r>=10&&t.rollupWarn("Too many font-size declarations ("+r+"), abstraction needed.",n)})}}),CSSLint.addRule({id:"gradients",name:"Require all gradient definitions",desc:"When using a vendor-prefixed gradient, make sure to use them all.",browsers:"All",init:function(e,t){var n=this,r;e.addListener("startrule",function(){r={moz:0,webkit:0,oldWebkit:0,o:0}}),e.addListener("property",function(e){/\-(moz|o|webkit)(?:\-(?:linear|radial))\-gradient/i.test(e.value)?r[RegExp.$1]=1:/\-webkit\-gradient/i.test(e.value)&&(r.oldWebkit=1)}),e.addListener("endrule",function(e){var i=[];r.moz||i.push("Firefox 3.6+"),r.webkit||i.push("Webkit (Safari 5+, Chrome)"),r.oldWebkit||i.push("Old Webkit (Safari 4+, Chrome)"),r.o||i.push("Opera 11.1+"),i.length&&i.length<4&&t.report("Missing vendor-prefixed CSS gradients for "+i.join(", ")+".",e.selectors[0].line,e.selectors[0].col,n)})}}),CSSLint.addRule({id:"ids",name:"Disallow IDs in selectors",desc:"Selectors should not contain IDs.",browsers:"All",init:function(e,t){var n=this;e.addListener("startrule",function(r){var i=r.selectors,s,o,u,a,f,l,c;for(f=0;f<i.length;f++){s=i[f],a=0;for(l=0;l<s.parts.length;l++){o=s.parts[l];if(o.type===e.SELECTOR_PART_TYPE)for(c=0;c<o.modifiers.length;c++)u=o.modifiers[c],u.type==="id"&&a++}a===1?t.report("Don't use IDs in selectors.",s.line,s.col,n):a>1&&t.report(a+" IDs in the selector, really?",s.line,s.col,n)}})}}),CSSLint.addRule({id:"import",name:"Disallow @import",desc:"Don't use @import, use <link> instead.",browsers:"All",init:function(e,t){var n=this;e.addListener("import",function(e){t.report("@import prevents parallel downloads, use <link> instead.",e.line,e.col,n)})}}),CSSLint.addRule({id:"important",name:"Disallow !important",desc:"Be careful when using !important declaration",browsers:"All",init:function(e,t){var n=this,r=0;e.addListener("property",function(e){e.important===!0&&(r++,t.report("Use of !important",e.line,e.col,n))}),e.addListener("endstylesheet",function(){t.stat("important",r),r>=10&&t.rollupWarn("Too many !important declarations ("+r+"), try to use less than 10 to avoid specificity issues.",n)})}}),CSSLint.addRule({id:"known-properties",name:"Require use of known properties",desc:"Properties should be known (listed in CSS3 specification) or be a vendor-prefixed property.",browsers:"All",init:function(e,t){var n=this;e.addListener("property",function(e){e.invalid&&t.report(e.invalid.message,e.line,e.col,n)})}}),CSSLint.addRule({id:"order-alphabetical",name:"Alphabetical order",desc:"Assure properties are in alphabetical order",browsers:"All",init:function(e,t){var n=this,r,i=function(){r=[]};e.addListener("startrule",i),e.addListener("startfontface",i),e.addListener("startpage",i),e.addListener("startpagemargin",i),e.addListener("startkeyframerule",i),e.addListener("property",function(e){var t=e.property.text,n=t.toLowerCase().replace(/^-.*?-/,"");r.push(n)}),e.addListener("endrule",function(e){var i=r.join(","),s=r.sort().join(",");i!==s&&t.report("Rule doesn't have all its properties in alphabetical ordered.",e.line,e.col,n)})}}),CSSLint.addRule({id:"outline-none",name:"Disallow outline: none",desc:"Use of outline: none or outline: 0 should be limited to :focus rules.",browsers:"All",tags:["Accessibility"],init:function(e,t){function i(e){e.selectors?r={line:e.line,col:e.col,selectors:e.selectors,propCount:0,outline:!1}:r=null}function s(){r&&r.outline&&(r.selectors.toString().toLowerCase().indexOf(":focus")===-1?t.report("Outlines should only be modified using :focus.",r.line,r.col,n):r.propCount===1&&t.report("Outlines shouldn't be hidden unless other visual changes are made.",r.line,r.col,n))}var n=this,r;e.addListener("startrule",i),e.addListener("startfontface",i),e.addListener("startpage",i),e.addListener("startpagemargin",i),e.addListener("startkeyframerule",i),e.addListener("property",function(e){var t=e.property.text.toLowerCase(),n=e.value;r&&(r.propCount++,t==="outline"&&(n.toString()==="none"||n.toString()==="0")&&(r.outline=!0))}),e.addListener("endrule",s),e.addListener("endfontface",s),e.addListener("endpage",s),e.addListener("endpagemargin",s),e.addListener("endkeyframerule",s)}}),CSSLint.addRule({id:"overqualified-elements",name:"Disallow overqualified elements",desc:"Don't use classes or IDs with elements (a.foo or a#foo).",browsers:"All",init:function(e,t){var n=this,r={};e.addListener("startrule",function(i){var s=i.selectors,o,u,a,f,l,c;for(f=0;f<s.length;f++){o=s[f];for(l=0;l<o.parts.length;l++){u=o.parts[l];if(u.type===e.SELECTOR_PART_TYPE)for(c=0;c<u.modifiers.length;c++)a=u.modifiers[c],u.elementName&&a.type==="id"?t.report("Element ("+u+") is overqualified, just use "+a+" without element name.",u.line,u.col,n):a.type==="class"&&(r[a]||(r[a]=[]),r[a].push({modifier:a,part:u}))}}}),e.addListener("endstylesheet",function(){var e;for(e in r)r.hasOwnProperty(e)&&r[e].length===1&&r[e][0].part.elementName&&t.report("Element ("+r[e][0].part+") is overqualified, just use "+r[e][0].modifier+" without element name.",r[e][0].part.line,r[e][0].part.col,n)})}}),CSSLint.addRule({id:"qualified-headings",name:"Disallow qualified headings",desc:"Headings should not be qualified (namespaced).",browsers:"All",init:function(e,t){var n=this;e.addListener("startrule",function(r){var i=r.selectors,s,o,u,a;for(u=0;u<i.length;u++){s=i[u];for(a=0;a<s.parts.length;a++)o=s.parts[a],o.type===e.SELECTOR_PART_TYPE&&o.elementName&&/h[1-6]/.test(o.elementName.toString())&&a>0&&t.report("Heading ("+o.elementName+") should not be qualified.",o.line,o.col,n)}})}}),CSSLint.addRule({id:"regex-selectors",name:"Disallow selectors that look like regexs",desc:"Selectors that look like regular expressions are slow and should be avoided.",browsers:"All",init:function(e,t){var n=this;e.addListener("startrule",function(r){var i=r.selectors,s,o,u,a,f,l;for(a=0;a<i.length;a++){s=i[a];for(f=0;f<s.parts.length;f++){o=s.parts[f];if(o.type===e.SELECTOR_PART_TYPE)for(l=0;l<o.modifiers.length;l++)u=o.modifiers[l],u.type==="attribute"&&/([\~\|\^\$\*]=)/.test(u)&&t.report("Attribute selectors with "+RegExp.$1+" are slow!",u.line,u.col,n)}}})}}),CSSLint.addRule({id:"rules-count",name:"Rules Count",desc:"Track how many rules there are.",browsers:"All",init:function(e,t){var n=0;e.addListener("startrule",function(){n++}),e.addListener("endstylesheet",function(){t.stat("rule-count",n)})}}),CSSLint.addRule({id:"selector-max-approaching",name:"Warn when approaching the 4095 selector limit for IE",desc:"Will warn when selector count is >= 3800 selectors.",browsers:"IE",init:function(e,t){var n=this,r=0;e.addListener("startrule",function(e){r+=e.selectors.length}),e.addListener("endstylesheet",function(){r>=3800&&t.report("You have "+r+" selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.",0,0,n)})}}),CSSLint.addRule({id:"selector-max",name:"Error when past the 4095 selector limit for IE",desc:"Will error when selector count is > 4095.",browsers:"IE",init:function(e,t){var n=this,r=0;e.addListener("startrule",function(e){r+=e.selectors.length}),e.addListener("endstylesheet",function(){r>4095&&t.report("You have "+r+" selectors. Internet Explorer supports a maximum of 4095 selectors per stylesheet. Consider refactoring.",0,0,n)})}}),CSSLint.addRule({id:"selector-newline",name:"Disallow new-line characters in selectors",desc:"New-line characters in selectors are usually a forgotten comma and not a descendant combinator.",browsers:"All",init:function(e,t){function r(e){var r,i,s,o,u,a,f,l,c,h,p,d=e.selectors;for(r=0,i=d.length;r<i;r++){s=d[r];for(o=0,a=s.parts.length;o<a;o++)for(u=o+1;u<a;u++)f=s.parts[o],l=s.parts[u],c=f.type,h=f.line,p=l.line,c==="descendant"&&p>h&&t.report("newline character found in selector (forgot a comma?)",h,d[r].parts[0].col,n)}}var n=this;e.addListener("startrule",r)}}),CSSLint.addRule({id:"shorthand",name:"Require shorthand properties",desc:"Use shorthand properties where possible.",browsers:"All",init:function(e,t){function f(){u={}}function l(e){var r,i,s,o;for(r in a)if(a.hasOwnProperty(r)){o=0;for(i=0,s=a[r].length;i<s;i++)o+=u[a[r][i]]?1:0;o===a[r].length&&t.report("The properties "+a[r].join(", ")+" can be replaced by "+r+".",e.line,e.col,n)}}var n=this,r,i,s,o={},u,a={margin:["margin-top","margin-bottom","margin-left","margin-right"],padding:["padding-top","padding-bottom","padding-left","padding-right"]};for(r in a)if(a.hasOwnProperty(r))for(i=0,s=a[r].length;i<s;i++)o[a[r][i]]=r;e.addListener("startrule",f),e.addListener("startfontface",f),e.addListener("property",function(e){var t=e.property.toString().toLowerCase();o[t]&&(u[t]=1)}),e.addListener("endrule",l),e.addListener("endfontface",l)}}),CSSLint.addRule({id:"star-property-hack",name:"Disallow properties with a star prefix",desc:"Checks for the star property hack (targets IE6/7)",browsers:"All",init:function(e,t){var n=this;e.addListener("property",function(e){var r=e.property;r.hack==="*"&&t.report("Property with star prefix found.",e.property.line,e.property.col,n)})}}),CSSLint.addRule({id:"text-indent",name:"Disallow negative text-indent",desc:"Checks for text indent less than -99px",browsers:"All",init:function(e,t){function s(){r=!1,i="inherit"}function o(){r&&i!=="ltr"&&t.report("Negative text-indent doesn't work well with RTL. If you use text-indent for image replacement explicitly set direction for that item to ltr.",r.line,r.col,n)}var n=this,r,i;e.addListener("startrule",s),e.addListener("startfontface",s),e.addListener("property",function(e){var t=e.property.toString().toLowerCase(),n=e.value;t==="text-indent"&&n.parts[0].value<-99?r=e.property:t==="direction"&&n.toString()==="ltr"&&(i="ltr")}),e.addListener("endrule",o),e.addListener("endfontface",o)}}),CSSLint.addRule({id:"underscore-property-hack",name:"Disallow properties with an underscore prefix",desc:"Checks for the underscore property hack (targets IE6)",browsers:"All",init:function(e,t){var n=this;e.addListener("property",function(e){var r=e.property;r.hack==="_"&&t.report("Property with underscore prefix found.",e.property.line,e.property.col,n)})}}),CSSLint.addRule({id:"unique-headings",name:"Headings should only be defined once",desc:"Headings should be defined only once.",browsers:"All",init:function(e,t){var n=this,r={h1:0,h2:0,h3:0,h4:0,h5:0,h6:0};e.addListener("startrule",function(e){var i=e.selectors,s,o,u,a,f;for(a=0;a<i.length;a++){s=i[a],o=s.parts[s.parts.length-1];if(o.elementName&&/(h[1-6])/i.test(o.elementName.toString())){for(f=0;f<o.modifiers.length;f++)if(o.modifiers[f].type==="pseudo"){u=!0;break}u||(r[RegExp.$1]++,r[RegExp.$1]>1&&t.report("Heading ("+o.elementName+") has already been defined.",o.line,o.col,n))}}}),e.addListener("endstylesheet",function(){var e,i=[];for(e in r)r.hasOwnProperty(e)&&r[e]>1&&i.push(r[e]+" "+e+"s");i.length&&t.rollupWarn("You have "+i.join(", ")+" defined in this stylesheet.",n)})}}),CSSLint.addRule({id:"universal-selector",name:"Disallow universal selector",desc:"The universal selector (*) is known to be slow.",browsers:"All",init:function(e,t){var n=this;e.addListener("startrule",function(e){var r=e.selectors,i,s,o;for(o=0;o<r.length;o++)i=r[o],s=i.parts[i.parts.length-1],s.elementName==="*"&&t.report(n.desc,s.line,s.col,n)})}}),CSSLint.addRule({id:"unqualified-attributes",name:"Disallow unqualified attribute selectors",desc:"Unqualified attribute selectors are known to be slow.",browsers:"All",init:function(e,t){var n=this;e.addListener("startrule",function(r){var i=r.selectors,s,o,u,a,f;for(a=0;a<i.length;a++){s=i[a],o=s.parts[s.parts.length-1];if(o.type===e.SELECTOR_PART_TYPE)for(f=0;f<o.modifiers.length;f++)u=o.modifiers[f],u.type==="attribute"&&(!o.elementName||o.elementName==="*")&&t.report(n.desc,o.line,o.col,n)}})}}),CSSLint.addRule({id:"vendor-prefix",name:"Require standard property with vendor prefix",desc:"When using a vendor-prefixed property, make sure to include the standard one.",browsers:"All",init:function(e,t){function o(){r={},i=1}function u(){var e,i,o,u,a,f=[];for(e in r)s[e]&&f.push({actual:e,needed:s[e]});for(i=0,o=f.length;i<o;i++)u=f[i].needed,a=f[i].actual,r[u]?r[u][0].pos<r[a][0].pos&&t.report("Standard property '"+u+"' should come after vendor-prefixed property '"+a+"'.",r[a][0].name.line,r[a][0].name.col,n):t.report("Missing standard property '"+u+"' to go along with '"+a+"'.",r[a][0].name.line,r[a][0].name.col,n)}var n=this,r,i,s={"-webkit-border-radius":"border-radius","-webkit-border-top-left-radius":"border-top-left-radius","-webkit-border-top-right-radius":"border-top-right-radius","-webkit-border-bottom-left-radius":"border-bottom-left-radius","-webkit-border-bottom-right-radius":"border-bottom-right-radius","-o-border-radius":"border-radius","-o-border-top-left-radius":"border-top-left-radius","-o-border-top-right-radius":"border-top-right-radius","-o-border-bottom-left-radius":"border-bottom-left-radius","-o-border-bottom-right-radius":"border-bottom-right-radius","-moz-border-radius":"border-radius","-moz-border-radius-topleft":"border-top-left-radius","-moz-border-radius-topright":"border-top-right-radius","-moz-border-radius-bottomleft":"border-bottom-left-radius","-moz-border-radius-bottomright":"border-bottom-right-radius","-moz-column-count":"column-count","-webkit-column-count":"column-count","-moz-column-gap":"column-gap","-webkit-column-gap":"column-gap","-moz-column-rule":"column-rule","-webkit-column-rule":"column-rule","-moz-column-rule-style":"column-rule-style","-webkit-column-rule-style":"column-rule-style","-moz-column-rule-color":"column-rule-color","-webkit-column-rule-color":"column-rule-color","-moz-column-rule-width":"column-rule-width","-webkit-column-rule-width":"column-rule-width","-moz-column-width":"column-width","-webkit-column-width":"column-width","-webkit-column-span":"column-span","-webkit-columns":"columns","-moz-box-shadow":"box-shadow","-webkit-box-shadow":"box-shadow","-moz-transform":"transform","-webkit-transform":"transform","-o-transform":"transform","-ms-transform":"transform","-moz-transform-origin":"transform-origin","-webkit-transform-origin":"transform-origin","-o-transform-origin":"transform-origin","-ms-transform-origin":"transform-origin","-moz-box-sizing":"box-sizing","-webkit-box-sizing":"box-sizing"};e.addListener("startrule",o),e.addListener("startfontface",o),e.addListener("startpage",o),e.addListener("startpagemargin",o),e.addListener("startkeyframerule",o),e.addListener("property",function(e){var t=e.property.text.toLowerCase();r[t]||(r[t]=[]),r[t].push({name:e.property,value:e.value,pos:i++})}),e.addListener("endrule",u),e.addListener("endfontface",u),e.addListener("endpage",u),e.addListener("endpagemargin",u),e.addListener("endkeyframerule",u)}}),CSSLint.addRule({id:"zero-units",name:"Disallow units for 0 values",desc:"You don't need to specify units when a value is 0.",browsers:"All",init:function(e,t){var n=this;e.addListener("property",function(e){var r=e.value.parts,i=0,s=r.length;while(i<s)(r[i].units||r[i].type==="percentage")&&r[i].value===0&&r[i].type!=="time"&&t.report("Values of 0 shouldn't have units specified.",r[i].line,r[i].col,n),i++})}}),function(){var e=function(e){return!e||e.constructor!==String?"":e.replace(/[\"&><]/g,function(e){switch(e){case'"':return"&quot;";case"&":return"&amp;";case"<":return"&lt;";case">":return"&gt;"}})};CSSLint.addFormatter({id:"checkstyle-xml",name:"Checkstyle XML format",startFormat:function(){return'<?xml version="1.0" encoding="utf-8"?><checkstyle>'},endFormat:function(){return"</checkstyle>"},readError:function(t,n){return'<file name="'+e(t)+'"><error line="0" column="0" severty="error" message="'+e(n)+'"></error></file>'},formatResults:function(t,n){var r=t.messages,i=[],s=function(e){return!!e&&"name"in e?"net.csslint."+e.name.replace(/\s/g,""):""};return r.length>0&&(i.push('<file name="'+n+'">'),CSSLint.Util.forEach(r,function(t){t.rollup||i.push('<error line="'+t.line+'" column="'+t.col+'" severity="'+t.type+'"'+' message="'+e(t.message)+'" source="'+s(t.rule)+'"/>')}),i.push("</file>")),i.join("")}})}(),CSSLint.addFormatter({id:"compact",name:"Compact, 'porcelain' format",startFormat:function(){return""},endFormat:function(){return""},formatResults:function(e,t,n){var r=e.messages,i="";n=n||{};var s=function(e){return e.charAt(0).toUpperCase()+e.slice(1)};return r.length===0?n.quiet?"":t+": Lint Free!":(CSSLint.Util.forEach(r,function(e){e.rollup?i+=t+": "+s(e.type)+" - "+e.message+"\n":i+=t+": "+"line "+e.line+", col "+e.col+", "+s(e.type)+" - "+e.message+" ("+e.rule.id+")\n"}),i)}}),CSSLint.addFormatter({id:"csslint-xml",name:"CSSLint XML format",startFormat:function(){return'<?xml version="1.0" encoding="utf-8"?><csslint>'},endFormat:function(){return"</csslint>"},formatResults:function(e,t){var n=e.messages,r=[],i=function(e){return!e||e.constructor!==String?"":e.replace(/\"/g,"'").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")};return n.length>0&&(r.push('<file name="'+t+'">'),CSSLint.Util.forEach(n,function(e){e.rollup?r.push('<issue severity="'+e.type+'" reason="'+i(e.message)+'" evidence="'+i(e.evidence)+'"/>'):r.push('<issue line="'+e.line+'" char="'+e.col+'" severity="'+e.type+'"'+' reason="'+i(e.message)+'" evidence="'+i(e.evidence)+'"/>')}),r.push("</file>")),r.join("")}}),CSSLint.addFormatter({id:"junit-xml",name:"JUNIT XML format",startFormat:function(){return'<?xml version="1.0" encoding="utf-8"?><testsuites>'},endFormat:function(){return"</testsuites>"},formatResults:function(e,t){var n=e.messages,r=[],i={error:0,failure:0},s=function(e){return!!e&&"name"in e?"net.csslint."+e.name.replace(/\s/g,""):""},o=function(e){return!e||e.constructor!==String?"":e.replace(/\"/g,"'").replace(/</g,"&lt;").replace(/>/g,"&gt;")};return n.length>0&&(n.forEach(function(e){var t=e.type==="warning"?"error":e.type;e.rollup||(r.push('<testcase time="0" name="'+s(e.rule)+'">'),r.push("<"+t+' message="'+o(e.message)+'"><![CDATA['+e.line+":"+e.col+":"+o(e.evidence)+"]]></"+t+">"),r.push("</testcase>"),i[t]+=1)}),r.unshift('<testsuite time="0" tests="'+n.length+'" skipped="0" errors="'+i.error+'" failures="'+i.failure+'" package="net.csslint" name="'+t+'">'),r.push("</testsuite>")),r.join("")}}),CSSLint.addFormatter({id:"lint-xml",name:"Lint XML format",startFormat:function(){return'<?xml version="1.0" encoding="utf-8"?><lint>'},endFormat:function(){return"</lint>"},formatResults:function(e,t){var n=e.messages,r=[],i=function(e){return!e||e.constructor!==String?"":e.replace(/\"/g,"'").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")};return n.length>0&&(r.push('<file name="'+t+'">'),CSSLint.Util.forEach(n,function(e){e.rollup?r.push('<issue severity="'+e.type+'" reason="'+i(e.message)+'" evidence="'+i(e.evidence)+'"/>'):r.push('<issue line="'+e.line+'" char="'+e.col+'" severity="'+e.type+'"'+' reason="'+i(e.message)+'" evidence="'+i(e.evidence)+'"/>')}),r.push("</file>")),r.join("")}}),CSSLint.addFormatter({id:"text",name:"Plain Text",startFormat:function(){return""},endFormat:function(){return""},formatResults:function(e,t,n){var r=e.messages,i="";n=n||{};if(r.length===0)return n.quiet?"":"\n\ncsslint: No errors in "+t+".";i="\n\ncsslint: There ",r.length===1?i+="is 1 problem":i+="are "+r.length+" problems",i+=" in "+t+".";var s=t.lastIndexOf("/"),o=t;return s===-1&&(s=t.lastIndexOf("\\")),s>-1&&(o=t.substring(s+1)),CSSLint.Util.forEach(r,function(e,t){i=i+"\n\n"+o,e.rollup?(i+="\n"+(t+1)+": "+e.type,i+="\n"+e.message):(i+="\n"+(t+1)+": "+e.type+" at line "+e.line+", col "+e.col,i+="\n"+e.message,i+="\n"+e.evidence)}),i}}),module.exports.CSSLint=CSSLint}),ace.define("ace/mode/css_worker",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/worker/mirror","ace/mode/css/csslint"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../lib/lang"),s=e("../worker/mirror").Mirror,o=e("./css/csslint").CSSLint,u=t.Worker=function(e){s.call(this,e),this.setTimeout(400),this.ruleset=null,this.setDisabledRules("ids|order-alphabetical"),this.setInfoRules("adjoining-classes|qualified-headings|zero-units|gradients|import|outline-none|vendor-prefix")};r.inherits(u,s),function(){this.setInfoRules=function(e){typeof e=="string"&&(e=e.split("|")),this.infoRules=i.arrayToMap(e),this.doc.getValue()&&this.deferredUpdate.schedule(100)},this.setDisabledRules=function(e){if(!e)this.ruleset=null;else{typeof e=="string"&&(e=e.split("|"));var t={};o.getRules().forEach(function(e){t[e.id]=!0}),e.forEach(function(e){delete t[e]}),this.ruleset=t}this.doc.getValue()&&this.deferredUpdate.schedule(100)},this.onUpdate=function(){var e=this.doc.getValue();if(!e)return this.sender.emit("annotate",[]);var t=this.infoRules,n=o.verify(e,this.ruleset);this.sender.emit("annotate",n.messages.map(function(e){return{row:e.line-1,column:e.col-1,text:e.message,type:t[e.rule.id]?"info":e.type,rule:e.rule.name}}))}}.call(u.prototype)}),ace.define("ace/lib/es5-shim",["require","exports","module"],function(e,t,n){function r(){}function w(e){try{return Object.defineProperty(e,"sentinel",{}),"sentinel"in e}catch(t){}}function H(e){return e=+e,e!==e?e=0:e!==0&&e!==1/0&&e!==-1/0&&(e=(e>0||-1)*Math.floor(Math.abs(e))),e}function B(e){var t=typeof e;return e===null||t==="undefined"||t==="boolean"||t==="number"||t==="string"}function j(e){var t,n,r;if(B(e))return e;n=e.valueOf;if(typeof n=="function"){t=n.call(e);if(B(t))return t}r=e.toString;if(typeof r=="function"){t=r.call(e);if(B(t))return t}throw new TypeError}Function.prototype.bind||(Function.prototype.bind=function(t){var n=this;if(typeof n!="function")throw new TypeError("Function.prototype.bind called on incompatible "+n);var i=u.call(arguments,1),s=function(){if(this instanceof s){var e=n.apply(this,i.concat(u.call(arguments)));return Object(e)===e?e:this}return n.apply(t,i.concat(u.call(arguments)))};return n.prototype&&(r.prototype=n.prototype,s.prototype=new r,r.prototype=null),s});var i=Function.prototype.call,s=Array.prototype,o=Object.prototype,u=s.slice,a=i.bind(o.toString),f=i.bind(o.hasOwnProperty),l,c,h,p,d;if(d=f(o,"__defineGetter__"))l=i.bind(o.__defineGetter__),c=i.bind(o.__defineSetter__),h=i.bind(o.__lookupGetter__),p=i.bind(o.__lookupSetter__);if([1,2].splice(0).length!=2)if(!function(){function e(e){var t=new Array(e+2);return t[0]=t[1]=0,t}var t=[],n;t.splice.apply(t,e(20)),t.splice.apply(t,e(26)),n=t.length,t.splice(5,0,"XXX"),n+1==t.length;if(n+1==t.length)return!0}())Array.prototype.splice=function(e,t){var n=this.length;e>0?e>n&&(e=n):e==void 0?e=0:e<0&&(e=Math.max(n+e,0)),e+t<n||(t=n-e);var r=this.slice(e,e+t),i=u.call(arguments,2),s=i.length;if(e===n)s&&this.push.apply(this,i);else{var o=Math.min(t,n-e),a=e+o,f=a+s-o,l=n-a,c=n-o;if(f<a)for(var h=0;h<l;++h)this[f+h]=this[a+h];else if(f>a)for(h=l;h--;)this[f+h]=this[a+h];if(s&&e===c)this.length=c,this.push.apply(this,i);else{this.length=c+s;for(h=0;h<s;++h)this[e+h]=i[h]}}return r};else{var v=Array.prototype.splice;Array.prototype.splice=function(e,t){return arguments.length?v.apply(this,[e===void 0?0:e,t===void 0?this.length-e:t].concat(u.call(arguments,2))):[]}}Array.isArray||(Array.isArray=function(t){return a(t)=="[object Array]"});var m=Object("a"),g=m[0]!="a"||!(0 in m);Array.prototype.forEach||(Array.prototype.forEach=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=arguments[1],s=-1,o=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError;while(++s<o)s in r&&t.call(i,r[s],s,n)}),Array.prototype.map||(Array.prototype.map=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=Array(i),o=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var u=0;u<i;u++)u in r&&(s[u]=t.call(o,r[u],u,n));return s}),Array.prototype.filter||(Array.prototype.filter=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=[],o,u=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var f=0;f<i;f++)f in r&&(o=r[f],t.call(u,o,f,n)&&s.push(o));return s}),Array.prototype.every||(Array.prototype.every=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&!t.call(s,r[o],o,n))return!1;return!0}),Array.prototype.some||(Array.prototype.some=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&t.call(s,r[o],o,n))return!0;return!1}),Array.prototype.reduce||(Array.prototype.reduce=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduce of empty array with no initial value");var s=0,o;if(arguments.length>=2)o=arguments[1];else do{if(s in r){o=r[s++];break}if(++s>=i)throw new TypeError("reduce of empty array with no initial value")}while(!0);for(;s<i;s++)s in r&&(o=t.call(void 0,o,r[s],s,n));return o}),Array.prototype.reduceRight||(Array.prototype.reduceRight=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduceRight of empty array with no initial value");var s,o=i-1;if(arguments.length>=2)s=arguments[1];else do{if(o in r){s=r[o--];break}if(--o<0)throw new TypeError("reduceRight of empty array with no initial value")}while(!0);do o in this&&(s=t.call(void 0,s,r[o],o,n));while(o--);return s});if(!Array.prototype.indexOf||[0,1].indexOf(1,2)!=-1)Array.prototype.indexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=0;arguments.length>1&&(i=H(arguments[1])),i=i>=0?i:Math.max(0,r+i);for(;i<r;i++)if(i in n&&n[i]===t)return i;return-1};if(!Array.prototype.lastIndexOf||[0,1].lastIndexOf(0,-3)!=-1)Array.prototype.lastIndexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=r-1;arguments.length>1&&(i=Math.min(i,H(arguments[1]))),i=i>=0?i:r-Math.abs(i);for(;i>=0;i--)if(i in n&&t===n[i])return i;return-1};Object.getPrototypeOf||(Object.getPrototypeOf=function(t){return t.__proto__||(t.constructor?t.constructor.prototype:o)});if(!Object.getOwnPropertyDescriptor){var y="Object.getOwnPropertyDescriptor called on a non-object: ";Object.getOwnPropertyDescriptor=function(t,n){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(y+t);if(!f(t,n))return;var r,i,s;r={enumerable:!0,configurable:!0};if(d){var u=t.__proto__;t.__proto__=o;var i=h(t,n),s=p(t,n);t.__proto__=u;if(i||s)return i&&(r.get=i),s&&(r.set=s),r}return r.value=t[n],r}}Object.getOwnPropertyNames||(Object.getOwnPropertyNames=function(t){return Object.keys(t)});if(!Object.create){var b;Object.prototype.__proto__===null?b=function(){return{__proto__:null}}:b=function(){var e={};for(var t in e)e[t]=null;return e.constructor=e.hasOwnProperty=e.propertyIsEnumerable=e.isPrototypeOf=e.toLocaleString=e.toString=e.valueOf=e.__proto__=null,e},Object.create=function(t,n){var r;if(t===null)r=b();else{if(typeof t!="object")throw new TypeError("typeof prototype["+typeof t+"] != 'object'");var i=function(){};i.prototype=t,r=new i,r.__proto__=t}return n!==void 0&&Object.defineProperties(r,n),r}}if(Object.defineProperty){var E=w({}),S=typeof document=="undefined"||w(document.createElement("div"));if(!E||!S)var x=Object.defineProperty}if(!Object.defineProperty||x){var T="Property description must be an object: ",N="Object.defineProperty called on non-object: ",C="getters & setters can not be defined on this javascript engine";Object.defineProperty=function(t,n,r){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(N+t);if(typeof r!="object"&&typeof r!="function"||r===null)throw new TypeError(T+r);if(x)try{return x.call(Object,t,n,r)}catch(i){}if(f(r,"value"))if(d&&(h(t,n)||p(t,n))){var s=t.__proto__;t.__proto__=o,delete t[n],t[n]=r.value,t.__proto__=s}else t[n]=r.value;else{if(!d)throw new TypeError(C);f(r,"get")&&l(t,n,r.get),f(r,"set")&&c(t,n,r.set)}return t}}Object.defineProperties||(Object.defineProperties=function(t,n){for(var r in n)f(n,r)&&Object.defineProperty(t,r,n[r]);return t}),Object.seal||(Object.seal=function(t){return t}),Object.freeze||(Object.freeze=function(t){return t});try{Object.freeze(function(){})}catch(k){Object.freeze=function(t){return function(n){return typeof n=="function"?n:t(n)}}(Object.freeze)}Object.preventExtensions||(Object.preventExtensions=function(t){return t}),Object.isSealed||(Object.isSealed=function(t){return!1}),Object.isFrozen||(Object.isFrozen=function(t){return!1}),Object.isExtensible||(Object.isExtensible=function(t){if(Object(t)===t)throw new TypeError;var n="";while(f(t,n))n+="?";t[n]=!0;var r=f(t,n);return delete t[n],r});if(!Object.keys){var L=!0,A=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],O=A.length;for(var M in{toString:null})L=!1;Object.keys=function I(e){if(typeof e!="object"&&typeof e!="function"||e===null)throw new TypeError("Object.keys called on a non-object");var I=[];for(var t in e)f(e,t)&&I.push(t);if(L)for(var n=0,r=O;n<r;n++){var i=A[n];f(e,i)&&I.push(i)}return I}}Date.now||(Date.now=function(){return(new Date).getTime()});var _="	\n\f\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\ufeff";if(!String.prototype.trim||_.trim()){_="["+_+"]";var D=new RegExp("^"+_+_+"*"),P=new RegExp(_+_+"*$");String.prototype.trim=function(){return String(this).replace(D,"").replace(P,"")}}var F=function(e){if(e==null)throw new TypeError("can't convert "+e+" to object");return Object(e)}})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-html.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-html.js
new file mode 100644
index 0000000..3062f4d
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-html.js
@@ -0,0 +1 @@
+"no use strict";(function(e){function t(e,t){var n=e,r="";while(n){var i=t[n];if(typeof i=="string")return i+r;if(i)return i.location.replace(/\/*$/,"/")+(r||i.main||i.name);if(i===!1)return"";var s=n.lastIndexOf("/");if(s===-1)break;r=n.substr(s)+r,n=n.slice(0,s)}return e}if(typeof e.window!="undefined"&&e.document)return;if(e.require&&e.define)return;e.console||(e.console=function(){var e=Array.prototype.slice.call(arguments,0);postMessage({type:"log",data:e})},e.console.error=e.console.warn=e.console.log=e.console.trace=e.console),e.window=e,e.ace=e,e.onerror=function(e,t,n,r,i){postMessage({type:"error",data:{message:e,data:i.data,file:t,line:n,col:r,stack:i.stack}})},e.normalizeModule=function(t,n){if(n.indexOf("!")!==-1){var r=n.split("!");return e.normalizeModule(t,r[0])+"!"+e.normalizeModule(t,r[1])}if(n.charAt(0)=="."){var i=t.split("/").slice(0,-1).join("/");n=(i?i+"/":"")+n;while(n.indexOf(".")!==-1&&s!=n){var s=n;n=n.replace(/^\.\//,"").replace(/\/\.\//,"/").replace(/[^\/]+\/\.\.\//,"")}}return n},e.require=function(r,i){i||(i=r,r=null);if(!i.charAt)throw new Error("worker.js require() accepts only (parentId, id) as arguments");i=e.normalizeModule(r,i);var s=e.require.modules[i];if(s)return s.initialized||(s.initialized=!0,s.exports=s.factory().exports),s.exports;if(!e.require.tlns)return console.log("unable to load "+i);var o=t(i,e.require.tlns);return o.slice(-3)!=".js"&&(o+=".js"),e.require.id=i,e.require.modules[i]={},importScripts(o),e.require(r,i)},e.require.modules={},e.require.tlns={},e.define=function(t,n,r){arguments.length==2?(r=n,typeof t!="string"&&(n=t,t=e.require.id)):arguments.length==1&&(r=t,n=[],t=e.require.id);if(typeof r!="function"){e.require.modules[t]={exports:r,initialized:!0};return}n.length||(n=["require","exports","module"]);var i=function(n){return e.require(t,n)};e.require.modules[t]={exports:{},factory:function(){var e=this,t=r.apply(this,n.map(function(t){switch(t){case"require":return i;case"exports":return e.exports;case"module":return e;default:return i(t)}}));return t&&(e.exports=t),e}}},e.define.amd={},require.tlns={},e.initBaseUrls=function(t){for(var n in t)require.tlns[n]=t[n]},e.initSender=function(){var n=e.require("ace/lib/event_emitter").EventEmitter,r=e.require("ace/lib/oop"),i=function(){};return function(){r.implement(this,n),this.callback=function(e,t){postMessage({type:"call",id:t,data:e})},this.emit=function(e,t){postMessage({type:"event",name:e,data:t})}}.call(i.prototype),new i};var n=e.main=null,r=e.sender=null;e.onmessage=function(t){var i=t.data;if(i.event&&r)r._signal(i.event,i.data);else if(i.command)if(n[i.command])n[i.command].apply(n,i.args);else{if(!e[i.command])throw new Error("Unknown command:"+i.command);e[i.command].apply(e,i.args)}else if(i.init){e.initBaseUrls(i.tlns),require("ace/lib/es5-shim"),r=e.sender=e.initSender();var s=require(i.module)[i.classname];n=e.main=new s(r)}}})(this),ace.define("ace/lib/oop",["require","exports","module"],function(e,t,n){"use strict";t.inherits=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})},t.mixin=function(e,t){for(var n in t)e[n]=t[n];return e},t.implement=function(e,n){t.mixin(e,n)}}),ace.define("ace/lib/lang",["require","exports","module"],function(e,t,n){"use strict";t.last=function(e){return e[e.length-1]},t.stringReverse=function(e){return e.split("").reverse().join("")},t.stringRepeat=function(e,t){var n="";while(t>0){t&1&&(n+=e);if(t>>=1)e+=e}return n};var r=/^\s\s*/,i=/\s\s*$/;t.stringTrimLeft=function(e){return e.replace(r,"")},t.stringTrimRight=function(e){return e.replace(i,"")},t.copyObject=function(e){var t={};for(var n in e)t[n]=e[n];return t},t.copyArray=function(e){var t=[];for(var n=0,r=e.length;n<r;n++)e[n]&&typeof e[n]=="object"?t[n]=this.copyObject(e[n]):t[n]=e[n];return t},t.deepCopy=function s(e){if(typeof e!="object"||!e)return e;var t;if(Array.isArray(e)){t=[];for(var n=0;n<e.length;n++)t[n]=s(e[n]);return t}var r=e.constructor;if(r===RegExp)return e;t=r();for(var n in e)t[n]=s(e[n]);return t},t.arrayToMap=function(e){var t={};for(var n=0;n<e.length;n++)t[e[n]]=1;return t},t.createMap=function(e){var t=Object.create(null);for(var n in e)t[n]=e[n];return t},t.arrayRemove=function(e,t){for(var n=0;n<=e.length;n++)t===e[n]&&e.splice(n,1)},t.escapeRegExp=function(e){return e.replace(/([.*+?^${}()|[\]\/\\])/g,"\\$1")},t.escapeHTML=function(e){return e.replace(/&/g,"&#38;").replace(/"/g,"&#34;").replace(/'/g,"&#39;").replace(/</g,"&#60;")},t.getMatchOffsets=function(e,t){var n=[];return e.replace(t,function(e){n.push({offset:arguments[arguments.length-2],length:e.length})}),n},t.deferredCall=function(e){var t=null,n=function(){t=null,e()},r=function(e){return r.cancel(),t=setTimeout(n,e||0),r};return r.schedule=r,r.call=function(){return this.cancel(),e(),r},r.cancel=function(){return clearTimeout(t),t=null,r},r.isPending=function(){return t},r},t.delayedCall=function(e,t){var n=null,r=function(){n=null,e()},i=function(e){n==null&&(n=setTimeout(r,e||t))};return i.delay=function(e){n&&clearTimeout(n),n=setTimeout(r,e||t)},i.schedule=i,i.call=function(){this.cancel(),e()},i.cancel=function(){n&&clearTimeout(n),n=null},i.isPending=function(){return n},i}}),ace.define("ace/range",["require","exports","module"],function(e,t,n){"use strict";var r=function(e,t){return e.row-t.row||e.column-t.column},i=function(e,t,n,r){this.start={row:e,column:t},this.end={row:n,column:r}};(function(){this.isEqual=function(e){return this.start.row===e.start.row&&this.end.row===e.end.row&&this.start.column===e.start.column&&this.end.column===e.end.column},this.toString=function(){return"Range: ["+this.start.row+"/"+this.start.column+"] -> ["+this.end.row+"/"+this.end.column+"]"},this.contains=function(e,t){return this.compare(e,t)==0},this.compareRange=function(e){var t,n=e.end,r=e.start;return t=this.compare(n.row,n.column),t==1?(t=this.compare(r.row,r.column),t==1?2:t==0?1:0):t==-1?-2:(t=this.compare(r.row,r.column),t==-1?-1:t==1?42:0)},this.comparePoint=function(e){return this.compare(e.row,e.column)},this.containsRange=function(e){return this.comparePoint(e.start)==0&&this.comparePoint(e.end)==0},this.intersects=function(e){var t=this.compareRange(e);return t==-1||t==0||t==1},this.isEnd=function(e,t){return this.end.row==e&&this.end.column==t},this.isStart=function(e,t){return this.start.row==e&&this.start.column==t},this.setStart=function(e,t){typeof e=="object"?(this.start.column=e.column,this.start.row=e.row):(this.start.row=e,this.start.column=t)},this.setEnd=function(e,t){typeof e=="object"?(this.end.column=e.column,this.end.row=e.row):(this.end.row=e,this.end.column=t)},this.inside=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)||this.isStart(e,t)?!1:!0:!1},this.insideStart=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)?!1:!0:!1},this.insideEnd=function(e,t){return this.compare(e,t)==0?this.isStart(e,t)?!1:!0:!1},this.compare=function(e,t){return!this.isMultiLine()&&e===this.start.row?t<this.start.column?-1:t>this.end.column?1:0:e<this.start.row?-1:e>this.end.row?1:this.start.row===e?t>=this.start.column?0:-1:this.end.row===e?t<=this.end.column?0:1:0},this.compareStart=function(e,t){return this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.compareEnd=function(e,t){return this.end.row==e&&this.end.column==t?1:this.compare(e,t)},this.compareInside=function(e,t){return this.end.row==e&&this.end.column==t?1:this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.clipRows=function(e,t){if(this.end.row>t)var n={row:t+1,column:0};else if(this.end.row<e)var n={row:e,column:0};if(this.start.row>t)var r={row:t+1,column:0};else if(this.start.row<e)var r={row:e,column:0};return i.fromPoints(r||this.start,n||this.end)},this.extend=function(e,t){var n=this.compare(e,t);if(n==0)return this;if(n==-1)var r={row:e,column:t};else var s={row:e,column:t};return i.fromPoints(r||this.start,s||this.end)},this.isEmpty=function(){return this.start.row===this.end.row&&this.start.column===this.end.column},this.isMultiLine=function(){return this.start.row!==this.end.row},this.clone=function(){return i.fromPoints(this.start,this.end)},this.collapseRows=function(){return this.end.column==0?new i(this.start.row,0,Math.max(this.start.row,this.end.row-1),0):new i(this.start.row,0,this.end.row,0)},this.toScreenRange=function(e){var t=e.documentToScreenPosition(this.start),n=e.documentToScreenPosition(this.end);return new i(t.row,t.column,n.row,n.column)},this.moveBy=function(e,t){this.start.row+=e,this.start.column+=t,this.end.row+=e,this.end.column+=t}}).call(i.prototype),i.fromPoints=function(e,t){return new i(e.row,e.column,t.row,t.column)},i.comparePoints=r,i.comparePoints=function(e,t){return e.row-t.row||e.column-t.column},t.Range=i}),ace.define("ace/apply_delta",["require","exports","module"],function(e,t,n){"use strict";function r(e,t){throw console.log("Invalid Delta:",e),"Invalid Delta: "+t}function i(e,t){return t.row>=0&&t.row<e.length&&t.column>=0&&t.column<=e[t.row].length}function s(e,t){t.action!="insert"&&t.action!="remove"&&r(t,"delta.action must be 'insert' or 'remove'"),t.lines instanceof Array||r(t,"delta.lines must be an Array"),(!t.start||!t.end)&&r(t,"delta.start/end must be an present");var n=t.start;i(e,t.start)||r(t,"delta.start must be contained in document");var s=t.end;t.action=="remove"&&!i(e,s)&&r(t,"delta.end must contained in document for 'remove' actions");var o=s.row-n.row,u=s.column-(o==0?n.column:0);(o!=t.lines.length-1||t.lines[o].length!=u)&&r(t,"delta.range must match delta lines")}t.applyDelta=function(e,t,n){var r=t.start.row,i=t.start.column,s=e[r]||"";switch(t.action){case"insert":var o=t.lines;if(o.length===1)e[r]=s.substring(0,i)+t.lines[0]+s.substring(i);else{var u=[r,1].concat(t.lines);e.splice.apply(e,u),e[r]=s.substring(0,i)+e[r],e[r+t.lines.length-1]+=s.substring(i)}break;case"remove":var a=t.end.column,f=t.end.row;r===f?e[r]=s.substring(0,i)+s.substring(a):e.splice(r,f-r+1,s.substring(0,i)+e[f].substring(a))}}}),ace.define("ace/lib/event_emitter",["require","exports","module"],function(e,t,n){"use strict";var r={},i=function(){this.propagationStopped=!0},s=function(){this.defaultPrevented=!0};r._emit=r._dispatchEvent=function(e,t){this._eventRegistry||(this._eventRegistry={}),this._defaultHandlers||(this._defaultHandlers={});var n=this._eventRegistry[e]||[],r=this._defaultHandlers[e];if(!n.length&&!r)return;if(typeof t!="object"||!t)t={};t.type||(t.type=e),t.stopPropagation||(t.stopPropagation=i),t.preventDefault||(t.preventDefault=s),n=n.slice();for(var o=0;o<n.length;o++){n[o](t,this);if(t.propagationStopped)break}if(r&&!t.defaultPrevented)return r(t,this)},r._signal=function(e,t){var n=(this._eventRegistry||{})[e];if(!n)return;n=n.slice();for(var r=0;r<n.length;r++)n[r](t,this)},r.once=function(e,t){var n=this;t&&this.addEventListener(e,function r(){n.removeEventListener(e,r),t.apply(null,arguments)})},r.setDefaultHandler=function(e,t){var n=this._defaultHandlers;n||(n=this._defaultHandlers={_disabled_:{}});if(n[e]){var r=n[e],i=n._disabled_[e];i||(n._disabled_[e]=i=[]),i.push(r);var s=i.indexOf(t);s!=-1&&i.splice(s,1)}n[e]=t},r.removeDefaultHandler=function(e,t){var n=this._defaultHandlers;if(!n)return;var r=n._disabled_[e];if(n[e]==t){var i=n[e];r&&this.setDefaultHandler(e,r.pop())}else if(r){var s=r.indexOf(t);s!=-1&&r.splice(s,1)}},r.on=r.addEventListener=function(e,t,n){this._eventRegistry=this._eventRegistry||{};var r=this._eventRegistry[e];return r||(r=this._eventRegistry[e]=[]),r.indexOf(t)==-1&&r[n?"unshift":"push"](t),t},r.off=r.removeListener=r.removeEventListener=function(e,t){this._eventRegistry=this._eventRegistry||{};var n=this._eventRegistry[e];if(!n)return;var r=n.indexOf(t);r!==-1&&n.splice(r,1)},r.removeAllListeners=function(e){this._eventRegistry&&(this._eventRegistry[e]=[])},t.EventEmitter=r}),ace.define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=t.Anchor=function(e,t,n){this.$onChange=this.onChange.bind(this),this.attach(e),typeof n=="undefined"?this.setPosition(t.row,t.column):this.setPosition(t,n)};(function(){function e(e,t,n){var r=n?e.column<=t.column:e.column<t.column;return e.row<t.row||e.row==t.row&&r}function t(t,n,r){var i=t.action=="insert",s=(i?1:-1)*(t.end.row-t.start.row),o=(i?1:-1)*(t.end.column-t.start.column),u=t.start,a=i?u:t.end;return e(n,u,r)?{row:n.row,column:n.column}:e(a,n,!r)?{row:n.row+s,column:n.column+(n.row==a.row?o:0)}:{row:u.row,column:u.column}}r.implement(this,i),this.getPosition=function(){return this.$clipPositionToDocument(this.row,this.column)},this.getDocument=function(){return this.document},this.$insertRight=!1,this.onChange=function(e){if(e.start.row==e.end.row&&e.start.row!=this.row)return;if(e.start.row>this.row)return;var n=t(e,{row:this.row,column:this.column},this.$insertRight);this.setPosition(n.row,n.column,!0)},this.setPosition=function(e,t,n){var r;n?r={row:e,column:t}:r=this.$clipPositionToDocument(e,t);if(this.row==r.row&&this.column==r.column)return;var i={row:this.row,column:this.column};this.row=r.row,this.column=r.column,this._signal("change",{old:i,value:r})},this.detach=function(){this.document.removeEventListener("change",this.$onChange)},this.attach=function(e){this.document=e||this.document,this.document.on("change",this.$onChange)},this.$clipPositionToDocument=function(e,t){var n={};return e>=this.document.getLength()?(n.row=Math.max(0,this.document.getLength()-1),n.column=this.document.getLine(n.row).length):e<0?(n.row=0,n.column=0):(n.row=e,n.column=Math.min(this.document.getLine(n.row).length,Math.max(0,t))),t<0&&(n.column=0),n}}).call(s.prototype)}),ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./apply_delta").applyDelta,s=e("./lib/event_emitter").EventEmitter,o=e("./range").Range,u=e("./anchor").Anchor,a=function(e){this.$lines=[""],e.length===0?this.$lines=[""]:Array.isArray(e)?this.insertMergedLines({row:0,column:0},e):this.insert({row:0,column:0},e)};(function(){r.implement(this,s),this.setValue=function(e){var t=this.getLength()-1;this.remove(new o(0,0,t,this.getLine(t).length)),this.insert({row:0,column:0},e)},this.getValue=function(){return this.getAllLines().join(this.getNewLineCharacter())},this.createAnchor=function(e,t){return new u(this,e,t)},"aaa".split(/a/).length===0?this.$split=function(e){return e.replace(/\r\n|\r/g,"\n").split("\n")}:this.$split=function(e){return e.split(/\r\n|\r|\n/)},this.$detectNewLine=function(e){var t=e.match(/^.*?(\r\n|\r|\n)/m);this.$autoNewLine=t?t[1]:"\n",this._signal("changeNewLineMode")},this.getNewLineCharacter=function(){switch(this.$newLineMode){case"windows":return"\r\n";case"unix":return"\n";default:return this.$autoNewLine||"\n"}},this.$autoNewLine="",this.$newLineMode="auto",this.setNewLineMode=function(e){if(this.$newLineMode===e)return;this.$newLineMode=e,this._signal("changeNewLineMode")},this.getNewLineMode=function(){return this.$newLineMode},this.isNewLine=function(e){return e=="\r\n"||e=="\r"||e=="\n"},this.getLine=function(e){return this.$lines[e]||""},this.getLines=function(e,t){return this.$lines.slice(e,t+1)},this.getAllLines=function(){return this.getLines(0,this.getLength())},this.getLength=function(){return this.$lines.length},this.getTextRange=function(e){return this.getLinesForRange(e).join(this.getNewLineCharacter())},this.getLinesForRange=function(e){var t;if(e.start.row===e.end.row)t=[this.getLine(e.start.row).substring(e.start.column,e.end.column)];else{t=this.getLines(e.start.row,e.end.row),t[0]=(t[0]||"").substring(e.start.column);var n=t.length-1;e.end.row-e.start.row==n&&(t[n]=t[n].substring(0,e.end.column))}return t},this.insertLines=function(e,t){return console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."),this.insertFullLines(e,t)},this.removeLines=function(e,t){return console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."),this.removeFullLines(e,t)},this.insertNewLine=function(e){return console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead."),this.insertMergedLines(e,["",""])},this.insert=function(e,t){return this.getLength()<=1&&this.$detectNewLine(t),this.insertMergedLines(e,this.$split(t))},this.insertInLine=function(e,t){var n=this.clippedPos(e.row,e.column),r=this.pos(e.row,e.column+t.length);return this.applyDelta({start:n,end:r,action:"insert",lines:[t]},!0),this.clonePos(r)},this.clippedPos=function(e,t){var n=this.getLength();e===undefined?e=n:e<0?e=0:e>=n&&(e=n-1,t=undefined);var r=this.getLine(e);return t==undefined&&(t=r.length),t=Math.min(Math.max(t,0),r.length),{row:e,column:t}},this.clonePos=function(e){return{row:e.row,column:e.column}},this.pos=function(e,t){return{row:e,column:t}},this.$clipPosition=function(e){var t=this.getLength();return e.row>=t?(e.row=Math.max(0,t-1),e.column=this.getLine(t-1).length):(e.row=Math.max(0,e.row),e.column=Math.min(Math.max(e.column,0),this.getLine(e.row).length)),e},this.insertFullLines=function(e,t){e=Math.min(Math.max(e,0),this.getLength());var n=0;e<this.getLength()?(t=t.concat([""]),n=0):(t=[""].concat(t),e--,n=this.$lines[e].length),this.insertMergedLines({row:e,column:n},t)},this.insertMergedLines=function(e,t){var n=this.clippedPos(e.row,e.column),r={row:n.row+t.length-1,column:(t.length==1?n.column:0)+t[t.length-1].length};return this.applyDelta({start:n,end:r,action:"insert",lines:t}),this.clonePos(r)},this.remove=function(e){var t=this.clippedPos(e.start.row,e.start.column),n=this.clippedPos(e.end.row,e.end.column);return this.applyDelta({start:t,end:n,action:"remove",lines:this.getLinesForRange({start:t,end:n})}),this.clonePos(t)},this.removeInLine=function(e,t,n){var r=this.clippedPos(e,t),i=this.clippedPos(e,n);return this.applyDelta({start:r,end:i,action:"remove",lines:this.getLinesForRange({start:r,end:i})},!0),this.clonePos(r)},this.removeFullLines=function(e,t){e=Math.min(Math.max(0,e),this.getLength()-1),t=Math.min(Math.max(0,t),this.getLength()-1);var n=t==this.getLength()-1&&e>0,r=t<this.getLength()-1,i=n?e-1:e,s=n?this.getLine(i).length:0,u=r?t+1:t,a=r?0:this.getLine(u).length,f=new o(i,s,u,a),l=this.$lines.slice(e,t+1);return this.applyDelta({start:f.start,end:f.end,action:"remove",lines:this.getLinesForRange(f)}),l},this.removeNewLine=function(e){e<this.getLength()-1&&e>=0&&this.applyDelta({start:this.pos(e,this.getLine(e).length),end:this.pos(e+1,0),action:"remove",lines:["",""]})},this.replace=function(e,t){e instanceof o||(e=o.fromPoints(e.start,e.end));if(t.length===0&&e.isEmpty())return e.start;if(t==this.getTextRange(e))return e.end;this.remove(e);var n;return t?n=this.insert(e.start,t):n=e.start,n},this.applyDeltas=function(e){for(var t=0;t<e.length;t++)this.applyDelta(e[t])},this.revertDeltas=function(e){for(var t=e.length-1;t>=0;t--)this.revertDelta(e[t])},this.applyDelta=function(e,t){var n=e.action=="insert";if(n?e.lines.length<=1&&!e.lines[0]:!o.comparePoints(e.start,e.end))return;n&&e.lines.length>2e4&&this.$splitAndapplyLargeDelta(e,2e4),i(this.$lines,e,t),this._signal("change",e)},this.$splitAndapplyLargeDelta=function(e,t){var n=e.lines,r=n.length,i=e.start.row,s=e.start.column,o=0,u=0;do{o=u,u+=t-1;var a=n.slice(o,u);if(u>r){e.lines=a,e.start.row=i+o,e.start.column=s;break}a.push(""),this.applyDelta({start:this.pos(i+o,s),end:this.pos(i+u,s=0),action:e.action,lines:a},!0)}while(!0)},this.revertDelta=function(e){this.applyDelta({start:this.clonePos(e.start),end:this.clonePos(e.end),action:e.action=="insert"?"remove":"insert",lines:e.lines.slice()})},this.indexToPosition=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length;for(var i=t||0,s=n.length;i<s;i++){e-=n[i].length+r;if(e<0)return{row:i,column:e+n[i].length+r}}return{row:s-1,column:n[s-1].length}},this.positionToIndex=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length,i=0,s=Math.min(e.row,n.length);for(var o=t||0;o<s;++o)i+=n[o].length+r;return i+e.column}}).call(a.prototype),t.Document=a}),ace.define("ace/worker/mirror",["require","exports","module","ace/range","ace/document","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../range").Range,i=e("../document").Document,s=e("../lib/lang"),o=t.Mirror=function(e){this.sender=e;var t=this.doc=new i(""),n=this.deferredUpdate=s.delayedCall(this.onUpdate.bind(this)),r=this;e.on("change",function(e){var i=e.data;if(i[0].start)t.applyDeltas(i);else for(var s=0;s<i.length;s+=2){if(Array.isArray(i[s+1]))var o={action:"insert",start:i[s],lines:i[s+1]};else var o={action:"remove",start:i[s],end:i[s+1]};t.applyDelta(o,!0)}if(r.$timeout)return n.schedule(r.$timeout);r.onUpdate()})};(function(){this.$timeout=500,this.setTimeout=function(e){this.$timeout=e},this.setValue=function(e){this.doc.setValue(e),this.deferredUpdate.schedule(this.$timeout)},this.getValue=function(e){this.sender.callback(this.doc.getValue(),e)},this.onUpdate=function(){},this.isPending=function(){return this.deferredUpdate.isPending()}}).call(o.prototype)}),ace.define("ace/mode/html/saxparser",["require","exports","module"],function(e,t,n){n.exports=function r(t,n,i){function s(u,a){if(!n[u]){if(!t[u]){var f=typeof e=="function"&&e;if(!a&&f)return f(u,!0);if(o)return o(u,!0);throw new Error("Cannot find module '"+u+"'")}var l=n[u]={exports:{}};t[u][0].call(l.exports,function(e){var n=t[u][1][e];return s(n?n:e)},l,l.exports,r,t,n,i)}return n[u].exports}var o=typeof e=="function"&&e;for(var u=0;u<i.length;u++)s(i[u]);return s}({1:[function(e,t,n){function r(e){if(e.namespaceURI==="http://www.w3.org/1999/xhtml")return e.localName==="applet"||e.localName==="caption"||e.localName==="marquee"||e.localName==="object"||e.localName==="table"||e.localName==="td"||e.localName==="th";if(e.namespaceURI==="http://www.w3.org/1998/Math/MathML")return e.localName==="mi"||e.localName==="mo"||e.localName==="mn"||e.localName==="ms"||e.localName==="mtext"||e.localName==="annotation-xml";if(e.namespaceURI==="http://www.w3.org/2000/svg")return e.localName==="foreignObject"||e.localName==="desc"||e.localName==="title"}function i(e){return r(e)||e.namespaceURI==="http://www.w3.org/1999/xhtml"&&e.localName==="ol"||e.namespaceURI==="http://www.w3.org/1999/xhtml"&&e.localName==="ul"}function s(e){return e.namespaceURI==="http://www.w3.org/1999/xhtml"&&e.localName==="table"||e.namespaceURI==="http://www.w3.org/1999/xhtml"&&e.localName==="html"}function o(e){return e.namespaceURI==="http://www.w3.org/1999/xhtml"&&e.localName==="tbody"||e.namespaceURI==="http://www.w3.org/1999/xhtml"&&e.localName==="tfoot"||e.namespaceURI==="http://www.w3.org/1999/xhtml"&&e.localName==="thead"||e.namespaceURI==="http://www.w3.org/1999/xhtml"&&e.localName==="html"}function u(e){return e.namespaceURI==="http://www.w3.org/1999/xhtml"&&e.localName==="tr"||e.namespaceURI==="http://www.w3.org/1999/xhtml"&&e.localName==="html"}function a(e){return r(e)||e.namespaceURI==="http://www.w3.org/1999/xhtml"&&e.localName==="button"}function f(e){return(e.namespaceURI!=="http://www.w3.org/1999/xhtml"||e.localName!=="optgroup")&&(e.namespaceURI!=="http://www.w3.org/1999/xhtml"||e.localName!=="option")}function l(){this.elements=[],this.rootNode=null,this.headElement=null,this.bodyElement=null}l.prototype._inScope=function(e,t){for(var n=this.elements.length-1;n>=0;n--){var r=this.elements[n];if(r.localName===e)return!0;if(t(r))return!1}},l.prototype.push=function(e){this.elements.push(e)},l.prototype.pushHtmlElement=function(e){this.rootNode=e.node,this.push(e)},l.prototype.pushHeadElement=function(e){this.headElement=e.node,this.push(e)},l.prototype.pushBodyElement=function(e){this.bodyElement=e.node,this.push(e)},l.prototype.pop=function(){return this.elements.pop()},l.prototype.remove=function(e){this.elements.splice(this.elements.indexOf(e),1)},l.prototype.popUntilPopped=function(e){var t;do t=this.pop();while(t.localName!=e)},l.prototype.popUntilTableScopeMarker=function(){while(!s(this.top))this.pop()},l.prototype.popUntilTableBodyScopeMarker=function(){while(!o(this.top))this.pop()},l.prototype.popUntilTableRowScopeMarker=function(){while(!u(this.top))this.pop()},l.prototype.item=function(e){return this.elements[e]},l.prototype.contains=function(e){return this.elements.indexOf(e)!==-1},l.prototype.inScope=function(e){return this._inScope(e,r)},l.prototype.inListItemScope=function(e){return this._inScope(e,i)},l.prototype.inTableScope=function(e){return this._inScope(e,s)},l.prototype.inButtonScope=function(e){return this._inScope(e,a)},l.prototype.inSelectScope=function(e){return this._inScope(e,f)},l.prototype.hasNumberedHeaderElementInScope=function(){for(var e=this.elements.length-1;e>=0;e--){var t=this.elements[e];if(t.isNumberedHeader())return!0;if(r(t))return!1}},l.prototype.furthestBlockForFormattingElement=function(e){var t=null;for(var n=this.elements.length-1;n>=0;n--){var r=this.elements[n];if(r.node===e)break;r.isSpecial()&&(t=r)}return t},l.prototype.findIndex=function(e){for(var t=this.elements.length-1;t>=0;t--)if(this.elements[t].localName==e)return t;return-1},l.prototype.remove_openElements_until=function(e){var t=!1,n;while(!t)n=this.elements.pop(),t=e(n);return n},Object.defineProperty(l.prototype,"top",{get:function(){return this.elements[this.elements.length-1]}}),Object.defineProperty(l.prototype,"length",{get:function(){return this.elements.length}}),n.ElementStack=l},{}],2:[function(e,t,n){function o(e){return e>="0"&&e<="9"||e>="a"&&e<="z"||e>="A"&&e<="Z"}function u(e){return e>="0"&&e<="9"||e>="a"&&e<="f"||e>="A"&&e<="F"}function a(e){return e>="0"&&e<="9"}var r=e("html5-entities"),i=e("./InputStream").InputStream,s={};Object.keys(r).forEach(function(e){for(var t=0;t<e.length;t++)s[e.substring(0,t+1)]=!0});var f={};f.consumeEntity=function(e,t,n){var f="",l="",c=e.char();if(c===i.EOF)return!1;l+=c;if(c=="	"||c=="\n"||c==""||c==" "||c=="<"||c=="&")return e.unget(l),!1;if(n===c)return e.unget(l),!1;if(c=="#"){c=e.shift(1);if(c===i.EOF)return t._parseError("expected-numeric-entity-but-got-eof"),e.unget(l),!1;l+=c;var h=10,p=a;if(c=="x"||c=="X"){h=16,p=u,c=e.shift(1);if(c===i.EOF)return t._parseError("expected-numeric-entity-but-got-eof"),e.unget(l),!1;l+=c}if(p(c)){var d="";while(c!==i.EOF&&p(c))d+=c,c=e.char();d=parseInt(d,h);var v=this.replaceEntityNumbers(d);v&&(t._parseError("invalid-numeric-entity-replaced"),d=v);if(d>65535&&d<=1114111){d-=65536;var m=((1047552&d)>>10)+55296,g=(1023&d)+56320;f=String.fromCharCode(m,g)}else f=String.fromCharCode(d);return c!==";"&&(t._parseError("numeric-entity-without-semicolon"),e.unget(c)),f}return e.unget(l),t._parseError("expected-numeric-entity"),!1}if(c>="a"&&c<="z"||c>="A"&&c<="Z"){var y="";while(s[l]){r[l]&&(y=l);if(c==";")break;c=e.char();if(c===i.EOF)break;l+=c}return y?(f=r[y],c===";"||!n||!o(c)&&c!=="="?(l.length>y.length&&e.unget(l.substring(y.length)),c!==";"&&t._parseError("named-entity-without-semicolon"),f):(e.unget(l),!1)):(t._parseError("expected-named-entity"),e.unget(l),!1)}},f.replaceEntityNumbers=function(e){switch(e){case 0:return 65533;case 19:return 16;case 128:return 8364;case 129:return 129;case 130:return 8218;case 131:return 402;case 132:return 8222;case 133:return 8230;case 134:return 8224;case 135:return 8225;case 136:return 710;case 137:return 8240;case 138:return 352;case 139:return 8249;case 140:return 338;case 141:return 141;case 142:return 381;case 143:return 143;case 144:return 144;case 145:return 8216;case 146:return 8217;case 147:return 8220;case 148:return 8221;case 149:return 8226;case 150:return 8211;case 151:return 8212;case 152:return 732;case 153:return 8482;case 154:return 353;case 155:return 8250;case 156:return 339;case 157:return 157;case 158:return 382;case 159:return 376;default:if(e>=55296&&e<=57343||e>1114111)return 65533;if(e>=1&&e<=8||e>=14&&e<=31||e>=127&&e<=159||e>=64976&&e<=65007||e==11||e==65534||e==131070||e==3145726||e==196607||e==262142||e==262143||e==327678||e==327679||e==393214||e==393215||e==458750||e==458751||e==524286||e==524287||e==589822||e==589823||e==655358||e==655359||e==720894||e==720895||e==786430||e==786431||e==851966||e==851967||e==917502||e==917503||e==983038||e==983039||e==1048574||e==1048575||e==1114110||e==1114111)return e}},n.EntityParser=f},{"./InputStream":3,"html5-entities":12}],3:[function(e,t,n){function r(){this.data="",this.start=0,this.committed=0,this.eof=!1,this.lastLocation={line:0,column:0}}r.EOF=-1,r.DRAIN=-2,r.prototype={slice:function(){if(this.start>=this.data.length){if(!this.eof)throw r.DRAIN;return r.EOF}return this.data.slice(this.start,this.data.length)},"char":function(){if(!this.eof&&this.start>=this.data.length-1)throw r.DRAIN;if(this.start>=this.data.length)return r.EOF;var e=this.data[this.start++];return e==="\r"&&(e="\n"),e},advance:function(e){this.start+=e;if(this.start>=this.data.length){if(!this.eof)throw r.DRAIN;return r.EOF}this.committed>this.data.length/2&&(this.lastLocation=this.location(),this.data=this.data.slice(this.committed),this.start=this.start-this.committed,this.committed=0)},matchWhile:function(e){if(this.eof&&this.start>=this.data.length)return"";var t=new RegExp("^"+e+"+"),n=t.exec(this.slice());if(n){if(!this.eof&&n[0].length==this.data.length-this.start)throw r.DRAIN;return this.advance(n[0].length),n[0]}return""},matchUntil:function(e){var t,n;n=this.slice();if(n===r.EOF)return"";if(t=(new RegExp(e+(this.eof?"|$":""))).exec(n)){var i=this.data.slice(this.start,this.start+t.index);return this.advance(t.index),i.replace(/\r/g,"\n").replace(/\n{2,}/g,"\n")}throw r.DRAIN},append:function(e){this.data+=e},shift:function(e){if(!this.eof&&this.start+e>=this.data.length)throw r.DRAIN;if(this.eof&&this.start>=this.data.length)return r.EOF;var t=this.data.slice(this.start,this.start+e).toString();return this.advance(Math.min(e,this.data.length-this.start)),t},peek:function(e){if(!this.eof&&this.start+e>=this.data.length)throw r.DRAIN;return this.eof&&this.start>=this.data.length?r.EOF:this.data.slice(this.start,Math.min(this.start+e,this.data.length)).toString()},length:function(){return this.data.length-this.start-1},unget:function(e){if(e===r.EOF)return;this.start-=e.length},undo:function(){this.start=this.committed},commit:function(){this.committed=this.start},location:function(){var e=this.lastLocation.line,t=this.lastLocation.column,n=this.data.slice(0,this.committed),r=n.match(/\n/g),i=r?e+r.length:e,s=r?n.length-n.lastIndexOf("\n")-1:t+n.length;return{line:i,column:s}}},n.InputStream=r},{}],4:[function(e,t,n){function i(e,t,n,r){this.localName=t,this.namespaceURI=e,this.attributes=n,this.node=r}function s(e,t){for(var n=0;n<e.attributes.length;n++)if(e.attributes[n].nodeName==t)return e.attributes[n].nodeValue;return null}var r={"http://www.w3.org/1999/xhtml":["address","applet","area","article","aside","base","basefont","bgsound","blockquote","body","br","button","caption","center","col","colgroup","dd","details","dir","div","dl","dt","embed","fieldset","figcaption","figure","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","iframe","img","input","isindex","li","link","listing","main","marquee","menu","menuitem","meta","nav","noembed","noframes","noscript","object","ol","p","param","plaintext","pre","script","section","select","source","style","summary","table","tbody","td","textarea","tfoot","th","thead","title","tr","track","ul","wbr","xmp"],"http://www.w3.org/1998/Math/MathML":["mi","mo","mn","ms","mtext","annotation-xml"],"http://www.w3.org/2000/svg":["foreignObject","desc","title"]};i.prototype.isSpecial=function(){return this.namespaceURI in r&&r[this.namespaceURI].indexOf(this.localName)>-1},i.prototype.isFosterParenting=function(){return this.namespaceURI==="http://www.w3.org/1999/xhtml"?this.localName==="table"||this.localName==="tbody"||this.localName==="tfoot"||this.localName==="thead"||this.localName==="tr":!1},i.prototype.isNumberedHeader=function(){return this.namespaceURI==="http://www.w3.org/1999/xhtml"?this.localName==="h1"||this.localName==="h2"||this.localName==="h3"||this.localName==="h4"||this.localName==="h5"||this.localName==="h6":!1},i.prototype.isForeign=function(){return this.namespaceURI!="http://www.w3.org/1999/xhtml"},i.prototype.isHtmlIntegrationPoint=function(){if(this.namespaceURI==="http://www.w3.org/1998/Math/MathML"){if(this.localName!=="annotation-xml")return!1;var e=s(this,"encoding");return e?(e=e.toLowerCase(),e==="text/html"||e==="application/xhtml+xml"):!1}return this.namespaceURI==="http://www.w3.org/2000/svg"?this.localName==="foreignObject"||this.localName==="desc"||this.localName==="title":!1},i.prototype.isMathMLTextIntegrationPoint=function(){return this.namespaceURI==="http://www.w3.org/1998/Math/MathML"?this.localName==="mi"||this.localName==="mo"||this.localName==="mn"||this.localName==="ms"||this.localName==="mtext":!1},n.StackItem=i},{}],5:[function(e,t,n){function s(e){return e===" "||e==="\n"||e==="	"||e==="\r"||e==="\f"}function o(e){return e>="A"&&e<="Z"||e>="a"&&e<="z"}function u(e){this._tokenHandler=e,this._state=u.DATA,this._inputStream=new r,this._currentToken=null,this._temporaryBuffer="",this._additionalAllowedCharacter=""}var r=e("./InputStream").InputStream,i=e("./EntityParser").EntityParser;u.prototype._parseError=function(e,t){this._tokenHandler.parseError(e,t)},u.prototype._emitToken=function(e){if(e.type==="StartTag")for(var t=1;t<e.data.length;t++)e.data[t].nodeName||e.data.splice(t--,1);else e.type==="EndTag"&&(e.selfClosing&&this._parseError("self-closing-flag-on-end-tag"),e.data.length!==0&&this._parseError("attributes-in-end-tag"));this._tokenHandler.processToken(e),e.type==="StartTag"&&e.selfClosing&&!this._tokenHandler.isSelfClosingFlagAcknowledged()&&this._parseError("non-void-element-with-trailing-solidus",{name:e.name})},u.prototype._emitCurrentToken=function(){this._state=u.DATA,this._emitToken(this._currentToken)},u.prototype._currentAttribute=function(){return this._currentToken.data[this._currentToken.data.length-1]},u.prototype.setState=function(e){this._state=e},u.prototype.tokenize=function(e){function n(e){var n=e.char();if(n===r.EOF)return t._emitToken({type:"EOF",data:null}),!1;if(n==="&")t.setState(a);else if(n==="<")t.setState(j);else if(n==="\0")t._emitToken({type:"Characters",data:n}),e.commit();else{var i=e.matchUntil("&|<|\0");t._emitToken({type:"Characters",data:n+i}),e.commit()}return!0}function a(e){var r=i.consumeEntity(e,t);return t.setState(n),t._emitToken({type:"Characters",data:r||"&"}),!0}function f(e){var n=e.char();if(n===r.EOF)return t._emitToken({type:"EOF",data:null}),!1;if(n==="&")t.setState(l);else if(n==="<")t.setState(d);else if(n==="\0")t._parseError("invalid-codepoint"),t._emitToken({type:"Characters",data:"\ufffd"}),e.commit();else{var i=e.matchUntil("&|<|\0");t._emitToken({type:"Characters",data:n+i}),e.commit()}return!0}function l(e){var n=i.consumeEntity(e,t);return t.setState(f),t._emitToken({type:"Characters",data:n||"&"}),!0}function c(e){var n=e.char();if(n===r.EOF)return t._emitToken({type:"EOF",data:null}),!1;if(n==="<")t.setState(g);else if(n==="\0")t._parseError("invalid-codepoint"),t._emitToken({type:"Characters",data:"\ufffd"}),e.commit();else{var i=e.matchUntil("<|\0");t._emitToken({type:"Characters",data:n+i})}return!0}function h(e){var n=e.char();if(n===r.EOF)return t._emitToken({type:"EOF",data:null}),!1;if(n==="\0")t._parseError("invalid-codepoint"),t._emitToken({type:"Characters",data:"\ufffd"}),e.commit();else{var i=e.matchUntil("\0");t._emitToken({type:"Characters",data:n+i})}return!0}function p(e){var n=e.char();if(n===r.EOF)return t._emitToken({type:"EOF",data:null}),!1;if(n==="<")t.setState(w);else if(n==="\0")t._parseError("invalid-codepoint"),t._emitToken({type:"Characters",data:"\ufffd"}),e.commit();else{var i=e.matchUntil("<|\0");t._emitToken({type:"Characters",data:n+i})}return!0}function d(e){var n=e.char();return n==="/"?(this._temporaryBuffer="",t.setState(v)):(t._emitToken({type:"Characters",data:"<"}),e.unget(n),t.setState(f)),!0}function v(e){var n=e.char();return o(n)?(this._temporaryBuffer+=n,t.setState(m)):(t._emitToken({type:"Characters",data:"</"}),e.unget(n),t.setState(f)),!0}function m(e){var r=t._currentToken&&t._currentToken.name===this._temporaryBuffer.toLowerCase(),i=e.char();return s(i)&&r?(t._currentToken={type:"EndTag",name:this._temporaryBuffer,data:[],selfClosing:!1},t.setState(q)):i==="/"&&r?(t._currentToken={type:"EndTag",name:this._temporaryBuffer,data:[],selfClosing:!1},t.setState(K)):i===">"&&r?(t._currentToken={type:"EndTag",name:this._temporaryBuffer,data:[],selfClosing:!1},t._emitCurrentToken(),t.setState(n)):o(i)?(this._temporaryBuffer+=i,e.commit()):(t._emitToken({type:"Characters",data:"</"+this._temporaryBuffer}),e.unget(i),t.setState(f)),!0}function g(e){var n=e.char();return n==="/"?(this._temporaryBuffer="",t.setState(y)):(t._emitToken({type:"Characters",data:"<"}),e.unget(n),t.setState(c)),!0}function y(e){var n=e.char();return o(n)?(this._temporaryBuffer+=n,t.setState(b)):(t._emitToken({type:"Characters",data:"</"}),e.unget(n),t.setState(c)),!0}function b(e){var r=t._currentToken&&t._currentToken.name===this._temporaryBuffer.toLowerCase(),i=e.char();return s(i)&&r?(t._currentToken={type:"EndTag",name:this._temporaryBuffer,data:[],selfClosing:!1},t.setState(q)):i==="/"&&r?(t._currentToken={type:"EndTag",name:this._temporaryBuffer,data:[],selfClosing:!1},t.setState(K)):i===">"&&r?(t._currentToken={type:"EndTag",name:this._temporaryBuffer,data:[],selfClosing:!1},t._emitCurrentToken(),t.setState(n)):o(i)?(this._temporaryBuffer+=i,e.commit()):(t._emitToken({type:"Characters",data:"</"+this._temporaryBuffer}),e.unget(i),t.setState(c)),!0}function w(e){var n=e.char();return n==="/"?(this._temporaryBuffer="",t.setState(E)):n==="!"?(t._emitToken({type:"Characters",data:"<!"}),t.setState(x)):(t._emitToken({type:"Characters",data:"<"}),e.unget(n),t.setState(p)),!0}function E(e){var n=e.char();return o(n)?(this._temporaryBuffer+=n,t.setState(S)):(t._emitToken({type:"Characters",data:"</"}),e.unget(n),t.setState(p)),!0}function S(e){var n=t._currentToken&&t._currentToken.name===this._temporaryBuffer.toLowerCase(),r=e.char();return s(r)&&n?(t._currentToken={type:"EndTag",name:"script",data:[],selfClosing:!1},t.setState(q)):r==="/"&&n?(t._currentToken={type:"EndTag",name:"script",data:[],selfClosing:!1},t.setState(K)):r===">"&&n?(t._currentToken={type:"EndTag",name:"script",data:[],selfClosing:!1},t._emitCurrentToken()):o(r)?(this._temporaryBuffer+=r,e.commit()):(t._emitToken({type:"Characters",data:"</"+this._temporaryBuffer}),e.unget(r),t.setState(p)),!0}function x(e){var n=e.char();return n==="-"?(t._emitToken({type:"Characters",data:"-"}),t.setState(T)):(e.unget(n),t.setState(p)),!0}function T(e){var n=e.char();return n==="-"?(t._emitToken({type:"Characters",data:"-"}),t.setState(k)):(e.unget(n),t.setState(p)),!0}function N(e){var i=e.char();if(i===r.EOF)e.unget(i),t.setState(n);else if(i==="-")t._emitToken({type:"Characters",data:"-"}),t.setState(C);else if(i==="<")t.setState(L);else if(i==="\0")t._parseError("invalid-codepoint"),t._emitToken({type:"Characters",data:"\ufffd"}),e.commit();else{var s=e.matchUntil("<|-|\0");t._emitToken({type:"Characters",data:i+s})}return!0}function C(e){var i=e.char();return i===r.EOF?(e.unget(i),t.setState(n)):i==="-"?(t._emitToken({type:"Characters",data:"-"}),t.setState(k)):i==="<"?t.setState(L):i==="\0"?(t._parseError("invalid-codepoint"),t._emitToken({type:"Characters",data:"\ufffd"}),t.setState(N)):(t._emitToken({type:"Characters",data:i}),t.setState(N)),!0}function k(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-script"),e.unget(i),t.setState(n)):i==="<"?t.setState(L):i===">"?(t._emitToken({type:"Characters",data:">"}),t.setState(p)):i==="\0"?(t._parseError("invalid-codepoint"),t._emitToken({type:"Characters",data:"\ufffd"}),t.setState(N)):(t._emitToken({type:"Characters",data:i}),t.setState(N)),!0}function L(e){var n=e.char();return n==="/"?(this._temporaryBuffer="",t.setState(A)):o(n)?(t._emitToken({type:"Characters",data:"<"+n}),this._temporaryBuffer=n,t.setState(M)):(t._emitToken({type:"Characters",data:"<"}),e.unget(n),t.setState(N)),!0}function A(e){var n=e.char();return o(n)?(this._temporaryBuffer=n,t.setState(O)):(t._emitToken({type:"Characters",data:"</"}),e.unget(n),t.setState(N)),!0}function O(e){var r=t._currentToken&&t._currentToken.name===this._temporaryBuffer.toLowerCase(),i=e.char();return s(i)&&r?(t._currentToken={type:"EndTag",name:"script",data:[],selfClosing:!1},t.setState(q)):i==="/"&&r?(t._currentToken={type:"EndTag",name:"script",data:[],selfClosing:!1},t.setState(K)):i===">"&&r?(t._currentToken={type:"EndTag",name:"script",data:[],selfClosing:!1},t.setState(n),t._emitCurrentToken()):o(i)?(this._temporaryBuffer+=i,e.commit()):(t._emitToken({type:"Characters",data:"</"+this._temporaryBuffer}),e.unget(i),t.setState(N)),!0}function M(e){var n=e.char();return s(n)||n==="/"||n===">"?(t._emitToken({type:"Characters",data:n}),this._temporaryBuffer.toLowerCase()==="script"?t.setState(_):t.setState(N)):o(n)?(t._emitToken({type:"Characters",data:n}),this._temporaryBuffer+=n,e.commit()):(e.unget(n),t.setState(N)),!0}function _(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-script"),e.unget(i),t.setState(n)):i==="-"?(t._emitToken({type:"Characters",data:"-"}),t.setState(D)):i==="<"?(t._emitToken({type:"Characters",data:"<"}),t.setState(H)):i==="\0"?(t._parseError("invalid-codepoint"),t._emitToken({type:"Characters",data:"\ufffd"}),e.commit()):(t._emitToken({type:"Characters",data:i}),e.commit()),!0}function D(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-script"),e.unget(i),t.setState(n)):i==="-"?(t._emitToken({type:"Characters",data:"-"}),t.setState(P)):i==="<"?(t._emitToken({type:"Characters",data:"<"}),t.setState(H)):i==="\0"?(t._parseError("invalid-codepoint"),t._emitToken({type:"Characters",data:"\ufffd"}),t.setState(_)):(t._emitToken({type:"Characters",data:i}),t.setState(_)),!0}function P(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-script"),e.unget(i),t.setState(n)):i==="-"?(t._emitToken({type:"Characters",data:"-"}),e.commit()):i==="<"?(t._emitToken({type:"Characters",data:"<"}),t.setState(H)):i===">"?(t._emitToken({type:"Characters",data:">"}),t.setState(p)):i==="\0"?(t._parseError("invalid-codepoint"),t._emitToken({type:"Characters",data:"\ufffd"}),t.setState(_)):(t._emitToken({type:"Characters",data:i}),t.setState(_)),!0}function H(e){var n=e.char();return n==="/"?(t._emitToken({type:"Characters",data:"/"}),this._temporaryBuffer="",t.setState(B)):(e.unget(n),t.setState(_)),!0}function B(e){var n=e.char();return s(n)||n==="/"||n===">"?(t._emitToken({type:"Characters",data:n}),this._temporaryBuffer.toLowerCase()==="script"?t.setState(N):t.setState(_)):o(n)?(t._emitToken({type:"Characters",data:n}),this._temporaryBuffer+=n,e.commit()):(e.unget(n),t.setState(_)),!0}function j(e){var i=e.char();return i===r.EOF?(t._parseError("bare-less-than-sign-at-eof"),t._emitToken({type:"Characters",data:"<"}),e.unget(i),t.setState(n)):o(i)?(t._currentToken={type:"StartTag",name:i.toLowerCase(),data:[]},t.setState(I)):i==="!"?t.setState(G):i==="/"?t.setState(F):i===">"?(t._parseError("expected-tag-name-but-got-right-bracket"),t._emitToken({type:"Characters",data:"<>"}),t.setState(n)):i==="?"?(t._parseError("expected-tag-name-but-got-question-mark"),e.unget(i),t.setState(Q)):(t._parseError("expected-tag-name"),t._emitToken({type:"Characters",data:"<"}),e.unget(i),t.setState(n)),!0}function F(e){var i=e.char();return i===r.EOF?(t._parseError("expected-closing-tag-but-got-eof"),t._emitToken({type:"Characters",data:"</"}),e.unget(i),t.setState(n)):o(i)?(t._currentToken={type:"EndTag",name:i.toLowerCase(),data:[]},t.setState(I)):i===">"?(t._parseError("expected-closing-tag-but-got-right-bracket"),t.setState(n)):(t._parseError("expected-closing-tag-but-got-char",{data:i}),e.unget(i),t.setState(Q)),!0}function I(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-tag-name"),e.unget(i),t.setState(n)):s(i)?t.setState(q):o(i)?t._currentToken.name+=i.toLowerCase():i===">"?t._emitCurrentToken():i==="/"?t.setState(K):i==="\0"?(t._parseError("invalid-codepoint"),t._currentToken.name+="\ufffd"):t._currentToken.name+=i,e.commit(),!0}function q(e){var i=e.char();if(i===r.EOF)t._parseError("expected-attribute-name-but-got-eof"),e.unget(i),t.setState(n);else{if(s(i))return!0;o(i)?(t._currentToken.data.push({nodeName:i.toLowerCase(),nodeValue:""}),t.setState(R)):i===">"?t._emitCurrentToken():i==="/"?t.setState(K):i==="'"||i==='"'||i==="="||i==="<"?(t._parseError("invalid-character-in-attribute-name"),t._currentToken.data.push({nodeName:i,nodeValue:""}),t.setState(R)):i==="\0"?(t._parseError("invalid-codepoint"),t._currentToken.data.push({nodeName:"\ufffd",nodeValue:""})):(t._currentToken.data.push({nodeName:i,nodeValue:""}),t.setState(R))}return!0}function R(e){var i=e.char(),u=!0,a=!1;i===r.EOF?(t._parseError("eof-in-attribute-name"),e.unget(i),t.setState(n),a=!0):i==="="?t.setState(z):o(i)?(t._currentAttribute().nodeName+=i.toLowerCase(),u=!1):i===">"?a=!0:s(i)?t.setState(U):i==="/"?t.setState(K):i==="'"||i==='"'?(t._parseError("invalid-character-in-attribute-name"),t._currentAttribute().nodeName+=i,u=!1):i==="\0"?(t._parseError("invalid-codepoint"),t._currentAttribute().nodeName+="\ufffd"):(t._currentAttribute().nodeName+=i,u=!1);if(u){var f=t._currentToken.data,l=f[f.length-1];for(var c=f.length-2;c>=0;c--)if(l.nodeName===f[c].nodeName){t._parseError("duplicate-attribute",{name:l.nodeName}),l.nodeName=null;break}a&&t._emitCurrentToken()}else e.commit();return!0}function U(e){var i=e.char();if(i===r.EOF)t._parseError("expected-end-of-tag-but-got-eof"),e.unget(i),t.setState(n);else{if(s(i))return!0;i==="="?t.setState(z):i===">"?t._emitCurrentToken():o(i)?(t._currentToken.data.push({nodeName:i,nodeValue:""}),t.setState(R)):i==="/"?t.setState(K):i==="'"||i==='"'||i==="<"?(t._parseError("invalid-character-after-attribute-name"),t._currentToken.data.push({nodeName:i,nodeValue:""}),t.setState(R)):i==="\0"?(t._parseError("invalid-codepoint"),t._currentToken.data.push({nodeName:"\ufffd",nodeValue:""})):(t._currentToken.data.push({nodeName:i,nodeValue:""}),t.setState(R))}return!0}function z(e){var i=e.char();if(i===r.EOF)t._parseError("expected-attribute-value-but-got-eof"),e.unget(i),t.setState(n);else{if(s(i))return!0;i==='"'?t.setState(W):i==="&"?(t.setState(V),e.unget(i)):i==="'"?t.setState(X):i===">"?(t._parseError("expected-attribute-value-but-got-right-bracket"),t._emitCurrentToken()):i==="="||i==="<"||i==="`"?(t._parseError("unexpected-character-in-unquoted-attribute-value"),t._currentAttribute().nodeValue+=i,t.setState(V)):i==="\0"?(t._parseError("invalid-codepoint"),t._currentAttribute().nodeValue+="\ufffd"):(t._currentAttribute().nodeValue+=i,t.setState(V))}return!0}function W(e){var i=e.char();if(i===r.EOF)t._parseError("eof-in-attribute-value-double-quote"),e.unget(i),t.setState(n);else if(i==='"')t.setState(J);else if(i==="&")this._additionalAllowedCharacter='"',t.setState($);else if(i==="\0")t._parseError("invalid-codepoint"),t._currentAttribute().nodeValue+="\ufffd";else{var s=e.matchUntil('[\0"&]');i+=s,t._currentAttribute().nodeValue+=i}return!0}function X(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-attribute-value-single-quote"),e.unget(i),t.setState(n)):i==="'"?t.setState(J):i==="&"?(this._additionalAllowedCharacter="'",t.setState($)):i==="\0"?(t._parseError("invalid-codepoint"),t._currentAttribute().nodeValue+="\ufffd"):t._currentAttribute().nodeValue+=i+e.matchUntil("\0|['&]"),!0}function V(e){var i=e.char();if(i===r.EOF)t._parseError("eof-after-attribute-value"),e.unget(i),t.setState(n);else if(s(i))t.setState(q);else if(i==="&")this._additionalAllowedCharacter=">",t.setState($);else if(i===">")t._emitCurrentToken();else if(i==='"'||i==="'"||i==="="||i==="`"||i==="<")t._parseError("unexpected-character-in-unquoted-attribute-value"),t._currentAttribute().nodeValue+=i,e.commit();else if(i==="\0")t._parseError("invalid-codepoint"),t._currentAttribute().nodeValue+="\ufffd";else{var o=e.matchUntil("\0|[	\n\f \r&<>\"'=`]");o===r.EOF&&(t._parseError("eof-in-attribute-value-no-quotes"),t._emitCurrentToken()),e.commit(),t._currentAttribute().nodeValue+=i+o}return!0}function $(e){var n=i.consumeEntity(e,t,this._additionalAllowedCharacter);return this._currentAttribute().nodeValue+=n||"&",this._additionalAllowedCharacter==='"'?t.setState(W):this._additionalAllowedCharacter==="'"?t.setState(X):this._additionalAllowedCharacter===">"&&t.setState(V),!0}function J(e){var i=e.char();return i===r.EOF?(t._parseError("eof-after-attribute-value"),e.unget(i),t.setState(n)):s(i)?t.setState(q):i===">"?(t.setState(n),t._emitCurrentToken()):i==="/"?t.setState(K):(t._parseError("unexpected-character-after-attribute-value"),e.unget(i),t.setState(q)),!0}function K(e){var i=e.char();return i===r.EOF?(t._parseError("unexpected-eof-after-solidus-in-tag"),e.unget(i),t.setState(n)):i===">"?(t._currentToken.selfClosing=!0,t.setState(n),t._emitCurrentToken()):(t._parseError("unexpected-character-after-solidus-in-tag"),e.unget(i),t.setState(q)),!0}function Q(e){var r=e.matchUntil(">");return r=r.replace(/\u0000/g,"\ufffd"),e.char(),t._emitToken({type:"Comment",data:r}),t.setState(n),!0}function G(e){var n=e.shift(2);if(n==="--")t._currentToken={type:"Comment",data:""},t.setState(Z);else{var i=e.shift(5);if(i===r.EOF||n===r.EOF)return t._parseError("expected-dashes-or-doctype"),t.setState(Q),e.unget(n),!0;n+=i,n.toUpperCase()==="DOCTYPE"?(t._currentToken={type:"Doctype",name:"",publicId:null,systemId:null,forceQuirks:!1},t.setState(st)):t._tokenHandler.isCdataSectionAllowed()&&n==="[CDATA["?t.setState(Y):(t._parseError("expected-dashes-or-doctype"),e.unget(n),t.setState(Q))}return!0}function Y(e){var r=e.matchUntil("]]>");return e.shift(3),r&&t._emitToken({type:"Characters",data:r}),t.setState(n),!0}function Z(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-comment"),t._emitToken(t._currentToken),e.unget(i),t.setState(n)):i==="-"?t.setState(et):i===">"?(t._parseError("incorrect-comment"),t._emitToken(t._currentToken),t.setState(n)):i==="\0"?(t._parseError("invalid-codepoint"),t._currentToken.data+="\ufffd"):(t._currentToken.data+=i,t.setState(tt)),!0}function et(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-comment"),t._emitToken(t._currentToken),e.unget(i),t.setState(n)):i==="-"?t.setState(rt):i===">"?(t._parseError("incorrect-comment"),t._emitToken(t._currentToken),t.setState(n)):i==="\0"?(t._parseError("invalid-codepoint"),t._currentToken.data+="\ufffd"):(t._currentToken.data+="-"+i,t.setState(tt)),!0}function tt(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-comment"),t._emitToken(t._currentToken),e.unget(i),t.setState(n)):i==="-"?t.setState(nt):i==="\0"?(t._parseError("invalid-codepoint"),t._currentToken.data+="\ufffd"):(t._currentToken.data+=i,e.commit()),!0}function nt(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-comment-end-dash"),t._emitToken(t._currentToken),e.unget(i),t.setState(n)):i==="-"?t.setState(rt):i==="\0"?(t._parseError("invalid-codepoint"),t._currentToken.data+="-\ufffd",t.setState(tt)):(t._currentToken.data+="-"+i+e.matchUntil("\0|-"),e.char()),!0}function rt(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-comment-double-dash"),t._emitToken(t._currentToken),e.unget(i),t.setState(n)):i===">"?(t._emitToken(t._currentToken),t.setState(n)):i==="!"?(t._parseError("unexpected-bang-after-double-dash-in-comment"),t.setState(it)):i==="-"?(t._parseError("unexpected-dash-after-double-dash-in-comment"),t._currentToken.data+=i):i==="\0"?(t._parseError("invalid-codepoint"),t._currentToken.data+="--\ufffd",t.setState(tt)):(t._parseError("unexpected-char-in-comment"),t._currentToken.data+="--"+i,t.setState(tt)),!0}function it(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-comment-end-bang-state"),t._emitToken(t._currentToken),e.unget(i),t.setState(n)):i===">"?(t._emitToken(t._currentToken),t.setState(n)):i==="-"?(t._currentToken.data+="--!",t.setState(nt)):(t._currentToken.data+="--!"+i,t.setState(tt)),!0}function st(e){var i=e.char();return i===r.EOF?(t._parseError("expected-doctype-name-but-got-eof"),t._currentToken.forceQuirks=!0,e.unget(i),t.setState(n),t._emitCurrentToken()):s(i)?t.setState(ot):(t._parseError("need-space-after-doctype"),e.unget(i),t.setState(ot)),!0}function ot(e){var i=e.char();return i===r.EOF?(t._parseError("expected-doctype-name-but-got-eof"),t._currentToken.forceQuirks=!0,e.unget(i),t.setState(n),t._emitCurrentToken()):s(i)||(i===">"?(t._parseError("expected-doctype-name-but-got-right-bracket"),t._currentToken.forceQuirks=!0,t.setState(n),t._emitCurrentToken()):(o(i)&&(i=i.toLowerCase()),t._currentToken.name=i,t.setState(ut))),!0}function ut(e){var i=e.char();return i===r.EOF?(t._currentToken.forceQuirks=!0,e.unget(i),t._parseError("eof-in-doctype-name"),t.setState(n),t._emitCurrentToken()):s(i)?t.setState(at):i===">"?(t.setState(n),t._emitCurrentToken()):(o(i)&&(i=i.toLowerCase()),t._currentToken.name+=i,e.commit()),!0}function at(e){var i=e.char();if(i===r.EOF)t._currentToken.forceQuirks=!0,e.unget(i),t._parseError("eof-in-doctype"),t.setState(n),t._emitCurrentToken();else if(!s(i))if(i===">")t.setState(n),t._emitCurrentToken();else{if(["p","P"].indexOf(i)>-1){var o=[["u","U"],["b","B"],["l","L"],["i","I"],["c","C"]],u=o.every(function(t){return i=e.char(),t.indexOf(i)>-1});if(u)return t.setState(ft),!0}else if(["s","S"].indexOf(i)>-1){var o=[["y","Y"],["s","S"],["t","T"],["e","E"],["m","M"]],u=o.every(function(t){return i=e.char(),t.indexOf(i)>-1});if(u)return t.setState(vt),!0}e.unget(i),t._currentToken.forceQuirks=!0,i===r.EOF?(t._parseError("eof-in-doctype"),e.unget(i),t.setState(n),t._emitCurrentToken()):(t._parseError("expected-space-or-right-bracket-in-doctype",{data:i}),t.setState(wt))}return!0}function ft(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-doctype"),t._currentToken.forceQuirks=!0,e.unget(i),t.setState(n),t._emitCurrentToken()):s(i)?t.setState(lt):i==="'"||i==='"'?(t._parseError("unexpected-char-in-doctype"),e.unget(i),t.setState(lt)):(e.unget(i),t.setState(lt)),!0}function lt(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-doctype"),t._currentToken.forceQuirks=!0,e.unget(i),t.setState(n),t._emitCurrentToken()):s(i)||(i==='"'?(t._currentToken.publicId="",t.setState(ct)):i==="'"?(t._currentToken.publicId="",t.setState(ht)):i===">"?(t._parseError("unexpected-end-of-doctype"),t._currentToken.forceQuirks=!0,t.setState(n),t._emitCurrentToken()):(t._parseError("unexpected-char-in-doctype"),t._currentToken.forceQuirks=!0,t.setState(wt))),!0}function ct(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-doctype"),t._currentToken.forceQuirks=!0,e.unget(i),t.setState(n),t._emitCurrentToken()):i==='"'?t.setState(pt):i===">"?(t._parseError("unexpected-end-of-doctype"),t._currentToken.forceQuirks=!0,t.setState(n),t._emitCurrentToken()):t._currentToken.publicId+=i,!0}function ht(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-doctype"),t._currentToken.forceQuirks=!0,e.unget(i),t.setState(n),t._emitCurrentToken()):i==="'"?t.setState(pt):i===">"?(t._parseError("unexpected-end-of-doctype"),t._currentToken.forceQuirks=!0,t.setState(n),t._emitCurrentToken()):t._currentToken.publicId+=i,!0}function pt(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-doctype"),t._currentToken.forceQuirks=!0,t._emitCurrentToken(),e.unget(i),t.setState(n)):s(i)?t.setState(dt):i===">"?(t.setState(n),t._emitCurrentToken()):i==='"'?(t._parseError("unexpected-char-in-doctype"),t._currentToken.systemId="",t.setState(gt)):i==="'"?(t._parseError("unexpected-char-in-doctype"),t._currentToken.systemId="",t.setState(yt)):(t._parseError("unexpected-char-in-doctype"),t._currentToken.forceQuirks=!0,t.setState(wt)),!0}function dt(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-doctype"),t._currentToken.forceQuirks=!0,t._emitCurrentToken(),e.unget(i),t.setState(n)):s(i)||(i===">"?(t._emitCurrentToken(),t.setState(n)):i==='"'?(t._currentToken.systemId="",t.setState(gt)):i==="'"?(t._currentToken.systemId="",t.setState(yt)):(t._parseError("unexpected-char-in-doctype"),t._currentToken.forceQuirks=!0,t.setState(wt))),!0}function vt(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-doctype"),t._currentToken.forceQuirks=!0,t._emitCurrentToken(),e.unget(i),t.setState(n)):s(i)?t.setState(mt):i==="'"||i==='"'?(t._parseError("unexpected-char-in-doctype"),e.unget(i),t.setState(mt)):(e.unget(i),t.setState(mt)),!0}function mt(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-doctype"),t._currentToken.forceQuirks=!0,t._emitCurrentToken(),e.unget(i),t.setState(n)):s(i)||(i==='"'?(t._currentToken.systemId="",t.setState(gt)):i==="'"?(t._currentToken.systemId="",t.setState(yt)):i===">"?(t._parseError("unexpected-end-of-doctype"),t._currentToken.forceQuirks=!0,t._emitCurrentToken(),t.setState(n)):(t._parseError("unexpected-char-in-doctype"),t._currentToken.forceQuirks=!0,t.setState(wt))),!0}function gt(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-doctype"),t._currentToken.forceQuirks=!0,t._emitCurrentToken(),e.unget(i),t.setState(n)):i==='"'?t.setState(bt):i===">"?(t._parseError("unexpected-end-of-doctype"),t._currentToken.forceQuirks=!0,t._emitCurrentToken(),t.setState(n)):t._currentToken.systemId+=i,!0}function yt(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-doctype"),t._currentToken.forceQuirks=!0,t._emitCurrentToken(),e.unget(i),t.setState(n)):i==="'"?t.setState(bt):i===">"?(t._parseError("unexpected-end-of-doctype"),t._currentToken.forceQuirks=!0,t._emitCurrentToken(),t.setState(n)):t._currentToken.systemId+=i,!0}function bt(e){var i=e.char();return i===r.EOF?(t._parseError("eof-in-doctype"),t._currentToken.forceQuirks=!0,t._emitCurrentToken(),e.unget(i),t.setState(n)):s(i)||(i===">"?(t._emitCurrentToken(),t.setState(n)):(t._parseError("unexpected-char-in-doctype"),t.setState(wt))),!0}function wt(e){var i=e.char();return i===r.EOF?(e.unget(i),t._emitCurrentToken(),t.setState(n)):i===">"&&(t._emitCurrentToken(),t.setState(n)),!0}u.DATA=n,u.RCDATA=f,u.RAWTEXT=c,u.SCRIPT_DATA=p,u.PLAINTEXT=h,this._state=u.DATA,this._inputStream.append(e),this._tokenHandler.startTokenization(this),this._inputStream.eof=!0;var t=this;while(this._state.call(this,this._inputStream));},Object.defineProperty(u.prototype,"lineNumber",{get:function(){return this._inputStream.location().line}}),Object.defineProperty(u.prototype,"columnNumber",{get:function(){return this._inputStream.location().column}}),n.Tokenizer=u},{"./EntityParser":2,"./InputStream":3}],6:[function(e,t,n){function c(e){return e===" "||e==="\n"||e==="	"||e==="\r"||e==="\f"}function h(e){return c(e)||e==="\ufffd"}function p(e){for(var t=0;t<e.length;t++){var n=e[t];if(!c(n))return!1}return!0}function d(e){for(var t=0;t<e.length;t++){var n=e[t];if(!h(n))return!1}return!0}function v(e,t){for(var n=0;n<e.attributes.length;n++){var r=e.attributes[n];if(r.nodeName===t)return r}return null}function m(e){this.characters=e,this.current=0,this.end=this.characters.length}function g(){this.tokenizer=null,this.errorHandler=null,this.scriptingEnabled=!1,this.document=null,this.head=null,this.form=null,this.openElements=new a,this.activeFormattingElements=[],this.insertionMode=null,this.insertionModeName="",this.originalInsertionMode="",this.inQuirksMode=!1,this.compatMode="no quirks",this.framesetOk=!0,this.redirectAttachToFosterParent=!1,this.selfClosingFlagAcknowledged=!1,this.context="",this.pendingTableCharacters=[],this.shouldSkipLeadingNewline=!1;var e=this,t=this.insertionModes={};t.base={end_tag_handlers:{"-default":"endTagOther"},start_tag_handlers:{"-default":"startTagOther"},processEOF:function(){e.generateImpliedEndTags(),e.openElements.length>2?e.parseError("expected-closing-tag-but-got-eof"):e.openElements.length==2&&e.openElements.item(1).localName!="body"?e.parseError("expected-closing-tag-but-got-eof"):e.context&&e.openElements.length>1},processComment:function(t){e.insertComment(t,e.currentStackItem().node)},processDoctype:function(t,n,r,i){e.parseError("unexpected-doctype")},processStartTag:function(e,t,n){if(this[this.start_tag_handlers[e]])this[this.start_tag_handlers[e]](e,t,n);else{if(!this[this.start_tag_handlers["-default"]])throw new Error("No handler found for "+e);this[this.start_tag_handlers["-default"]](e,t,n)}},processEndTag:function(e){if(this[this.end_tag_handlers[e]])this[this.end_tag_handlers[e]](e);else{if(!this[this.end_tag_handlers["-default"]])throw new Error("No handler found for "+e);this[this.end_tag_handlers["-default"]](e)}},startTagHtml:function(e,n){t.inBody.startTagHtml(e,n)}},t.initial=Object.create(t.base),t.initial.processEOF=function(){e.parseError("expected-doctype-but-got-eof"),this.anythingElse(),e.insertionMode.processEOF()},t.initial.processComment=function(t){e.insertComment(t,e.document)},t.initial.processDoctype=function(t,n,r,i){function s(e){return n.toLowerCase().indexOf(e)===0}e.insertDoctype(t||"",n||"",r||""),i||t!="html"||n!=null&&(["+//silmaril//dtd html pro v0r11 19970101//","-//advasoft ltd//dtd html 3.0 aswedit + extensions//","-//as//dtd html 3.0 aswedit + extensions//","-//ietf//dtd html 2.0 level 1//","-//ietf//dtd html 2.0 level 2//","-//ietf//dtd html 2.0 strict level 1//","-//ietf//dtd html 2.0 strict level 2//","-//ietf//dtd html 2.0 strict//","-//ietf//dtd html 2.0//","-//ietf//dtd html 2.1e//","-//ietf//dtd html 3.0//","-//ietf//dtd html 3.0//","-//ietf//dtd html 3.2 final//","-//ietf//dtd html 3.2//","-//ietf//dtd html 3//","-//ietf//dtd html level 0//","-//ietf//dtd html level 0//","-//ietf//dtd html level 1//","-//ietf//dtd html level 1//","-//ietf//dtd html level 2//","-//ietf//dtd html level 2//","-//ietf//dtd html level 3//","-//ietf//dtd html level 3//","-//ietf//dtd html strict level 0//","-//ietf//dtd html strict level 0//","-//ietf//dtd html strict level 1//","-//ietf//dtd html strict level 1//","-//ietf//dtd html strict level 2//","-//ietf//dtd html strict level 2//","-//ietf//dtd html strict level 3//","-//ietf//dtd html strict level 3//","-//ietf//dtd html strict//","-//ietf//dtd html strict//","-//ietf//dtd html strict//","-//ietf//dtd html//","-//ietf//dtd html//","-//ietf//dtd html//","-//metrius//dtd metrius presentational//","-//microsoft//dtd internet explorer 2.0 html strict//","-//microsoft//dtd internet explorer 2.0 html//","-//microsoft//dtd internet explorer 2.0 tables//","-//microsoft//dtd internet explorer 3.0 html strict//","-//microsoft//dtd internet explorer 3.0 html//","-//microsoft//dtd internet explorer 3.0 tables//","-//netscape comm. corp.//dtd html//","-//netscape comm. corp.//dtd strict html//","-//o'reilly and associates//dtd html 2.0//","-//o'reilly and associates//dtd html extended 1.0//","-//spyglass//dtd html 2.0 extended//","-//sq//dtd html 2.0 hotmetal + extensions//","-//sun microsystems corp.//dtd hotjava html//","-//sun microsystems corp.//dtd hotjava strict html//","-//w3c//dtd html 3 1995-03-24//","-//w3c//dtd html 3.2 draft//","-//w3c//dtd html 3.2 final//","-//w3c//dtd html 3.2//","-//w3c//dtd html 3.2s draft//","-//w3c//dtd html 4.0 frameset//","-//w3c//dtd html 4.0 transitional//","-//w3c//dtd html experimental 19960712//","-//w3c//dtd html experimental 970421//","-//w3c//dtd w3 html//","-//w3o//dtd w3 html 3.0//","-//webtechs//dtd mozilla html 2.0//","-//webtechs//dtd mozilla html//","html"].some(s)||["-//w3o//dtd w3 html strict 3.0//en//","-/w3c/dtd html 4.0 transitional/en","html"].indexOf(n.toLowerCase())>-1||r==null&&["-//w3c//dtd html 4.01 transitional//","-//w3c//dtd html 4.01 frameset//"].some(s))||r!=null&&r.toLowerCase()=="http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd"?(e.compatMode="quirks",e.parseError("quirky-doctype")):n!=null&&(["-//w3c//dtd xhtml 1.0 transitional//","-//w3c//dtd xhtml 1.0 frameset//"].some(s)||r!=null&&["-//w3c//dtd html 4.01 transitional//","-//w3c//dtd html 4.01 frameset//"].indexOf(n.toLowerCase())>-1)?(e.compatMode="limited quirks",e.parseError("almost-standards-doctype")):n=="-//W3C//DTD HTML 4.0//EN"&&(r==null||r=="http://www.w3.org/TR/REC-html40/strict.dtd")||n=="-//W3C//DTD HTML 4.01//EN"&&(r==null||r=="http://www.w3.org/TR/html4/strict.dtd")||n=="-//W3C//DTD XHTML 1.0 Strict//EN"&&r=="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"||n=="-//W3C//DTD XHTML 1.1//EN"&&r=="http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"||(r!=null&&r!="about:legacy-compat"||n!=null)&&e.parseError("unknown-doctype"),e.setInsertionMode("beforeHTML")},t.initial.processCharacters=function(t){t.skipLeadingWhitespace();if(!t.length)return;e.parseError("expected-doctype-but-got-chars"),this.anythingElse(),e.insertionMode.processCharacters(t)},t.initial.processStartTag=function(t,n,r){e.parseError("expected-doctype-but-got-start-tag",{name:t}),this.anythingElse(),e.insertionMode.processStartTag(t,n,r)},t.initial.processEndTag=function(t){e.parseError("expected-doctype-but-got-end-tag",{name:t}),this.anythingElse(),e.insertionMode.processEndTag(t)},t.initial.anythingElse=function(){e.compatMode="quirks",e.setInsertionMode("beforeHTML")},t.beforeHTML=Object.create(t.base),t.beforeHTML.start_tag_handlers={html:"startTagHtml","-default":"startTagOther"},t.beforeHTML.processEOF=function(){this.anythingElse(),e.insertionMode.processEOF()},t.beforeHTML.processComment=function(t){e.insertComment(t,e.document)},t.beforeHTML.processCharacters=function(t){t.skipLeadingWhitespace();if(!t.length)return;this.anythingElse(),e.insertionMode.processCharacters(t)},t.beforeHTML.startTagHtml=function(t,n,r){e.insertHtmlElement(n),e.setInsertionMode("beforeHead")},t.beforeHTML.startTagOther=function(t,n,r){this.anythingElse(),e.insertionMode.processStartTag(t,n,r)},t.beforeHTML.processEndTag=function(t){this.anythingElse(),e.insertionMode.processEndTag(t)},t.beforeHTML.anythingElse=function(){e.insertHtmlElement(),e.setInsertionMode("beforeHead")},t.afterAfterBody=Object.create(t.base),t.afterAfterBody.start_tag_handlers={html:"startTagHtml","-default":"startTagOther"},t.afterAfterBody.processComment=function(t){e.insertComment(t,e.document)},t.afterAfterBody.processDoctype=function(e){t.inBody.processDoctype(e)},t.afterAfterBody.startTagHtml=function(e,n){t.inBody.startTagHtml(e,n)},t.afterAfterBody.startTagOther=function(t,n,r){e.parseError("unexpected-start-tag",{name:t}),e.setInsertionMode("inBody"),e.insertionMode.processStartTag(t,n,r)},t.afterAfterBody.endTagOther=function(t){e.parseError("unexpected-end-tag",{name:t}),e.setInsertionMode("inBody"),e.insertionMode.processEndTag(t)},t.afterAfterBody.processCharacters=function(n){if(!p(n.characters))return e.parseError("unexpected-char-after-body"),e.setInsertionMode("inBody"),e.insertionMode.processCharacters(n);t.inBody.processCharacters(n)},t.afterBody=Object.create(t.base),t.afterBody.end_tag_handlers={html:"endTagHtml","-default":"endTagOther"},t.afterBody.processComment=function(t){e.insertComment(t,e.openElements.rootNode)},t.afterBody.processCharacters=function(n){if(!p(n.characters))return e.parseError("unexpected-char-after-body"),e.setInsertionMode("inBody"),e.insertionMode.processCharacters(n);t.inBody.processCharacters(n)},t.afterBody.processStartTag=function(t,n,r){e.parseError("unexpected-start-tag-after-body",{name:t}),e.setInsertionMode("inBody"),e.insertionMode.processStartTag(t,n,r)},t.afterBody.endTagHtml=function(t){e.context?e.parseError("end-html-in-innerhtml"):e.setInsertionMode("afterAfterBody")},t.afterBody.endTagOther=function(t){e.parseError("unexpected-end-tag-after-body",{name:t}),e.setInsertionMode("inBody"),e.insertionMode.processEndTag(t)},t.afterFrameset=Object.create(t.base),t.afterFrameset.start_tag_handlers={html:"startTagHtml",noframes:"startTagNoframes","-default":"startTagOther"},t.afterFrameset.end_tag_handlers={html:"endTagHtml","-default":"endTagOther"},t.afterFrameset.processCharacters=function(t){var n=t.takeRemaining(),r="";for(var i=0;i<n.length;i++){var s=n[i];c(s)&&(r+=s)}r&&e.insertText(r),r.length<n.length&&e.parseError("expected-eof-but-got-char")},t.afterFrameset.startTagNoframes=function(e,n){t.inHead.processStartTag(e,n)},t.afterFrameset.startTagOther=function(t,n){e.parseError("unexpected-start-tag-after-frameset",{name:t})},t.afterFrameset.endTagHtml=function(t){e.setInsertionMode("afterAfterFrameset")},t.afterFrameset.endTagOther=function(t){e.parseError("unexpected-end-tag-after-frameset",{name:t})},t.beforeHead=Object.create(t.base),t.beforeHead.start_tag_handlers={html:"startTagHtml",head:"startTagHead","-default":"startTagOther"},t.beforeHead.end_tag_handlers={html:"endTagImplyHead",head:"endTagImplyHead",body:"endTagImplyHead",br:"endTagImplyHead","-default":"endTagOther"},t.beforeHead.processEOF=function(){this.startTagHead("head",[]),e.insertionMode.processEOF()},t.beforeHead.processCharacters=function(t){t.skipLeadingWhitespace();if(!t.length)return;this.startTagHead("head",[]),e.insertionMode.processCharacters(t)},t.beforeHead.startTagHead=function(t,n){e.insertHeadElement(n),e.setInsertionMode("inHead")},t.beforeHead.startTagOther=function(t,n,r){this.startTagHead("head",[]),e.insertionMode.processStartTag(t,n,r)},t.beforeHead.endTagImplyHead=function(t){this.startTagHead("head",[]),e.insertionMode.processEndTag(t)},t.beforeHead.endTagOther=function(t){e.parseError("end-tag-after-implied-root",{name:t})},t.inHead=Object.create(t.base),t.inHead.start_tag_handlers={html:"startTagHtml",head:"startTagHead",title:"startTagTitle",script:"startTagScript",style:"startTagNoFramesStyle",noscript:"startTagNoScript",noframes:"startTagNoFramesStyle",base:"startTagBaseBasefontBgsoundLink",basefont:"startTagBaseBasefontBgsoundLink",bgsound:"startTagBaseBasefontBgsoundLink",link:"startTagBaseBasefontBgsoundLink",meta:"startTagMeta","-default":"startTagOther"},t.inHead.end_tag_handlers={head:"endTagHead",html:"endTagHtmlBodyBr",body:"endTagHtmlBodyBr",br:"endTagHtmlBodyBr","-default":"endTagOther"},t.inHead.processEOF=function(){var t=e.currentStackItem().localName;["title","style","script"].indexOf(t)!=-1&&(e.parseError("expected-named-closing-tag-but-got-eof",{name:t}),e.popElement()),this.anythingElse(),e.insertionMode.processEOF()},t.inHead.processCharacters=function(t){var n=t.takeLeadingWhitespace();n&&e.insertText(n);if(!t.length)return;this.anythingElse(),e.insertionMode.processCharacters(t)},t.inHead.startTagHtml=function(e,n){t.inBody.processStartTag(e,n)},t.inHead.startTagHead=function(t,n){e.parseError("two-heads-are-not-better-than-one")},t.inHead.startTagTitle=function(t,n){e.processGenericRCDATAStartTag(t,n)},t.inHead.startTagNoScript=function(t,n){if(e.scriptingEnabled)return e.processGenericRawTextStartTag(t,n);e.insertElement(t,n),e.setInsertionMode("inHeadNoscript")},t.inHead.startTagNoFramesStyle=function(t,n){e.processGenericRawTextStartTag(t,n)},t.inHead.startTagScript=function(t,n){e.insertElement(t,n),e.tokenizer.setState(u.SCRIPT_DATA),e.originalInsertionMode=e.insertionModeName,e.setInsertionMode("text")},t.inHead.startTagBaseBasefontBgsoundLink=function(t,n){e.insertSelfClosingElement(t,n)},t.inHead.startTagMeta=function(t,n){e.insertSelfClosingElement(t,n)},t.inHead.startTagOther=function(t,n,r){this.anythingElse(),e.insertionMode.processStartTag(t,n,r)},t.inHead.endTagHead=function(t){e.openElements.item(e.openElements.length-1).localName=="head"?e.openElements.pop():e.parseError("unexpected-end-tag",{name:"head"}),e.setInsertionMode("afterHead")},t.inHead.endTagHtmlBodyBr=function(t){this.anythingElse(),e.insertionMode.processEndTag(t)},t.inHead.endTagOther=function(t){e.parseError("unexpected-end-tag",{name:t})},t.inHead.anythingElse=function(){this.endTagHead("head")},t.afterHead=Object.create(t.base),t.afterHead.start_tag_handlers={html:"startTagHtml",head:"startTagHead",body:"startTagBody",frameset:"startTagFrameset",base:"startTagFromHead",link:"startTagFromHead",meta:"startTagFromHead",script:"startTagFromHead",style:"startTagFromHead",title:"startTagFromHead","-default":"startTagOther"},t.afterHead.end_tag_handlers={body:"endTagBodyHtmlBr",html:"endTagBodyHtmlBr",br:"endTagBodyHtmlBr","-default":"endTagOther"},t.afterHead.processEOF=function(){this.anythingElse(),e.insertionMode.processEOF()},t.afterHead.processCharacters=function(t){var n=t.takeLeadingWhitespace();n&&e.insertText(n);if(!t.length)return;this.anythingElse(),e.insertionMode.processCharacters(t)},t.afterHead.startTagHtml=function(e,n){t.inBody.processStartTag(e,n)},t.afterHead.startTagBody=function(t,n){e.framesetOk=!1,e.insertBodyElement(n),e.setInsertionMode("inBody")},t.afterHead.startTagFrameset=function(t,n){e.insertElement(t,n),e.setInsertionMode("inFrameset")},t.afterHead.startTagFromHead=function(n,r,i){e.parseError("unexpected-start-tag-out-of-my-head",{name:n}),e.openElements.push(e.head),t.inHead.processStartTag(n,r,i),e.openElements.remove(e.head)},t.afterHead.startTagHead=function(t,n,r){e.parseError("unexpected-start-tag",{name:t})},t.afterHead.startTagOther=function(t,n,r){this.anythingElse(),e.insertionMode.processStartTag(t,n,r)},t.afterHead.endTagBodyHtmlBr=function(t){this.anythingElse(),e.insertionMode.processEndTag(t)},t.afterHead.endTagOther=function(t){e.parseError("unexpected-end-tag",{name:t})},t.afterHead.anythingElse=function(){e.insertBodyElement([]),e.setInsertionMode("inBody"),e.framesetOk=!0},t.inBody=Object.create(t.base),t.inBody.start_tag_handlers={html:"startTagHtml",head:"startTagMisplaced",base:"startTagProcessInHead",basefont:"startTagProcessInHead",bgsound:"startTagProcessInHead",link:"startTagProcessInHead",meta:"startTagProcessInHead",noframes:"startTagProcessInHead",script:"startTagProcessInHead",style:"startTagProcessInHead",title:"startTagProcessInHead",body:"startTagBody",form:"startTagForm",plaintext:"startTagPlaintext",a:"startTagA",button:"startTagButton",xmp:"startTagXmp",table:"startTagTable",hr:"startTagHr",image:"startTagImage",input:"startTagInput",textarea:"startTagTextarea",select:"startTagSelect",isindex:"startTagIsindex",applet:"startTagAppletMarqueeObject",marquee:"startTagAppletMarqueeObject",object:"startTagAppletMarqueeObject",li:"startTagListItem",dd:"startTagListItem",dt:"startTagListItem",address:"startTagCloseP",article:"startTagCloseP",aside:"startTagCloseP",blockquote:"startTagCloseP",center:"startTagCloseP",details:"startTagCloseP",dir:"startTagCloseP",div:"startTagCloseP",dl:"startTagCloseP",fieldset:"startTagCloseP",figcaption:"startTagCloseP",figure:"startTagCloseP",footer:"startTagCloseP",header:"startTagCloseP",hgroup:"startTagCloseP",main:"startTagCloseP",menu:"startTagCloseP",nav:"startTagCloseP",ol:"startTagCloseP",p:"startTagCloseP",section:"startTagCloseP",summary:"startTagCloseP",ul:"startTagCloseP",listing:"startTagPreListing",pre:"startTagPreListing",b:"startTagFormatting",big:"startTagFormatting",code:"startTagFormatting",em:"startTagFormatting",font:"startTagFormatting",i:"startTagFormatting",s:"startTagFormatting",small:"startTagFormatting",strike:"startTagFormatting",strong:"startTagFormatting",tt:"startTagFormatting",u:"startTagFormatting",nobr:"startTagNobr",area:"startTagVoidFormatting",br:"startTagVoidFormatting",embed:"startTagVoidFormatting",img:"startTagVoidFormatting",keygen:"startTagVoidFormatting",wbr:"startTagVoidFormatting",param:"startTagParamSourceTrack",source:"startTagParamSourceTrack",track:"startTagParamSourceTrack",iframe:"startTagIFrame",noembed:"startTagRawText",noscript:"startTagRawText",h1:"startTagHeading",h2:"startTagHeading",h3:"startTagHeading",h4:"startTagHeading",h5:"startTagHeading",h6:"startTagHeading",caption:"startTagMisplaced",col:"startTagMisplaced",colgroup:"startTagMisplaced",frame:"startTagMisplaced",frameset:"startTagFrameset",tbody:"startTagMisplaced",td:"startTagMisplaced",tfoot:"startTagMisplaced",th:"startTagMisplaced",thead:"startTagMisplaced",tr:"startTagMisplaced",option:"startTagOptionOptgroup",optgroup:"startTagOptionOptgroup",math:"startTagMath",svg:"startTagSVG",rt:"startTagRpRt",rp:"startTagRpRt","-default":"startTagOther"},t.inBody.end_tag_handlers={p:"endTagP",body:"endTagBody",html:"endTagHtml",address:"endTagBlock",article:"endTagBlock",aside:"endTagBlock",blockquote:"endTagBlock",button:"endTagBlock",center:"endTagBlock",details:"endTagBlock",dir:"endTagBlock",div:"endTagBlock",dl:"endTagBlock",fieldset:"endTagBlock",figcaption:"endTagBlock",figure:"endTagBlock",footer:"endTagBlock",header:"endTagBlock",hgroup:"endTagBlock",listing:"endTagBlock",main:"endTagBlock",menu:"endTagBlock",nav:"endTagBlock",ol:"endTagBlock",pre:"endTagBlock",section:"endTagBlock",summary:"endTagBlock",ul:"endTagBlock",form:"endTagForm",applet:"endTagAppletMarqueeObject",marquee:"endTagAppletMarqueeObject",object:"endTagAppletMarqueeObject",dd:"endTagListItem",dt:"endTagListItem",li:"endTagListItem",h1:"endTagHeading",h2:"endTagHeading",h3:"endTagHeading",h4:"endTagHeading",h5:"endTagHeading",h6:"endTagHeading",a:"endTagFormatting",b:"endTagFormatting",big:"endTagFormatting",code:"endTagFormatting",em:"endTagFormatting",font:"endTagFormatting",i:"endTagFormatting",nobr:"endTagFormatting",s:"endTagFormatting",small:"endTagFormatting",strike:"endTagFormatting",strong:"endTagFormatting",tt:"endTagFormatting",u:"endTagFormatting",br:"endTagBr","-default":"endTagOther"},t.inBody.processCharacters=function(t){e.shouldSkipLeadingNewline&&(e.shouldSkipLeadingNewline=!1,t.skipAtMostOneLeadingNewline()),e.reconstructActiveFormattingElements();var n=t.takeRemaining();n=n.replace(/\u0000/g,function(t,n){return e.parseError("invalid-codepoint"),""});if(!n)return;e.insertText(n),e.framesetOk&&!d(n)&&(e.framesetOk=!1)},t.inBody.startTagHtml=function(t,n){e.parseError("non-html-root"),e.addAttributesToElement(e.openElements.rootNode,n)},t.inBody.startTagProcessInHead=function(e,n){t.inHead.processStartTag(e,n)},t.inBody.startTagBody=function(t,n){e.parseError("unexpected-start-tag",{name:"body"}),e.openElements.length==1||e.openElements.item(1).localName!="body"?r.ok(e.context):(e.framesetOk=!1,e.addAttributesToElement(e.openElements.bodyElement,n))},t.inBody.startTagFrameset=function(t,n){e.parseError("unexpected-start-tag",{name:"frameset"});if(e.openElements.length==1||e.openElements.item(1).localName!="body")r.ok(e.context);else if(e.framesetOk){e.detachFromParent(e.openElements.bodyElement);while(e.openElements.length>1)e.openElements.pop();e.insertElement(t,n),e.setInsertionMode("inFrameset")}},t.inBody.startTagCloseP=function(t,n){e.openElements.inButtonScope("p")&&this.endTagP("p"),e.insertElement(t,n)},t.inBody.startTagPreListing=function(t,n){e.openElements.inButtonScope("p")&&this.endTagP("p"),e.insertElement(t,n),e.framesetOk=!1,e.shouldSkipLeadingNewline=!0},t.inBody.startTagForm=function(t,n){e.form?e.parseError("unexpected-start-tag",{name:t}):(e.openElements.inButtonScope("p")&&this.endTagP("p"),e.insertElement(t,n),e.form=e.currentStackItem())},t.inBody.startTagRpRt=function(t,n){e.openElements.inScope("ruby")&&(e.generateImpliedEndTags(),e.currentStackItem().localName!="ruby"&&e.parseError("unexpected-start-tag",{name:t})),e.insertElement(t,n)},t.inBody.startTagListItem=function(t,n){var r={li:["li"],dd:["dd","dt"],dt:["dd","dt"]},i=r[t],s=e.openElements;for(var o=s.length-1;o>=0;o--){var u=s.item(o);if(i.indexOf(u.localName)!=-1){e.insertionMode.processEndTag(u.localName);break}if(u.isSpecial()&&u.localName!=="p"&&u.localName!=="address"&&u.localName!=="div")break}e.openElements.inButtonScope("p")&&this.endTagP("p"),e.insertElement(t,n),e.framesetOk=!1},t.inBody.startTagPlaintext=function(t,n){e.openElements.inButtonScope("p")&&this.endTagP("p"),e.insertElement(t,n),e.tokenizer.setState(u.PLAINTEXT)},t.inBody.startTagHeading=function(t,n){e.openElements.inButtonScope("p")&&this.endTagP("p"),e.currentStackItem().isNumberedHeader()&&(e.parseError("unexpected-start-tag",{name:t}),e.popElement()),e.insertElement(t,n)},t.inBody.startTagA=function(t,n){var r=e.elementInActiveFormattingElements("a");r&&(e.parseError("unexpected-start-tag-implies-end-tag",{startName:"a",endName:"a"}),e.adoptionAgencyEndTag("a"),e.openElements.contains(r)&&e.openElements.remove(r),e.removeElementFromActiveFormattingElements(r)),e.reconstructActiveFormattingElements(),e.insertFormattingElement(t,n)},t.inBody.startTagFormatting=function(t,n){e.reconstructActiveFormattingElements(),e.insertFormattingElement(t,n)},t.inBody.startTagNobr=function(t,n){e.reconstructActiveFormattingElements(),e.openElements.inScope("nobr")&&(e.parseError("unexpected-start-tag-implies-end-tag",{startName:"nobr",endName:"nobr"}),this.processEndTag("nobr"),e.reconstructActiveFormattingElements()),e.insertFormattingElement(t,n)},t.inBody.startTagButton=function(t,n){e.openElements.inScope("button")?(e.parseError("unexpected-start-tag-implies-end-tag",{startName:"button",endName:"button"}),this.processEndTag("button"),e.insertionMode.processStartTag(t,n)):(e.framesetOk=!1,e.reconstructActiveFormattingElements(),e.insertElement(t,n))},t.inBody.startTagAppletMarqueeObject=function(t,n){e.reconstructActiveFormattingElements(),e.insertElement(t,n),e.activeFormattingElements.push(l),e.framesetOk=!1},t.inBody.endTagAppletMarqueeObject=function(t){e.openElements.inScope(t)?(e.generateImpliedEndTags(),e.currentStackItem().localName!=t&&e.parseError("end-tag-too-early",{name:t}),e.openElements.popUntilPopped(t),e.clearActiveFormattingElements()):e.parseError("unexpected-end-tag",{name:t})},t.inBody.startTagXmp=function(t,n){e.openElements.inButtonScope("p")&&this.processEndTag("p"),e.reconstructActiveFormattingElements(),e.processGenericRawTextStartTag(t,n),e.framesetOk=!1},t.inBody.startTagTable=function(t,n){e.compatMode!=="quirks"&&e.openElements.inButtonScope("p")&&this.processEndTag("p"),e.insertElement(t,n),e.setInsertionMode("inTable"),e.framesetOk=!1},t.inBody.startTagVoidFormatting=function(t,n){e.reconstructActiveFormattingElements(),e.insertSelfClosingElement(t,n),e.framesetOk=!1},t.inBody.startTagParamSourceTrack=function(t,n){e.insertSelfClosingElement(t,n)},t.inBody.startTagHr=function(t,n){e.openElements.inButtonScope("p")&&this.endTagP("p"),e.insertSelfClosingElement(t,n),e.framesetOk=!1},t.inBody.startTagImage=function(t,n){e.parseError("unexpected-start-tag-treated-as",{originalName:"image",newName:"img"}),this.processStartTag("img",n)},t.inBody.startTagInput=function(t,n){var r=e.framesetOk;this.startTagVoidFormatting(t,n);for(var i in n)if(n[i].nodeName=="type"){n[i].nodeValue.toLowerCase()=="hidden"&&(e.framesetOk=r);break}},t.inBody.startTagIsindex=function(t,n){e.parseError("deprecated-tag",{name:"isindex"}),e.selfClosingFlagAcknowledged=!0;if(e.form)return;var r=[],i=[],s="This is a searchable index. Enter search keywords: ";for(var o in n)switch(n[o].nodeName){case"action":r.push({nodeName:"action",nodeValue:n[o].nodeValue});break;case"prompt":s=n[o].nodeValue;break;case"name":break;default:i.push({nodeName:n[o].nodeName,nodeValue:n[o].nodeValue})}i.push({nodeName:"name",nodeValue:"isindex"}),this.processStartTag("form",r),this.processStartTag("hr"),this.processStartTag("label"),this.processCharacters(new m(s)),this.processStartTag("input",i),this.processEndTag("label"),this.processStartTag("hr"),this.processEndTag("form")},t.inBody.startTagTextarea=function(t,n){e.insertElement(t,n),e.tokenizer.setState(u.RCDATA),e.originalInsertionMode=e.insertionModeName,e.shouldSkipLeadingNewline=!0,e.framesetOk=!1,e.setInsertionMode("text")},t.inBody.startTagIFrame=function(t,n){e.framesetOk=!1,this.startTagRawText(t,n)},t.inBody.startTagRawText=function(t,n){e.processGenericRawTextStartTag(t,n)},t.inBody.startTagSelect=function(t,n){e.reconstructActiveFormattingElements(),e.insertElement(t,n),e.framesetOk=!1;var r=e.insertionModeName;r=="inTable"||r=="inCaption"||r=="inColumnGroup"||r=="inTableBody"||r=="inRow"||r=="inCell"?e.setInsertionMode("inSelectInTable"):e.setInsertionMode("inSelect")},t.inBody.startTagMisplaced=function(t,n){e.parseError("unexpected-start-tag-ignored",{name:t})},t.inBody.endTagMisplaced=function(t){e.parseError("unexpected-end-tag",{name:t})},t.inBody.endTagBr=function(t){e.parseError("unexpected-end-tag-treated-as",{originalName:"br",newName:"br element"}),e.reconstructActiveFormattingElements(),e.insertElement(t,[]),e.popElement()},t.inBody.startTagOptionOptgroup=function(t,n){e.currentStackItem().localName=="option"&&e.popElement(),e.reconstructActiveFormattingElements(),e.insertElement(t,n)},t.inBody.startTagOther=function(t,n){e.reconstructActiveFormattingElements(),e.insertElement(t,n)},t.inBody.endTagOther=function(t){var n;for(var r=e.openElements.length-1;r>0;r--){n=e.openElements.item(r);if(n.localName==t){e.generateImpliedEndTags(t),e.currentStackItem().localName!=t&&e.parseError("unexpected-end-tag",{name:t}),e.openElements.remove_openElements_until(function(e){return e===n});break}if(n.isSpecial()){e.parseError("unexpected-end-tag",{name:t});break}}},t.inBody.startTagMath=function(t,n,r){e.reconstructActiveFormattingElements(),n=e.adjustMathMLAttributes(n),n=e.adjustForeignAttributes(n),e.insertForeignElement(t,n,"http://www.w3.org/1998/Math/MathML",r)},t.inBody.startTagSVG=function(t,n,r){e.reconstructActiveFormattingElements(),n=e.adjustSVGAttributes(n),n=e.adjustForeignAttributes(n),e.insertForeignElement(t,n,"http://www.w3.org/2000/svg",r)},t.inBody.endTagP=function(t){e.openElements.inButtonScope("p")?(e.generateImpliedEndTags("p"),e.currentStackItem().localName!="p"&&e.parseError("unexpected-implied-end-tag",{name:"p"}),e.openElements.popUntilPopped(t)):(e.parseError("unexpected-end-tag",{name:"p"}),this.startTagCloseP("p",[]),this.endTagP("p"))},t.inBody.endTagBody=function(t){if(!e.openElements.inScope("body")){e.parseError("unexpected-end-tag",{name:t});return}e.currentStackItem().localName!="body"&&e.parseError("expected-one-end-tag-but-got-another",{expectedName:e.currentStackItem().localName,gotName:t}),e.setInsertionMode("afterBody")},t.inBody.endTagHtml=function(t){if(!e.openElements.inScope("body")){e.parseError("unexpected-end-tag",{name:t});return}e.currentStackItem().localName!="body"&&e.parseError("expected-one-end-tag-but-got-another",{expectedName:e.currentStackItem().localName,gotName:t}),e.setInsertionMode("afterBody"),e.insertionMode.processEndTag(t)},t.inBody.endTagBlock=function(t){e.openElements.inScope(t)?(e.generateImpliedEndTags(),e.currentStackItem().localName!=t&&e.parseError("end-tag-too-early",{name:t}),e.openElements.popUntilPopped(t)):e.parseError("unexpected-end-tag",{name:t})},t.inBody.endTagForm=function(t){var n=e.form;e.form=null,!n||!e.openElements.inScope(t)?e.parseError("unexpected-end-tag",{name:t}):(e.generateImpliedEndTags(),e.currentStackItem()!=n&&e.parseError("end-tag-too-early-ignored",{name:"form"}),e.openElements.remove(n))},t.inBody.endTagListItem=function(t){e.openElements.inListItemScope(t)?(e.generateImpliedEndTags(t),e.currentStackItem().localName!=t&&e.parseError("end-tag-too-early",{name:t}),e.openElements.popUntilPopped(t)):e.parseError("unexpected-end-tag",{name:t})},t.inBody.endTagHeading=function(t){if(!e.openElements.hasNumberedHeaderElementInScope()){e.parseError("unexpected-end-tag",{name:t});return}e.generateImpliedEndTags(),e.currentStackItem().localName!=t&&e.parseError("end-tag-too-early",{name:t}),e.openElements.remove_openElements_until(function(e){return e.isNumberedHeader()})},t.inBody.endTagFormatting=function(t,n){e.adoptionAgencyEndTag(t)||this.endTagOther(t,n)},t.inCaption=Object.create(t.base),t.inCaption.start_tag_handlers={html:"startTagHtml",caption:"startTagTableElement",col:"startTagTableElement",colgroup:"startTagTableElement",tbody:"startTagTableElement",td:"startTagTableElement",tfoot:"startTagTableElement",thead:"startTagTableElement",tr:"startTagTableElement","-default":"startTagOther"},t.inCaption.end_tag_handlers={caption:"endTagCaption",table:"endTagTable",body:"endTagIgnore",col:"endTagIgnore",colgroup:"endTagIgnore",html:"endTagIgnore",tbody:"endTagIgnore",td:"endTagIgnore",tfood:"endTagIgnore",thead:"endTagIgnore",tr:"endTagIgnore","-default":"endTagOther"},t.inCaption.processCharacters=function(e){t.inBody.processCharacters(e)},t.inCaption.startTagTableElement=function(t,n){e.parseError("unexpected-end-tag",{name:t});var r=!e.openElements.inTableScope("caption");e.insertionMode.processEndTag("caption"),r||e.insertionMode.processStartTag(t,n)},t.inCaption.startTagOther=function(e,n,r){t.inBody.processStartTag(e,n,r)},t.inCaption.endTagCaption=function(t){e.openElements.inTableScope("caption")?(e.generateImpliedEndTags(),e.currentStackItem().localName!="caption"&&e.parseError("expected-one-end-tag-but-got-another",{gotName:"caption",expectedName:e.currentStackItem().localName}),e.openElements.popUntilPopped("caption"),e.clearActiveFormattingElements(),e.setInsertionMode("inTable")):(r.ok(e.context),e.parseError("unexpected-end-tag",{name:t}))},t.inCaption.endTagTable=function(t){e.parseError("unexpected-end-table-in-caption");var n=!e.openElements.inTableScope("caption");e.insertionMode.processEndTag("caption"),n||e.insertionMode.processEndTag(t)},t.inCaption.endTagIgnore=function(t){e.parseError("unexpected-end-tag",{name:t})},t.inCaption.endTagOther=function(e){t.inBody.processEndTag(e)},t.inCell=Object.create(t.base),t.inCell.start_tag_handlers={html:"startTagHtml",caption:"startTagTableOther",col:"startTagTableOther",colgroup:"startTagTableOther",tbody:"startTagTableOther",td:"startTagTableOther",tfoot:"startTagTableOther",th:"startTagTableOther",thead:"startTagTableOther",tr:"startTagTableOther","-default":"startTagOther"},t.inCell.end_tag_handlers={td:"endTagTableCell",th:"endTagTableCell",body:"endTagIgnore",caption:"endTagIgnore",col:"endTagIgnore",colgroup:"endTagIgnore",html:"endTagIgnore",table:"endTagImply",tbody:"endTagImply",tfoot:"endTagImply",thead:"endTagImply",tr:"endTagImply","-default":"endTagOther"},t.inCell.processCharacters=function(e){t.inBody.processCharacters(e)},t.inCell.startTagTableOther=function(t,n,r){e.openElements.inTableScope("td")||e.openElements.inTableScope("th")?(this.closeCell(),e.insertionMode.processStartTag(t,n,r)):e.parseError("unexpected-start-tag",{name:t})},t.inCell.startTagOther=function(e,n,r){t.inBody.processStartTag(e,n,r)},t.inCell.endTagTableCell=function(t){e.openElements.inTableScope(t)?(e.generateImpliedEndTags(t),e.currentStackItem().localName!=t.toLowerCase()?(e.parseError("unexpected-cell-end-tag",{name:t}),e.openElements.popUntilPopped(t)):e.popElement(),e.clearActiveFormattingElements(),e.setInsertionMode("inRow")):e.parseError("unexpected-end-tag",{name:t})},t.inCell.endTagIgnore=function(t){e.parseError("unexpected-end-tag",{name:t})},t.inCell.endTagImply=function(t){e.openElements.inTableScope(t)?(this.closeCell(),e.insertionMode.processEndTag(t)):e.parseError("unexpected-end-tag",{name:t})},t.inCell.endTagOther=function(e){t.inBody.processEndTag(e)},t.inCell.closeCell=function(){e.openElements.inTableScope("td")?this.endTagTableCell("td"):e.openElements.inTableScope("th")&&this.endTagTableCell("th")},t.inColumnGroup=Object.create(t.base),t.inColumnGroup.start_tag_handlers={html:"startTagHtml",col:"startTagCol","-default":"startTagOther"},t.inColumnGroup.end_tag_handlers={colgroup:"endTagColgroup",col:"endTagCol","-default":"endTagOther"},t.inColumnGroup.ignoreEndTagColgroup=function(){return e.currentStackItem().localName=="html"},t.inColumnGroup.processCharacters=function(t){var n=t.takeLeadingWhitespace();n&&e.insertText(n);if(!t.length)return;var r=this.ignoreEndTagColgroup();this.endTagColgroup("colgroup"),r||e.insertionMode.processCharacters(t)},t.inColumnGroup.startTagCol=function(t,n){e.insertSelfClosingElement(t,n)},t.inColumnGroup.startTagOther=function(t,n,r){var i=this.ignoreEndTagColgroup();this.endTagColgroup("colgroup"),i||e.insertionMode.processStartTag(t,n,r)},t.inColumnGroup.endTagColgroup=function(t){this.ignoreEndTagColgroup()?(r.ok(e.context),e.parseError("unexpected-end-tag",{name:t})):(e.popElement(),e.setInsertionMode("inTable"))},t.inColumnGroup.endTagCol=function(t){e.parseError("no-end-tag",{name:"col"})},t.inColumnGroup.endTagOther=function(t){var n=this.ignoreEndTagColgroup();this.endTagColgroup("colgroup"),n||e.insertionMode.processEndTag(t)},t.inForeignContent=Object.create(t.base),t.inForeignContent.processStartTag=function(t,n,r){if(["b","big","blockquote","body","br","center","code","dd","div","dl","dt","em","embed","h1","h2","h3","h4","h5","h6","head","hr","i","img","li","listing","menu","meta","nobr","ol","p","pre","ruby","s","small","span","strong","strike","sub","sup","table","tt","u","ul","var"].indexOf(t)!=-1||t=="font"&&n.some(function(e){return["color","face","size"].indexOf(e.nodeName)>=0})){e.parseError("unexpected-html-element-in-foreign-content",{name:t});while(e.currentStackItem().isForeign()&&!e.currentStackItem().isHtmlIntegrationPoint()&&!e.currentStackItem().isMathMLTextIntegrationPoint())e.openElements.pop();e.insertionMode.processStartTag(t,n,r);return}e.currentStackItem().namespaceURI=="http://www.w3.org/1998/Math/MathML"&&(n=e.adjustMathMLAttributes(n)),e.currentStackItem().namespaceURI=="http://www.w3.org/2000/svg"&&(t=e.adjustSVGTagNameCase(t),n=e.adjustSVGAttributes(n)),n=e.adjustForeignAttributes(n),e.insertForeignElement(t,n,e.currentStackItem().namespaceURI,r)},t.inForeignContent.processEndTag=function(t){var n=e.currentStackItem(),r=e.openElements.length-1;n.localName.toLowerCase()!=t&&e.parseError("unexpected-end-tag",{name:t});for(;;){if(r===0)break;if(n.localName.toLowerCase()==t){while(e.openElements.pop()!=n);break}r-=1,n=e.openElements.item(r);if(n.isForeign())continue;e.insertionMode.processEndTag(t);break}},t.inForeignContent.processCharacters=function(t){var n=t.takeRemaining();n=n.replace(/\u0000/g,function(t,n){return e.parseError("invalid-codepoint"),"\ufffd"}),e.framesetOk&&!d(n)&&(e.framesetOk=!1),e.insertText(n)},t.inHeadNoscript=Object.create(t.base),t.inHeadNoscript.start_tag_handlers={html:"startTagHtml",basefont:"startTagBasefontBgsoundLinkMetaNoframesStyle",bgsound:"startTagBasefontBgsoundLinkMetaNoframesStyle",link:"startTagBasefontBgsoundLinkMetaNoframesStyle",meta:"startTagBasefontBgsoundLinkMetaNoframesStyle",noframes:"startTagBasefontBgsoundLinkMetaNoframesStyle",style:"startTagBasefontBgsoundLinkMetaNoframesStyle",head:"startTagHeadNoscript",noscript:"startTagHeadNoscript","-default":"startTagOther"},t.inHeadNoscript.end_tag_handlers={noscript:"endTagNoscript",br:"endTagBr","-default":"endTagOther"},t.inHeadNoscript.processCharacters=function(t){var n=t.takeLeadingWhitespace();n&&e.insertText(n);if(!t.length)return;e.parseError("unexpected-char-in-frameset"),this.anythingElse(),e.insertionMode.processCharacters(t)},t.inHeadNoscript.processComment=function(e){t.inHead.processComment(e)},t.inHeadNoscript.startTagBasefontBgsoundLinkMetaNoframesStyle=function(e,n){t.inHead.processStartTag(e,n)},t.inHeadNoscript.startTagHeadNoscript=function(t,n){e.parseError("unexpected-start-tag-in-frameset",{name:t})},t.inHeadNoscript.startTagOther=function(t,n){e.parseError("unexpected-start-tag-in-frameset",{name:t}),this.anythingElse(),e.insertionMode.processStartTag(t,n)},t.inHeadNoscript.endTagBr=function(t,n){e.parseError("unexpected-end-tag-in-frameset",{name:t}),this.anythingElse(),e.insertionMode.processEndTag(t,n)},t.inHeadNoscript.endTagNoscript=function(t,n){e.popElement(),e.setInsertionMode("inHead")},t.inHeadNoscript.endTagOther=function(t,n){e.parseError("unexpected-end-tag-in-frameset",{name:t})},t.inHeadNoscript.anythingElse=function(){e.popElement(),e.setInsertionMode("inHead")},t.inFrameset=Object.create(t.base),t.inFrameset.start_tag_handlers={html:"startTagHtml",frameset:"startTagFrameset",frame:"startTagFrame",noframes:"startTagNoframes","-default":"startTagOther"},t.inFrameset.end_tag_handlers={frameset:"endTagFrameset",noframes:"endTagNoframes","-default":"endTagOther"},t.inFrameset.processCharacters=function(t){e.parseError("unexpected-char-in-frameset")},t.inFrameset.startTagFrameset=function(t,n){e.insertElement(t,n)},t.inFrameset.startTagFrame=function(t,n){e.insertSelfClosingElement(t,n)},t.inFrameset.startTagNoframes=function(e,n){t.inBody.processStartTag(e,n)},t.inFrameset.startTagOther=function(t,n){e.parseError("unexpected-start-tag-in-frameset",{name:t})},t.inFrameset.endTagFrameset=function(t,n){e.currentStackItem().localName=="html"?e.parseError("unexpected-frameset-in-frameset-innerhtml"):e.popElement(),!e.context&&e.currentStackItem().localName!="frameset"&&e.setInsertionMode("afterFrameset")},t.inFrameset.endTagNoframes=function(e){t.inBody.processEndTag(e)},t.inFrameset.endTagOther=function(t){e.parseError("unexpected-end-tag-in-frameset",{name:t})},t.inTable=Object.create(t.base),t.inTable.start_tag_handlers={html:"startTagHtml",caption:"startTagCaption",colgroup:"startTagColgroup",col:"startTagCol",table:"startTagTable",tbody:"startTagRowGroup",tfoot:"startTagRowGroup",thead:"startTagRowGroup",td:"startTagImplyTbody",th:"startTagImplyTbody",tr:"startTagImplyTbody",style:"startTagStyleScript",script:"startTagStyleScript",input:"startTagInput",form:"startTagForm","-default":"startTagOther"},t.inTable.end_tag_handlers={table:"endTagTable",body:"endTagIgnore",caption:"endTagIgnore",col:"endTagIgnore",colgroup:"endTagIgnore",html:"endTagIgnore",tbody:"endTagIgnore",td:"endTagIgnore",tfoot:"endTagIgnore",th:"endTagIgnore",thead:"endTagIgnore",tr:"endTagIgnore","-default":"endTagOther"},t.inTable.processCharacters=function(n){if(e.currentStackItem().isFosterParenting()){var r=e.insertionModeName;e.setInsertionMode("inTableText"),e.originalInsertionMode=r,e.insertionMode.processCharacters(n)}else e.redirectAttachToFosterParent=!0,t.inBody.processCharacters(n),e.redirectAttachToFosterParent=!1},t.inTable.startTagCaption=function(t,n){e.openElements.popUntilTableScopeMarker(),e.activeFormattingElements.push(l),e.insertElement(t,n),e.setInsertionMode("inCaption")},t.inTable.startTagColgroup=function(t,n){e.openElements.popUntilTableScopeMarker(),e.insertElement(t,n),e.setInsertionMode("inColumnGroup")},t.inTable.startTagCol=function(t,n){this.startTagColgroup("colgroup",[]),e.insertionMode.processStartTag(t,n)},t.inTable.startTagRowGroup=function(t,n){e.openElements.popUntilTableScopeMarker(),e.insertElement(t,n),e.setInsertionMode("inTableBody")},t.inTable.startTagImplyTbody=function(t,n){this.startTagRowGroup("tbody",[]),e.insertionMode.processStartTag(t,n)},t.inTable.startTagTable=function(t,n){e.parseError("unexpected-start-tag-implies-end-tag",{startName:"table",endName:"table"}),e.insertionMode.processEndTag("table"),e.context||e.insertionMode.processStartTag(t,n)},t.inTable.startTagStyleScript=function(e,n){t.inHead.processStartTag(e,n)},t.inTable.startTagInput=function(t,n){for(var r in n)if(n[r].nodeName.toLowerCase()=="type"){if(n[r].nodeValue.toLowerCase()=="hidden"){e.parseError("unexpected-hidden-input-in-table"),e.insertElement(t,n),e.openElements.pop();return}break}this.startTagOther(t,n)},t.inTable.startTagForm=function(t,n){e.parseError("unexpected-form-in-table"),e.form||(e.insertElement(t,n),e.form=e.currentStackItem(),e.openElements.pop())},t.inTable.startTagOther=function(n,r,i){e.parseError("unexpected-start-tag-implies-table-voodoo",{name:n}),e.redirectAttachToFosterParent=!0,t.inBody.processStartTag(n,r,i),e.redirectAttachToFosterParent=!1},t.inTable.endTagTable=function(t){e.openElements.inTableScope(t)?(e.generateImpliedEndTags(),e.currentStackItem().localName!=t&&e.parseError("end-tag-too-early-named",{gotName:"table",expectedName:e.currentStackItem().localName}),e.openElements.popUntilPopped("table"),e.resetInsertionMode()):(r.ok(e.context),e.parseError("unexpected-end-tag",{name:t}))},t.inTable.endTagIgnore=function(t){e.parseError("unexpected-end-tag",{name:t})},t.inTable.endTagOther=function(n){e.parseError("unexpected-end-tag-implies-table-voodoo",{name:n}),e.redirectAttachToFosterParent=!0,t.inBody.processEndTag(n),e.redirectAttachToFosterParent=!1},t.inTableText=Object.create(t.base),t.inTableText.flushCharacters=function(){var t=e.pendingTableCharacters.join("");p(t)?e.insertText(t):(e.redirectAttachToFosterParent=!0,e.reconstructActiveFormattingElements(),e.insertText(t),e.framesetOk=!1,e.redirectAttachToFosterParent=!1),e.pendingTableCharacters=[]},t.inTableText.processComment=function(t){this.flushCharacters(),e.setInsertionMode(e.originalInsertionMode),e.insertionMode.processComment(t)},t.inTableText.processEOF=function(t){this.flushCharacters(),e.setInsertionMode(e.originalInsertionMode),e.insertionMode.processEOF()},t.inTableText.processCharacters=function(t){var n=t.takeRemaining();n=n.replace(/\u0000/g,function(t,n){return e.parseError("invalid-codepoint"),""});if(!n)return;e.pendingTableCharacters.push(n)},t.inTableText.processStartTag=function(t,n,r){this.flushCharacters(),e.setInsertionMode(e.originalInsertionMode),e.insertionMode.processStartTag(t,n,r)},t.inTableText.processEndTag=function(t,n){this.flushCharacters(),e.setInsertionMode(e.originalInsertionMode),e.insertionMode.processEndTag(t,n)},t.inTableBody=Object.create(t.base),t.inTableBody.start_tag_handlers={html:"startTagHtml",tr:"startTagTr",td:"startTagTableCell",th:"startTagTableCell",caption:"startTagTableOther",col:"startTagTableOther",colgroup:"startTagTableOther",tbody:"startTagTableOther",tfoot:"startTagTableOther",thead:"startTagTableOther","-default":"startTagOther"},t.inTableBody.end_tag_handlers={table:"endTagTable",tbody:"endTagTableRowGroup",tfoot:"endTagTableRowGroup",thead:"endTagTableRowGroup",body:"endTagIgnore",caption:"endTagIgnore",col:"endTagIgnore",colgroup:"endTagIgnore",html:"endTagIgnore",td:"endTagIgnore",th:"endTagIgnore",tr:"endTagIgnore","-default":"endTagOther"},t.inTableBody.processCharacters=function(e){t.inTable.processCharacters(e)},t.inTableBody.startTagTr=function(t,n){e.openElements.popUntilTableBodyScopeMarker(),e.insertElement(t,n),e.setInsertionMode("inRow")},t.inTableBody.startTagTableCell=function(t,n){e.parseError("unexpected-cell-in-table-body",{name:t}),this.startTagTr("tr",[]),e.insertionMode.processStartTag(t,n)},t.inTableBody.startTagTableOther=function(t,n){e.openElements.inTableScope("tbody")||e.openElements.inTableScope("thead")||e.openElements.inTableScope("tfoot")?(e.openElements.popUntilTableBodyScopeMarker(),this.endTagTableRowGroup(e.currentStackItem().localName),e.insertionMode.processStartTag(t,n)):e.parseError("unexpected-start-tag",{name:t})},t.inTableBody.startTagOther=function(e,n){t.inTable.processStartTag(e,n)},t.inTableBody.endTagTableRowGroup=function(t){e.openElements.inTableScope(t)?(e.openElements.popUntilTableBodyScopeMarker(),e.popElement(),e.setInsertionMode("inTable")):e.parseError("unexpected-end-tag-in-table-body",{name:t})},t.inTableBody.endTagTable=function(t){e.openElements.inTableScope("tbody")||e.openElements.inTableScope("thead")||e.openElements.inTableScope("tfoot")?(e.openElements.popUntilTableBodyScopeMarker(),this.endTagTableRowGroup(e.currentStackItem().localName),e.insertionMode.processEndTag(t)):e.parseError("unexpected-end-tag",{name:t})},t.inTableBody.endTagIgnore=function(t){e.parseError("unexpected-end-tag-in-table-body",{name:t})},t.inTableBody.endTagOther=function(e){t.inTable.processEndTag(e)},t.inSelect=Object.create(t.base),t.inSelect.start_tag_handlers={html:"startTagHtml",option:"startTagOption",optgroup:"startTagOptgroup",select:"startTagSelect",input:"startTagInput",keygen:"startTagInput",textarea:"startTagInput",script:"startTagScript","-default":"startTagOther"},t.inSelect.end_tag_handlers={option:"endTagOption",optgroup:"endTagOptgroup",select:"endTagSelect",caption:"endTagTableElements",table:"endTagTableElements",tbody:"endTagTableElements",tfoot:"endTagTableElements",thead:"endTagTableElements",tr:"endTagTableElements",td:"endTagTableElements",th:"endTagTableElements","-default":"endTagOther"},t.inSelect.processCharacters=function(t){var n=t.takeRemaining();n=n.replace(/\u0000/g,function(t,n){return e.parseError("invalid-codepoint"),""});if(!n)return;e.insertText(n)},t.inSelect.startTagOption=function(t,n){e.currentStackItem().localName=="option"&&e.popElement(),e.insertElement(t,n)},t.inSelect.startTagOptgroup=function(t,n){e.currentStackItem().localName=="option"&&e.popElement(),e.currentStackItem().localName=="optgroup"&&e.popElement(),e.insertElement(t,n)},t.inSelect.endTagOption=function(t){if(e.currentStackItem().localName!=="option"){e.parseError("unexpected-end-tag-in-select",{name:t});return}e.popElement()},t.inSelect.endTagOptgroup=function(t){e.currentStackItem().localName=="option"&&e.openElements.item(e.openElements.length-2).localName=="optgroup"&&e.popElement(),e.currentStackItem().localName=="optgroup"?e.popElement():e.parseError("unexpected-end-tag-in-select",{name:"optgroup"})},t.inSelect.startTagSelect=function(t){e.parseError("unexpected-select-in-select"),this.endTagSelect("select")},t.inSelect.endTagSelect=function(t){e.openElements.inTableScope("select")?(e.openElements.popUntilPopped("select"),e.resetInsertionMode()):e.parseError("unexpected-end-tag",{name:t})},t.inSelect.startTagInput=function(t,n){e.parseError("unexpected-input-in-select"),e.openElements.inSelectScope("select")&&(this.endTagSelect("select"),e.insertionMode.processStartTag(t,n))},t.inSelect.startTagScript=function(e,n){t.inHead.processStartTag(e,n)},t.inSelect.endTagTableElements=function(t){e.parseError("unexpected-end-tag-in-select",{name:t}),e.openElements.inTableScope(t)&&(this.endTagSelect("select"),e.insertionMode.processEndTag(t))},t.inSelect.startTagOther=function(t,n){e.parseError("unexpected-start-tag-in-select",{name:t})},t.inSelect.endTagOther=function(t){e.parseError("unexpected-end-tag-in-select",{name:t})},t.inSelectInTable=Object.create(t.base),t.inSelectInTable.start_tag_handlers={caption:"startTagTable",table:"startTagTable",tbody:"startTagTable",tfoot:"startTagTable",thead:"startTagTable",tr:"startTagTable",td:"startTagTable",th:"startTagTable","-default":"startTagOther"},t.inSelectInTable.end_tag_handlers={caption:"endTagTable",table:"endTagTable",tbody:"endTagTable",tfoot:"endTagTable",thead:"endTagTable",tr:"endTagTable",td:"endTagTable",th:"endTagTable","-default":"endTagOther"},t.inSelectInTable.processCharacters=function(e){t.inSelect.processCharacters(e)},t.inSelectInTable.startTagTable=function(t,n){e.parseError("unexpected-table-element-start-tag-in-select-in-table",{name:t}),this.endTagOther("select"),e.insertionMode.processStartTag(t,n)},t.inSelectInTable.startTagOther=function(e,n,r){t.inSelect.processStartTag(e,n,r)},t.inSelectInTable.endTagTable=function(t){e.parseError("unexpected-table-element-end-tag-in-select-in-table",{name:t}),e.openElements.inTableScope(t)&&(this.endTagOther("select"),e.insertionMode.processEndTag(t))},t.inSelectInTable.endTagOther=function(e){t.inSelect.processEndTag(e)},t.inRow=Object.create(t.base),t.inRow.start_tag_handlers={html:"startTagHtml",td:"startTagTableCell",th:"startTagTableCell",caption:"startTagTableOther",col:"startTagTableOther",colgroup:"startTagTableOther",tbody:"startTagTableOther",tfoot:"startTagTableOther",thead:"startTagTableOther",tr:"startTagTableOther","-default":"startTagOther"},t.inRow.end_tag_handlers={tr:"endTagTr",table:"endTagTable",tbody:"endTagTableRowGroup",tfoot:"endTagTableRowGroup",thead:"endTagTableRowGroup",body:"endTagIgnore",caption:"endTagIgnore",col:"endTagIgnore",colgroup:"endTagIgnore",html:"endTagIgnore",td:"endTagIgnore",th:"endTagIgnore","-default":"endTagOther"},t.inRow.processCharacters=function(e){t.inTable.processCharacters(e)},t.inRow.startTagTableCell=function(t,n){e.openElements.popUntilTableRowScopeMarker(),e.insertElement(t,n),e.setInsertionMode("inCell"),e.activeFormattingElements.push(l)},t.inRow.startTagTableOther=function(t,n){var r=this.ignoreEndTagTr();this.endTagTr("tr"),r||e.insertionMode.processStartTag(t,n)},t.inRow.startTagOther=function(e,n,r){t.inTable.processStartTag(e,n,r)},t.inRow.endTagTr=function(t){this.ignoreEndTagTr()?(r.ok(e.context),e.parseError("unexpected-end-tag",{name:t})):(e.openElements.popUntilTableRowScopeMarker(),e.popElement(),e.setInsertionMode("inTableBody"))},t.inRow.endTagTable=function(t){var n=this.ignoreEndTagTr();this.endTagTr("tr"),n||e.insertionMode.processEndTag(t)},t.inRow.endTagTableRowGroup=function(t){e.openElements.inTableScope(t)?(this.endTagTr("tr"),e.insertionMode.processEndTag(t)):e.parseError("unexpected-end-tag",{name:t})},t.inRow.endTagIgnore=function(t){e.parseError("unexpected-end-tag-in-table-row",{name:t})},t.inRow.endTagOther=function(e){t.inTable.processEndTag(e)},t.inRow.ignoreEndTagTr=function(){return!e.openElements.inTableScope("tr")},t.afterAfterFrameset=Object.create(t.base),t.afterAfterFrameset.start_tag_handlers={html:"startTagHtml",noframes:"startTagNoFrames","-default":"startTagOther"},t.afterAfterFrameset.processEOF=function(){},t.afterAfterFrameset.processComment=function(t){e.insertComment(t,e.document)},t.afterAfterFrameset.processCharacters=function(t){var n=t.takeRemaining(),r="";for(var i=0;i<n.length;i++){var s=n[i];c(s)&&(r+=s)}r&&(e.reconstructActiveFormattingElements(),e.insertText(r)),r.length<n.length&&e.parseError("expected-eof-but-got-char")},t.afterAfterFrameset.startTagNoFrames=function(e,n){t.inHead.processStartTag(e,n)},t.afterAfterFrameset.startTagOther=function(t,n,r){e.parseError("expected-eof-but-got-start-tag",{name:t})},t.afterAfterFrameset.processEndTag=function(t,n){e.parseError("expected-eof-but-got-end-tag",{name:t})},t.text=Object.create(t.base),t.text.start_tag_handlers={"-default":"startTagOther"},t.text.end_tag_handlers={script:"endTagScript","-default":"endTagOther"},t.text.processCharacters=function(t){e.shouldSkipLeadingNewline&&(e.shouldSkipLeadingNewline=!1,t.skipAtMostOneLeadingNewline());var n=t.takeRemaining();if(!n)return;e.insertText(n)},t.text.processEOF=function(){e.parseError("expected-named-closing-tag-but-got-eof",{name:e.currentStackItem().localName}),e.openElements.pop(),e.setInsertionMode(e.originalInsertionMode),e.insertionMode.processEOF()},t.text.startTagOther=function(e){throw"Tried to process start tag "+e+" in RCDATA/RAWTEXT mode"},t.text.endTagScript=function(t){var n=e.openElements.pop();r.ok(n.localName=="script"),e.setInsertionMode(e.originalInsertionMode)},t.text.endTagOther=function(t){e.openElements.pop(),e.setInsertionMode(e.originalInsertionMode)}}function y(e,t){return e.replace(new RegExp("{[0-9a-z-]+}","gi"),function(e){return t[e.slice(1,-1)]||e})}var r=e("assert"),i=e("./messages.json"),s=e("./constants"),o=e("events").EventEmitter,u=e("./Tokenizer").Tokenizer,a=e("./ElementStack").ElementStack,f=e("./StackItem").StackItem,l={};m.prototype.skipAtMostOneLeadingNewline=function(){this.characters[this.current]==="\n"&&this.current++},m.prototype.skipLeadingWhitespace=function(){while(c(this.characters[this.current]))if(++this.current==this.end)return},m.prototype.skipLeadingNonWhitespace=function(){while(!c(this.characters[this.current]))if(++this.current==this.end)return},m.prototype.takeRemaining=function(){return this.characters.substring(this.current)},m.prototype.takeLeadingWhitespace=function(){var e=this.current;return this.skipLeadingWhitespace(),e===this.current?"":this.characters.substring(e,this.current-e)},Object.defineProperty(m.prototype,"length",{get:function(){return this.end-this.current}}),g.prototype.setInsertionMode=function(e){this.insertionMode=this.insertionModes[e],this.insertionModeName=e},g.prototype.adoptionAgencyEndTag=function(e){function i(e){return e===r}var t=8,n=3,r,s=0;while(s++<t){r=this.elementInActiveFormattingElements(e);if(!r||this.openElements.contains(r)&&!this.openElements.inScope(r.localName))return this.parseError("adoption-agency-1.1",{name:e}),!1;if(!this.openElements.contains(r))return this.parseError("adoption-agency-1.2",{name:e}),this.removeElementFromActiveFormattingElements(r),!0;this.openElements.inScope(r.localName)||this.parseError("adoption-agency-4.4",{name:e}),r!=this.currentStackItem()&&this.parseError("adoption-agency-1.3",{name:e});var o=this.openElements.furthestBlockForFormattingElement(r.node);if(!o)return this.openElements.remove_openElements_until(i),this.removeElementFromActiveFormattingElements(r),!0;var u=this.openElements.elements.indexOf(r),a=this.openElements.item(u-1),l=this.activeFormattingElements.indexOf(r),c=o,h=o,p=this.openElements.elements.indexOf(c),d=0;while(d++<n){p-=1,c=this.openElements.item(p);if(this.activeFormattingElements.indexOf(c)<0){this.openElements.elements.splice(p,1);continue}if(c==r)break;h==o&&(l=this.activeFormattingElements.indexOf(c)+1);var v=this.createElement(c.namespaceURI,c.localName,c.attributes),m=new f(c.namespaceURI,c.localName,c.attributes,v);this.activeFormattingElements[this.activeFormattingElements.indexOf(c)]=m,this.openElements.elements[this.openElements.elements.indexOf(c)]=m,c=m,this.detachFromParent(h.node),this.attachNode(h.node,c.node),h=c}this.detachFromParent(h.node),a.isFosterParenting()?this.insertIntoFosterParent(h.node):this.attachNode(h.node,a.node);var v=this.createElement("http://www.w3.org/1999/xhtml",r.localName,r.attributes),g=new f(r.namespaceURI,r.localName,r.attributes,v);this.reparentChildren(o.node,v),this.attachNode(v,o.node),this.removeElementFromActiveFormattingElements(r),this.activeFormattingElements.splice(Math.min(l,this.activeFormattingElements.length),0,g),this.openElements.remove(r),this.openElements.elements.splice(this.openElements.elements.indexOf(o)+1,0,g)}return!0},g.prototype.start=function(){throw"Not mplemented"},g.prototype.startTokenization=function(e){this.tokenizer=e,this.compatMode="no quirks",this.originalInsertionMode="initial",this.framesetOk=!0,this.openElements=new a,this.activeFormattingElements=[],this.start();if(this.context){switch(this.context){case"title":case"textarea":this.tokenizer.setState(u.RCDATA);break;case"style":case"xmp":case"iframe":case"noembed":case"noframes":this.tokenizer.setState(u.RAWTEXT);break;case"script":this.tokenizer.setState(u.SCRIPT_DATA);break;case"noscript":this.scriptingEnabled&&this.tokenizer.setState(u.RAWTEXT);break;case"plaintext":this.tokenizer.setState(u.PLAINTEXT)}this.insertHtmlElement(),this.resetInsertionMode()}else this.setInsertionMode("initial")},g.prototype.processToken=function(e){this.selfClosingFlagAcknowledged=!1;var t=this.openElements.top||null,n;!t||!t.isForeign()||t.isMathMLTextIntegrationPoint()&&(e.type=="StartTag"&&!(e.name in{mglyph:0,malignmark:0})||e.type==="Characters")||t.namespaceURI=="http://www.w3.org/1998/Math/MathML"&&t.localName=="annotation-xml"&&e.type=="StartTag"&&e.name=="svg"||t.isHtmlIntegrationPoint()&&e.type in{StartTag:0,Characters:0}||e.type=="EOF"?n=this.insertionMode:n=this.insertionModes.inForeignContent;switch(e.type){case"Characters":var r=new m(e.data);n.processCharacters(r);break;case"Comment":n.processComment(e.data);break;case"StartTag":n.processStartTag(e.name,e.data,e.selfClosing);break;case"EndTag":n.processEndTag(e.name);break;case"Doctype":n.processDoctype(e.name,e.publicId,e.systemId,e.forceQuirks);break;case"EOF":n.processEOF()}},g.prototype.isCdataSectionAllowed=function(){return this.openElements.length>0&&this.currentStackItem().isForeign()},g.prototype.isSelfClosingFlagAcknowledged=function(){return this.selfClosingFlagAcknowledged},g.prototype.createElement=function(e,t,n){throw new Error("Not implemented")},g.prototype.attachNode=function(e,t){throw new Error("Not implemented")},g.prototype.attachNodeToFosterParent=function(e,t,n){throw new Error("Not implemented")},g.prototype.detachFromParent=function(e){throw new Error("Not implemented")},g.prototype.addAttributesToElement=function(e,t){throw new Error("Not implemented")},g.prototype.insertHtmlElement=function(e){var t=this.createElement("http://www.w3.org/1999/xhtml","html",e);return this.attachNode(t,this.document),this.openElements.pushHtmlElement(new f("http://www.w3.org/1999/xhtml","html",e,t)),t},g.prototype.insertHeadElement=function(e){var t=this.createElement("http://www.w3.org/1999/xhtml","head",e);return this.head=new f("http://www.w3.org/1999/xhtml","head",e,t),this.attachNode(t,this.openElements.top.node),this.openElements.pushHeadElement(this.head),t},g.prototype.insertBodyElement=function(e){var t=this.createElement("http://www.w3.org/1999/xhtml","body",e);return this.attachNode(t,this.openElements.top.node),this.openElements.pushBodyElement(new f("http://www.w3.org/1999/xhtml","body",e,t)),t},g.prototype.insertIntoFosterParent=function(e){var t=this.openElements.findIndex("table"),n=this.openElements.item(t).node;if(t===0)return this.attachNode(e,n);this.attachNodeToFosterParent(e,n,this.openElements.item(t-1).node)},g.prototype.insertElement=function(e,t,n,r){n||(n="http://www.w3.org/1999/xhtml");var i=this.createElement(n,e,t);this.shouldFosterParent()?this.insertIntoFosterParent(i):this.attachNode(i,this.openElements.top.node),r||this.openElements.push(new f(n,e,t,i))},g.prototype.insertFormattingElement=function(e,t){this.insertElement(e,t,"http://www.w3.org/1999/xhtml"),this.appendElementToActiveFormattingElements(this.currentStackItem())},g.prototype.insertSelfClosingElement=function(e,t){this.selfClosingFlagAcknowledged=!0,this.insertElement(e,t,"http://www.w3.org/1999/xhtml",!0)},g.prototype.insertForeignElement=function(e,t,n,r){r&&(this.selfClosingFlagAcknowledged=!0),this.insertElement(e,t,n,r)},g.prototype.insertComment=function(e,t){throw new Error("Not implemented")},g.prototype.insertDoctype=function(e,t,n){throw new Error("Not implemented")},g.prototype.insertText=function(e){throw new Error("Not implemented")},g.prototype.currentStackItem=function(){return this.openElements.top},g.prototype.popElement=function(){return this.openElements.pop()},g.prototype.shouldFosterParent=function(){return this.redirectAttachToFosterParent&&this.currentStackItem().isFosterParenting()},g.prototype.generateImpliedEndTags=function(e){var t=this.openElements.top.localName;["dd","dt","li","option","optgroup","p","rp","rt"].indexOf(t)!=-1&&t!=e&&(this.popElement(),this.generateImpliedEndTags(e))},g.prototype.reconstructActiveFormattingElements=function(){if(this.activeFormattingElements.length===0)return;var e=this.activeFormattingElements.length-1,t=this.activeFormattingElements[e];if(t==l||this.openElements.contains(t))return;while(t!=l&&!this.openElements.contains(t)){e-=1,t=this.activeFormattingElements[e];if(!t)break}for(;;){e+=1,t=this.activeFormattingElements[e],this.insertElement(t.localName,t.attributes);var n=this.currentStackItem();this.activeFormattingElements[e]=n;if(n==this.activeFormattingElements[this.activeFormattingElements.length-1])break}},g.prototype.ensureNoahsArkCondition=function(e){var t=3;if(this.activeFormattingElements.length<t)return;var n=[],r=e.attributes.length;for(var i=this.activeFormattingElements.length-1;i>=0;i--){var s=this.activeFormattingElements[i];if(s===l)break;if(e.localName!==s.localName||e.namespaceURI!==s.namespaceURI)continue;if(s.attributes.length!=r)continue;n.push(s)}if(n.length<t)return;var o=[],u=e.attributes;for(var i=0;i<u.length;i++){var a=u[i];for(var f=0;f<n.length;f++){var s=n[f],c=v(s,a.nodeName);c&&c.nodeValue===a.nodeValue&&o.push(s)}if(o.length<t)return;n=o,o=[]}for(var i=t-1;i<n.length;i++)this.removeElementFromActiveFormattingElements(n[i])},g.prototype.appendElementToActiveFormattingElements=function(e){this.ensureNoahsArkCondition(e),this.activeFormattingElements.push(e)},g.prototype.removeElementFromActiveFormattingElements=function(e){var t=this.activeFormattingElements.indexOf(e);t>=0&&this.activeFormattingElements.splice(t,1)},g.prototype.elementInActiveFormattingElements=function(e){var t=this.activeFormattingElements;for(var n=t.length-1;n>=0;n--){if(t[n]==l)break;if(t[n].localName==e)return t[n]}return!1},g.prototype.clearActiveFormattingElements=function(){while(this.activeFormattingElements.length!==0&&this.activeFormattingElements.pop()!=l);},g.prototype.reparentChildren=function(e,t){throw new Error("Not implemented")},g.prototype.setFragmentContext=function(e){this.context=e},g.prototype.parseError=function(e,t){if(!this.errorHandler)return;var n=y(i[e],t);this.errorHandler.error(n,this.tokenizer._inputStream.location(),e)},g.prototype.resetInsertionMode=function(){var e=!1,t=null;for(var n=this.openElements.length-1;n>=0;n--){t=this.openElements.item(n),n===0&&(r.ok(this.context),e=!0,t=new f("http://www.w3.org/1999/xhtml",this.context,[],null));if(t.namespaceURI==="http://www.w3.org/1999/xhtml"){if(t.localName==="select")return this.setInsertionMode("inSelect");if(t.localName==="td"||t.localName==="th")return this.setInsertionMode("inCell");if(t.localName==="tr")return this.setInsertionMode("inRow");if(t.localName==="tbody"||t.localName==="thead"||t.localName==="tfoot")return this.setInsertionMode("inTableBody");if(t.localName==="caption")return this.setInsertionMode("inCaption");if(t.localName==="colgroup")return this.setInsertionMode("inColumnGroup");if(t.localName==="table")return this.setInsertionMode("inTable");if(t.localName==="head"&&!e)return this.setInsertionMode("inHead");if(t.localName==="body")return this.setInsertionMode("inBody");if(t.localName==="frameset")return this.setInsertionMode("inFrameset");if(t.localName==="html")return this.openElements.headElement?this.setInsertionMode("afterHead"):this.setInsertionMode("beforeHead")}if(e)return this.setInsertionMode("inBody")}},g.prototype.processGenericRCDATAStartTag=function(e,t){this.insertElement(e,t),this.tokenizer.setState(u.RCDATA),this.originalInsertionMode=this.insertionModeName,this.setInsertionMode("text")},g.prototype.processGenericRawTextStartTag=function(e,t){this.insertElement(e,t),this.tokenizer.setState(u.RAWTEXT),this.originalInsertionMode=this.insertionModeName,this.setInsertionMode("text")},g.prototype.adjustMathMLAttributes=function(e){return e.forEach(function(e){e.namespaceURI="http://www.w3.org/1998/Math/MathML",s.MATHMLAttributeMap[e.nodeName]&&(e.nodeName=s.MATHMLAttributeMap[e.nodeName])}),e},g.prototype.adjustSVGTagNameCase=function(e){return s.SVGTagMap[e]||e},g.prototype.adjustSVGAttributes=function(e){return e.forEach(function(e){e.namespaceURI="http://www.w3.org/2000/svg",s.SVGAttributeMap[e.nodeName]&&(e.nodeName=s.SVGAttributeMap[e.nodeName])}),e},g.prototype.adjustForeignAttributes=function(e){for(var t=0;t<e.length;t++){var n=e[t],r=s.ForeignAttributeMap[n.nodeName];r&&(n.nodeName=r.localName,n.prefix=r.prefix,n.namespaceURI=r.namespaceURI)}return e},n.TreeBuilder=g},{"./ElementStack":1,"./StackItem":4,"./Tokenizer":5,"./constants":7,"./messages.json":8,assert:13,events:16}],7:[function(e,t,n){n.SVGTagMap={altglyph:"altGlyph",altglyphdef:"altGlyphDef",altglyphitem:"altGlyphItem",animatecolor:"animateColor",animatemotion:"animateMotion",animatetransform:"animateTransform",clippath:"clipPath",feblend:"feBlend",fecolormatrix:"feColorMatrix",fecomponenttransfer:"feComponentTransfer",fecomposite:"feComposite",feconvolvematrix:"feConvolveMatrix",fediffuselighting:"feDiffuseLighting",fedisplacementmap:"feDisplacementMap",fedistantlight:"feDistantLight",feflood:"feFlood",fefunca:"feFuncA",fefuncb:"feFuncB",fefuncg:"feFuncG",fefuncr:"feFuncR",fegaussianblur:"feGaussianBlur",feimage:"feImage",femerge:"feMerge",femergenode:"feMergeNode",femorphology:"feMorphology",feoffset:"feOffset",fepointlight:"fePointLight",fespecularlighting:"feSpecularLighting",fespotlight:"feSpotLight",fetile:"feTile",feturbulence:"feTurbulence",foreignobject:"foreignObject",glyphref:"glyphRef",lineargradient:"linearGradient",radialgradient:"radialGradient",textpath:"textPath"},n.MATHMLAttributeMap={definitionurl:"definitionURL"},n.SVGAttributeMap={attributename:"attributeName",attributetype:"attributeType",basefrequency:"baseFrequency",baseprofile:"baseProfile",calcmode:"calcMode",clippathunits:"clipPathUnits",contentscripttype:"contentScriptType",contentstyletype:"contentStyleType",diffuseconstant:"diffuseConstant",edgemode:"edgeMode",externalresourcesrequired:"externalResourcesRequired",filterres:"filterRes",filterunits:"filterUnits",glyphref:"glyphRef",gradienttransform:"gradientTransform",gradientunits:"gradientUnits",kernelmatrix:"kernelMatrix",kernelunitlength:"kernelUnitLength",keypoints:"keyPoints",keysplines:"keySplines",keytimes:"keyTimes",lengthadjust:"lengthAdjust",limitingconeangle:"limitingConeAngle",markerheight:"markerHeight",markerunits:"markerUnits",markerwidth:"markerWidth",maskcontentunits:"maskContentUnits",maskunits:"maskUnits",numoctaves:"numOctaves",pathlength:"pathLength",patterncontentunits:"patternContentUnits",patterntransform:"patternTransform",patternunits:"patternUnits",pointsatx:"pointsAtX",pointsaty:"pointsAtY",pointsatz:"pointsAtZ",preservealpha:"preserveAlpha",preserveaspectratio:"preserveAspectRatio",primitiveunits:"primitiveUnits",refx:"refX",refy:"refY",repeatcount:"repeatCount",repeatdur:"repeatDur",requiredextensions:"requiredExtensions",requiredfeatures:"requiredFeatures",specularconstant:"specularConstant",specularexponent:"specularExponent",spreadmethod:"spreadMethod",startoffset:"startOffset",stddeviation:"stdDeviation",stitchtiles:"stitchTiles",surfacescale:"surfaceScale",systemlanguage:"systemLanguage",tablevalues:"tableValues",targetx:"targetX",targety:"targetY",textlength:"textLength",viewbox:"viewBox",viewtarget:"viewTarget",xchannelselector:"xChannelSelector",ychannelselector:"yChannelSelector",zoomandpan:"zoomAndPan"},n.ForeignAttributeMap={"xlink:actuate":{prefix:"xlink",localName:"actuate",namespaceURI:"http://www.w3.org/1999/xlink"},"xlink:arcrole":{prefix:"xlink",localName:"arcrole",namespaceURI:"http://www.w3.org/1999/xlink"},"xlink:href":{prefix:"xlink",localName:"href",namespaceURI:"http://www.w3.org/1999/xlink"},"xlink:role":{prefix:"xlink",localName:"role",namespaceURI:"http://www.w3.org/1999/xlink"},"xlink:show":{prefix:"xlink",localName:"show",namespaceURI:"http://www.w3.org/1999/xlink"},"xlink:title":{prefix:"xlink",localName:"title",namespaceURI:"http://www.w3.org/1999/xlink"},"xlink:type":{prefix:"xlink",localName:"title",namespaceURI:"http://www.w3.org/1999/xlink"},"xml:base":{prefix:"xml",localName:"base",namespaceURI:"http://www.w3.org/XML/1998/namespace"},"xml:lang":{prefix:"xml",localName:"lang",namespaceURI:"http://www.w3.org/XML/1998/namespace"},"xml:space":{prefix:"xml",localName:"space",namespaceURI:"http://www.w3.org/XML/1998/namespace"},xmlns:{prefix:null,localName:"xmlns",namespaceURI:"http://www.w3.org/2000/xmlns/"},"xmlns:xlink":{prefix:"xmlns",localName:"xlink",namespaceURI:"http://www.w3.org/2000/xmlns/"}}},{}],8:[function(e,t,n){t.exports={"null-character":"Null character in input stream, replaced with U+FFFD.","invalid-codepoint":"Invalid codepoint in stream","incorrectly-placed-solidus":"Solidus (/) incorrectly placed in tag.","incorrect-cr-newline-entity":"Incorrect CR newline entity, replaced with LF.","illegal-windows-1252-entity":"Entity used with illegal number (windows-1252 reference).","cant-convert-numeric-entity":"Numeric entity couldn't be converted to character (codepoint U+{charAsInt}).","invalid-numeric-entity-replaced":"Numeric entity represents an illegal codepoint. Expanded to the C1 controls range.","numeric-entity-without-semicolon":"Numeric entity didn't end with ';'.","expected-numeric-entity-but-got-eof":"Numeric entity expected. Got end of file instead.","expected-numeric-entity":"Numeric entity expected but none found.","named-entity-without-semicolon":"Named entity didn't end with ';'.","expected-named-entity":"Named entity expected. Got none.","attributes-in-end-tag":"End tag contains unexpected attributes.","self-closing-flag-on-end-tag":"End tag contains unexpected self-closing flag.","bare-less-than-sign-at-eof":"End of file after <.","expected-tag-name-but-got-right-bracket":"Expected tag name. Got '>' instead.","expected-tag-name-but-got-question-mark":"Expected tag name. Got '?' instead. (HTML doesn't support processing instructions.)","expected-tag-name":"Expected tag name. Got something else instead.","expected-closing-tag-but-got-right-bracket":"Expected closing tag. Got '>' instead. Ignoring '</>'.","expected-closing-tag-but-got-eof":"Expected closing tag. Unexpected end of file.","expected-closing-tag-but-got-char":"Expected closing tag. Unexpected character '{data}' found.","eof-in-tag-name":"Unexpected end of file in the tag name.","expected-attribute-name-but-got-eof":"Unexpected end of file. Expected attribute name instead.","eof-in-attribute-name":"Unexpected end of file in attribute name.","invalid-character-in-attribute-name":"Invalid character in attribute name.","duplicate-attribute":"Dropped duplicate attribute '{name}' on tag.","expected-end-of-tag-but-got-eof":"Unexpected end of file. Expected = or end of tag.","expected-attribute-value-but-got-eof":"Unexpected end of file. Expected attribute value.","expected-attribute-value-but-got-right-bracket":"Expected attribute value. Got '>' instead.","unexpected-character-in-unquoted-attribute-value":"Unexpected character in unquoted attribute","invalid-character-after-attribute-name":"Unexpected character after attribute name.","unexpected-character-after-attribute-value":"Unexpected character after attribute value.","eof-in-attribute-value-double-quote":'Unexpected end of file in attribute value (").',"eof-in-attribute-value-single-quote":"Unexpected end of file in attribute value (').","eof-in-attribute-value-no-quotes":"Unexpected end of file in attribute value.","eof-after-attribute-value":"Unexpected end of file after attribute value.","unexpected-eof-after-solidus-in-tag":"Unexpected end of file in tag. Expected >.","unexpected-character-after-solidus-in-tag":"Unexpected character after / in tag. Expected >.","expected-dashes-or-doctype":"Expected '--' or 'DOCTYPE'. Not found.","unexpected-bang-after-double-dash-in-comment":"Unexpected ! after -- in comment.","incorrect-comment":"Incorrect comment.","eof-in-comment":"Unexpected end of file in comment.","eof-in-comment-end-dash":"Unexpected end of file in comment (-).","unexpected-dash-after-double-dash-in-comment":"Unexpected '-' after '--' found in comment.","eof-in-comment-double-dash":"Unexpected end of file in comment (--).","eof-in-comment-end-bang-state":"Unexpected end of file in comment.","unexpected-char-in-comment":"Unexpected character in comment found.","need-space-after-doctype":"No space after literal string 'DOCTYPE'.","expected-doctype-name-but-got-right-bracket":"Unexpected > character. Expected DOCTYPE name.","expected-doctype-name-but-got-eof":"Unexpected end of file. Expected DOCTYPE name.","eof-in-doctype-name":"Unexpected end of file in DOCTYPE name.","eof-in-doctype":"Unexpected end of file in DOCTYPE.","expected-space-or-right-bracket-in-doctype":"Expected space or '>'. Got '{data}'.","unexpected-end-of-doctype":"Unexpected end of DOCTYPE.","unexpected-char-in-doctype":"Unexpected character in DOCTYPE.","eof-in-bogus-doctype":"Unexpected end of file in bogus doctype.","eof-in-innerhtml":"Unexpected EOF in inner html mode.","unexpected-doctype":"Unexpected DOCTYPE. Ignored.","non-html-root":"html needs to be the first start tag.","expected-doctype-but-got-eof":"Unexpected End of file. Expected DOCTYPE.","unknown-doctype":"Erroneous DOCTYPE. Expected <!DOCTYPE html>.","quirky-doctype":"Quirky doctype. Expected <!DOCTYPE html>.","almost-standards-doctype":"Almost standards mode doctype. Expected <!DOCTYPE html>.","obsolete-doctype":"Obsolete doctype. Expected <!DOCTYPE html>.","expected-doctype-but-got-chars":"Non-space characters found without seeing a doctype first. Expected e.g. <!DOCTYPE html>.","expected-doctype-but-got-start-tag":"Start tag seen without seeing a doctype first. Expected e.g. <!DOCTYPE html>.","expected-doctype-but-got-end-tag":"End tag seen without seeing a doctype first. Expected e.g. <!DOCTYPE html>.","end-tag-after-implied-root":"Unexpected end tag ({name}) after the (implied) root element.","expected-named-closing-tag-but-got-eof":"Unexpected end of file. Expected end tag ({name}).","two-heads-are-not-better-than-one":"Unexpected start tag head in existing head. Ignored.","unexpected-end-tag":"Unexpected end tag ({name}). Ignored.","unexpected-implied-end-tag":"End tag {name} implied, but there were open elements.","unexpected-start-tag-out-of-my-head":"Unexpected start tag ({name}) that can be in head. Moved.","unexpected-start-tag":"Unexpected start tag ({name}).","missing-end-tag":"Missing end tag ({name}).","missing-end-tags":"Missing end tags ({name}).","unexpected-start-tag-implies-end-tag":"Unexpected start tag ({startName}) implies end tag ({endName}).","unexpected-start-tag-treated-as":"Unexpected start tag ({originalName}). Treated as {newName}.","deprecated-tag":"Unexpected start tag {name}. Don't use it!","unexpected-start-tag-ignored":"Unexpected start tag {name}. Ignored.","expected-one-end-tag-but-got-another":"Unexpected end tag ({gotName}). Missing end tag ({expectedName}).","end-tag-too-early":"End tag ({name}) seen too early. Expected other end tag.","end-tag-too-early-named":"Unexpected end tag ({gotName}). Expected end tag ({expectedName}.","end-tag-too-early-ignored":"End tag ({name}) seen too early. Ignored.","adoption-agency-1.1":"End tag ({name}) violates step 1, paragraph 1 of the adoption agency algorithm.","adoption-agency-1.2":"End tag ({name}) violates step 1, paragraph 2 of the adoption agency algorithm.","adoption-agency-1.3":"End tag ({name}) violates step 1, paragraph 3 of the adoption agency algorithm.","adoption-agency-4.4":"End tag ({name}) violates step 4, paragraph 4 of the adoption agency algorithm.","unexpected-end-tag-treated-as":"Unexpected end tag ({originalName}). Treated as {newName}.","no-end-tag":"This element ({name}) has no end tag.","unexpected-implied-end-tag-in-table":"Unexpected implied end tag ({name}) in the table phase.","unexpected-implied-end-tag-in-table-body":"Unexpected implied end tag ({name}) in the table body phase.","unexpected-char-implies-table-voodoo":"Unexpected non-space characters in table context caused voodoo mode.","unexpected-hidden-input-in-table":"Unexpected input with type hidden in table context.","unexpected-form-in-table":"Unexpected form in table context.","unexpected-start-tag-implies-table-voodoo":"Unexpected start tag ({name}) in table context caused voodoo mode.","unexpected-end-tag-implies-table-voodoo":"Unexpected end tag ({name}) in table context caused voodoo mode.","unexpected-cell-in-table-body":"Unexpected table cell start tag ({name}) in the table body phase.","unexpected-cell-end-tag":"Got table cell end tag ({name}) while required end tags are missing.","unexpected-end-tag-in-table-body":"Unexpected end tag ({name}) in the table body phase. Ignored.","unexpected-implied-end-tag-in-table-row":"Unexpected implied end tag ({name}) in the table row phase.","unexpected-end-tag-in-table-row":"Unexpected end tag ({name}) in the table row phase. Ignored.","unexpected-select-in-select":"Unexpected select start tag in the select phase treated as select end tag.","unexpected-input-in-select":"Unexpected input start tag in the select phase.","unexpected-start-tag-in-select":"Unexpected start tag token ({name}) in the select phase. Ignored.","unexpected-end-tag-in-select":"Unexpected end tag ({name}) in the select phase. Ignored.","unexpected-table-element-start-tag-in-select-in-table":"Unexpected table element start tag ({name}) in the select in table phase.","unexpected-table-element-end-tag-in-select-in-table":"Unexpected table element end tag ({name}) in the select in table phase.","unexpected-char-after-body":"Unexpected non-space characters in the after body phase.","unexpected-start-tag-after-body":"Unexpected start tag token ({name}) in the after body phase.","unexpected-end-tag-after-body":"Unexpected end tag token ({name}) in the after body phase.","unexpected-char-in-frameset":"Unepxected characters in the frameset phase. Characters ignored.","unexpected-start-tag-in-frameset":"Unexpected start tag token ({name}) in the frameset phase. Ignored.","unexpected-frameset-in-frameset-innerhtml":"Unexpected end tag token (frameset in the frameset phase (innerHTML).","unexpected-end-tag-in-frameset":"Unexpected end tag token ({name}) in the frameset phase. Ignored.","unexpected-char-after-frameset":"Unexpected non-space characters in the after frameset phase. Ignored.","unexpected-start-tag-after-frameset":"Unexpected start tag ({name}) in the after frameset phase. Ignored.","unexpected-end-tag-after-frameset":"Unexpected end tag ({name}) in the after frameset phase. Ignored.","expected-eof-but-got-char":"Unexpected non-space characters. Expected end of file.","expected-eof-but-got-start-tag":"Unexpected start tag ({name}). Expected end of file.","expected-eof-but-got-end-tag":"Unexpected end tag ({name}). Expected end of file.","unexpected-end-table-in-caption":"Unexpected end table tag in caption. Generates implied end caption.","end-html-in-innerhtml":"Unexpected html end tag in inner html mode.","eof-in-table":"Unexpected end of file. Expected table content.","eof-in-script":"Unexpected end of file. Expected script content.","non-void-element-with-trailing-solidus":"Trailing solidus not allowed on element {name}.","unexpected-html-element-in-foreign-content":'HTML start tag "{name}" in a foreign namespace context.',"unexpected-start-tag-in-table":"Unexpected {name}. Expected table content."}},{}],9:[function(e,t,n){function o(){this.contentHandler=null,this._errorHandler=null,this._treeBuilder=new r,this._tokenizer=new i(this._treeBuilder),this._scriptingEnabled=!1}var r=e("./SAXTreeBuilder").SAXTreeBuilder,i=e("../Tokenizer").Tokenizer,s=e("./TreeParser").TreeParser;o.prototype.parse=function(e){this._tokenizer.tokenize(e);var t=this._treeBuilder.document;t&&(new s(this.contentHandler)).parse(t)},o.prototype.parseFragment=function(e,t){this._treeBuilder.setFragmentContext(t),this._tokenizer.tokenize(e);var n=this._treeBuilder.getFragment();n&&(new s(this.contentHandler)).parse(n)},Object.defineProperty(o.prototype,"scriptingEnabled",{get:function(){return this._scriptingEnabled},set:function(e){this._scriptingEnabled=e,this._treeBuilder.scriptingEnabled=e}}),Object.defineProperty(o.prototype,"errorHandler",{get:function(){return this._errorHandler},set:function(e){this._errorHandler=e,this._treeBuilder.errorHandler=e}}),n.SAXParser=o},{"../Tokenizer":5,"./SAXTreeBuilder":10,"./TreeParser":11}],10:[function(e,t,n){function s(){i.call(this)}function o(e,t){for(var n=0;n<e.attributes.length;n++){var r=e.attributes[n];if(r.nodeName===t)return r.nodeValue}}function a(e){e?(this.columnNumber=e.columnNumber,this.lineNumber=e.lineNumber):(this.columnNumber=-1,this.lineNumber=-1),this.parentNode=null,this.nextSibling=null,this.firstChild=null}function f(e){a.call(this,e),this.lastChild=null,this._endLocator=null}function l(e){f.call(this,e),this.nodeType=u.DOCUMENT}function c(){f.call(this,new Locator),this.nodeType=u.DOCUMENT_FRAGMENT}function h(e,t,n,r,i,s){f.call(this,e),this.uri=t,this.localName=n,this.qName=r,this.attributes=i,this.prefixMappings=s,this.nodeType=u.ELEMENT}function p(e,t){a.call(this,e),this.data=t,this.nodeType=u.CHARACTERS}function d(e,t){a.call(this,e),this.data=t,this.nodeType=u.IGNORABLE_WHITESPACE}function v(e,t){a.call(this,e),this.data=t,this.nodeType=u.COMMENT}function m(e){f.call(this,e),this.nodeType=u.CDATA}function g(e){f.call(this),this.name=e,this.nodeType=u.ENTITY}function y(e){a.call(this),this.name=e,this.nodeType=u.SKIPPED_ENTITY}function b(e,t){a.call(this),this.target=e,this.data=t}function w(e,t,n){f.call(this),this.name=e,this.publicIdentifier=t,this.systemIdentifier=n,this.nodeType=u.DTD}var r=e("util"),i=e("../TreeBuilder").TreeBuilder;r.inherits(s,i),s.prototype.start=function(e){this.document=new l(this.tokenizer)},s.prototype.end=function(){this.document.endLocator=this.tokenizer},s.prototype.insertDoctype=function(e,t,n){var r=new w(this.tokenizer,e,t,n);r.endLocator=this.tokenizer,this.document.appendChild(r)},s.prototype.createElement=function(e,t,n){var r=new h(this.tokenizer,e,t,t,n||[]);return r},s.prototype.insertComment=function(e,t){t||(t=this.currentStackItem());var n=new v(this.tokenizer,e);t.appendChild(n)},s.prototype.appendCharacters=function(e,t){var n=new p(this.tokenizer,t);e.appendChild(n)},s.prototype.insertText=function(e){if(this.redirectAttachToFosterParent&&this.openElements.top.isFosterParenting()){var t=this.openElements.findIndex("table"),n=this.openElements.item(t),r=n.node;if(t===0)return this.appendCharacters(r,e);var i=new p(this.tokenizer,e),s=r.parentNode;if(s){s.insertBetween(i,r.previousSibling,r);return}var o=this.openElements.item(t-1).node;o.appendChild(i);return}this.appendCharacters(this.currentStackItem().node,e)},s.prototype.attachNode=function(e,t){t.appendChild(e)},s.prototype.attachNodeToFosterParent=function(e,t,n){var r=t.parentNode;r?r.insertBetween(e,t.previousSibling,t):n.appendChild(e)},s.prototype.detachFromParent=function(e){e.detach()},s.prototype.reparentChildren=function(e,t){t.appendChildren(e.firstChild)},s.prototype.getFragment=function(){var e=new c;return this.reparentChildren(this.openElements.rootNode,e),e},s.prototype.addAttributesToElement=function(e,t){for(var n=0;n<t.length;n++){var r=t[n];o(e,r.nodeName)||e.attributes.push(r)}};var u={CDATA:1,CHARACTERS:2,COMMENT:3,DOCUMENT:4,DOCUMENT_FRAGMENT:5,DTD:6,ELEMENT:7,ENTITY:8,IGNORABLE_WHITESPACE:9,PROCESSING_INSTRUCTION:10,SKIPPED_ENTITY:11};a.prototype.visit=function(e){throw new Error("Not Implemented")},a.prototype.revisit=function(e){return},a.prototype.detach=function(){this.parentNode!==null&&(this.parentNode.removeChild(this),this.parentNode=null)},Object.defineProperty(a.prototype,"previousSibling",{get:function(){var e=null,t=this.parentNode.firstChild;for(;;){if(this==t)return e;e=t,t=t.nextSibling}}}),f.prototype=Object.create(a.prototype),f.prototype.insertBefore=function(e,t){if(!t)return this.appendChild(e);e.detach(),e.parentNode=this;if(this.firstChild==t)e.nextSibling=t,this.firstChild=e;else{var n=this.firstChild,r=this.firstChild.nextSibling;while(r!=t)n=r,r=r.nextSibling;n.nextSibling=e,e.nextSibling=r}return e},f.prototype.insertBetween=function(e,t,n){return n?(e.detach(),e.parentNode=this,e.nextSibling=n,t?t.nextSibling=e:firstChild=e,e):this.appendChild(e)},f.prototype.appendChild=function(e){return e.detach(),e.parentNode=this,this.firstChild?this.lastChild.nextSibling=e:this.firstChild=e,this.lastChild=e,e},f.prototype.appendChildren=function(e){var t=e.firstChild;if(!t)return;var n=e;this.firstChild?this.lastChild.nextSibling=t:this.firstChild=t,this.lastChild=n.lastChild;do t.parentNode=this;while(t=t.nextSibling);n.firstChild=null,n.lastChild=null},f.prototype.removeChild=function(e){if(this.firstChild==e)this.firstChild=e.nextSibling,this.lastChild==e&&(this.lastChild=null);else{var t=this.firstChild,n=this.firstChild.nextSibling;while(n!=e)t=n,n=n.nextSibling;t.nextSibling=e.nextSibling,this.lastChild==e&&(this.lastChild=t)}return e.parentNode=null,e},Object.defineProperty(f.prototype,"endLocator",{get:function(){return this._endLocator},set:function(e){this._endLocator={lineNumber:e.lineNumber,columnNumber:e.columnNumber}}}),l.prototype=Object.create(f.prototype),l.prototype.visit=function(e){e.startDocument(this)},l.prototype.revisit=function(e){e.endDocument(this.endLocator)},c.prototype=Object.create(f.prototype),c.prototype.visit=function(e){},h.prototype=Object.create(f.prototype),h.prototype.visit=function(e){if(this.prefixMappings)for(var t in prefixMappings){var n=prefixMappings[t];e.startPrefixMapping(n.getPrefix(),n.getUri(),this)}e.startElement(this.uri,this.localName,this.qName,this.attributes,this)},h.prototype.revisit=function(e){e.endElement(this.uri,this.localName,this.qName,this.endLocator);if(this.prefixMappings)for(var t in prefixMappings){var n=prefixMappings[t];e.endPrefixMapping(n.getPrefix(),this.endLocator)}},p.prototype=Object.create(a.prototype),p.prototype.visit=function(e){e.characters(this.data,0,this.data.length,this)},d.prototype=Object.create(a.prototype),d.prototype.visit=function(e){e.ignorableWhitespace(this.data,0,this.data.length,this)},v.prototype=Object.create(a.prototype),v.prototype.visit=function(e){e.comment(this.data,0,this.data.length,this)},m.prototype=Object.create(f.prototype),m.prototype.visit=function(e){e.startCDATA(this)},m.prototype.revisit=function(e){e.endCDATA(this.endLocator)},g.prototype=Object.create(f.prototype),g.prototype.visit=function(e){e.startEntity(this.name,this)},g.prototype.revisit=function(e){e.endEntity(this.name)},y.prototype=Object.create(a.prototype),y.prototype.visit=function(e){e.skippedEntity(this.name,this)},b.prototype=Object.create(a.prototype),b.prototype.visit=function(e){e.processingInstruction(this.target,this.data,this)},b.prototype.getNodeType=function(){return u.PROCESSING_INSTRUCTION},w.prototype=Object.create(f.prototype),w.prototype.visit=function(e){e.startDTD(this.name,this.publicIdentifier,this.systemIdentifier,this)},w.prototype.revisit=function(e){e.endDTD()},n.SAXTreeBuilder=s},{"../TreeBuilder":6,util:20}],11:[function(e,t,n){function r(e,t){this.contentHandler,this.lexicalHandler,this.locatorDelegate;if(!e)throw new IllegalArgumentException("contentHandler was null.");this.contentHandler=e,t?this.lexicalHandler=t:this.lexicalHandler=new i}function i(){}r.prototype.parse=function(e){this.contentHandler.documentLocator=this;var t=e,n;for(;;){t.visit(this);if(n=t.firstChild){t=n;continue}for(;;){t.revisit(this);if(t==e)return;if(n=t.nextSibling){t=n;break}t=t.parentNode}}},r.prototype.characters=function(e,t,n,r){this.locatorDelegate=r,this.contentHandler.characters(e,t,n)},r.prototype.endDocument=function(e){this.locatorDelegate=e,this.contentHandler.endDocument()},r.prototype.endElement=function(e,t,n,r){this.locatorDelegate=r,this.contentHandler.endElement(e,t,n)},r.prototype.endPrefixMapping=function(e,t){this.locatorDelegate=t,this.contentHandler.endPrefixMapping(e)},r.prototype.ignorableWhitespace=function(e,t,n,r){this.locatorDelegate=r,this.contentHandler.ignorableWhitespace(e,t,n)},r.prototype.processingInstruction=function(e,t,n){this.locatorDelegate=n,this.contentHandler.processingInstruction(e,t)},r.prototype.skippedEntity=function(e,t){this.locatorDelegate=t,this.contentHandler.skippedEntity(e)},r.prototype.startDocument=function(e){this.locatorDelegate=e,this.contentHandler.startDocument()},r.prototype.startElement=function(e,t,n,r,i){this.locatorDelegate=i,this.contentHandler.startElement(e,t,n,r)},r.prototype.startPrefixMapping=function(e,t,n){this.locatorDelegate=n,this.contentHandler.startPrefixMapping(e,t)},r.prototype.comment=function(e,t,n,r){this.locatorDelegate=r,this.lexicalHandler.comment(e,t,n)},r.prototype.endCDATA=function(e){this.locatorDelegate=e,this.lexicalHandler.endCDATA()},r.prototype.endDTD=function(e){this.locatorDelegate=e,this.lexicalHandler.endDTD()},r.prototype.endEntity=function(e,t){this.locatorDelegate=t,this.lexicalHandler.endEntity(e)},r.prototype.startCDATA=function(e){this.locatorDelegate=e,this.lexicalHandler.startCDATA()},r.prototype.startDTD=function(e,t,n,r){this.locatorDelegate=r,this.lexicalHandler.startDTD(e,t,n)},r.prototype.startEntity=function(e,t){this.locatorDelegate=t,this.lexicalHandler.startEntity(e)},Object.defineProperty(r.prototype,"columnNumber",{get:function(){return this.locatorDelegate?this.locatorDelegate.columnNumber:-1}}),Object.defineProperty(r.prototype,"lineNumber",{get:function(){return this.locatorDelegate?this.locatorDelegate.lineNumber:-1}}),i.prototype.comment=function(){},i.prototype.endCDATA=function(){},i.prototype.endDTD=function(){},i.prototype.endEntity=function(){},i.prototype.startCDATA=function(){},i.prototype.startDTD=function(){},i.prototype.startEntity=function(){},n.TreeParser=r},{}],12:[function(e,t,n){t.exports={"Aacute;":"\u00c1",Aacute:"\u00c1","aacute;":"\u00e1",aacute:"\u00e1","Abreve;":"\u0102","abreve;":"\u0103","ac;":"\u223e","acd;":"\u223f","acE;":"\u223e\u0333","Acirc;":"\u00c2",Acirc:"\u00c2","acirc;":"\u00e2",acirc:"\u00e2","acute;":"\u00b4",acute:"\u00b4","Acy;":"\u0410","acy;":"\u0430","AElig;":"\u00c6",AElig:"\u00c6","aelig;":"\u00e6",aelig:"\u00e6","af;":"\u2061","Afr;":"\ud835\udd04","afr;":"\ud835\udd1e","Agrave;":"\u00c0",Agrave:"\u00c0","agrave;":"\u00e0",agrave:"\u00e0","alefsym;":"\u2135","aleph;":"\u2135","Alpha;":"\u0391","alpha;":"\u03b1","Amacr;":"\u0100","amacr;":"\u0101","amalg;":"\u2a3f","amp;":"&",amp:"&","AMP;":"&",AMP:"&","andand;":"\u2a55","And;":"\u2a53","and;":"\u2227","andd;":"\u2a5c","andslope;":"\u2a58","andv;":"\u2a5a","ang;":"\u2220","ange;":"\u29a4","angle;":"\u2220","angmsdaa;":"\u29a8","angmsdab;":"\u29a9","angmsdac;":"\u29aa","angmsdad;":"\u29ab","angmsdae;":"\u29ac","angmsdaf;":"\u29ad","angmsdag;":"\u29ae","angmsdah;":"\u29af","angmsd;":"\u2221","angrt;":"\u221f","angrtvb;":"\u22be","angrtvbd;":"\u299d","angsph;":"\u2222","angst;":"\u00c5","angzarr;":"\u237c","Aogon;":"\u0104","aogon;":"\u0105","Aopf;":"\ud835\udd38","aopf;":"\ud835\udd52","apacir;":"\u2a6f","ap;":"\u2248","apE;":"\u2a70","ape;":"\u224a","apid;":"\u224b","apos;":"'","ApplyFunction;":"\u2061","approx;":"\u2248","approxeq;":"\u224a","Aring;":"\u00c5",Aring:"\u00c5","aring;":"\u00e5",aring:"\u00e5","Ascr;":"\ud835\udc9c","ascr;":"\ud835\udcb6","Assign;":"\u2254","ast;":"*","asymp;":"\u2248","asympeq;":"\u224d","Atilde;":"\u00c3",Atilde:"\u00c3","atilde;":"\u00e3",atilde:"\u00e3","Auml;":"\u00c4",Auml:"\u00c4","auml;":"\u00e4",auml:"\u00e4","awconint;":"\u2233","awint;":"\u2a11","backcong;":"\u224c","backepsilon;":"\u03f6","backprime;":"\u2035","backsim;":"\u223d","backsimeq;":"\u22cd","Backslash;":"\u2216","Barv;":"\u2ae7","barvee;":"\u22bd","barwed;":"\u2305","Barwed;":"\u2306","barwedge;":"\u2305","bbrk;":"\u23b5","bbrktbrk;":"\u23b6","bcong;":"\u224c","Bcy;":"\u0411","bcy;":"\u0431","bdquo;":"\u201e","becaus;":"\u2235","because;":"\u2235","Because;":"\u2235","bemptyv;":"\u29b0","bepsi;":"\u03f6","bernou;":"\u212c","Bernoullis;":"\u212c","Beta;":"\u0392","beta;":"\u03b2","beth;":"\u2136","between;":"\u226c","Bfr;":"\ud835\udd05","bfr;":"\ud835\udd1f","bigcap;":"\u22c2","bigcirc;":"\u25ef","bigcup;":"\u22c3","bigodot;":"\u2a00","bigoplus;":"\u2a01","bigotimes;":"\u2a02","bigsqcup;":"\u2a06","bigstar;":"\u2605","bigtriangledown;":"\u25bd","bigtriangleup;":"\u25b3","biguplus;":"\u2a04","bigvee;":"\u22c1","bigwedge;":"\u22c0","bkarow;":"\u290d","blacklozenge;":"\u29eb","blacksquare;":"\u25aa","blacktriangle;":"\u25b4","blacktriangledown;":"\u25be","blacktriangleleft;":"\u25c2","blacktriangleright;":"\u25b8","blank;":"\u2423","blk12;":"\u2592","blk14;":"\u2591","blk34;":"\u2593","block;":"\u2588","bne;":"=\u20e5","bnequiv;":"\u2261\u20e5","bNot;":"\u2aed","bnot;":"\u2310","Bopf;":"\ud835\udd39","bopf;":"\ud835\udd53","bot;":"\u22a5","bottom;":"\u22a5","bowtie;":"\u22c8","boxbox;":"\u29c9","boxdl;":"\u2510","boxdL;":"\u2555","boxDl;":"\u2556","boxDL;":"\u2557","boxdr;":"\u250c","boxdR;":"\u2552","boxDr;":"\u2553","boxDR;":"\u2554","boxh;":"\u2500","boxH;":"\u2550","boxhd;":"\u252c","boxHd;":"\u2564","boxhD;":"\u2565","boxHD;":"\u2566","boxhu;":"\u2534","boxHu;":"\u2567","boxhU;":"\u2568","boxHU;":"\u2569","boxminus;":"\u229f","boxplus;":"\u229e","boxtimes;":"\u22a0","boxul;":"\u2518","boxuL;":"\u255b","boxUl;":"\u255c","boxUL;":"\u255d","boxur;":"\u2514","boxuR;":"\u2558","boxUr;":"\u2559","boxUR;":"\u255a","boxv;":"\u2502","boxV;":"\u2551","boxvh;":"\u253c","boxvH;":"\u256a","boxVh;":"\u256b","boxVH;":"\u256c","boxvl;":"\u2524","boxvL;":"\u2561","boxVl;":"\u2562","boxVL;":"\u2563","boxvr;":"\u251c","boxvR;":"\u255e","boxVr;":"\u255f","boxVR;":"\u2560","bprime;":"\u2035","breve;":"\u02d8","Breve;":"\u02d8","brvbar;":"\u00a6",brvbar:"\u00a6","bscr;":"\ud835\udcb7","Bscr;":"\u212c","bsemi;":"\u204f","bsim;":"\u223d","bsime;":"\u22cd","bsolb;":"\u29c5","bsol;":"\\","bsolhsub;":"\u27c8","bull;":"\u2022","bullet;":"\u2022","bump;":"\u224e","bumpE;":"\u2aae","bumpe;":"\u224f","Bumpeq;":"\u224e","bumpeq;":"\u224f","Cacute;":"\u0106","cacute;":"\u0107","capand;":"\u2a44","capbrcup;":"\u2a49","capcap;":"\u2a4b","cap;":"\u2229","Cap;":"\u22d2","capcup;":"\u2a47","capdot;":"\u2a40","CapitalDifferentialD;":"\u2145","caps;":"\u2229\ufe00","caret;":"\u2041","caron;":"\u02c7","Cayleys;":"\u212d","ccaps;":"\u2a4d","Ccaron;":"\u010c","ccaron;":"\u010d","Ccedil;":"\u00c7",Ccedil:"\u00c7","ccedil;":"\u00e7",ccedil:"\u00e7","Ccirc;":"\u0108","ccirc;":"\u0109","Cconint;":"\u2230","ccups;":"\u2a4c","ccupssm;":"\u2a50","Cdot;":"\u010a","cdot;":"\u010b","cedil;":"\u00b8",cedil:"\u00b8","Cedilla;":"\u00b8","cemptyv;":"\u29b2","cent;":"\u00a2",cent:"\u00a2","centerdot;":"\u00b7","CenterDot;":"\u00b7","cfr;":"\ud835\udd20","Cfr;":"\u212d","CHcy;":"\u0427","chcy;":"\u0447","check;":"\u2713","checkmark;":"\u2713","Chi;":"\u03a7","chi;":"\u03c7","circ;":"\u02c6","circeq;":"\u2257","circlearrowleft;":"\u21ba","circlearrowright;":"\u21bb","circledast;":"\u229b","circledcirc;":"\u229a","circleddash;":"\u229d","CircleDot;":"\u2299","circledR;":"\u00ae","circledS;":"\u24c8","CircleMinus;":"\u2296","CirclePlus;":"\u2295","CircleTimes;":"\u2297","cir;":"\u25cb","cirE;":"\u29c3","cire;":"\u2257","cirfnint;":"\u2a10","cirmid;":"\u2aef","cirscir;":"\u29c2","ClockwiseContourIntegral;":"\u2232","CloseCurlyDoubleQuote;":"\u201d","CloseCurlyQuote;":"\u2019","clubs;":"\u2663","clubsuit;":"\u2663","colon;":":","Colon;":"\u2237","Colone;":"\u2a74","colone;":"\u2254","coloneq;":"\u2254","comma;":",","commat;":"@","comp;":"\u2201","compfn;":"\u2218","complement;":"\u2201","complexes;":"\u2102","cong;":"\u2245","congdot;":"\u2a6d","Congruent;":"\u2261","conint;":"\u222e","Conint;":"\u222f","ContourIntegral;":"\u222e","copf;":"\ud835\udd54","Copf;":"\u2102","coprod;":"\u2210","Coproduct;":"\u2210","copy;":"\u00a9",copy:"\u00a9","COPY;":"\u00a9",COPY:"\u00a9","copysr;":"\u2117","CounterClockwiseContourIntegral;":"\u2233","crarr;":"\u21b5","cross;":"\u2717","Cross;":"\u2a2f","Cscr;":"\ud835\udc9e","cscr;":"\ud835\udcb8","csub;":"\u2acf","csube;":"\u2ad1","csup;":"\u2ad0","csupe;":"\u2ad2","ctdot;":"\u22ef","cudarrl;":"\u2938","cudarrr;":"\u2935","cuepr;":"\u22de","cuesc;":"\u22df","cularr;":"\u21b6","cularrp;":"\u293d","cupbrcap;":"\u2a48","cupcap;":"\u2a46","CupCap;":"\u224d","cup;":"\u222a","Cup;":"\u22d3","cupcup;":"\u2a4a","cupdot;":"\u228d","cupor;":"\u2a45","cups;":"\u222a\ufe00","curarr;":"\u21b7","curarrm;":"\u293c","curlyeqprec;":"\u22de","curlyeqsucc;":"\u22df","curlyvee;":"\u22ce","curlywedge;":"\u22cf","curren;":"\u00a4",curren:"\u00a4","curvearrowleft;":"\u21b6","curvearrowright;":"\u21b7","cuvee;":"\u22ce","cuwed;":"\u22cf","cwconint;":"\u2232","cwint;":"\u2231","cylcty;":"\u232d","dagger;":"\u2020","Dagger;":"\u2021","daleth;":"\u2138","darr;":"\u2193","Darr;":"\u21a1","dArr;":"\u21d3","dash;":"\u2010","Dashv;":"\u2ae4","dashv;":"\u22a3","dbkarow;":"\u290f","dblac;":"\u02dd","Dcaron;":"\u010e","dcaron;":"\u010f","Dcy;":"\u0414","dcy;":"\u0434","ddagger;":"\u2021","ddarr;":"\u21ca","DD;":"\u2145","dd;":"\u2146","DDotrahd;":"\u2911","ddotseq;":"\u2a77","deg;":"\u00b0",deg:"\u00b0","Del;":"\u2207","Delta;":"\u0394","delta;":"\u03b4","demptyv;":"\u29b1","dfisht;":"\u297f","Dfr;":"\ud835\udd07","dfr;":"\ud835\udd21","dHar;":"\u2965","dharl;":"\u21c3","dharr;":"\u21c2","DiacriticalAcute;":"\u00b4","DiacriticalDot;":"\u02d9","DiacriticalDoubleAcute;":"\u02dd","DiacriticalGrave;":"`","DiacriticalTilde;":"\u02dc","diam;":"\u22c4","diamond;":"\u22c4","Diamond;":"\u22c4","diamondsuit;":"\u2666","diams;":"\u2666","die;":"\u00a8","DifferentialD;":"\u2146","digamma;":"\u03dd","disin;":"\u22f2","div;":"\u00f7","divide;":"\u00f7",divide:"\u00f7","divideontimes;":"\u22c7","divonx;":"\u22c7","DJcy;":"\u0402","djcy;":"\u0452","dlcorn;":"\u231e","dlcrop;":"\u230d","dollar;":"$","Dopf;":"\ud835\udd3b","dopf;":"\ud835\udd55","Dot;":"\u00a8","dot;":"\u02d9","DotDot;":"\u20dc","doteq;":"\u2250","doteqdot;":"\u2251","DotEqual;":"\u2250","dotminus;":"\u2238","dotplus;":"\u2214","dotsquare;":"\u22a1","doublebarwedge;":"\u2306","DoubleContourIntegral;":"\u222f","DoubleDot;":"\u00a8","DoubleDownArrow;":"\u21d3","DoubleLeftArrow;":"\u21d0","DoubleLeftRightArrow;":"\u21d4","DoubleLeftTee;":"\u2ae4","DoubleLongLeftArrow;":"\u27f8","DoubleLongLeftRightArrow;":"\u27fa","DoubleLongRightArrow;":"\u27f9","DoubleRightArrow;":"\u21d2","DoubleRightTee;":"\u22a8","DoubleUpArrow;":"\u21d1","DoubleUpDownArrow;":"\u21d5","DoubleVerticalBar;":"\u2225","DownArrowBar;":"\u2913","downarrow;":"\u2193","DownArrow;":"\u2193","Downarrow;":"\u21d3","DownArrowUpArrow;":"\u21f5","DownBreve;":"\u0311","downdownarrows;":"\u21ca","downharpoonleft;":"\u21c3","downharpoonright;":"\u21c2","DownLeftRightVector;":"\u2950","DownLeftTeeVector;":"\u295e","DownLeftVectorBar;":"\u2956","DownLeftVector;":"\u21bd","DownRightTeeVector;":"\u295f","DownRightVectorBar;":"\u2957","DownRightVector;":"\u21c1","DownTeeArrow;":"\u21a7","DownTee;":"\u22a4","drbkarow;":"\u2910","drcorn;":"\u231f","drcrop;":"\u230c","Dscr;":"\ud835\udc9f","dscr;":"\ud835\udcb9","DScy;":"\u0405","dscy;":"\u0455","dsol;":"\u29f6","Dstrok;":"\u0110","dstrok;":"\u0111","dtdot;":"\u22f1","dtri;":"\u25bf","dtrif;":"\u25be","duarr;":"\u21f5","duhar;":"\u296f","dwangle;":"\u29a6","DZcy;":"\u040f","dzcy;":"\u045f","dzigrarr;":"\u27ff","Eacute;":"\u00c9",Eacute:"\u00c9","eacute;":"\u00e9",eacute:"\u00e9","easter;":"\u2a6e","Ecaron;":"\u011a","ecaron;":"\u011b","Ecirc;":"\u00ca",Ecirc:"\u00ca","ecirc;":"\u00ea",ecirc:"\u00ea","ecir;":"\u2256","ecolon;":"\u2255","Ecy;":"\u042d","ecy;":"\u044d","eDDot;":"\u2a77","Edot;":"\u0116","edot;":"\u0117","eDot;":"\u2251","ee;":"\u2147","efDot;":"\u2252","Efr;":"\ud835\udd08","efr;":"\ud835\udd22","eg;":"\u2a9a","Egrave;":"\u00c8",Egrave:"\u00c8","egrave;":"\u00e8",egrave:"\u00e8","egs;":"\u2a96","egsdot;":"\u2a98","el;":"\u2a99","Element;":"\u2208","elinters;":"\u23e7","ell;":"\u2113","els;":"\u2a95","elsdot;":"\u2a97","Emacr;":"\u0112","emacr;":"\u0113","empty;":"\u2205","emptyset;":"\u2205","EmptySmallSquare;":"\u25fb","emptyv;":"\u2205","EmptyVerySmallSquare;":"\u25ab","emsp13;":"\u2004","emsp14;":"\u2005","emsp;":"\u2003","ENG;":"\u014a","eng;":"\u014b","ensp;":"\u2002","Eogon;":"\u0118","eogon;":"\u0119","Eopf;":"\ud835\udd3c","eopf;":"\ud835\udd56","epar;":"\u22d5","eparsl;":"\u29e3","eplus;":"\u2a71","epsi;":"\u03b5","Epsilon;":"\u0395","epsilon;":"\u03b5","epsiv;":"\u03f5","eqcirc;":"\u2256","eqcolon;":"\u2255","eqsim;":"\u2242","eqslantgtr;":"\u2a96","eqslantless;":"\u2a95","Equal;":"\u2a75","equals;":"=","EqualTilde;":"\u2242","equest;":"\u225f","Equilibrium;":"\u21cc","equiv;":"\u2261","equivDD;":"\u2a78","eqvparsl;":"\u29e5","erarr;":"\u2971","erDot;":"\u2253","escr;":"\u212f","Escr;":"\u2130","esdot;":"\u2250","Esim;":"\u2a73","esim;":"\u2242","Eta;":"\u0397","eta;":"\u03b7","ETH;":"\u00d0",ETH:"\u00d0","eth;":"\u00f0",eth:"\u00f0","Euml;":"\u00cb",Euml:"\u00cb","euml;":"\u00eb",euml:"\u00eb","euro;":"\u20ac","excl;":"!","exist;":"\u2203","Exists;":"\u2203","expectation;":"\u2130","exponentiale;":"\u2147","ExponentialE;":"\u2147","fallingdotseq;":"\u2252","Fcy;":"\u0424","fcy;":"\u0444","female;":"\u2640","ffilig;":"\ufb03","fflig;":"\ufb00","ffllig;":"\ufb04","Ffr;":"\ud835\udd09","ffr;":"\ud835\udd23","filig;":"\ufb01","FilledSmallSquare;":"\u25fc","FilledVerySmallSquare;":"\u25aa","fjlig;":"fj","flat;":"\u266d","fllig;":"\ufb02","fltns;":"\u25b1","fnof;":"\u0192","Fopf;":"\ud835\udd3d","fopf;":"\ud835\udd57","forall;":"\u2200","ForAll;":"\u2200","fork;":"\u22d4","forkv;":"\u2ad9","Fouriertrf;":"\u2131","fpartint;":"\u2a0d","frac12;":"\u00bd",frac12:"\u00bd","frac13;":"\u2153","frac14;":"\u00bc",frac14:"\u00bc","frac15;":"\u2155","frac16;":"\u2159","frac18;":"\u215b","frac23;":"\u2154","frac25;":"\u2156","frac34;":"\u00be",frac34:"\u00be","frac35;":"\u2157","frac38;":"\u215c","frac45;":"\u2158","frac56;":"\u215a","frac58;":"\u215d","frac78;":"\u215e","frasl;":"\u2044","frown;":"\u2322","fscr;":"\ud835\udcbb","Fscr;":"\u2131","gacute;":"\u01f5","Gamma;":"\u0393","gamma;":"\u03b3","Gammad;":"\u03dc","gammad;":"\u03dd","gap;":"\u2a86","Gbreve;":"\u011e","gbreve;":"\u011f","Gcedil;":"\u0122","Gcirc;":"\u011c","gcirc;":"\u011d","Gcy;":"\u0413","gcy;":"\u0433","Gdot;":"\u0120","gdot;":"\u0121","ge;":"\u2265","gE;":"\u2267","gEl;":"\u2a8c","gel;":"\u22db","geq;":"\u2265","geqq;":"\u2267","geqslant;":"\u2a7e","gescc;":"\u2aa9","ges;":"\u2a7e","gesdot;":"\u2a80","gesdoto;":"\u2a82","gesdotol;":"\u2a84","gesl;":"\u22db\ufe00","gesles;":"\u2a94","Gfr;":"\ud835\udd0a","gfr;":"\ud835\udd24","gg;":"\u226b","Gg;":"\u22d9","ggg;":"\u22d9","gimel;":"\u2137","GJcy;":"\u0403","gjcy;":"\u0453","gla;":"\u2aa5","gl;":"\u2277","glE;":"\u2a92","glj;":"\u2aa4","gnap;":"\u2a8a","gnapprox;":"\u2a8a","gne;":"\u2a88","gnE;":"\u2269","gneq;":"\u2a88","gneqq;":"\u2269","gnsim;":"\u22e7","Gopf;":"\ud835\udd3e","gopf;":"\ud835\udd58","grave;":"`","GreaterEqual;":"\u2265","GreaterEqualLess;":"\u22db","GreaterFullEqual;":"\u2267","GreaterGreater;":"\u2aa2","GreaterLess;":"\u2277","GreaterSlantEqual;":"\u2a7e","GreaterTilde;":"\u2273","Gscr;":"\ud835\udca2","gscr;":"\u210a","gsim;":"\u2273","gsime;":"\u2a8e","gsiml;":"\u2a90","gtcc;":"\u2aa7","gtcir;":"\u2a7a","gt;":">",gt:">","GT;":">",GT:">","Gt;":"\u226b","gtdot;":"\u22d7","gtlPar;":"\u2995","gtquest;":"\u2a7c","gtrapprox;":"\u2a86","gtrarr;":"\u2978","gtrdot;":"\u22d7","gtreqless;":"\u22db","gtreqqless;":"\u2a8c","gtrless;":"\u2277","gtrsim;":"\u2273","gvertneqq;":"\u2269\ufe00","gvnE;":"\u2269\ufe00","Hacek;":"\u02c7","hairsp;":"\u200a","half;":"\u00bd","hamilt;":"\u210b","HARDcy;":"\u042a","hardcy;":"\u044a","harrcir;":"\u2948","harr;":"\u2194","hArr;":"\u21d4","harrw;":"\u21ad","Hat;":"^","hbar;":"\u210f","Hcirc;":"\u0124","hcirc;":"\u0125","hearts;":"\u2665","heartsuit;":"\u2665","hellip;":"\u2026","hercon;":"\u22b9","hfr;":"\ud835\udd25","Hfr;":"\u210c","HilbertSpace;":"\u210b","hksearow;":"\u2925","hkswarow;":"\u2926","hoarr;":"\u21ff","homtht;":"\u223b","hookleftarrow;":"\u21a9","hookrightarrow;":"\u21aa","hopf;":"\ud835\udd59","Hopf;":"\u210d","horbar;":"\u2015","HorizontalLine;":"\u2500","hscr;":"\ud835\udcbd","Hscr;":"\u210b","hslash;":"\u210f","Hstrok;":"\u0126","hstrok;":"\u0127","HumpDownHump;":"\u224e","HumpEqual;":"\u224f","hybull;":"\u2043","hyphen;":"\u2010","Iacute;":"\u00cd",Iacute:"\u00cd","iacute;":"\u00ed",iacute:"\u00ed","ic;":"\u2063","Icirc;":"\u00ce",Icirc:"\u00ce","icirc;":"\u00ee",icirc:"\u00ee","Icy;":"\u0418","icy;":"\u0438","Idot;":"\u0130","IEcy;":"\u0415","iecy;":"\u0435","iexcl;":"\u00a1",iexcl:"\u00a1","iff;":"\u21d4","ifr;":"\ud835\udd26","Ifr;":"\u2111","Igrave;":"\u00cc",Igrave:"\u00cc","igrave;":"\u00ec",igrave:"\u00ec","ii;":"\u2148","iiiint;":"\u2a0c","iiint;":"\u222d","iinfin;":"\u29dc","iiota;":"\u2129","IJlig;":"\u0132","ijlig;":"\u0133","Imacr;":"\u012a","imacr;":"\u012b","image;":"\u2111","ImaginaryI;":"\u2148","imagline;":"\u2110","imagpart;":"\u2111","imath;":"\u0131","Im;":"\u2111","imof;":"\u22b7","imped;":"\u01b5","Implies;":"\u21d2","incare;":"\u2105","in;":"\u2208","infin;":"\u221e","infintie;":"\u29dd","inodot;":"\u0131","intcal;":"\u22ba","int;":"\u222b","Int;":"\u222c","integers;":"\u2124","Integral;":"\u222b","intercal;":"\u22ba","Intersection;":"\u22c2","intlarhk;":"\u2a17","intprod;":"\u2a3c","InvisibleComma;":"\u2063","InvisibleTimes;":"\u2062","IOcy;":"\u0401","iocy;":"\u0451","Iogon;":"\u012e","iogon;":"\u012f","Iopf;":"\ud835\udd40","iopf;":"\ud835\udd5a","Iota;":"\u0399","iota;":"\u03b9","iprod;":"\u2a3c","iquest;":"\u00bf",iquest:"\u00bf","iscr;":"\ud835\udcbe","Iscr;":"\u2110","isin;":"\u2208","isindot;":"\u22f5","isinE;":"\u22f9","isins;":"\u22f4","isinsv;":"\u22f3","isinv;":"\u2208","it;":"\u2062","Itilde;":"\u0128","itilde;":"\u0129","Iukcy;":"\u0406","iukcy;":"\u0456","Iuml;":"\u00cf",Iuml:"\u00cf","iuml;":"\u00ef",iuml:"\u00ef","Jcirc;":"\u0134","jcirc;":"\u0135","Jcy;":"\u0419","jcy;":"\u0439","Jfr;":"\ud835\udd0d","jfr;":"\ud835\udd27","jmath;":"\u0237","Jopf;":"\ud835\udd41","jopf;":"\ud835\udd5b","Jscr;":"\ud835\udca5","jscr;":"\ud835\udcbf","Jsercy;":"\u0408","jsercy;":"\u0458","Jukcy;":"\u0404","jukcy;":"\u0454","Kappa;":"\u039a","kappa;":"\u03ba","kappav;":"\u03f0","Kcedil;":"\u0136","kcedil;":"\u0137","Kcy;":"\u041a","kcy;":"\u043a","Kfr;":"\ud835\udd0e","kfr;":"\ud835\udd28","kgreen;":"\u0138","KHcy;":"\u0425","khcy;":"\u0445","KJcy;":"\u040c","kjcy;":"\u045c","Kopf;":"\ud835\udd42","kopf;":"\ud835\udd5c","Kscr;":"\ud835\udca6","kscr;":"\ud835\udcc0","lAarr;":"\u21da","Lacute;":"\u0139","lacute;":"\u013a","laemptyv;":"\u29b4","lagran;":"\u2112","Lambda;":"\u039b","lambda;":"\u03bb","lang;":"\u27e8","Lang;":"\u27ea","langd;":"\u2991","langle;":"\u27e8","lap;":"\u2a85","Laplacetrf;":"\u2112","laquo;":"\u00ab",laquo:"\u00ab","larrb;":"\u21e4","larrbfs;":"\u291f","larr;":"\u2190","Larr;":"\u219e","lArr;":"\u21d0","larrfs;":"\u291d","larrhk;":"\u21a9","larrlp;":"\u21ab","larrpl;":"\u2939","larrsim;":"\u2973","larrtl;":"\u21a2","latail;":"\u2919","lAtail;":"\u291b","lat;":"\u2aab","late;":"\u2aad","lates;":"\u2aad\ufe00","lbarr;":"\u290c","lBarr;":"\u290e","lbbrk;":"\u2772","lbrace;":"{","lbrack;":"[","lbrke;":"\u298b","lbrksld;":"\u298f","lbrkslu;":"\u298d","Lcaron;":"\u013d","lcaron;":"\u013e","Lcedil;":"\u013b","lcedil;":"\u013c","lceil;":"\u2308","lcub;":"{","Lcy;":"\u041b","lcy;":"\u043b","ldca;":"\u2936","ldquo;":"\u201c","ldquor;":"\u201e","ldrdhar;":"\u2967","ldrushar;":"\u294b","ldsh;":"\u21b2","le;":"\u2264","lE;":"\u2266","LeftAngleBracket;":"\u27e8","LeftArrowBar;":"\u21e4","leftarrow;":"\u2190","LeftArrow;":"\u2190","Leftarrow;":"\u21d0","LeftArrowRightArrow;":"\u21c6","leftarrowtail;":"\u21a2","LeftCeiling;":"\u2308","LeftDoubleBracket;":"\u27e6","LeftDownTeeVector;":"\u2961","LeftDownVectorBar;":"\u2959","LeftDownVector;":"\u21c3","LeftFloor;":"\u230a","leftharpoondown;":"\u21bd","leftharpoonup;":"\u21bc","leftleftarrows;":"\u21c7","leftrightarrow;":"\u2194","LeftRightArrow;":"\u2194","Leftrightarrow;":"\u21d4","leftrightarrows;":"\u21c6","leftrightharpoons;":"\u21cb","leftrightsquigarrow;":"\u21ad","LeftRightVector;":"\u294e","LeftTeeArrow;":"\u21a4","LeftTee;":"\u22a3","LeftTeeVector;":"\u295a","leftthreetimes;":"\u22cb","LeftTriangleBar;":"\u29cf","LeftTriangle;":"\u22b2","LeftTriangleEqual;":"\u22b4","LeftUpDownVector;":"\u2951","LeftUpTeeVector;":"\u2960","LeftUpVectorBar;":"\u2958","LeftUpVector;":"\u21bf","LeftVectorBar;":"\u2952","LeftVector;":"\u21bc","lEg;":"\u2a8b","leg;":"\u22da","leq;":"\u2264","leqq;":"\u2266","leqslant;":"\u2a7d","lescc;":"\u2aa8","les;":"\u2a7d","lesdot;":"\u2a7f","lesdoto;":"\u2a81","lesdotor;":"\u2a83","lesg;":"\u22da\ufe00","lesges;":"\u2a93","lessapprox;":"\u2a85","lessdot;":"\u22d6","lesseqgtr;":"\u22da","lesseqqgtr;":"\u2a8b","LessEqualGreater;":"\u22da","LessFullEqual;":"\u2266","LessGreater;":"\u2276","lessgtr;":"\u2276","LessLess;":"\u2aa1","lesssim;":"\u2272","LessSlantEqual;":"\u2a7d","LessTilde;":"\u2272","lfisht;":"\u297c","lfloor;":"\u230a","Lfr;":"\ud835\udd0f","lfr;":"\ud835\udd29","lg;":"\u2276","lgE;":"\u2a91","lHar;":"\u2962","lhard;":"\u21bd","lharu;":"\u21bc","lharul;":"\u296a","lhblk;":"\u2584","LJcy;":"\u0409","ljcy;":"\u0459","llarr;":"\u21c7","ll;":"\u226a","Ll;":"\u22d8","llcorner;":"\u231e","Lleftarrow;":"\u21da","llhard;":"\u296b","lltri;":"\u25fa","Lmidot;":"\u013f","lmidot;":"\u0140","lmoustache;":"\u23b0","lmoust;":"\u23b0","lnap;":"\u2a89","lnapprox;":"\u2a89","lne;":"\u2a87","lnE;":"\u2268","lneq;":"\u2a87","lneqq;":"\u2268","lnsim;":"\u22e6","loang;":"\u27ec","loarr;":"\u21fd","lobrk;":"\u27e6","longleftarrow;":"\u27f5","LongLeftArrow;":"\u27f5","Longleftarrow;":"\u27f8","longleftrightarrow;":"\u27f7","LongLeftRightArrow;":"\u27f7","Longleftrightarrow;":"\u27fa","longmapsto;":"\u27fc","longrightarrow;":"\u27f6","LongRightArrow;":"\u27f6","Longrightarrow;":"\u27f9","looparrowleft;":"\u21ab","looparrowright;":"\u21ac","lopar;":"\u2985","Lopf;":"\ud835\udd43","lopf;":"\ud835\udd5d","loplus;":"\u2a2d","lotimes;":"\u2a34","lowast;":"\u2217","lowbar;":"_","LowerLeftArrow;":"\u2199","LowerRightArrow;":"\u2198","loz;":"\u25ca","lozenge;":"\u25ca","lozf;":"\u29eb","lpar;":"(","lparlt;":"\u2993","lrarr;":"\u21c6","lrcorner;":"\u231f","lrhar;":"\u21cb","lrhard;":"\u296d","lrm;":"\u200e","lrtri;":"\u22bf","lsaquo;":"\u2039","lscr;":"\ud835\udcc1","Lscr;":"\u2112","lsh;":"\u21b0","Lsh;":"\u21b0","lsim;":"\u2272","lsime;":"\u2a8d","lsimg;":"\u2a8f","lsqb;":"[","lsquo;":"\u2018","lsquor;":"\u201a","Lstrok;":"\u0141","lstrok;":"\u0142","ltcc;":"\u2aa6","ltcir;":"\u2a79","lt;":"<",lt:"<","LT;":"<",LT:"<","Lt;":"\u226a","ltdot;":"\u22d6","lthree;":"\u22cb","ltimes;":"\u22c9","ltlarr;":"\u2976","ltquest;":"\u2a7b","ltri;":"\u25c3","ltrie;":"\u22b4","ltrif;":"\u25c2","ltrPar;":"\u2996","lurdshar;":"\u294a","luruhar;":"\u2966","lvertneqq;":"\u2268\ufe00","lvnE;":"\u2268\ufe00","macr;":"\u00af",macr:"\u00af","male;":"\u2642","malt;":"\u2720","maltese;":"\u2720","Map;":"\u2905","map;":"\u21a6","mapsto;":"\u21a6","mapstodown;":"\u21a7","mapstoleft;":"\u21a4","mapstoup;":"\u21a5","marker;":"\u25ae","mcomma;":"\u2a29","Mcy;":"\u041c","mcy;":"\u043c","mdash;":"\u2014","mDDot;":"\u223a","measuredangle;":"\u2221","MediumSpace;":"\u205f","Mellintrf;":"\u2133","Mfr;":"\ud835\udd10","mfr;":"\ud835\udd2a","mho;":"\u2127","micro;":"\u00b5",micro:"\u00b5","midast;":"*","midcir;":"\u2af0","mid;":"\u2223","middot;":"\u00b7",middot:"\u00b7","minusb;":"\u229f","minus;":"\u2212","minusd;":"\u2238","minusdu;":"\u2a2a","MinusPlus;":"\u2213","mlcp;":"\u2adb","mldr;":"\u2026","mnplus;":"\u2213","models;":"\u22a7","Mopf;":"\ud835\udd44","mopf;":"\ud835\udd5e","mp;":"\u2213","mscr;":"\ud835\udcc2","Mscr;":"\u2133","mstpos;":"\u223e","Mu;":"\u039c","mu;":"\u03bc","multimap;":"\u22b8","mumap;":"\u22b8","nabla;":"\u2207","Nacute;":"\u0143","nacute;":"\u0144","nang;":"\u2220\u20d2","nap;":"\u2249","napE;":"\u2a70\u0338","napid;":"\u224b\u0338","napos;":"\u0149","napprox;":"\u2249","natural;":"\u266e","naturals;":"\u2115","natur;":"\u266e","nbsp;":"\u00a0",nbsp:"\u00a0","nbump;":"\u224e\u0338","nbumpe;":"\u224f\u0338","ncap;":"\u2a43","Ncaron;":"\u0147","ncaron;":"\u0148","Ncedil;":"\u0145","ncedil;":"\u0146","ncong;":"\u2247","ncongdot;":"\u2a6d\u0338","ncup;":"\u2a42","Ncy;":"\u041d","ncy;":"\u043d","ndash;":"\u2013","nearhk;":"\u2924","nearr;":"\u2197","neArr;":"\u21d7","nearrow;":"\u2197","ne;":"\u2260","nedot;":"\u2250\u0338","NegativeMediumSpace;":"\u200b","NegativeThickSpace;":"\u200b","NegativeThinSpace;":"\u200b","NegativeVeryThinSpace;":"\u200b","nequiv;":"\u2262","nesear;":"\u2928","nesim;":"\u2242\u0338","NestedGreaterGreater;":"\u226b","NestedLessLess;":"\u226a","NewLine;":"\n","nexist;":"\u2204","nexists;":"\u2204","Nfr;":"\ud835\udd11","nfr;":"\ud835\udd2b","ngE;":"\u2267\u0338","nge;":"\u2271","ngeq;":"\u2271","ngeqq;":"\u2267\u0338","ngeqslant;":"\u2a7e\u0338","nges;":"\u2a7e\u0338","nGg;":"\u22d9\u0338","ngsim;":"\u2275","nGt;":"\u226b\u20d2","ngt;":"\u226f","ngtr;":"\u226f","nGtv;":"\u226b\u0338","nharr;":"\u21ae","nhArr;":"\u21ce","nhpar;":"\u2af2","ni;":"\u220b","nis;":"\u22fc","nisd;":"\u22fa","niv;":"\u220b","NJcy;":"\u040a","njcy;":"\u045a","nlarr;":"\u219a","nlArr;":"\u21cd","nldr;":"\u2025","nlE;":"\u2266\u0338","nle;":"\u2270","nleftarrow;":"\u219a","nLeftarrow;":"\u21cd","nleftrightarrow;":"\u21ae","nLeftrightarrow;":"\u21ce","nleq;":"\u2270","nleqq;":"\u2266\u0338","nleqslant;":"\u2a7d\u0338","nles;":"\u2a7d\u0338","nless;":"\u226e","nLl;":"\u22d8\u0338","nlsim;":"\u2274","nLt;":"\u226a\u20d2","nlt;":"\u226e","nltri;":"\u22ea","nltrie;":"\u22ec","nLtv;":"\u226a\u0338","nmid;":"\u2224","NoBreak;":"\u2060","NonBreakingSpace;":"\u00a0","nopf;":"\ud835\udd5f","Nopf;":"\u2115","Not;":"\u2aec","not;":"\u00ac",not:"\u00ac","NotCongruent;":"\u2262","NotCupCap;":"\u226d","NotDoubleVerticalBar;":"\u2226","NotElement;":"\u2209","NotEqual;":"\u2260","NotEqualTilde;":"\u2242\u0338","NotExists;":"\u2204","NotGreater;":"\u226f","NotGreaterEqual;":"\u2271","NotGreaterFullEqual;":"\u2267\u0338","NotGreaterGreater;":"\u226b\u0338","NotGreaterLess;":"\u2279","NotGreaterSlantEqual;":"\u2a7e\u0338","NotGreaterTilde;":"\u2275","NotHumpDownHump;":"\u224e\u0338","NotHumpEqual;":"\u224f\u0338","notin;":"\u2209","notindot;":"\u22f5\u0338","notinE;":"\u22f9\u0338","notinva;":"\u2209","notinvb;":"\u22f7","notinvc;":"\u22f6","NotLeftTriangleBar;":"\u29cf\u0338","NotLeftTriangle;":"\u22ea","NotLeftTriangleEqual;":"\u22ec","NotLess;":"\u226e","NotLessEqual;":"\u2270","NotLessGreater;":"\u2278","NotLessLess;":"\u226a\u0338","NotLessSlantEqual;":"\u2a7d\u0338","NotLessTilde;":"\u2274","NotNestedGreaterGreater;":"\u2aa2\u0338","NotNestedLessLess;":"\u2aa1\u0338","notni;":"\u220c","notniva;":"\u220c","notnivb;":"\u22fe","notnivc;":"\u22fd","NotPrecedes;":"\u2280","NotPrecedesEqual;":"\u2aaf\u0338","NotPrecedesSlantEqual;":"\u22e0","NotReverseElement;":"\u220c","NotRightTriangleBar;":"\u29d0\u0338","NotRightTriangle;":"\u22eb","NotRightTriangleEqual;":"\u22ed","NotSquareSubset;":"\u228f\u0338","NotSquareSubsetEqual;":"\u22e2","NotSquareSuperset;":"\u2290\u0338","NotSquareSupersetEqual;":"\u22e3","NotSubset;":"\u2282\u20d2","NotSubsetEqual;":"\u2288","NotSucceeds;":"\u2281","NotSucceedsEqual;":"\u2ab0\u0338","NotSucceedsSlantEqual;":"\u22e1","NotSucceedsTilde;":"\u227f\u0338","NotSuperset;":"\u2283\u20d2","NotSupersetEqual;":"\u2289","NotTilde;":"\u2241","NotTildeEqual;":"\u2244","NotTildeFullEqual;":"\u2247","NotTildeTilde;":"\u2249","NotVerticalBar;":"\u2224","nparallel;":"\u2226","npar;":"\u2226","nparsl;":"\u2afd\u20e5","npart;":"\u2202\u0338","npolint;":"\u2a14","npr;":"\u2280","nprcue;":"\u22e0","nprec;":"\u2280","npreceq;":"\u2aaf\u0338","npre;":"\u2aaf\u0338","nrarrc;":"\u2933\u0338","nrarr;":"\u219b","nrArr;":"\u21cf","nrarrw;":"\u219d\u0338","nrightarrow;":"\u219b","nRightarrow;":"\u21cf","nrtri;":"\u22eb","nrtrie;":"\u22ed","nsc;":"\u2281","nsccue;":"\u22e1","nsce;":"\u2ab0\u0338","Nscr;":"\ud835\udca9","nscr;":"\ud835\udcc3","nshortmid;":"\u2224","nshortparallel;":"\u2226","nsim;":"\u2241","nsime;":"\u2244","nsimeq;":"\u2244","nsmid;":"\u2224","nspar;":"\u2226","nsqsube;":"\u22e2","nsqsupe;":"\u22e3","nsub;":"\u2284","nsubE;":"\u2ac5\u0338","nsube;":"\u2288","nsubset;":"\u2282\u20d2","nsubseteq;":"\u2288","nsubseteqq;":"\u2ac5\u0338","nsucc;":"\u2281","nsucceq;":"\u2ab0\u0338","nsup;":"\u2285","nsupE;":"\u2ac6\u0338","nsupe;":"\u2289","nsupset;":"\u2283\u20d2","nsupseteq;":"\u2289","nsupseteqq;":"\u2ac6\u0338","ntgl;":"\u2279","Ntilde;":"\u00d1",Ntilde:"\u00d1","ntilde;":"\u00f1",ntilde:"\u00f1","ntlg;":"\u2278","ntriangleleft;":"\u22ea","ntrianglelefteq;":"\u22ec","ntriangleright;":"\u22eb","ntrianglerighteq;":"\u22ed","Nu;":"\u039d","nu;":"\u03bd","num;":"#","numero;":"\u2116","numsp;":"\u2007","nvap;":"\u224d\u20d2","nvdash;":"\u22ac","nvDash;":"\u22ad","nVdash;":"\u22ae","nVDash;":"\u22af","nvge;":"\u2265\u20d2","nvgt;":">\u20d2","nvHarr;":"\u2904","nvinfin;":"\u29de","nvlArr;":"\u2902","nvle;":"\u2264\u20d2","nvlt;":"<\u20d2","nvltrie;":"\u22b4\u20d2","nvrArr;":"\u2903","nvrtrie;":"\u22b5\u20d2","nvsim;":"\u223c\u20d2","nwarhk;":"\u2923","nwarr;":"\u2196","nwArr;":"\u21d6","nwarrow;":"\u2196","nwnear;":"\u2927","Oacute;":"\u00d3",Oacute:"\u00d3","oacute;":"\u00f3",oacute:"\u00f3","oast;":"\u229b","Ocirc;":"\u00d4",Ocirc:"\u00d4","ocirc;":"\u00f4",ocirc:"\u00f4","ocir;":"\u229a","Ocy;":"\u041e","ocy;":"\u043e","odash;":"\u229d","Odblac;":"\u0150","odblac;":"\u0151","odiv;":"\u2a38","odot;":"\u2299","odsold;":"\u29bc","OElig;":"\u0152","oelig;":"\u0153","ofcir;":"\u29bf","Ofr;":"\ud835\udd12","ofr;":"\ud835\udd2c","ogon;":"\u02db","Ograve;":"\u00d2",Ograve:"\u00d2","ograve;":"\u00f2",ograve:"\u00f2","ogt;":"\u29c1","ohbar;":"\u29b5","ohm;":"\u03a9","oint;":"\u222e","olarr;":"\u21ba","olcir;":"\u29be","olcross;":"\u29bb","oline;":"\u203e","olt;":"\u29c0","Omacr;":"\u014c","omacr;":"\u014d","Omega;":"\u03a9","omega;":"\u03c9","Omicron;":"\u039f","omicron;":"\u03bf","omid;":"\u29b6","ominus;":"\u2296","Oopf;":"\ud835\udd46","oopf;":"\ud835\udd60","opar;":"\u29b7","OpenCurlyDoubleQuote;":"\u201c","OpenCurlyQuote;":"\u2018","operp;":"\u29b9","oplus;":"\u2295","orarr;":"\u21bb","Or;":"\u2a54","or;":"\u2228","ord;":"\u2a5d","order;":"\u2134","orderof;":"\u2134","ordf;":"\u00aa",ordf:"\u00aa","ordm;":"\u00ba",ordm:"\u00ba","origof;":"\u22b6","oror;":"\u2a56","orslope;":"\u2a57","orv;":"\u2a5b","oS;":"\u24c8","Oscr;":"\ud835\udcaa","oscr;":"\u2134","Oslash;":"\u00d8",Oslash:"\u00d8","oslash;":"\u00f8",oslash:"\u00f8","osol;":"\u2298","Otilde;":"\u00d5",Otilde:"\u00d5","otilde;":"\u00f5",otilde:"\u00f5","otimesas;":"\u2a36","Otimes;":"\u2a37","otimes;":"\u2297","Ouml;":"\u00d6",Ouml:"\u00d6","ouml;":"\u00f6",ouml:"\u00f6","ovbar;":"\u233d","OverBar;":"\u203e","OverBrace;":"\u23de","OverBracket;":"\u23b4","OverParenthesis;":"\u23dc","para;":"\u00b6",para:"\u00b6","parallel;":"\u2225","par;":"\u2225","parsim;":"\u2af3","parsl;":"\u2afd","part;":"\u2202","PartialD;":"\u2202","Pcy;":"\u041f","pcy;":"\u043f","percnt;":"%","period;":".","permil;":"\u2030","perp;":"\u22a5","pertenk;":"\u2031","Pfr;":"\ud835\udd13","pfr;":"\ud835\udd2d","Phi;":"\u03a6","phi;":"\u03c6","phiv;":"\u03d5","phmmat;":"\u2133","phone;":"\u260e","Pi;":"\u03a0","pi;":"\u03c0","pitchfork;":"\u22d4","piv;":"\u03d6","planck;":"\u210f","planckh;":"\u210e","plankv;":"\u210f","plusacir;":"\u2a23","plusb;":"\u229e","pluscir;":"\u2a22","plus;":"+","plusdo;":"\u2214","plusdu;":"\u2a25","pluse;":"\u2a72","PlusMinus;":"\u00b1","plusmn;":"\u00b1",plusmn:"\u00b1","plussim;":"\u2a26","plustwo;":"\u2a27","pm;":"\u00b1","Poincareplane;":"\u210c","pointint;":"\u2a15","popf;":"\ud835\udd61","Popf;":"\u2119","pound;":"\u00a3",pound:"\u00a3","prap;":"\u2ab7","Pr;":"\u2abb","pr;":"\u227a","prcue;":"\u227c","precapprox;":"\u2ab7","prec;":"\u227a","preccurlyeq;":"\u227c","Precedes;":"\u227a","PrecedesEqual;":"\u2aaf","PrecedesSlantEqual;":"\u227c","PrecedesTilde;":"\u227e","preceq;":"\u2aaf","precnapprox;":"\u2ab9","precneqq;":"\u2ab5","precnsim;":"\u22e8","pre;":"\u2aaf","prE;":"\u2ab3","precsim;":"\u227e","prime;":"\u2032","Prime;":"\u2033","primes;":"\u2119","prnap;":"\u2ab9","prnE;":"\u2ab5","prnsim;":"\u22e8","prod;":"\u220f","Product;":"\u220f","profalar;":"\u232e","profline;":"\u2312","profsurf;":"\u2313","prop;":"\u221d","Proportional;":"\u221d","Proportion;":"\u2237","propto;":"\u221d","prsim;":"\u227e","prurel;":"\u22b0","Pscr;":"\ud835\udcab","pscr;":"\ud835\udcc5","Psi;":"\u03a8","psi;":"\u03c8","puncsp;":"\u2008","Qfr;":"\ud835\udd14","qfr;":"\ud835\udd2e","qint;":"\u2a0c","qopf;":"\ud835\udd62","Qopf;":"\u211a","qprime;":"\u2057","Qscr;":"\ud835\udcac","qscr;":"\ud835\udcc6","quaternions;":"\u210d","quatint;":"\u2a16","quest;":"?","questeq;":"\u225f","quot;":'"',quot:'"',"QUOT;":'"',QUOT:'"',"rAarr;":"\u21db","race;":"\u223d\u0331","Racute;":"\u0154","racute;":"\u0155","radic;":"\u221a","raemptyv;":"\u29b3","rang;":"\u27e9","Rang;":"\u27eb","rangd;":"\u2992","range;":"\u29a5","rangle;":"\u27e9","raquo;":"\u00bb",raquo:"\u00bb","rarrap;":"\u2975","rarrb;":"\u21e5","rarrbfs;":"\u2920","rarrc;":"\u2933","rarr;":"\u2192","Rarr;":"\u21a0","rArr;":"\u21d2","rarrfs;":"\u291e","rarrhk;":"\u21aa","rarrlp;":"\u21ac","rarrpl;":"\u2945","rarrsim;":"\u2974","Rarrtl;":"\u2916","rarrtl;":"\u21a3","rarrw;":"\u219d","ratail;":"\u291a","rAtail;":"\u291c","ratio;":"\u2236","rationals;":"\u211a","rbarr;":"\u290d","rBarr;":"\u290f","RBarr;":"\u2910","rbbrk;":"\u2773","rbrace;":"}","rbrack;":"]","rbrke;":"\u298c","rbrksld;":"\u298e","rbrkslu;":"\u2990","Rcaron;":"\u0158","rcaron;":"\u0159","Rcedil;":"\u0156","rcedil;":"\u0157","rceil;":"\u2309","rcub;":"}","Rcy;":"\u0420","rcy;":"\u0440","rdca;":"\u2937","rdldhar;":"\u2969","rdquo;":"\u201d","rdquor;":"\u201d","rdsh;":"\u21b3","real;":"\u211c","realine;":"\u211b","realpart;":"\u211c","reals;":"\u211d","Re;":"\u211c","rect;":"\u25ad","reg;":"\u00ae",reg:"\u00ae","REG;":"\u00ae",REG:"\u00ae","ReverseElement;":"\u220b","ReverseEquilibrium;":"\u21cb","ReverseUpEquilibrium;":"\u296f","rfisht;":"\u297d","rfloor;":"\u230b","rfr;":"\ud835\udd2f","Rfr;":"\u211c","rHar;":"\u2964","rhard;":"\u21c1","rharu;":"\u21c0","rharul;":"\u296c","Rho;":"\u03a1","rho;":"\u03c1","rhov;":"\u03f1","RightAngleBracket;":"\u27e9","RightArrowBar;":"\u21e5","rightarrow;":"\u2192","RightArrow;":"\u2192","Rightarrow;":"\u21d2","RightArrowLeftArrow;":"\u21c4","rightarrowtail;":"\u21a3","RightCeiling;":"\u2309","RightDoubleBracket;":"\u27e7","RightDownTeeVector;":"\u295d","RightDownVectorBar;":"\u2955","RightDownVector;":"\u21c2","RightFloor;":"\u230b","rightharpoondown;":"\u21c1","rightharpoonup;":"\u21c0","rightleftarrows;":"\u21c4","rightleftharpoons;":"\u21cc","rightrightarrows;":"\u21c9","rightsquigarrow;":"\u219d","RightTeeArrow;":"\u21a6","RightTee;":"\u22a2","RightTeeVector;":"\u295b","rightthreetimes;":"\u22cc","RightTriangleBar;":"\u29d0","RightTriangle;":"\u22b3","RightTriangleEqual;":"\u22b5","RightUpDownVector;":"\u294f","RightUpTeeVector;":"\u295c","RightUpVectorBar;":"\u2954","RightUpVector;":"\u21be","RightVectorBar;":"\u2953","RightVector;":"\u21c0","ring;":"\u02da","risingdotseq;":"\u2253","rlarr;":"\u21c4","rlhar;":"\u21cc","rlm;":"\u200f","rmoustache;":"\u23b1","rmoust;":"\u23b1","rnmid;":"\u2aee","roang;":"\u27ed","roarr;":"\u21fe","robrk;":"\u27e7","ropar;":"\u2986","ropf;":"\ud835\udd63","Ropf;":"\u211d","roplus;":"\u2a2e","rotimes;":"\u2a35","RoundImplies;":"\u2970","rpar;":")","rpargt;":"\u2994","rppolint;":"\u2a12","rrarr;":"\u21c9","Rrightarrow;":"\u21db","rsaquo;":"\u203a","rscr;":"\ud835\udcc7","Rscr;":"\u211b","rsh;":"\u21b1","Rsh;":"\u21b1","rsqb;":"]","rsquo;":"\u2019","rsquor;":"\u2019","rthree;":"\u22cc","rtimes;":"\u22ca","rtri;":"\u25b9","rtrie;":"\u22b5","rtrif;":"\u25b8","rtriltri;":"\u29ce","RuleDelayed;":"\u29f4","ruluhar;":"\u2968","rx;":"\u211e","Sacute;":"\u015a","sacute;":"\u015b","sbquo;":"\u201a","scap;":"\u2ab8","Scaron;":"\u0160","scaron;":"\u0161","Sc;":"\u2abc","sc;":"\u227b","sccue;":"\u227d","sce;":"\u2ab0","scE;":"\u2ab4","Scedil;":"\u015e","scedil;":"\u015f","Scirc;":"\u015c","scirc;":"\u015d","scnap;":"\u2aba","scnE;":"\u2ab6","scnsim;":"\u22e9","scpolint;":"\u2a13","scsim;":"\u227f","Scy;":"\u0421","scy;":"\u0441","sdotb;":"\u22a1","sdot;":"\u22c5","sdote;":"\u2a66","searhk;":"\u2925","searr;":"\u2198","seArr;":"\u21d8","searrow;":"\u2198","sect;":"\u00a7",sect:"\u00a7","semi;":";","seswar;":"\u2929","setminus;":"\u2216","setmn;":"\u2216","sext;":"\u2736","Sfr;":"\ud835\udd16","sfr;":"\ud835\udd30","sfrown;":"\u2322","sharp;":"\u266f","SHCHcy;":"\u0429","shchcy;":"\u0449","SHcy;":"\u0428","shcy;":"\u0448","ShortDownArrow;":"\u2193","ShortLeftArrow;":"\u2190","shortmid;":"\u2223","shortparallel;":"\u2225","ShortRightArrow;":"\u2192","ShortUpArrow;":"\u2191","shy;":"\u00ad",shy:"\u00ad","Sigma;":"\u03a3","sigma;":"\u03c3","sigmaf;":"\u03c2","sigmav;":"\u03c2","sim;":"\u223c","simdot;":"\u2a6a","sime;":"\u2243","simeq;":"\u2243","simg;":"\u2a9e","simgE;":"\u2aa0","siml;":"\u2a9d","simlE;":"\u2a9f","simne;":"\u2246","simplus;":"\u2a24","simrarr;":"\u2972","slarr;":"\u2190","SmallCircle;":"\u2218","smallsetminus;":"\u2216","smashp;":"\u2a33","smeparsl;":"\u29e4","smid;":"\u2223","smile;":"\u2323","smt;":"\u2aaa","smte;":"\u2aac","smtes;":"\u2aac\ufe00","SOFTcy;":"\u042c","softcy;":"\u044c","solbar;":"\u233f","solb;":"\u29c4","sol;":"/","Sopf;":"\ud835\udd4a","sopf;":"\ud835\udd64","spades;":"\u2660","spadesuit;":"\u2660","spar;":"\u2225","sqcap;":"\u2293","sqcaps;":"\u2293\ufe00","sqcup;":"\u2294","sqcups;":"\u2294\ufe00","Sqrt;":"\u221a","sqsub;":"\u228f","sqsube;":"\u2291","sqsubset;":"\u228f","sqsubseteq;":"\u2291","sqsup;":"\u2290","sqsupe;":"\u2292","sqsupset;":"\u2290","sqsupseteq;":"\u2292","square;":"\u25a1","Square;":"\u25a1","SquareIntersection;":"\u2293","SquareSubset;":"\u228f","SquareSubsetEqual;":"\u2291","SquareSuperset;":"\u2290","SquareSupersetEqual;":"\u2292","SquareUnion;":"\u2294","squarf;":"\u25aa","squ;":"\u25a1","squf;":"\u25aa","srarr;":"\u2192","Sscr;":"\ud835\udcae","sscr;":"\ud835\udcc8","ssetmn;":"\u2216","ssmile;":"\u2323","sstarf;":"\u22c6","Star;":"\u22c6","star;":"\u2606","starf;":"\u2605","straightepsilon;":"\u03f5","straightphi;":"\u03d5","strns;":"\u00af","sub;":"\u2282","Sub;":"\u22d0","subdot;":"\u2abd","subE;":"\u2ac5","sube;":"\u2286","subedot;":"\u2ac3","submult;":"\u2ac1","subnE;":"\u2acb","subne;":"\u228a","subplus;":"\u2abf","subrarr;":"\u2979","subset;":"\u2282","Subset;":"\u22d0","subseteq;":"\u2286","subseteqq;":"\u2ac5","SubsetEqual;":"\u2286","subsetneq;":"\u228a","subsetneqq;":"\u2acb","subsim;":"\u2ac7","subsub;":"\u2ad5","subsup;":"\u2ad3","succapprox;":"\u2ab8","succ;":"\u227b","succcurlyeq;":"\u227d","Succeeds;":"\u227b","SucceedsEqual;":"\u2ab0","SucceedsSlantEqual;":"\u227d","SucceedsTilde;":"\u227f","succeq;":"\u2ab0","succnapprox;":"\u2aba","succneqq;":"\u2ab6","succnsim;":"\u22e9","succsim;":"\u227f","SuchThat;":"\u220b","sum;":"\u2211","Sum;":"\u2211","sung;":"\u266a","sup1;":"\u00b9",sup1:"\u00b9","sup2;":"\u00b2",sup2:"\u00b2","sup3;":"\u00b3",sup3:"\u00b3","sup;":"\u2283","Sup;":"\u22d1","supdot;":"\u2abe","supdsub;":"\u2ad8","supE;":"\u2ac6","supe;":"\u2287","supedot;":"\u2ac4","Superset;":"\u2283","SupersetEqual;":"\u2287","suphsol;":"\u27c9","suphsub;":"\u2ad7","suplarr;":"\u297b","supmult;":"\u2ac2","supnE;":"\u2acc","supne;":"\u228b","supplus;":"\u2ac0","supset;":"\u2283","Supset;":"\u22d1","supseteq;":"\u2287","supseteqq;":"\u2ac6","supsetneq;":"\u228b","supsetneqq;":"\u2acc","supsim;":"\u2ac8","supsub;":"\u2ad4","supsup;":"\u2ad6","swarhk;":"\u2926","swarr;":"\u2199","swArr;":"\u21d9","swarrow;":"\u2199","swnwar;":"\u292a","szlig;":"\u00df",szlig:"\u00df","Tab;":"	","target;":"\u2316","Tau;":"\u03a4","tau;":"\u03c4","tbrk;":"\u23b4","Tcaron;":"\u0164","tcaron;":"\u0165","Tcedil;":"\u0162","tcedil;":"\u0163","Tcy;":"\u0422","tcy;":"\u0442","tdot;":"\u20db","telrec;":"\u2315","Tfr;":"\ud835\udd17","tfr;":"\ud835\udd31","there4;":"\u2234","therefore;":"\u2234","Therefore;":"\u2234","Theta;":"\u0398","theta;":"\u03b8","thetasym;":"\u03d1","thetav;":"\u03d1","thickapprox;":"\u2248","thicksim;":"\u223c","ThickSpace;":"\u205f\u200a","ThinSpace;":"\u2009","thinsp;":"\u2009","thkap;":"\u2248","thksim;":"\u223c","THORN;":"\u00de",THORN:"\u00de","thorn;":"\u00fe",thorn:"\u00fe","tilde;":"\u02dc","Tilde;":"\u223c","TildeEqual;":"\u2243","TildeFullEqual;":"\u2245","TildeTilde;":"\u2248","timesbar;":"\u2a31","timesb;":"\u22a0","times;":"\u00d7",times:"\u00d7","timesd;":"\u2a30","tint;":"\u222d","toea;":"\u2928","topbot;":"\u2336","topcir;":"\u2af1","top;":"\u22a4","Topf;":"\ud835\udd4b","topf;":"\ud835\udd65","topfork;":"\u2ada","tosa;":"\u2929","tprime;":"\u2034","trade;":"\u2122","TRADE;":"\u2122","triangle;":"\u25b5","triangledown;":"\u25bf","triangleleft;":"\u25c3","trianglelefteq;":"\u22b4","triangleq;":"\u225c","triangleright;":"\u25b9","trianglerighteq;":"\u22b5","tridot;":"\u25ec","trie;":"\u225c","triminus;":"\u2a3a","TripleDot;":"\u20db","triplus;":"\u2a39","trisb;":"\u29cd","tritime;":"\u2a3b","trpezium;":"\u23e2","Tscr;":"\ud835\udcaf","tscr;":"\ud835\udcc9","TScy;":"\u0426","tscy;":"\u0446","TSHcy;":"\u040b","tshcy;":"\u045b","Tstrok;":"\u0166","tstrok;":"\u0167","twixt;":"\u226c","twoheadleftarrow;":"\u219e","twoheadrightarrow;":"\u21a0","Uacute;":"\u00da",Uacute:"\u00da","uacute;":"\u00fa",uacute:"\u00fa","uarr;":"\u2191","Uarr;":"\u219f","uArr;":"\u21d1","Uarrocir;":"\u2949","Ubrcy;":"\u040e","ubrcy;":"\u045e","Ubreve;":"\u016c","ubreve;":"\u016d","Ucirc;":"\u00db",Ucirc:"\u00db","ucirc;":"\u00fb",ucirc:"\u00fb","Ucy;":"\u0423","ucy;":"\u0443","udarr;":"\u21c5","Udblac;":"\u0170","udblac;":"\u0171","udhar;":"\u296e","ufisht;":"\u297e","Ufr;":"\ud835\udd18","ufr;":"\ud835\udd32","Ugrave;":"\u00d9",Ugrave:"\u00d9","ugrave;":"\u00f9",ugrave:"\u00f9","uHar;":"\u2963","uharl;":"\u21bf","uharr;":"\u21be","uhblk;":"\u2580","ulcorn;":"\u231c","ulcorner;":"\u231c","ulcrop;":"\u230f","ultri;":"\u25f8","Umacr;":"\u016a","umacr;":"\u016b","uml;":"\u00a8",uml:"\u00a8","UnderBar;":"_","UnderBrace;":"\u23df","UnderBracket;":"\u23b5","UnderParenthesis;":"\u23dd","Union;":"\u22c3","UnionPlus;":"\u228e","Uogon;":"\u0172","uogon;":"\u0173","Uopf;":"\ud835\udd4c","uopf;":"\ud835\udd66","UpArrowBar;":"\u2912","uparrow;":"\u2191","UpArrow;":"\u2191","Uparrow;":"\u21d1","UpArrowDownArrow;":"\u21c5","updownarrow;":"\u2195","UpDownArrow;":"\u2195","Updownarrow;":"\u21d5","UpEquilibrium;":"\u296e","upharpoonleft;":"\u21bf","upharpoonright;":"\u21be","uplus;":"\u228e","UpperLeftArrow;":"\u2196","UpperRightArrow;":"\u2197","upsi;":"\u03c5","Upsi;":"\u03d2","upsih;":"\u03d2","Upsilon;":"\u03a5","upsilon;":"\u03c5","UpTeeArrow;":"\u21a5","UpTee;":"\u22a5","upuparrows;":"\u21c8","urcorn;":"\u231d","urcorner;":"\u231d","urcrop;":"\u230e","Uring;":"\u016e","uring;":"\u016f","urtri;":"\u25f9","Uscr;":"\ud835\udcb0","uscr;":"\ud835\udcca","utdot;":"\u22f0","Utilde;":"\u0168","utilde;":"\u0169","utri;":"\u25b5","utrif;":"\u25b4","uuarr;":"\u21c8","Uuml;":"\u00dc",Uuml:"\u00dc","uuml;":"\u00fc",uuml:"\u00fc","uwangle;":"\u29a7","vangrt;":"\u299c","varepsilon;":"\u03f5","varkappa;":"\u03f0","varnothing;":"\u2205","varphi;":"\u03d5","varpi;":"\u03d6","varpropto;":"\u221d","varr;":"\u2195","vArr;":"\u21d5","varrho;":"\u03f1","varsigma;":"\u03c2","varsubsetneq;":"\u228a\ufe00","varsubsetneqq;":"\u2acb\ufe00","varsupsetneq;":"\u228b\ufe00","varsupsetneqq;":"\u2acc\ufe00","vartheta;":"\u03d1","vartriangleleft;":"\u22b2","vartriangleright;":"\u22b3","vBar;":"\u2ae8","Vbar;":"\u2aeb","vBarv;":"\u2ae9","Vcy;":"\u0412","vcy;":"\u0432","vdash;":"\u22a2","vDash;":"\u22a8","Vdash;":"\u22a9","VDash;":"\u22ab","Vdashl;":"\u2ae6","veebar;":"\u22bb","vee;":"\u2228","Vee;":"\u22c1","veeeq;":"\u225a","vellip;":"\u22ee","verbar;":"|","Verbar;":"\u2016","vert;":"|","Vert;":"\u2016","VerticalBar;":"\u2223","VerticalLine;":"|","VerticalSeparator;":"\u2758","VerticalTilde;":"\u2240","VeryThinSpace;":"\u200a","Vfr;":"\ud835\udd19","vfr;":"\ud835\udd33","vltri;":"\u22b2","vnsub;":"\u2282\u20d2","vnsup;":"\u2283\u20d2","Vopf;":"\ud835\udd4d","vopf;":"\ud835\udd67","vprop;":"\u221d","vrtri;":"\u22b3","Vscr;":"\ud835\udcb1","vscr;":"\ud835\udccb","vsubnE;":"\u2acb\ufe00","vsubne;":"\u228a\ufe00","vsupnE;":"\u2acc\ufe00","vsupne;":"\u228b\ufe00","Vvdash;":"\u22aa","vzigzag;":"\u299a","Wcirc;":"\u0174","wcirc;":"\u0175","wedbar;":"\u2a5f","wedge;":"\u2227","Wedge;":"\u22c0","wedgeq;":"\u2259","weierp;":"\u2118","Wfr;":"\ud835\udd1a","wfr;":"\ud835\udd34","Wopf;":"\ud835\udd4e","wopf;":"\ud835\udd68","wp;":"\u2118","wr;":"\u2240","wreath;":"\u2240","Wscr;":"\ud835\udcb2","wscr;":"\ud835\udccc","xcap;":"\u22c2","xcirc;":"\u25ef","xcup;":"\u22c3","xdtri;":"\u25bd","Xfr;":"\ud835\udd1b","xfr;":"\ud835\udd35","xharr;":"\u27f7","xhArr;":"\u27fa","Xi;":"\u039e","xi;":"\u03be","xlarr;":"\u27f5","xlArr;":"\u27f8","xmap;":"\u27fc","xnis;":"\u22fb","xodot;":"\u2a00","Xopf;":"\ud835\udd4f","xopf;":"\ud835\udd69","xoplus;":"\u2a01","xotime;":"\u2a02","xrarr;":"\u27f6","xrArr;":"\u27f9","Xscr;":"\ud835\udcb3","xscr;":"\ud835\udccd","xsqcup;":"\u2a06","xuplus;":"\u2a04","xutri;":"\u25b3","xvee;":"\u22c1","xwedge;":"\u22c0","Yacute;":"\u00dd",Yacute:"\u00dd","yacute;":"\u00fd",yacute:"\u00fd","YAcy;":"\u042f","yacy;":"\u044f","Ycirc;":"\u0176","ycirc;":"\u0177","Ycy;":"\u042b","ycy;":"\u044b","yen;":"\u00a5",yen:"\u00a5","Yfr;":"\ud835\udd1c","yfr;":"\ud835\udd36","YIcy;":"\u0407","yicy;":"\u0457","Yopf;":"\ud835\udd50","yopf;":"\ud835\udd6a","Yscr;":"\ud835\udcb4","yscr;":"\ud835\udcce","YUcy;":"\u042e","yucy;":"\u044e","yuml;":"\u00ff",yuml:"\u00ff","Yuml;":"\u0178","Zacute;":"\u0179","zacute;":"\u017a","Zcaron;":"\u017d","zcaron;":"\u017e","Zcy;":"\u0417","zcy;":"\u0437","Zdot;":"\u017b","zdot;":"\u017c","zeetrf;":"\u2128","ZeroWidthSpace;":"\u200b","Zeta;":"\u0396","zeta;":"\u03b6","zfr;":"\ud835\udd37","Zfr;":"\u2128","ZHcy;":"\u0416","zhcy;":"\u0436","zigrarr;":"\u21dd","zopf;":"\ud835\udd6b","Zopf;":"\u2124","Zscr;":"\ud835\udcb5","zscr;":"\ud835\udccf","zwj;":"\u200d","zwnj;":"\u200c"}},{}],13:[function(e,t,n){function u(e,t){return r.isUndefined(t)?""+t:r.isNumber(t)&&(isNaN(t)||!isFinite(t))?t.toString():r.isFunction(t)||r.isRegExp(t)?t.toString():t}function a(e,t){return r.isString(e)?e.length<t?e:e.slice(0,t):e}function f(e){return a(JSON.stringify(e.actual,u),128)+" "+e.operator+" "+a(JSON.stringify(e.expected,u),128)}function l(e,t,n,r,i){throw new o.AssertionError({message:n,actual:e,expected:t,operator:r,stackStartFunction:i})}function c(e,t){e||l(e,!0,t,"==",o.ok)}function h(e,t){if(e===t)return!0;if(r.isBuffer(e)&&r.isBuffer(t)){if(e.length!=t.length)return!1;for(var n=0;n<e.length;n++)if(e[n]!==t[n])return!1;return!0}return r.isDate(e)&&r.isDate(t)?e.getTime()===t.getTime():r.isRegExp(e)&&r.isRegExp(t)?e.source===t.source&&e.global===t.global&&e.multiline===t.multiline&&e.lastIndex===t.lastIndex&&e.ignoreCase===t.ignoreCase:!r.isObject(e)&&!r.isObject(t)?e==t:d(e,t)}function p(e){return Object.prototype.toString.call(e)=="[object Arguments]"}function d(e,t){if(r.isNullOrUndefined(e)||r.isNullOrUndefined(t))return!1;if(e.prototype!==t.prototype)return!1;if(p(e))return p(t)?(e=i.call(e),t=i.call(t),h(e,t)):!1;try{var n=g(e),s=g(t),o,u}catch(a){return!1}if(n.length!=s.length)return!1;n.sort(),s.sort();for(u=n.length-1;u>=0;u--)if(n[u]!=s[u])return!1;for(u=n.length-1;u>=0;u--){o=n[u];if(!h(e[o],t[o]))return!1}return!0}function v(e,t){return!e||!t?!1:Object.prototype.toString.call(t)=="[object RegExp]"?t.test(e):e instanceof t?!0:t.call({},e)===!0?!0:!1}function m(e,t,n,i){var s;r.isString(n)&&(i=n,n=null);try{t()}catch(o){s=o}i=(n&&n.name?" ("+n.name+").":".")+(i?" "+i:"."),e&&!s&&l(s,n,"Missing expected exception"+i),!e&&v(s,n)&&l(s,n,"Got unwanted exception"+i);if(e&&s&&n&&!v(s,n)||!e&&s)throw s}var r=e("util/"),i=Array.prototype.slice,s=Object.prototype.hasOwnProperty,o=t.exports=c;o.AssertionError=function(t){this.name="AssertionError",this.actual=t.actual,this.expected=t.expected,this.operator=t.operator,t.message?(this.message=t.message,this.generatedMessage=!1):(this.message=f(this),this.generatedMessage=!0);var n=t.stackStartFunction||l;if(Error.captureStackTrace)Error.captureStackTrace(this,n);else{var r=new Error;if(r.stack){var i=r.stack,s=n.name,o=i.indexOf("\n"+s);if(o>=0){var u=i.indexOf("\n",o+1);i=i.substring(u+1)}this.stack=i}}},r.inherits(o.AssertionError,Error),o.fail=l,o.ok=c,o.equal=function(t,n,r){t!=n&&l(t,n,r,"==",o.equal)},o.notEqual=function(t,n,r){t==n&&l(t,n,r,"!=",o.notEqual)},o.deepEqual=function(t,n,r){h(t,n)||l(t,n,r,"deepEqual",o.deepEqual)},o.notDeepEqual=function(t,n,r){h(t,n)&&l(t,n,r,"notDeepEqual",o.notDeepEqual)},o.strictEqual=function(t,n,r){t!==n&&l(t,n,r,"===",o.strictEqual)},o.notStrictEqual=function(t,n,r){t===n&&l(t,n,r,"!==",o.notStrictEqual)},o.throws=function(e,t,n){m.apply(this,[!0].concat(i.call(arguments)))},o.doesNotThrow=function(e,t){m.apply(this,[!1].concat(i.call(arguments)))},o.ifError=function(e){if(e)throw e};var g=Object.keys||function(e){var t=[];for(var n in e)s.call(e,n)&&t.push(n);return t}},{"util/":15}],14:[function(e,t,n){t.exports=function(t){return t&&typeof t=="object"&&typeof t.copy=="function"&&typeof t.fill=="function"&&typeof t.readUInt8=="function"}},{}],15:[function(e,t,n){(function(t,r){function u(e,t){var r={seen:[],stylize:f};return arguments.length>=3&&(r.depth=arguments[2]),arguments.length>=4&&(r.colors=arguments[3]),y(t)?r.showHidden=t:t&&n._extend(r,t),T(r.showHidden)&&(r.showHidden=!1),T(r.depth)&&(r.depth=2),T(r.colors)&&(r.colors=!1),T(r.customInspect)&&(r.customInspect=!0),r.colors&&(r.stylize=a),c(r,e,r.depth)}function a(e,t){var n=u.styles[t];return n?"["+u.colors[n][0]+"m"+e+"["+u.colors[n][1]+"m":e}function f(e,t){return e}function l(e){var t={};return e.forEach(function(e,n){t[e]=!0}),t}function c(e,t,r){if(e.customInspect&&t&&A(t.inspect)&&t.inspect!==n.inspect&&(!t.constructor||t.constructor.prototype!==t)){var i=t.inspect(r,e);return S(i)||(i=c(e,i,r)),i}var s=h(e,t);if(s)return s;var o=Object.keys(t),u=l(o);e.showHidden&&(o=Object.getOwnPropertyNames(t));if(L(t)&&(o.indexOf("message")>=0||o.indexOf("description")>=0))return p(t);if(o.length===0){if(A(t)){var a=t.name?": "+t.name:"";return e.stylize("[Function"+a+"]","special")}if(N(t))return e.stylize(RegExp.prototype.toString.call(t),"regexp");if(k(t))return e.stylize(Date.prototype.toString.call(t),"date");if(L(t))return p(t)}var f="",y=!1,b=["{","}"];g(t)&&(y=!0,b=["[","]"]);if(A(t)){var w=t.name?": "+t.name:"";f=" [Function"+w+"]"}N(t)&&(f=" "+RegExp.prototype.toString.call(t)),k(t)&&(f=" "+Date.prototype.toUTCString.call(t)),L(t)&&(f=" "+p(t));if(o.length!==0||!!y&&t.length!=0){if(r<0)return N(t)?e.stylize(RegExp.prototype.toString.call(t),"regexp"):e.stylize("[Object]","special");e.seen.push(t);var E;return y?E=d(e,t,r,u,o):E=o.map(function(n){return v(e,t,r,u,n,y)}),e.seen.pop(),m(E,f,b)}return b[0]+f+b[1]}function h(e,t){if(T(t))return e.stylize("undefined","undefined");if(S(t)){var n="'"+JSON.stringify(t).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return e.stylize(n,"string")}if(E(t))return e.stylize(""+t,"number");if(y(t))return e.stylize(""+t,"boolean");if(b(t))return e.stylize("null","null")}function p(e){return"["+Error.prototype.toString.call(e)+"]"}function d(e,t,n,r,i){var s=[];for(var o=0,u=t.length;o<u;++o)H(t,String(o))?s.push(v(e,t,n,r,String(o),!0)):s.push("");return i.forEach(function(i){i.match(/^\d+$/)||s.push(v(e,t,n,r,i,!0))}),s}function v(e,t,n,r,i,s){var o,u,a;a=Object.getOwnPropertyDescriptor(t,i)||{value:t[i]},a.get?a.set?u=e.stylize("[Getter/Setter]","special"):u=e.stylize("[Getter]","special"):a.set&&(u=e.stylize("[Setter]","special")),H(r,i)||(o="["+i+"]"),u||(e.seen.indexOf(a.value)<0?(b(n)?u=c(e,a.value,null):u=c(e,a.value,n-1),u.indexOf("\n")>-1&&(s?u=u.split("\n").map(function(e){return"  "+e}).join("\n").substr(2):u="\n"+u.split("\n").map(function(e){return"   "+e}).join("\n"))):u=e.stylize("[Circular]","special"));if(T(o)){if(s&&i.match(/^\d+$/))return u;o=JSON.stringify(""+i),o.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(o=o.substr(1,o.length-2),o=e.stylize(o,"name")):(o=o.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),o=e.stylize(o,"string"))}return o+": "+u}function m(e,t,n){var r=0,i=e.reduce(function(e,t){return r++,t.indexOf("\n")>=0&&r++,e+t.replace(/\u001b\[\d\d?m/g,"").length+1},0);return i>60?n[0]+(t===""?"":t+"\n ")+" "+e.join(",\n  ")+" "+n[1]:n[0]+t+" "+e.join(", ")+" "+n[1]}function g(e){return Array.isArray(e)}function y(e){return typeof e=="boolean"}function b(e){return e===null}function w(e){return e==null}function E(e){return typeof e=="number"}function S(e){return typeof e=="string"}function x(e){return typeof e=="symbol"}function T(e){return e===void 0}function N(e){return C(e)&&M(e)==="[object RegExp]"}function C(e){return typeof e=="object"&&e!==null}function k(e){return C(e)&&M(e)==="[object Date]"}function L(e){return C(e)&&(M(e)==="[object Error]"||e instanceof Error)}function A(e){return typeof e=="function"}function O(e){return e===null||typeof e=="boolean"||typeof e=="number"||typeof e=="string"||typeof e=="symbol"||typeof e=="undefined"}function M(e){return Object.prototype.toString.call(e)}function _(e){return e<10?"0"+e.toString(10):e.toString(10)}function P(){var e=new Date,t=[_(e.getHours()),_(e.getMinutes()),_(e.getSeconds())].join(":");return[e.getDate(),D[e.getMonth()],t].join(" ")}function H(e,t){return Object.prototype.hasOwnProperty.call(e,t)}var i=/%[sdj%]/g;n.format=function(e){if(!S(e)){var t=[];for(var n=0;n<arguments.length;n++)t.push(u(arguments[n]));return t.join(" ")}var n=1,r=arguments,s=r.length,o=String(e).replace(i,function(e){if(e==="%%")return"%";if(n>=s)return e;switch(e){case"%s":return String(r[n++]);case"%d":return Number(r[n++]);case"%j":try{return JSON.stringify(r[n++])}catch(t){return"[Circular]"};default:return e}});for(var a=r[n];n<s;a=r[++n])b(a)||!C(a)?o+=" "+a:o+=" "+u(a);return o},n.deprecate=function(e,i){function o(){if(!s){if(t.throwDeprecation)throw new Error(i);t.traceDeprecation?console.trace(i):console.error(i),s=!0}return e.apply(this,arguments)}if(T(r.process))return function(){return n.deprecate(e,i).apply(this,arguments)};if(t.noDeprecation===!0)return e;var s=!1;return o};var s={},o;n.debuglog=function(e){T(o)&&(o=t.env.NODE_DEBUG||""),e=e.toUpperCase();if(!s[e])if((new RegExp("\\b"+e+"\\b","i")).test(o)){var r=t.pid;s[e]=function(){var t=n.format.apply(n,arguments);console.error("%s %d: %s",e,r,t)}}else s[e]=function(){};return s[e]},n.inspect=u,u.colors={bold:[1,22],italic:[3,23],underline:[4,24],inverse:[7,27],white:[37,39],grey:[90,39],black:[30,39],blue:[34,39],cyan:[36,39],green:[32,39],magenta:[35,39],red:[31,39],yellow:[33,39]},u.styles={special:"cyan",number:"yellow","boolean":"yellow","undefined":"grey","null":"bold",string:"green",date:"magenta",regexp:"red"},n.isArray=g,n.isBoolean=y,n.isNull=b,n.isNullOrUndefined=w,n.isNumber=E,n.isString=S,n.isSymbol=x,n.isUndefined=T,n.isRegExp=N,n.isObject=C,n.isDate=k,n.isError=L,n.isFunction=A,n.isPrimitive=O,n.isBuffer=e("./support/isBuffer");var D=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];n.log=function(){console.log("%s - %s",P(),n.format.apply(n,arguments))},n.inherits=e("inherits"),n._extend=function(e,t){if(!t||!C(t))return e;var n=Object.keys(t),r=n.length;while(r--)e[n[r]]=t[n[r]];return e}}).call(this,e("/usr/local/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js"),typeof self!="undefined"?self:typeof window!="undefined"?window:{})},{"./support/isBuffer":14,"/usr/local/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":18,inherits:17}],16:[function(e,t,n){function r(){this._events=this._events||{},this._maxListeners=this._maxListeners||undefined}function i(e){return typeof e=="function"}function s(e){return typeof e=="number"}function o(e){return typeof e=="object"&&e!==null}function u(e){return e===void 0}t.exports=r,r.EventEmitter=r,r.prototype._events=undefined,r.prototype._maxListeners=undefined,r.defaultMaxListeners=10,r.prototype.setMaxListeners=function(e){if(!s(e)||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},r.prototype.emit=function(e){var t,n,r,s,a,f;this._events||(this._events={});if(e==="error")if(!this._events.error||o(this._events.error)&&!this._events.error.length)throw t=arguments[1],t instanceof Error?t:TypeError('Uncaught, unspecified "error" event.');n=this._events[e];if(u(n))return!1;if(i(n))switch(arguments.length){case 1:n.call(this);break;case 2:n.call(this,arguments[1]);break;case 3:n.call(this,arguments[1],arguments[2]);break;default:r=arguments.length,s=new Array(r-1);for(a=1;a<r;a++)s[a-1]=arguments[a];n.apply(this,s)}else if(o(n)){r=arguments.length,s=new Array(r-1);for(a=1;a<r;a++)s[a-1]=arguments[a];f=n.slice(),r=f.length;for(a=0;a<r;a++)f[a].apply(this,s)}return!0},r.prototype.addListener=function(e,t){var n;if(!i(t))throw TypeError("listener must be a function");this._events||(this._events={}),this._events.newListener&&this.emit("newListener",e,i(t.listener)?t.listener:t),this._events[e]?o(this._events[e])?this._events[e].push(t):this._events[e]=[this._events[e],t]:this._events[e]=t;if(o(this._events[e])&&!this._events[e].warned){var n;u(this._maxListeners)?n=r.defaultMaxListeners:n=this._maxListeners,n&&n>0&&this._events[e].length>n&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),console.trace())}return this},r.prototype.on=r.prototype.addListener,r.prototype.once=function(e,t){function r(){this.removeListener(e,r),n||(n=!0,t.apply(this,arguments))}if(!i(t))throw TypeError("listener must be a function");var n=!1;return r.listener=t,this.on(e,r),this},r.prototype.removeListener=function(e,t){var n,r,s,u;if(!i(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;n=this._events[e],s=n.length,r=-1;if(n===t||i(n.listener)&&n.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(o(n)){for(u=s;u-->0;)if(n[u]===t||n[u].listener&&n[u].listener===t){r=u;break}if(r<0)return this;n.length===1?(n.length=0,delete this._events[e]):n.splice(r,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},r.prototype.removeAllListeners=function(e){var t,n;if(!this._events)return this;if(!this._events.removeListener)return arguments.length===0?this._events={}:this._events[e]&&delete this._events[e],this;if(arguments.length===0){for(t in this._events){if(t==="removeListener")continue;this.removeAllListeners(t)}return this.removeAllListeners("removeListener"),this._events={},this}n=this._events[e];if(i(n))this.removeListener(e,n);else while(n.length)this.removeListener(e,n[n.length-1]);return delete this._events[e],this},r.prototype.listeners=function(e){var t;return!this._events||!this._events[e]?t=[]:i(this._events[e])?t=[this._events[e]]:t=this._events[e].slice(),t},r.listenerCount=function(e,t){var n;return!e._events||!e._events[t]?n=0:i(e._events[t])?n=1:n=e._events[t].length,n}},{}],17:[function(e,t,n){typeof Object.create=="function"?t.exports=function(t,n){t.super_=n,t.prototype=Object.create(n.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}})}:t.exports=function(t,n){t.super_=n;var r=function(){};r.prototype=n.prototype,t.prototype=new r,t.prototype.constructor=t}},{}],18:[function(e,t,n){function i(){}var r=t.exports={};r.nextTick=function(){var e=typeof window!="undefined"&&window.setImmediate,t=typeof window!="undefined"&&window.postMessage&&window.addEventListener;if(e)return function(e){return window.setImmediate(e)};if(t){var n=[];return window.addEventListener("message",function(e){var t=e.source;if((t===window||t===null)&&e.data==="process-tick"){e.stopPropagation();if(n.length>0){var r=n.shift();r()}}},!0),function(t){n.push(t),window.postMessage("process-tick","*")}}return function(t){setTimeout(t,0)}}(),r.title="browser",r.browser=!0,r.env={},r.argv=[],r.on=i,r.once=i,r.off=i,r.emit=i,r.binding=function(e){throw new Error("process.binding is not supported")},r.cwd=function(){return"/"},r.chdir=function(e){throw new Error("process.chdir is not supported")}},{}],19:[function(e,t,n){t.exports=e(14)},{}],20:[function(e,t,n){t.exports=e(15)},{"./support/isBuffer":19,"/usr/local/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":18,inherits:17}]},{},[9])(9)}),ace.define("ace/mode/html_worker",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/worker/mirror","ace/mode/html/saxparser"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../lib/lang"),s=e("../worker/mirror").Mirror,o=e("./html/saxparser").SAXParser,u={"expected-doctype-but-got-start-tag":"info","expected-doctype-but-got-chars":"info","non-html-root":"info"},a=t.Worker=function(e){s.call(this,e),this.setTimeout(400),this.context=null};r.inherits(a,s),function(){this.setOptions=function(e){this.context=e.context},this.onUpdate=function(){var e=this.doc.getValue();if(!e)return;var t=new o,n=[],r=function(){};t.contentHandler={startDocument:r,endDocument:r,startElement:r,endElement:r,characters:r},t.errorHandler={error:function(e,t,r){n.push({row:t.line,column:t.column,text:e,type:u[r]||"error"})}},this.context?t.parseFragment(e,this.context):t.parse(e),this.sender.emit("error",n)}}.call(a.prototype)}),ace.define("ace/lib/es5-shim",["require","exports","module"],function(e,t,n){function r(){}function w(e){try{return Object.defineProperty(e,"sentinel",{}),"sentinel"in e}catch(t){}}function H(e){return e=+e,e!==e?e=0:e!==0&&e!==1/0&&e!==-1/0&&(e=(e>0||-1)*Math.floor(Math.abs(e))),e}function B(e){var t=typeof e;return e===null||t==="undefined"||t==="boolean"||t==="number"||t==="string"}function j(e){var t,n,r;if(B(e))return e;n=e.valueOf;if(typeof n=="function"){t=n.call(e);if(B(t))return t}r=e.toString;if(typeof r=="function"){t=r.call(e);if(B(t))return t}throw new TypeError}Function.prototype.bind||(Function.prototype.bind=function(t){var n=this;if(typeof n!="function")throw new TypeError("Function.prototype.bind called on incompatible "+n);var i=u.call(arguments,1),s=function(){if(this instanceof s){var e=n.apply(this,i.concat(u.call(arguments)));return Object(e)===e?e:this}return n.apply(t,i.concat(u.call(arguments)))};return n.prototype&&(r.prototype=n.prototype,s.prototype=new r,r.prototype=null),s});var i=Function.prototype.call,s=Array.prototype,o=Object.prototype,u=s.slice,a=i.bind(o.toString),f=i.bind(o.hasOwnProperty),l,c,h,p,d;if(d=f(o,"__defineGetter__"))l=i.bind(o.__defineGetter__),c=i.bind(o.__defineSetter__),h=i.bind(o.__lookupGetter__),p=i.bind(o.__lookupSetter__);if([1,2].splice(0).length!=2)if(!function(){function e(e){var t=new Array(e+2);return t[0]=t[1]=0,t}var t=[],n;t.splice.apply(t,e(20)),t.splice.apply(t,e(26)),n=t.length,t.splice(5,0,"XXX"),n+1==t.length;if(n+1==t.length)return!0}())Array.prototype.splice=function(e,t){var n=this.length;e>0?e>n&&(e=n):e==void 0?e=0:e<0&&(e=Math.max(n+e,0)),e+t<n||(t=n-e);var r=this.slice(e,e+t),i=u.call(arguments,2),s=i.length;if(e===n)s&&this.push.apply(this,i);else{var o=Math.min(t,n-e),a=e+o,f=a+s-o,l=n-a,c=n-o;if(f<a)for(var h=0;h<l;++h)this[f+h]=this[a+h];else if(f>a)for(h=l;h--;)this[f+h]=this[a+h];if(s&&e===c)this.length=c,this.push.apply(this,i);else{this.length=c+s;for(h=0;h<s;++h)this[e+h]=i[h]}}return r};else{var v=Array.prototype.splice;Array.prototype.splice=function(e,t){return arguments.length?v.apply(this,[e===void 0?0:e,t===void 0?this.length-e:t].concat(u.call(arguments,2))):[]}}Array.isArray||(Array.isArray=function(t){return a(t)=="[object Array]"});var m=Object("a"),g=m[0]!="a"||!(0 in m);Array.prototype.forEach||(Array.prototype.forEach=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=arguments[1],s=-1,o=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError;while(++s<o)s in r&&t.call(i,r[s],s,n)}),Array.prototype.map||(Array.prototype.map=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=Array(i),o=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var u=0;u<i;u++)u in r&&(s[u]=t.call(o,r[u],u,n));return s}),Array.prototype.filter||(Array.prototype.filter=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=[],o,u=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var f=0;f<i;f++)f in r&&(o=r[f],t.call(u,o,f,n)&&s.push(o));return s}),Array.prototype.every||(Array.prototype.every=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&!t.call(s,r[o],o,n))return!1;return!0}),Array.prototype.some||(Array.prototype.some=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&t.call(s,r[o],o,n))return!0;return!1}),Array.prototype.reduce||(Array.prototype.reduce=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduce of empty array with no initial value");var s=0,o;if(arguments.length>=2)o=arguments[1];else do{if(s in r){o=r[s++];break}if(++s>=i)throw new TypeError("reduce of empty array with no initial value")}while(!0);for(;s<i;s++)s in r&&(o=t.call(void 0,o,r[s],s,n));return o}),Array.prototype.reduceRight||(Array.prototype.reduceRight=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduceRight of empty array with no initial value");var s,o=i-1;if(arguments.length>=2)s=arguments[1];else do{if(o in r){s=r[o--];break}if(--o<0)throw new TypeError("reduceRight of empty array with no initial value")}while(!0);do o in this&&(s=t.call(void 0,s,r[o],o,n));while(o--);return s});if(!Array.prototype.indexOf||[0,1].indexOf(1,2)!=-1)Array.prototype.indexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=0;arguments.length>1&&(i=H(arguments[1])),i=i>=0?i:Math.max(0,r+i);for(;i<r;i++)if(i in n&&n[i]===t)return i;return-1};if(!Array.prototype.lastIndexOf||[0,1].lastIndexOf(0,-3)!=-1)Array.prototype.lastIndexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=r-1;arguments.length>1&&(i=Math.min(i,H(arguments[1]))),i=i>=0?i:r-Math.abs(i);for(;i>=0;i--)if(i in n&&t===n[i])return i;return-1};Object.getPrototypeOf||(Object.getPrototypeOf=function(t){return t.__proto__||(t.constructor?t.constructor.prototype:o)});if(!Object.getOwnPropertyDescriptor){var y="Object.getOwnPropertyDescriptor called on a non-object: ";Object.getOwnPropertyDescriptor=function(t,n){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(y+t);if(!f(t,n))return;var r,i,s;r={enumerable:!0,configurable:!0};if(d){var u=t.__proto__;t.__proto__=o;var i=h(t,n),s=p(t,n);t.__proto__=u;if(i||s)return i&&(r.get=i),s&&(r.set=s),r}return r.value=t[n],r}}Object.getOwnPropertyNames||(Object.getOwnPropertyNames=function(t){return Object.keys(t)});if(!Object.create){var b;Object.prototype.__proto__===null?b=function(){return{__proto__:null}}:b=function(){var e={};for(var t in e)e[t]=null;return e.constructor=e.hasOwnProperty=e.propertyIsEnumerable=e.isPrototypeOf=e.toLocaleString=e.toString=e.valueOf=e.__proto__=null,e},Object.create=function(t,n){var r;if(t===null)r=b();else{if(typeof t!="object")throw new TypeError("typeof prototype["+typeof t+"] != 'object'");var i=function(){};i.prototype=t,r=new i,r.__proto__=t}return n!==void 0&&Object.defineProperties(r,n),r}}if(Object.defineProperty){var E=w({}),S=typeof document=="undefined"||w(document.createElement("div"));if(!E||!S)var x=Object.defineProperty}if(!Object.defineProperty||x){var T="Property description must be an object: ",N="Object.defineProperty called on non-object: ",C="getters & setters can not be defined on this javascript engine";Object.defineProperty=function(t,n,r){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(N+t);if(typeof r!="object"&&typeof r!="function"||r===null)throw new TypeError(T+r);if(x)try{return x.call(Object,t,n,r)}catch(i){}if(f(r,"value"))if(d&&(h(t,n)||p(t,n))){var s=t.__proto__;t.__proto__=o,delete t[n],t[n]=r.value,t.__proto__=s}else t[n]=r.value;else{if(!d)throw new TypeError(C);f(r,"get")&&l(t,n,r.get),f(r,"set")&&c(t,n,r.set)}return t}}Object.defineProperties||(Object.defineProperties=function(t,n){for(var r in n)f(n,r)&&Object.defineProperty(t,r,n[r]);return t}),Object.seal||(Object.seal=function(t){return t}),Object.freeze||(Object.freeze=function(t){return t});try{Object.freeze(function(){})}catch(k){Object.freeze=function(t){return function(n){return typeof n=="function"?n:t(n)}}(Object.freeze)}Object.preventExtensions||(Object.preventExtensions=function(t){return t}),Object.isSealed||(Object.isSealed=function(t){return!1}),Object.isFrozen||(Object.isFrozen=function(t){return!1}),Object.isExtensible||(Object.isExtensible=function(t){if(Object(t)===t)throw new TypeError;var n="";while(f(t,n))n+="?";t[n]=!0;var r=f(t,n);return delete t[n],r});if(!Object.keys){var L=!0,A=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],O=A.length;for(var M in{toString:null})L=!1;Object.keys=function I(e){if(typeof e!="object"&&typeof e!="function"||e===null)throw new TypeError("Object.keys called on a non-object");var I=[];for(var t in e)f(e,t)&&I.push(t);if(L)for(var n=0,r=O;n<r;n++){var i=A[n];f(e,i)&&I.push(i)}return I}}Date.now||(Date.now=function(){return(new Date).getTime()});var _="	\n\f\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\ufeff";if(!String.prototype.trim||_.trim()){_="["+_+"]";var D=new RegExp("^"+_+_+"*"),P=new RegExp(_+_+"*$");String.prototype.trim=function(){return String(this).replace(D,"").replace(P,"")}}var F=function(e){if(e==null)throw new TypeError("can't convert "+e+" to object");return Object(e)}})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-javascript.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-javascript.js
new file mode 100644
index 0000000..bca38f0
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-javascript.js
@@ -0,0 +1 @@
+"no use strict";(function(e){function t(e,t){var n=e,r="";while(n){var i=t[n];if(typeof i=="string")return i+r;if(i)return i.location.replace(/\/*$/,"/")+(r||i.main||i.name);if(i===!1)return"";var s=n.lastIndexOf("/");if(s===-1)break;r=n.substr(s)+r,n=n.slice(0,s)}return e}if(typeof e.window!="undefined"&&e.document)return;if(e.require&&e.define)return;e.console||(e.console=function(){var e=Array.prototype.slice.call(arguments,0);postMessage({type:"log",data:e})},e.console.error=e.console.warn=e.console.log=e.console.trace=e.console),e.window=e,e.ace=e,e.onerror=function(e,t,n,r,i){postMessage({type:"error",data:{message:e,data:i.data,file:t,line:n,col:r,stack:i.stack}})},e.normalizeModule=function(t,n){if(n.indexOf("!")!==-1){var r=n.split("!");return e.normalizeModule(t,r[0])+"!"+e.normalizeModule(t,r[1])}if(n.charAt(0)=="."){var i=t.split("/").slice(0,-1).join("/");n=(i?i+"/":"")+n;while(n.indexOf(".")!==-1&&s!=n){var s=n;n=n.replace(/^\.\//,"").replace(/\/\.\//,"/").replace(/[^\/]+\/\.\.\//,"")}}return n},e.require=function(r,i){i||(i=r,r=null);if(!i.charAt)throw new Error("worker.js require() accepts only (parentId, id) as arguments");i=e.normalizeModule(r,i);var s=e.require.modules[i];if(s)return s.initialized||(s.initialized=!0,s.exports=s.factory().exports),s.exports;if(!e.require.tlns)return console.log("unable to load "+i);var o=t(i,e.require.tlns);return o.slice(-3)!=".js"&&(o+=".js"),e.require.id=i,e.require.modules[i]={},importScripts(o),e.require(r,i)},e.require.modules={},e.require.tlns={},e.define=function(t,n,r){arguments.length==2?(r=n,typeof t!="string"&&(n=t,t=e.require.id)):arguments.length==1&&(r=t,n=[],t=e.require.id);if(typeof r!="function"){e.require.modules[t]={exports:r,initialized:!0};return}n.length||(n=["require","exports","module"]);var i=function(n){return e.require(t,n)};e.require.modules[t]={exports:{},factory:function(){var e=this,t=r.apply(this,n.map(function(t){switch(t){case"require":return i;case"exports":return e.exports;case"module":return e;default:return i(t)}}));return t&&(e.exports=t),e}}},e.define.amd={},require.tlns={},e.initBaseUrls=function(t){for(var n in t)require.tlns[n]=t[n]},e.initSender=function(){var n=e.require("ace/lib/event_emitter").EventEmitter,r=e.require("ace/lib/oop"),i=function(){};return function(){r.implement(this,n),this.callback=function(e,t){postMessage({type:"call",id:t,data:e})},this.emit=function(e,t){postMessage({type:"event",name:e,data:t})}}.call(i.prototype),new i};var n=e.main=null,r=e.sender=null;e.onmessage=function(t){var i=t.data;if(i.event&&r)r._signal(i.event,i.data);else if(i.command)if(n[i.command])n[i.command].apply(n,i.args);else{if(!e[i.command])throw new Error("Unknown command:"+i.command);e[i.command].apply(e,i.args)}else if(i.init){e.initBaseUrls(i.tlns),require("ace/lib/es5-shim"),r=e.sender=e.initSender();var s=require(i.module)[i.classname];n=e.main=new s(r)}}})(this),ace.define("ace/lib/oop",["require","exports","module"],function(e,t,n){"use strict";t.inherits=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})},t.mixin=function(e,t){for(var n in t)e[n]=t[n];return e},t.implement=function(e,n){t.mixin(e,n)}}),ace.define("ace/range",["require","exports","module"],function(e,t,n){"use strict";var r=function(e,t){return e.row-t.row||e.column-t.column},i=function(e,t,n,r){this.start={row:e,column:t},this.end={row:n,column:r}};(function(){this.isEqual=function(e){return this.start.row===e.start.row&&this.end.row===e.end.row&&this.start.column===e.start.column&&this.end.column===e.end.column},this.toString=function(){return"Range: ["+this.start.row+"/"+this.start.column+"] -> ["+this.end.row+"/"+this.end.column+"]"},this.contains=function(e,t){return this.compare(e,t)==0},this.compareRange=function(e){var t,n=e.end,r=e.start;return t=this.compare(n.row,n.column),t==1?(t=this.compare(r.row,r.column),t==1?2:t==0?1:0):t==-1?-2:(t=this.compare(r.row,r.column),t==-1?-1:t==1?42:0)},this.comparePoint=function(e){return this.compare(e.row,e.column)},this.containsRange=function(e){return this.comparePoint(e.start)==0&&this.comparePoint(e.end)==0},this.intersects=function(e){var t=this.compareRange(e);return t==-1||t==0||t==1},this.isEnd=function(e,t){return this.end.row==e&&this.end.column==t},this.isStart=function(e,t){return this.start.row==e&&this.start.column==t},this.setStart=function(e,t){typeof e=="object"?(this.start.column=e.column,this.start.row=e.row):(this.start.row=e,this.start.column=t)},this.setEnd=function(e,t){typeof e=="object"?(this.end.column=e.column,this.end.row=e.row):(this.end.row=e,this.end.column=t)},this.inside=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)||this.isStart(e,t)?!1:!0:!1},this.insideStart=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)?!1:!0:!1},this.insideEnd=function(e,t){return this.compare(e,t)==0?this.isStart(e,t)?!1:!0:!1},this.compare=function(e,t){return!this.isMultiLine()&&e===this.start.row?t<this.start.column?-1:t>this.end.column?1:0:e<this.start.row?-1:e>this.end.row?1:this.start.row===e?t>=this.start.column?0:-1:this.end.row===e?t<=this.end.column?0:1:0},this.compareStart=function(e,t){return this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.compareEnd=function(e,t){return this.end.row==e&&this.end.column==t?1:this.compare(e,t)},this.compareInside=function(e,t){return this.end.row==e&&this.end.column==t?1:this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.clipRows=function(e,t){if(this.end.row>t)var n={row:t+1,column:0};else if(this.end.row<e)var n={row:e,column:0};if(this.start.row>t)var r={row:t+1,column:0};else if(this.start.row<e)var r={row:e,column:0};return i.fromPoints(r||this.start,n||this.end)},this.extend=function(e,t){var n=this.compare(e,t);if(n==0)return this;if(n==-1)var r={row:e,column:t};else var s={row:e,column:t};return i.fromPoints(r||this.start,s||this.end)},this.isEmpty=function(){return this.start.row===this.end.row&&this.start.column===this.end.column},this.isMultiLine=function(){return this.start.row!==this.end.row},this.clone=function(){return i.fromPoints(this.start,this.end)},this.collapseRows=function(){return this.end.column==0?new i(this.start.row,0,Math.max(this.start.row,this.end.row-1),0):new i(this.start.row,0,this.end.row,0)},this.toScreenRange=function(e){var t=e.documentToScreenPosition(this.start),n=e.documentToScreenPosition(this.end);return new i(t.row,t.column,n.row,n.column)},this.moveBy=function(e,t){this.start.row+=e,this.start.column+=t,this.end.row+=e,this.end.column+=t}}).call(i.prototype),i.fromPoints=function(e,t){return new i(e.row,e.column,t.row,t.column)},i.comparePoints=r,i.comparePoints=function(e,t){return e.row-t.row||e.column-t.column},t.Range=i}),ace.define("ace/apply_delta",["require","exports","module"],function(e,t,n){"use strict";function r(e,t){throw console.log("Invalid Delta:",e),"Invalid Delta: "+t}function i(e,t){return t.row>=0&&t.row<e.length&&t.column>=0&&t.column<=e[t.row].length}function s(e,t){t.action!="insert"&&t.action!="remove"&&r(t,"delta.action must be 'insert' or 'remove'"),t.lines instanceof Array||r(t,"delta.lines must be an Array"),(!t.start||!t.end)&&r(t,"delta.start/end must be an present");var n=t.start;i(e,t.start)||r(t,"delta.start must be contained in document");var s=t.end;t.action=="remove"&&!i(e,s)&&r(t,"delta.end must contained in document for 'remove' actions");var o=s.row-n.row,u=s.column-(o==0?n.column:0);(o!=t.lines.length-1||t.lines[o].length!=u)&&r(t,"delta.range must match delta lines")}t.applyDelta=function(e,t,n){var r=t.start.row,i=t.start.column,s=e[r]||"";switch(t.action){case"insert":var o=t.lines;if(o.length===1)e[r]=s.substring(0,i)+t.lines[0]+s.substring(i);else{var u=[r,1].concat(t.lines);e.splice.apply(e,u),e[r]=s.substring(0,i)+e[r],e[r+t.lines.length-1]+=s.substring(i)}break;case"remove":var a=t.end.column,f=t.end.row;r===f?e[r]=s.substring(0,i)+s.substring(a):e.splice(r,f-r+1,s.substring(0,i)+e[f].substring(a))}}}),ace.define("ace/lib/event_emitter",["require","exports","module"],function(e,t,n){"use strict";var r={},i=function(){this.propagationStopped=!0},s=function(){this.defaultPrevented=!0};r._emit=r._dispatchEvent=function(e,t){this._eventRegistry||(this._eventRegistry={}),this._defaultHandlers||(this._defaultHandlers={});var n=this._eventRegistry[e]||[],r=this._defaultHandlers[e];if(!n.length&&!r)return;if(typeof t!="object"||!t)t={};t.type||(t.type=e),t.stopPropagation||(t.stopPropagation=i),t.preventDefault||(t.preventDefault=s),n=n.slice();for(var o=0;o<n.length;o++){n[o](t,this);if(t.propagationStopped)break}if(r&&!t.defaultPrevented)return r(t,this)},r._signal=function(e,t){var n=(this._eventRegistry||{})[e];if(!n)return;n=n.slice();for(var r=0;r<n.length;r++)n[r](t,this)},r.once=function(e,t){var n=this;t&&this.addEventListener(e,function r(){n.removeEventListener(e,r),t.apply(null,arguments)})},r.setDefaultHandler=function(e,t){var n=this._defaultHandlers;n||(n=this._defaultHandlers={_disabled_:{}});if(n[e]){var r=n[e],i=n._disabled_[e];i||(n._disabled_[e]=i=[]),i.push(r);var s=i.indexOf(t);s!=-1&&i.splice(s,1)}n[e]=t},r.removeDefaultHandler=function(e,t){var n=this._defaultHandlers;if(!n)return;var r=n._disabled_[e];if(n[e]==t){var i=n[e];r&&this.setDefaultHandler(e,r.pop())}else if(r){var s=r.indexOf(t);s!=-1&&r.splice(s,1)}},r.on=r.addEventListener=function(e,t,n){this._eventRegistry=this._eventRegistry||{};var r=this._eventRegistry[e];return r||(r=this._eventRegistry[e]=[]),r.indexOf(t)==-1&&r[n?"unshift":"push"](t),t},r.off=r.removeListener=r.removeEventListener=function(e,t){this._eventRegistry=this._eventRegistry||{};var n=this._eventRegistry[e];if(!n)return;var r=n.indexOf(t);r!==-1&&n.splice(r,1)},r.removeAllListeners=function(e){this._eventRegistry&&(this._eventRegistry[e]=[])},t.EventEmitter=r}),ace.define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=t.Anchor=function(e,t,n){this.$onChange=this.onChange.bind(this),this.attach(e),typeof n=="undefined"?this.setPosition(t.row,t.column):this.setPosition(t,n)};(function(){function e(e,t,n){var r=n?e.column<=t.column:e.column<t.column;return e.row<t.row||e.row==t.row&&r}function t(t,n,r){var i=t.action=="insert",s=(i?1:-1)*(t.end.row-t.start.row),o=(i?1:-1)*(t.end.column-t.start.column),u=t.start,a=i?u:t.end;return e(n,u,r)?{row:n.row,column:n.column}:e(a,n,!r)?{row:n.row+s,column:n.column+(n.row==a.row?o:0)}:{row:u.row,column:u.column}}r.implement(this,i),this.getPosition=function(){return this.$clipPositionToDocument(this.row,this.column)},this.getDocument=function(){return this.document},this.$insertRight=!1,this.onChange=function(e){if(e.start.row==e.end.row&&e.start.row!=this.row)return;if(e.start.row>this.row)return;var n=t(e,{row:this.row,column:this.column},this.$insertRight);this.setPosition(n.row,n.column,!0)},this.setPosition=function(e,t,n){var r;n?r={row:e,column:t}:r=this.$clipPositionToDocument(e,t);if(this.row==r.row&&this.column==r.column)return;var i={row:this.row,column:this.column};this.row=r.row,this.column=r.column,this._signal("change",{old:i,value:r})},this.detach=function(){this.document.removeEventListener("change",this.$onChange)},this.attach=function(e){this.document=e||this.document,this.document.on("change",this.$onChange)},this.$clipPositionToDocument=function(e,t){var n={};return e>=this.document.getLength()?(n.row=Math.max(0,this.document.getLength()-1),n.column=this.document.getLine(n.row).length):e<0?(n.row=0,n.column=0):(n.row=e,n.column=Math.min(this.document.getLine(n.row).length,Math.max(0,t))),t<0&&(n.column=0),n}}).call(s.prototype)}),ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./apply_delta").applyDelta,s=e("./lib/event_emitter").EventEmitter,o=e("./range").Range,u=e("./anchor").Anchor,a=function(e){this.$lines=[""],e.length===0?this.$lines=[""]:Array.isArray(e)?this.insertMergedLines({row:0,column:0},e):this.insert({row:0,column:0},e)};(function(){r.implement(this,s),this.setValue=function(e){var t=this.getLength()-1;this.remove(new o(0,0,t,this.getLine(t).length)),this.insert({row:0,column:0},e)},this.getValue=function(){return this.getAllLines().join(this.getNewLineCharacter())},this.createAnchor=function(e,t){return new u(this,e,t)},"aaa".split(/a/).length===0?this.$split=function(e){return e.replace(/\r\n|\r/g,"\n").split("\n")}:this.$split=function(e){return e.split(/\r\n|\r|\n/)},this.$detectNewLine=function(e){var t=e.match(/^.*?(\r\n|\r|\n)/m);this.$autoNewLine=t?t[1]:"\n",this._signal("changeNewLineMode")},this.getNewLineCharacter=function(){switch(this.$newLineMode){case"windows":return"\r\n";case"unix":return"\n";default:return this.$autoNewLine||"\n"}},this.$autoNewLine="",this.$newLineMode="auto",this.setNewLineMode=function(e){if(this.$newLineMode===e)return;this.$newLineMode=e,this._signal("changeNewLineMode")},this.getNewLineMode=function(){return this.$newLineMode},this.isNewLine=function(e){return e=="\r\n"||e=="\r"||e=="\n"},this.getLine=function(e){return this.$lines[e]||""},this.getLines=function(e,t){return this.$lines.slice(e,t+1)},this.getAllLines=function(){return this.getLines(0,this.getLength())},this.getLength=function(){return this.$lines.length},this.getTextRange=function(e){return this.getLinesForRange(e).join(this.getNewLineCharacter())},this.getLinesForRange=function(e){var t;if(e.start.row===e.end.row)t=[this.getLine(e.start.row).substring(e.start.column,e.end.column)];else{t=this.getLines(e.start.row,e.end.row),t[0]=(t[0]||"").substring(e.start.column);var n=t.length-1;e.end.row-e.start.row==n&&(t[n]=t[n].substring(0,e.end.column))}return t},this.insertLines=function(e,t){return console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."),this.insertFullLines(e,t)},this.removeLines=function(e,t){return console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."),this.removeFullLines(e,t)},this.insertNewLine=function(e){return console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead."),this.insertMergedLines(e,["",""])},this.insert=function(e,t){return this.getLength()<=1&&this.$detectNewLine(t),this.insertMergedLines(e,this.$split(t))},this.insertInLine=function(e,t){var n=this.clippedPos(e.row,e.column),r=this.pos(e.row,e.column+t.length);return this.applyDelta({start:n,end:r,action:"insert",lines:[t]},!0),this.clonePos(r)},this.clippedPos=function(e,t){var n=this.getLength();e===undefined?e=n:e<0?e=0:e>=n&&(e=n-1,t=undefined);var r=this.getLine(e);return t==undefined&&(t=r.length),t=Math.min(Math.max(t,0),r.length),{row:e,column:t}},this.clonePos=function(e){return{row:e.row,column:e.column}},this.pos=function(e,t){return{row:e,column:t}},this.$clipPosition=function(e){var t=this.getLength();return e.row>=t?(e.row=Math.max(0,t-1),e.column=this.getLine(t-1).length):(e.row=Math.max(0,e.row),e.column=Math.min(Math.max(e.column,0),this.getLine(e.row).length)),e},this.insertFullLines=function(e,t){e=Math.min(Math.max(e,0),this.getLength());var n=0;e<this.getLength()?(t=t.concat([""]),n=0):(t=[""].concat(t),e--,n=this.$lines[e].length),this.insertMergedLines({row:e,column:n},t)},this.insertMergedLines=function(e,t){var n=this.clippedPos(e.row,e.column),r={row:n.row+t.length-1,column:(t.length==1?n.column:0)+t[t.length-1].length};return this.applyDelta({start:n,end:r,action:"insert",lines:t}),this.clonePos(r)},this.remove=function(e){var t=this.clippedPos(e.start.row,e.start.column),n=this.clippedPos(e.end.row,e.end.column);return this.applyDelta({start:t,end:n,action:"remove",lines:this.getLinesForRange({start:t,end:n})}),this.clonePos(t)},this.removeInLine=function(e,t,n){var r=this.clippedPos(e,t),i=this.clippedPos(e,n);return this.applyDelta({start:r,end:i,action:"remove",lines:this.getLinesForRange({start:r,end:i})},!0),this.clonePos(r)},this.removeFullLines=function(e,t){e=Math.min(Math.max(0,e),this.getLength()-1),t=Math.min(Math.max(0,t),this.getLength()-1);var n=t==this.getLength()-1&&e>0,r=t<this.getLength()-1,i=n?e-1:e,s=n?this.getLine(i).length:0,u=r?t+1:t,a=r?0:this.getLine(u).length,f=new o(i,s,u,a),l=this.$lines.slice(e,t+1);return this.applyDelta({start:f.start,end:f.end,action:"remove",lines:this.getLinesForRange(f)}),l},this.removeNewLine=function(e){e<this.getLength()-1&&e>=0&&this.applyDelta({start:this.pos(e,this.getLine(e).length),end:this.pos(e+1,0),action:"remove",lines:["",""]})},this.replace=function(e,t){e instanceof o||(e=o.fromPoints(e.start,e.end));if(t.length===0&&e.isEmpty())return e.start;if(t==this.getTextRange(e))return e.end;this.remove(e);var n;return t?n=this.insert(e.start,t):n=e.start,n},this.applyDeltas=function(e){for(var t=0;t<e.length;t++)this.applyDelta(e[t])},this.revertDeltas=function(e){for(var t=e.length-1;t>=0;t--)this.revertDelta(e[t])},this.applyDelta=function(e,t){var n=e.action=="insert";if(n?e.lines.length<=1&&!e.lines[0]:!o.comparePoints(e.start,e.end))return;n&&e.lines.length>2e4&&this.$splitAndapplyLargeDelta(e,2e4),i(this.$lines,e,t),this._signal("change",e)},this.$splitAndapplyLargeDelta=function(e,t){var n=e.lines,r=n.length,i=e.start.row,s=e.start.column,o=0,u=0;do{o=u,u+=t-1;var a=n.slice(o,u);if(u>r){e.lines=a,e.start.row=i+o,e.start.column=s;break}a.push(""),this.applyDelta({start:this.pos(i+o,s),end:this.pos(i+u,s=0),action:e.action,lines:a},!0)}while(!0)},this.revertDelta=function(e){this.applyDelta({start:this.clonePos(e.start),end:this.clonePos(e.end),action:e.action=="insert"?"remove":"insert",lines:e.lines.slice()})},this.indexToPosition=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length;for(var i=t||0,s=n.length;i<s;i++){e-=n[i].length+r;if(e<0)return{row:i,column:e+n[i].length+r}}return{row:s-1,column:n[s-1].length}},this.positionToIndex=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length,i=0,s=Math.min(e.row,n.length);for(var o=t||0;o<s;++o)i+=n[o].length+r;return i+e.column}}).call(a.prototype),t.Document=a}),ace.define("ace/lib/lang",["require","exports","module"],function(e,t,n){"use strict";t.last=function(e){return e[e.length-1]},t.stringReverse=function(e){return e.split("").reverse().join("")},t.stringRepeat=function(e,t){var n="";while(t>0){t&1&&(n+=e);if(t>>=1)e+=e}return n};var r=/^\s\s*/,i=/\s\s*$/;t.stringTrimLeft=function(e){return e.replace(r,"")},t.stringTrimRight=function(e){return e.replace(i,"")},t.copyObject=function(e){var t={};for(var n in e)t[n]=e[n];return t},t.copyArray=function(e){var t=[];for(var n=0,r=e.length;n<r;n++)e[n]&&typeof e[n]=="object"?t[n]=this.copyObject(e[n]):t[n]=e[n];return t},t.deepCopy=function s(e){if(typeof e!="object"||!e)return e;var t;if(Array.isArray(e)){t=[];for(var n=0;n<e.length;n++)t[n]=s(e[n]);return t}var r=e.constructor;if(r===RegExp)return e;t=r();for(var n in e)t[n]=s(e[n]);return t},t.arrayToMap=function(e){var t={};for(var n=0;n<e.length;n++)t[e[n]]=1;return t},t.createMap=function(e){var t=Object.create(null);for(var n in e)t[n]=e[n];return t},t.arrayRemove=function(e,t){for(var n=0;n<=e.length;n++)t===e[n]&&e.splice(n,1)},t.escapeRegExp=function(e){return e.replace(/([.*+?^${}()|[\]\/\\])/g,"\\$1")},t.escapeHTML=function(e){return e.replace(/&/g,"&#38;").replace(/"/g,"&#34;").replace(/'/g,"&#39;").replace(/</g,"&#60;")},t.getMatchOffsets=function(e,t){var n=[];return e.replace(t,function(e){n.push({offset:arguments[arguments.length-2],length:e.length})}),n},t.deferredCall=function(e){var t=null,n=function(){t=null,e()},r=function(e){return r.cancel(),t=setTimeout(n,e||0),r};return r.schedule=r,r.call=function(){return this.cancel(),e(),r},r.cancel=function(){return clearTimeout(t),t=null,r},r.isPending=function(){return t},r},t.delayedCall=function(e,t){var n=null,r=function(){n=null,e()},i=function(e){n==null&&(n=setTimeout(r,e||t))};return i.delay=function(e){n&&clearTimeout(n),n=setTimeout(r,e||t)},i.schedule=i,i.call=function(){this.cancel(),e()},i.cancel=function(){n&&clearTimeout(n),n=null},i.isPending=function(){return n},i}}),ace.define("ace/worker/mirror",["require","exports","module","ace/range","ace/document","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../range").Range,i=e("../document").Document,s=e("../lib/lang"),o=t.Mirror=function(e){this.sender=e;var t=this.doc=new i(""),n=this.deferredUpdate=s.delayedCall(this.onUpdate.bind(this)),r=this;e.on("change",function(e){var i=e.data;if(i[0].start)t.applyDeltas(i);else for(var s=0;s<i.length;s+=2){if(Array.isArray(i[s+1]))var o={action:"insert",start:i[s],lines:i[s+1]};else var o={action:"remove",start:i[s],end:i[s+1]};t.applyDelta(o,!0)}if(r.$timeout)return n.schedule(r.$timeout);r.onUpdate()})};(function(){this.$timeout=500,this.setTimeout=function(e){this.$timeout=e},this.setValue=function(e){this.doc.setValue(e),this.deferredUpdate.schedule(this.$timeout)},this.getValue=function(e){this.sender.callback(this.doc.getValue(),e)},this.onUpdate=function(){},this.isPending=function(){return this.deferredUpdate.isPending()}}).call(o.prototype)}),ace.define("ace/mode/javascript/jshint",["require","exports","module"],function(e,t,n){n.exports=function r(t,n,i){function o(u,a){if(!n[u]){if(!t[u]){var f=typeof e=="function"&&e;if(!a&&f)return f(u,!0);if(s)return s(u,!0);var l=new Error("Cannot find module '"+u+"'");throw l.code="MODULE_NOT_FOUND",l}var c=n[u]={exports:{}};t[u][0].call(c.exports,function(e){var n=t[u][1][e];return o(n?n:e)},c,c.exports,r,t,n,i)}return n[u].exports}var s=typeof e=="function"&&e;for(var u=0;u<i.length;u++)o(i[u]);return o(i[0])}({"/node_modules/browserify/node_modules/events/events.js":[function(e,t,n){function r(){this._events=this._events||{},this._maxListeners=this._maxListeners||undefined}function i(e){return typeof e=="function"}function s(e){return typeof e=="number"}function o(e){return typeof e=="object"&&e!==null}function u(e){return e===void 0}t.exports=r,r.EventEmitter=r,r.prototype._events=undefined,r.prototype._maxListeners=undefined,r.defaultMaxListeners=10,r.prototype.setMaxListeners=function(e){if(!s(e)||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},r.prototype.emit=function(e){var t,n,r,s,a,f;this._events||(this._events={});if(e==="error")if(!this._events.error||o(this._events.error)&&!this._events.error.length)throw t=arguments[1],t instanceof Error?t:TypeError('Uncaught, unspecified "error" event.');n=this._events[e];if(u(n))return!1;if(i(n))switch(arguments.length){case 1:n.call(this);break;case 2:n.call(this,arguments[1]);break;case 3:n.call(this,arguments[1],arguments[2]);break;default:r=arguments.length,s=new Array(r-1);for(a=1;a<r;a++)s[a-1]=arguments[a];n.apply(this,s)}else if(o(n)){r=arguments.length,s=new Array(r-1);for(a=1;a<r;a++)s[a-1]=arguments[a];f=n.slice(),r=f.length;for(a=0;a<r;a++)f[a].apply(this,s)}return!0},r.prototype.addListener=function(e,t){var n;if(!i(t))throw TypeError("listener must be a function");this._events||(this._events={}),this._events.newListener&&this.emit("newListener",e,i(t.listener)?t.listener:t),this._events[e]?o(this._events[e])?this._events[e].push(t):this._events[e]=[this._events[e],t]:this._events[e]=t;if(o(this._events[e])&&!this._events[e].warned){var n;u(this._maxListeners)?n=r.defaultMaxListeners:n=this._maxListeners,n&&n>0&&this._events[e].length>n&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),typeof console.trace=="function"&&console.trace())}return this},r.prototype.on=r.prototype.addListener,r.prototype.once=function(e,t){function r(){this.removeListener(e,r),n||(n=!0,t.apply(this,arguments))}if(!i(t))throw TypeError("listener must be a function");var n=!1;return r.listener=t,this.on(e,r),this},r.prototype.removeListener=function(e,t){var n,r,s,u;if(!i(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;n=this._events[e],s=n.length,r=-1;if(n===t||i(n.listener)&&n.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(o(n)){for(u=s;u-->0;)if(n[u]===t||n[u].listener&&n[u].listener===t){r=u;break}if(r<0)return this;n.length===1?(n.length=0,delete this._events[e]):n.splice(r,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},r.prototype.removeAllListeners=function(e){var t,n;if(!this._events)return this;if(!this._events.removeListener)return arguments.length===0?this._events={}:this._events[e]&&delete this._events[e],this;if(arguments.length===0){for(t in this._events){if(t==="removeListener")continue;this.removeAllListeners(t)}return this.removeAllListeners("removeListener"),this._events={},this}n=this._events[e];if(i(n))this.removeListener(e,n);else while(n.length)this.removeListener(e,n[n.length-1]);return delete this._events[e],this},r.prototype.listeners=function(e){var t;return!this._events||!this._events[e]?t=[]:i(this._events[e])?t=[this._events[e]]:t=this._events[e].slice(),t},r.listenerCount=function(e,t){var n;return!e._events||!e._events[t]?n=0:i(e._events[t])?n=1:n=e._events[t].length,n}},{}],"/node_modules/jshint/data/ascii-identifier-data.js":[function(e,t,n){var r=[];for(var i=0;i<128;i++)r[i]=i===36||i>=65&&i<=90||i===95||i>=97&&i<=122;var s=[];for(var i=0;i<128;i++)s[i]=r[i]||i>=48&&i<=57;t.exports={asciiIdentifierStartTable:r,asciiIdentifierPartTable:s}},{}],"/node_modules/jshint/lodash.js":[function(e,t,n){(function(e){(function(){function $(e,t,n){var r=e.length,i=n?r:-1;while(n?i--:++i<r)if(t(e[i],i,e))return i;return-1}function J(e,t,n){if(t!==t)return G(e,n);var r=n-1,i=e.length;while(++r<i)if(e[r]===t)return r;return-1}function K(e){return typeof e=="function"||!1}function Q(e){return typeof e=="string"?e:e==null?"":e+""}function G(e,t,n){var r=e.length,i=t+(n?0:-1);while(n?i--:++i<r){var s=e[i];if(s!==s)return i}return-1}function Y(e){return!!e&&typeof e=="object"}function Ct(){}function Lt(e,t){var n=-1,r=e.length;t||(t=Array(r));while(++n<r)t[n]=e[n];return t}function At(e,t){var n=-1,r=e.length;while(++n<r)if(t(e[n],n,e)===!1)break;return e}function Ot(e,t){var n=-1,r=e.length,i=-1,s=[];while(++n<r){var o=e[n];t(o,n,e)&&(s[++i]=o)}return s}function Mt(e,t){var n=-1,r=e.length,i=Array(r);while(++n<r)i[n]=t(e[n],n,e);return i}function _t(e){var t=-1,n=e.length,r=wt;while(++t<n){var i=e[t];i>r&&(r=i)}return r}function Dt(e,t){var n=-1,r=e.length;while(++n<r)if(t(e[n],n,e))return!0;return!1}function Pt(e,t,n){var i=rr(t);lt.apply(i,bn(t));var s=-1,o=i.length;while(++s<o){var u=i[s],a=e[u],f=n(a,t[u],u,e,t);if((f===f?f!==a:a===a)||a===r&&!(u in e))e[u]=f}return e}function Bt(e,t,n){n||(n={});var r=-1,i=t.length;while(++r<i){var s=t[r];n[s]=e[s]}return n}function jt(e,t,n){var i=typeof e;return i=="function"?t===r?e:on(e,t,n):e==null?lr:i=="object"?Jt(e):t===r?cr(e):Kt(e,t)}function Ft(e,t,n,i,s,u,a){var f;n&&(f=s?n(e,i,s):n(e));if(f!==r)return f;if(!Jn(e))return e;var l=Xn(e);if(l){f=wn(e);if(!t)return Lt(e,f)}else{var h=rt.call(e),p=h==c;if(!(h==d||h==o||p&&!s))return F[h]?Sn(e,h,t):s?e:{};f=En(p?{}:e);if(!t)return Ht(f,e)}u||(u=[]),a||(a=[]);var v=u.length;while(v--)if(u[v]==e)return a[v];return u.push(e),a.push(f),(l?At:zt)(e,function(r,i){f[i]=Ft(r,t,n,i,e,u,a)}),f}function qt(e,t){var n=[];return It(e,function(e,r,i){t(e,r,i)&&n.push(e)}),n}function Ut(e,t){return Rt(e,t,ir)}function zt(e,t){return Rt(e,t,rr)}function Wt(e,t,n){if(e==null)return;n!==r&&n in On(e)&&(t=[n]);var i=-1,s=t.length;while(e!=null&&++i<s)var o=e=e[t[i]];return o}function Xt(e,t,n,r,i,s){if(e===t)return e!==0||1/e==1/t;var o=typeof e,u=typeof t;return o!="function"&&o!="object"&&u!="function"&&u!="object"||e==null||t==null?e!==e&&t!==t:Vt(e,t,Xt,n,r,i,s)}function Vt(e,t,n,r,i,s,a){var f=Xn(e),l=Xn(t),c=u,h=u;f||(c=rt.call(e),c==o?c=d:c!=d&&(f=Zn(e))),l||(h=rt.call(t),h==o?h=d:h!=d&&(l=Zn(t)));var p=c==d,v=h==d,m=c==h;if(m&&!f&&!p)return dn(e,t,c);if(!i){var g=p&&nt.call(e,"__wrapped__"),y=v&&nt.call(t,"__wrapped__");if(g||y)return n(g?e.value():e,y?t.value():t,r,i,s,a)}if(!m)return!1;s||(s=[]),a||(a=[]);var b=s.length;while(b--)if(s[b]==e)return a[b]==t;s.push(e),a.push(t);var w=(f?pn:vn)(e,t,n,r,i,s,a);return s.pop(),a.pop(),w}function $t(e,t,n,i,s){var o=-1,u=t.length,a=!s;while(++o<u)if(a&&i[o]?n[o]!==e[t[o]]:!(t[o]in e))return!1;o=-1;while(++o<u){var f=t[o],l=e[f],c=n[o];if(a&&i[o])var h=l!==r||f in e;else h=s?s(l,c,f):r,h===r&&(h=Xt(c,l,s,!0));if(!h)return!1}return!0}function Jt(e){var t=rr(e),n=t.length;if(!n)return fr(!0);if(n==1){var i=t[0],s=e[i];if(kn(s))return function(e){return e==null?!1:e[i]===s&&(s!==r||i in On(e))}}var o=Array(n),u=Array(n);while(n--)s=e[t[n]],o[n]=s,u[n]=kn(s);return function(e){return e!=null&&$t(On(e),t,o,u)}}function Kt(e,t){var n=Xn(e),i=Nn(e)&&kn(t),s=e+"";return e=Mn(e),function(o){if(o==null)return!1;var u=s;o=On(o);if((n||!i)&&!(u in o)){o=e.length==1?o:Wt(o,en(e,0,-1));if(o==null)return!1;u=Pn(e),o=On(o)}return o[u]===t?t!==r||u in o:Xt(t,o[u],null,!0)}}function Qt(e,t,n,i,s){if(!Jn(e))return e;var o=Cn(t.length)&&(Xn(t)||Zn(t));if(!o){var u=rr(t);lt.apply(u,bn(t))}return At(u||t,function(a,f){u&&(f=a,a=t[f]);if(Y(a))i||(i=[]),s||(s=[]),Gt(e,t,f,Qt,n,i,s);else{var l=e[f],c=n?n(l,a,f,e,t):r,h=c===r;h&&(c=a),(o||c!==r)&&(h||(c===c?c!==l:l===l))&&(e[f]=c)}}),e}function Gt(e,t,n,i,s,o,u){var a=o.length,f=t[n];while(a--)if(o[a]==f){e[n]=u[a];return}var l=e[n],c=s?s(l,f,n,e,t):r,h=c===r;h&&(c=f,Cn(f.length)&&(Xn(f)||Zn(f))?c=Xn(l)?l:yn(l)?Lt(l):[]:Gn(f)||Wn(f)?c=Wn(l)?er(l):Gn(l)?l:{}:h=!1),o.push(f),u.push(c);if(h)e[n]=i(c,f,s,o,u);else if(c===c?c!==l:l===l)e[n]=c}function Yt(e){return function(t){return t==null?r:t[e]}}function Zt(e){var t=e+"";return e=Mn(e),function(n){return Wt(n,e,t)}}function en(e,t,n){var i=-1,s=e.length;t=t==null?0:+t||0,t<0&&(t=-t>s?0:s+t),n=n===r||n>s?s:+n||0,n<0&&(n+=s),s=t>n?0:n-t>>>0,t>>>=0;var o=Array(s);while(++i<s)o[i]=e[i+t];return o}function tn(e,t){var n;return It(e,function(e,r,i){return n=t(e,r,i),!n}),!!n}function nn(e,t){var n=-1,r=t.length,i=Array(r);while(++n<r)i[n]=e[t[n]];return i}function rn(e,t,n){var r=0,i=e?e.length:r;if(typeof t=="number"&&t===t&&i<=xt){while(r<i){var s=r+i>>>1,o=e[s];(n?o<=t:o<t)?r=s+1:i=s}return i}return sn(e,t,lr,n)}function sn(e,t,n,i){t=n(t);var s=0,o=e?e.length:0,u=t!==t,a=t===r;while(s<o){var f=ut((s+o)/2),l=n(e[f]),c=l===l;if(u)var h=c||i;else a?h=c&&(i||l!==r):h=i?l<=t:l<t;h?s=f+1:o=f}return bt(o,St)}function on(e,t,n){if(typeof e!="function")return lr;if(t===r)return e;switch(n){case 1:return function(n){return e.call(t,n)};case 3:return function(n,r,i){return e.call(t,n,r,i)};case 4:return function(n,r,i,s){return e.call(t,n,r,i,s)};case 5:return function(n,r,i,s,o){return e.call(t,n,r,i,s,o)}}return function(){return e.apply(t,arguments)}}function un(e){return ot.call(e,0)}function an(e){return Un(function(t,n){var r=-1,i=t==null?0:n.length,s=i>2&&n[i-2],o=i>2&&n[2],u=i>1&&n[i-1];typeof s=="function"?(s=on(s,u,5),i-=2):(s=typeof u=="function"?u:null,i-=s?1:0),o&&Tn(n[0],n[1],o)&&(s=i<3?null:s,i=1);while(++r<i){var a=n[r];a&&e(t,a,s)}return t})}function fn(e,t){return function(n,r){var i=n?yn(n):0;if(!Cn(i))return e(n,r);var s=t?i:-1,o=On(n);while(t?s--:++s<i)if(r(o[s],s,o)===!1)break;return n}}function ln(e){return function(t,n,r){var i=On(t),s=r(t),o=s.length,u=e?o:-1;while(e?u--:++u<o){var a=s[u];if(n(i[a],a,i)===!1)break}return t}}function cn(e){return function(t,n,r){return!t||!t.length?-1:(n=mn(n,r,3),$(t,n,e))}}function hn(e,t){return function(n,i,s){return typeof i=="function"&&s===r&&Xn(n)?e(n,i):t(n,on(i,s,3))}}function pn(e,t,n,i,s,o,u){var a=-1,f=e.length,l=t.length,c=!0;if(f!=l&&!(s&&l>f))return!1;while(c&&++a<f){var h=e[a],p=t[a];c=r,i&&(c=s?i(p,h,a):i(h,p,a));if(c===r)if(s){var d=l;while(d--){p=t[d],c=h&&h===p||n(h,p,i,s,o,u);if(c)break}}else c=h&&h===p||n(h,p,i,s,o,u)}return!!c}function dn(e,t,n){switch(n){case a:case f:return+e==+t;case l:return e.name==t.name&&e.message==t.message;case p:return e!=+e?t!=+t:e==0?1/e==1/t:e==+t;case v:case g:return e==t+""}return!1}function vn(e,t,n,i,s,o,u){var a=rr(e),f=a.length,l=rr(t),c=l.length;if(f!=c&&!s)return!1;var h=s,p=-1;while(++p<f){var d=a[p],v=s?d in t:nt.call(t,d);if(v){var m=e[d],g=t[d];v=r,i&&(v=s?i(g,m,d):i(m,g,d)),v===r&&(v=m&&m===g||n(m,g,i,s,o,u))}if(!v)return!1;h||(h=d=="constructor")}if(!h){var y=e.constructor,b=t.constructor;if(y!=b&&"constructor"in e&&"constructor"in t&&!(typeof y=="function"&&y instanceof y&&typeof b=="function"&&b instanceof b))return!1}return!0}function mn(e,t,n){var r=Ct.callback||ar;return r=r===ar?jt:r,n?r(e,t,n):r}function gn(e,t,n){var r=Ct.indexOf||Dn;return r=r===Dn?J:r,e?r(e,t,n):r}function wn(e){var t=e.length,n=new e.constructor(t);return t&&typeof e[0]=="string"&&nt.call(e,"index")&&(n.index=e.index,n.input=e.input),n}function En(e){var t=e.constructor;return typeof t=="function"&&t instanceof t||(t=Object),new t}function Sn(e,t,n){var r=e.constructor;switch(t){case b:return un(e);case a:case f:return new r(+e);case w:case E:case S:case x:case T:case N:case C:case k:case L:var i=e.buffer;return new r(n?un(i):i,e.byteOffset,e.length);case p:case g:return new r(e);case v:var s=new r(e.source,H.exec(e));s.lastIndex=e.lastIndex}return s}function xn(e,t){return e=+e,t=t==null?Nt:t,e>-1&&e%1==0&&e<t}function Tn(e,t,n){if(!Jn(n))return!1;var r=typeof t;if(r=="number")var i=yn(n),s=Cn(i)&&xn(t,i);else s=r=="string"&&t in n;if(s){var o=n[t];return e===e?e===o:o!==o}return!1}function Nn(e,t){var n=typeof e;if(n=="string"&&O.test(e)||n=="number")return!0;if(Xn(e))return!1;var r=!A.test(e);return r||t!=null&&e in On(t)}function Cn(e){return typeof e=="number"&&e>-1&&e%1==0&&e<=Nt}function kn(e){return e===e&&(e===0?1/e>0:!Jn(e))}function Ln(e){var t,n=Ct.support;if(!Y(e)||rt.call(e)!=d||!nt.call(e,"constructor")&&(t=e.constructor,typeof t=="function"&&!(t instanceof t)))return!1;var i;return Ut(e,function(e,t){i=t}),i===r||nt.call(e,i)}function An(e){var t=ir(e),n=t.length,r=n&&e.length,i=Ct.support,s=r&&Cn(r)&&(Xn(e)||i.nonEnumArgs&&Wn(e)),o=-1,u=[];while(++o<n){var a=t[o];(s&&xn(a,r)||nt.call(e,a))&&u.push(a)}return u}function On(e){return Jn(e)?e:Object(e)}function Mn(e){if(Xn(e))return e;var t=[];return Q(e).replace(M,function(e,n,r,i){t.push(r?i.replace(P,"$1"):n||e)}),t}function Dn(e,t,n){var r=e?e.length:0;if(!r)return-1;if(typeof n=="number")n=n<0?yt(r+n,0):n;else if(n){var i=rn(e,t),s=e[i];return(t===t?t===s:s!==s)?i:-1}return J(e,t,n||0)}function Pn(e){var t=e?e.length:0;return t?e[t-1]:r}function Hn(e,t,n){var r=e?e.length:0;return r?(n&&typeof n!="number"&&Tn(e,t,n)&&(t=0,n=r),en(e,t,n)):[]}function Bn(e){var t=-1,n=(e&&e.length&&_t(Mt(e,yn)))>>>0,r=Array(n);while(++t<n)r[t]=Mt(e,Yt(t));return r}function In(e,t,n,r){var i=e?yn(e):0;return Cn(i)||(e=or(e),i=e.length),i?(typeof n!="number"||r&&Tn(t,n,r)?n=0:n=n<0?yt(i+n,0):n||0,typeof e=="string"||!Xn(e)&&Yn(e)?n<i&&e.indexOf(t,n)>-1:gn(e,t,n)>-1):!1}function qn(e,t,n){var r=Xn(e)?Ot:qt;return t=mn(t,n,3),r(e,function(e,n,r){return!t(e,n,r)})}function Rn(e,t,n){var i=Xn(e)?Dt:tn;n&&Tn(e,t,n)&&(t=null);if(typeof t!="function"||n!==r)t=mn(t,n,3);return i(e,t)}function Un(e,t){if(typeof e!="function")throw new TypeError(s);return t=yt(t===r?e.length-1:+t||0,0),function(){var n=arguments,r=-1,i=yt(n.length-t,0),s=Array(i);while(++r<i)s[r]=n[t+r];switch(t){case 0:return e.call(this,s);case 1:return e.call(this,n[0],s);case 2:return e.call(this,n[0],n[1],s)}var o=Array(t+1);r=-1;while(++r<t)o[r]=n[r];return o[t]=s,e.apply(this,o)}}function zn(e,t,n,r){return t&&typeof t!="boolean"&&Tn(e,t,n)?t=!1:typeof t=="function"&&(r=n,n=t,t=!1),n=typeof n=="function"&&on(n,r,1),Ft(e,t,n)}function Wn(e){var t=Y(e)?e.length:r;return Cn(t)&&rt.call(e)==o}function Vn(e){if(e==null)return!0;var t=yn(e);return Cn(t)&&(Xn(e)||Yn(e)||Wn(e)||Y(e)&&$n(e.splice))?!t:!rr(e).length}function Jn(e){var t=typeof e;return t=="function"||!!e&&t=="object"}function Kn(e){return e==null?!1:rt.call(e)==c?it.test(tt.call(e)):Y(e)&&B.test(e)}function Qn(e){return typeof e=="number"||Y(e)&&rt.call(e)==p}function Yn(e){return typeof e=="string"||Y(e)&&rt.call(e)==g}function Zn(e){return Y(e)&&Cn(e.length)&&!!j[rt.call(e)]}function er(e){return Bt(e,ir(e))}function nr(e,t){if(e==null)return!1;var n=nt.call(e,t);return!n&&!Nn(t)&&(t=Mn(t),e=t.length==1?e:Wt(e,en(t,0,-1)),t=Pn(t),n=e!=null&&nt.call(e,t)),n}function ir(e){if(e==null)return[];Jn(e)||(e=Object(e));var t=e.length;t=t&&Cn(t)&&(Xn(e)||kt.nonEnumArgs&&Wn(e))&&t||0;var n=e.constructor,r=-1,i=typeof n=="function"&&n.prototype===e,s=Array(t),o=t>0;while(++r<t)s[r]=r+"";for(var u in e)(!o||!xn(u,t))&&(u!="constructor"||!i&&!!nt.call(e,u))&&s.push(u);return s}function or(e){return nn(e,rr(e))}function ur(e){return e=Q(e),e&&D.test(e)?e.replace(_,"\\$&"):e}function ar(e,t,n){return n&&Tn(e,t,n)&&(t=null),jt(e,t)}function fr(e){return function(){return e}}function lr(e){return e}function cr(e){return Nn(e)?Yt(e):Zt(e)}var r,i="3.7.0",s="Expected a function",o="[object Arguments]",u="[object Array]",a="[object Boolean]",f="[object Date]",l="[object Error]",c="[object Function]",h="[object Map]",p="[object Number]",d="[object Object]",v="[object RegExp]",m="[object Set]",g="[object String]",y="[object WeakMap]",b="[object ArrayBuffer]",w="[object Float32Array]",E="[object Float64Array]",S="[object Int8Array]",x="[object Int16Array]",T="[object Int32Array]",N="[object Uint8Array]",C="[object Uint8ClampedArray]",k="[object Uint16Array]",L="[object Uint32Array]",A=/\.|\[(?:[^[\]]+|(["'])(?:(?!\1)[^\n\\]|\\.)*?)\1\]/,O=/^\w*$/,M=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g,_=/[.*+?^${}()|[\]\/\\]/g,D=RegExp(_.source),P=/\\(\\)?/g,H=/\w*$/,B=/^\[object .+?Constructor\]$/,j={};j[w]=j[E]=j[S]=j[x]=j[T]=j[N]=j[C]=j[k]=j[L]=!0,j[o]=j[u]=j[b]=j[a]=j[f]=j[l]=j[c]=j[h]=j[p]=j[d]=j[v]=j[m]=j[g]=j[y]=!1;var F={};F[o]=F[u]=F[b]=F[a]=F[f]=F[w]=F[E]=F[S]=F[x]=F[T]=F[p]=F[d]=F[v]=F[g]=F[N]=F[C]=F[k]=F[L]=!0,F[l]=F[c]=F[h]=F[m]=F[y]=!1;var I={"function":!0,object:!0},q=I[typeof n]&&n&&!n.nodeType&&n,R=I[typeof t]&&t&&!t.nodeType&&t,U=q&&R&&typeof e=="object"&&e&&e.Object&&e,z=I[typeof self]&&self&&self.Object&&self,W=I[typeof window]&&window&&window.Object&&window,X=R&&R.exports===q&&q,V=U||W!==(this&&this.window)&&W||z||this,Z=Array.prototype,et=Object.prototype,tt=Function.prototype.toString,nt=et.hasOwnProperty,rt=et.toString,it=RegExp("^"+ur(rt).replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),st=Kn(st=V.ArrayBuffer)&&st,ot=Kn(ot=st&&(new st(0)).slice)&&ot,ut=Math.floor,at=Kn(at=Object.getOwnPropertySymbols)&&at,ft=Kn(ft=Object.getPrototypeOf)&&ft,lt=Z.push,ct=Kn(Object.preventExtensions=Object.preventExtensions)&&ct,ht=et.propertyIsEnumerable,pt=Kn(pt=V.Uint8Array)&&pt,dt=function(){try{var e=Kn(e=V.Float64Array)&&e,t=new e(new st(10),0,1)&&e}catch(n){}return t}(),vt=function(){var e={1:0},t=ct&&Kn(t=Object.assign)&&t;try{t(ct(e),"xo")}catch(n){}return!e[1]&&t}(),mt=Kn(mt=Array.isArray)&&mt,gt=Kn(gt=Object.keys)&&gt,yt=Math.max,bt=Math.min,wt=Number.NEGATIVE_INFINITY,Et=Math.pow(2,32)-1,St=Et-1,xt=Et>>>1,Tt=dt?dt.BYTES_PER_ELEMENT:0,Nt=Math.pow(2,53)-1,kt=Ct.support={};(function(e){var t=function(){this.x=e},n={0:e,length:e},r=[];t.prototype={valueOf:e,y:e};for(var i in new t)r.push(i);kt.funcDecomp=/\bthis\b/.test(function(){return this}),kt.funcNames=typeof Function.name=="string";try{kt.nonEnumArgs=!ht.call(arguments,1)}catch(s){kt.nonEnumArgs=!0}})(1,0);var Ht=vt||function(e,t){return t==null?e:Bt(t,bn(t),Bt(t,rr(t),e))},It=fn(zt),Rt=ln();ot||(un=!st||!pt?fr(null):function(e){var t=e.byteLength,n=dt?ut(t/Tt):0,r=n*Tt,i=new st(t);if(n){var s=new dt(i,0,n);s.set(new dt(e,0,n))}return t!=r&&(s=new pt(i,r),s.set(new pt(e,r))),i});var yn=Yt("length"),bn=at?function(e){return at(On(e))}:fr([]),_n=cn(!0),jn=Un(Bn),Fn=hn(At,It),Xn=mt||function(e){return Y(e)&&Cn(e.length)&&rt.call(e)==u},$n=K(/x/)||pt&&!K(pt)?function(e){return rt.call(e)==c}:K,Gn=ft?function(e){if(!e||rt.call(e)!=d)return!1;var t=e.valueOf,n=Kn(t)&&(n=ft(t))&&ft(n);return n?e==n||ft(e)==n:Ln(e)}:Ln,tr=an(function(e,t,n){return n?Pt(e,t,n):Ht(e,t)}),rr=gt?function(e){if(e)var t=e.constructor,n=e.length;return typeof t=="function"&&t.prototype===e||typeof e!="function"&&Cn(n)?An(e):Jn(e)?gt(e):[]}:An,sr=an(Qt);Ct.assign=tr,Ct.callback=ar,Ct.constant=fr,Ct.forEach=Fn,Ct.keys=rr,Ct.keysIn=ir,Ct.merge=sr,Ct.property=cr,Ct.reject=qn,Ct.restParam=Un,Ct.slice=Hn,Ct.toPlainObject=er,Ct.unzip=Bn,Ct.values=or,Ct.zip=jn,Ct.each=Fn,Ct.extend=tr,Ct.iteratee=ar,Ct.clone=zn,Ct.escapeRegExp=ur,Ct.findLastIndex=_n,Ct.has=nr,Ct.identity=lr,Ct.includes=In,Ct.indexOf=Dn,Ct.isArguments=Wn,Ct.isArray=Xn,Ct.isEmpty=Vn,Ct.isFunction=$n,Ct.isNative=Kn,Ct.isNumber=Qn,Ct.isObject=Jn,Ct.isPlainObject=Gn,Ct.isString=Yn,Ct.isTypedArray=Zn,Ct.last=Pn,Ct.some=Rn,Ct.any=Rn,Ct.contains=In,Ct.include=In,Ct.VERSION=i,q&&R?X?(R.exports=Ct)._=Ct:q._=Ct:V._=Ct}).call(this)}).call(this,typeof global!="undefined"?global:typeof self!="undefined"?self:typeof window!="undefined"?window:{})},{}],"/node_modules/jshint/src/jshint.js":[function(e,t,n){var r=e("../lodash"),i=e("events"),s=e("./vars.js"),o=e("./messages.js"),u=e("./lex.js").Lexer,a=e("./reg.js"),f=e("./state.js").state,l=e("./style.js"),c=e("./options.js"),h=e("./scope-manager.js"),p=function(){"use strict";function k(e,t){return e=e.trim(),/^[+-]W\d{3}$/g.test(e)?!0:c.validNames.indexOf(e)===-1&&t.type!=="jslint"&&!r.has(c.removed,e)?(q("E001",t,e),!1):!0}function L(e){return Object.prototype.toString.call(e)==="[object String]"}function A(e,t){return e?!e.identifier||e.value!==t?!1:!0:!1}function O(e){if(!e.reserved)return!1;var t=e.meta;if(t&&t.isFutureReservedWord&&f.inES5()){if(!t.es5)return!1;if(t.strictOnly&&!f.option.strict&&!f.isStrict())return!1;if(e.isProperty)return!1}return!0}function M(e,t){return e.replace(/\{([^{}]*)\}/g,function(e,n){var r=t[n];return typeof r=="string"||typeof r=="number"?r:e})}function D(e,t){Object.keys(t).forEach(function(n){if(r.has(p.blacklist,n))return;e[n]=t[n]})}function P(){if(f.option.enforceall){for(var e in c.bool.enforcing)f.option[e]===undefined&&!c.noenforceall[e]&&(f.option[e]=!0);for(var t in c.bool.relaxing)f.option[t]===undefined&&(f.option[t]=!1)}}function H(){P(),!f.option.esversion&&!f.option.moz&&(f.option.es3?f.option.esversion=3:f.option.esnext?f.option.esversion=6:f.option.esversion=5),f.inES5()&&D(S,s.ecmaIdentifiers[5]),f.inES6()&&D(S,s.ecmaIdentifiers[6]),f.option.module&&(f.option.strict===!0&&(f.option.strict="global"),f.inES6()||F("W134",f.tokens.next,"module",6)),f.option.couch&&D(S,s.couch),f.option.qunit&&D(S,s.qunit),f.option.rhino&&D(S,s.rhino),f.option.shelljs&&(D(S,s.shelljs),D(S,s.node)),f.option.typed&&D(S,s.typed),f.option.phantom&&(D(S,s.phantom),f.option.strict===!0&&(f.option.strict="global")),f.option.prototypejs&&D(S,s.prototypejs),f.option.node&&(D(S,s.node),D(S,s.typed),f.option.strict===!0&&(f.option.strict="global")),f.option.devel&&D(S,s.devel),f.option.dojo&&D(S,s.dojo),f.option.browser&&(D(S,s.browser),D(S,s.typed)),f.option.browserify&&(D(S,s.browser),D(S,s.typed),D(S,s.browserify),f.option.strict===!0&&(f.option.strict="global")),f.option.nonstandard&&D(S,s.nonstandard),f.option.jasmine&&D(S,s.jasmine),f.option.jquery&&D(S,s.jquery),f.option.mootools&&D(S,s.mootools),f.option.worker&&D(S,s.worker),f.option.wsh&&D(S,s.wsh),f.option.globalstrict&&f.option.strict!==!1&&(f.option.strict="global"),f.option.yui&&D(S,s.yui),f.option.mocha&&D(S,s.mocha)}function B(e,t,n){var r=Math.floor(t/f.lines.length*100),i=o.errors[e].desc;throw{name:"JSHintError",line:t,character:n,message:i+" ("+r+"% scanned).",raw:i,code:e}}function j(){var e=f.ignoredLines;if(r.isEmpty(e))return;p.errors=r.reject(p.errors,function(t){return e[t.line]})}function F(e,t,n,r,i,s){var u,a,l,c;if(/^W\d{3}$/.test(e)){if(f.ignored[e])return;c=o.warnings[e]}else/E\d{3}/.test(e)?c=o.errors[e]:/I\d{3}/.test(e)&&(c=o.info[e]);return t=t||f.tokens.next||{},t.id==="(end)"&&(t=f.tokens.curr),a=t.line||0,u=t.from||0,l={id:"(error)",raw:c.desc,code:c.code,evidence:f.lines[a-1]||"",line:a,character:u,scope:p.scope,a:n,b:r,c:i,d:s},l.reason=M(c.desc,l),p.errors.push(l),j(),p.errors.length>=f.option.maxerr&&B("E043",a,u),l}function I(e,t,n,r,i,s,o){return F(e,{line:t,from:n},r,i,s,o)}function q(e,t,n,r,i,s){F(e,t,n,r,i,s)}function R(e,t,n,r,i,s,o){return q(e,{line:t,from:n},r,i,s,o)}function U(e,t){var n;return n={id:"(internal)",elem:e,value:t},p.internals.push(n),n}function z(){var e=f.tokens.next,t=e.body.match(/(-\s+)?[^\s,:]+(?:\s*:\s*(-\s+)?[^\s,]+)?/g)||[],i={};if(e.type==="globals"){t.forEach(function(n,r){n=n.split(":");var s=(n[0]||"").trim(),o=(n[1]||"").trim();if(s==="-"||!s.length){if(r>0&&r===t.length-1)return;q("E002",e);return}s.charAt(0)==="-"?(s=s.slice(1),o=!1,p.blacklist[s]=s,delete S[s]):i[s]=o==="true"}),D(S,i);for(var s in i)r.has(i,s)&&(n[s]=e)}e.type==="exported"&&t.forEach(function(n,r){if(!n.length){if(r>0&&r===t.length-1)return;q("E002",e);return}f.funct["(scope)"].addExported(n)}),e.type==="members"&&(E=E||{},t.forEach(function(e){var t=e.charAt(0),n=e.charAt(e.length-1);t===n&&(t==='"'||t==="'")&&(e=e.substr(1,e.length-2).replace('\\"','"')),E[e]=!1}));var o=["maxstatements","maxparams","maxdepth","maxcomplexity","maxerr","maxlen","indent"];if(e.type==="jshint"||e.type==="jslint")t.forEach(function(t){t=t.split(":");var n=(t[0]||"").trim(),i=(t[1]||"").trim();if(!k(n,e))return;if(o.indexOf(n)>=0){if(i!=="false"){i=+i;if(typeof i!="number"||!isFinite(i)||i<=0||Math.floor(i)!==i){q("E032",e,t[1].trim());return}f.option[n]=i}else f.option[n]=n==="indent"?4:!1;return}if(n==="validthis"){if(f.funct["(global)"])return void q("E009");if(i!=="true"&&i!=="false")return void q("E002",e);f.option.validthis=i==="true";return}if(n==="quotmark"){switch(i){case"true":case"false":f.option.quotmark=i==="true";break;case"double":case"single":f.option.quotmark=i;break;default:q("E002",e)}return}if(n==="shadow"){switch(i){case"true":f.option.shadow=!0;break;case"outer":f.option.shadow="outer";break;case"false":case"inner":f.option.shadow="inner";break;default:q("E002",e)}return}if(n==="unused"){switch(i){case"true":f.option.unused=!0;break;case"false":f.option.unused=!1;break;case"vars":case"strict":f.option.unused=i;break;default:q("E002",e)}return}if(n==="latedef"){switch(i){case"true":f.option.latedef=!0;break;case"false":f.option.latedef=!1;break;case"nofunc":f.option.latedef="nofunc";break;default:q("E002",e)}return}if(n==="ignore"){switch(i){case"line":f.ignoredLines[e.line]=!0,j();break;default:q("E002",e)}return}if(n==="strict"){switch(i){case"true":f.option.strict=!0;break;case"false":f.option.strict=!1;break;case"func":case"global":case"implied":f.option.strict=i;break;default:q("E002",e)}return}n==="module"&&(zt(f.funct)||q("E055",f.tokens.next,"module"));var s={es3:3,es5:5,esnext:6};if(r.has(s,n)){switch(i){case"true":f.option.moz=!1,f.option.esversion=s[n];break;case"false":f.option.moz||(f.option.esversion=5);break;default:q("E002",e)}return}if(n==="esversion"){switch(i){case"5":f.inES5(!0)&&F("I003");case"3":case"6":f.option.moz=!1,f.option.esversion=+i;break;case"2015":f.option.moz=!1,f.option.esversion=6;break;default:q("E002",e)}zt(f.funct)||q("E055",f.tokens.next,"esversion");return}var u=/^([+-])(W\d{3})$/g.exec(n);if(u){f.ignored[u[2]]=u[1]==="-";return}var a;if(i==="true"||i==="false"){e.type==="jslint"?(a=c.renamed[n]||n,f.option[a]=i==="true",c.inverted[a]!==undefined&&(f.option[a]=!f.option[a])):f.option[n]=i==="true",n==="newcap"&&(f.option["(explicitNewcap)"]=!0);return}q("E002",e)}),H()}function W(e){var t=e||0,n=y.length,r;if(t<n)return y[t];while(n<=t)r=y[n],r||(r=y[n]=b.token()),n+=1;return!r&&f.tokens.next.id==="(end)"?f.tokens.next:r}function X(){var e=0,t;do t=W(e++);while(t.id==="(endline)");return t}function V(e,t){switch(f.tokens.curr.id){case"(number)":f.tokens.next.id==="."&&F("W005",f.tokens.curr);break;case"-":(f.tokens.next.id==="-"||f.tokens.next.id==="--")&&F("W006");break;case"+":(f.tokens.next.id==="+"||f.tokens.next.id==="++")&&F("W007")}e&&f.tokens.next.id!==e&&(t?f.tokens.next.id==="(end)"?q("E019",t,t.id):q("E020",f.tokens.next,e,t.id,t.line,f.tokens.next.value):(f.tokens.next.type!=="(identifier)"||f.tokens.next.value!==e)&&F("W116",f.tokens.next,e,f.tokens.next.value)),f.tokens.prev=f.tokens.curr,f.tokens.curr=f.tokens.next;for(;;){f.tokens.next=y.shift()||b.token(),f.tokens.next||B("E041",f.tokens.curr.line);if(f.tokens.next.id==="(end)"||f.tokens.next.id==="(error)")return;f.tokens.next.check&&f.tokens.next.check();if(f.tokens.next.isSpecial)f.tokens.next.type==="falls through"?f.tokens.curr.caseFallsThrough=!0:z();else if(f.tokens.next.id!=="(endline)")break}}function $(e){return e.infix||!e.identifier&&!e.template&&!!e.led}function J(){var e=f.tokens.curr,t=f.tokens.next;return t.id===";"||t.id==="}"||t.id===":"?!0:$(t)===$(e)||e.id==="yield"&&f.inMoz()?e.line!==G(t):!1}function K(e){return!e.left&&e.arity!=="unary"}function Q(e,t){var n,i=!1,s=!1,o=!1;f.nameStack.push(),!t&&f.tokens.next.value==="let"&&W(0).value==="("&&(f.inMoz()||F("W118",f.tokens.next,"let expressions"),o=!0,f.funct["(scope)"].stack(),V("let"),V("("),f.tokens.prev.fud(),V(")")),f.tokens.next.id==="(end)"&&q("E006",f.tokens.curr);var u=f.option.asi&&f.tokens.prev.line!==G(f.tokens.curr)&&r.contains(["]",")"],f.tokens.prev.id)&&r.contains(["[","("],f.tokens.curr.id);u&&F("W014",f.tokens.curr,f.tokens.curr.id),V(),t&&(f.funct["(verb)"]=f.tokens.curr.value,f.tokens.curr.beginsStmt=!0);if(t===!0&&f.tokens.curr.fud)n=f.tokens.curr.fud();else{f.tokens.curr.nud?n=f.tokens.curr.nud():q("E030",f.tokens.curr,f.tokens.curr.id);while((e<f.tokens.next.lbp||f.tokens.next.type==="(template)")&&!J())i=f.tokens.curr.value==="Array",s=f.tokens.curr.value==="Object",n&&(n.value||n.first&&n.first.value)&&(n.value!=="new"||n.first&&n.first.value&&n.first.value===".")&&(i=!1,n.value!==f.tokens.curr.value&&(s=!1)),V(),i&&f.tokens.curr.id==="("&&f.tokens.next.id===")"&&F("W009",f.tokens.curr),s&&f.tokens.curr.id==="("&&f.tokens.next.id===")"&&F("W010",f.tokens.curr),n&&f.tokens.curr.led?n=f.tokens.curr.led(n):q("E033",f.tokens.curr,f.tokens.curr.id)}return o&&f.funct["(scope)"].unstack(),f.nameStack.pop(),n}function G(e){return e.startLine||e.line}function Y(e,t){e=e||f.tokens.curr,t=t||f.tokens.next,!f.option.laxbreak&&e.line!==G(t)&&F("W014",t,t.value)}function Z(e){e=e||f.tokens.curr,e.line!==G(f.tokens.next)&&F("E022",e,e.value)}function et(e,t){e.line!==G(t)&&(f.option.laxcomma||(tt.first&&(F("I001"),tt.first=!1),F("W014",e,t.value)))}function tt(e){e=e||{},e.peek?et(f.tokens.prev,f.tokens.curr):(et(f.tokens.curr,f.tokens.next),V(","));if(f.tokens.next.identifier&&(!e.property||!f.inES5()))switch(f.tokens.next.value){case"break":case"case":case"catch":case"continue":case"default":case"do":case"else":case"finally":case"for":case"if":case"in":case"instanceof":case"return":case"switch":case"throw":case"try":case"var":case"let":case"while":case"with":return q("E024",f.tokens.next,f.tokens.next.value),!1}if(f.tokens.next.type==="(punctuator)")switch(f.tokens.next.value){case"}":case"]":case",":if(e.allowTrailing)return!0;case")":return q("E024",f.tokens.next,f.tokens.next.value),!1}return!0}function nt(e,t){var n=f.syntax[e];if(!n||typeof n!="object")f.syntax[e]=n={id:e,lbp:t,value:e};return n}function rt(e){var t=nt(e,0);return t.delim=!0,t}function it(e,t){var n=rt(e);return n.identifier=n.reserved=!0,n.fud=t,n}function st(e,t){var n=it(e,t);return n.block=!0,n}function ot(e){var t=e.id.charAt(0);if(t>="a"&&t<="z"||t>="A"&&t<="Z")e.identifier=e.reserved=!0;return e}function ut(e,t){var n=nt(e,150);return ot(n),n.nud=typeof t=="function"?t:function(){this.arity="unary",this.right=Q(150);if(this.id==="++"||this.id==="--")f.option.plusplus?F("W016",this,this.id):this.right&&(!this.right.identifier||O(this.right))&&this.right.id!=="."&&this.right.id!=="["&&F("W017",this),this.right&&this.right.isMetaProperty?q("E031",this):this.right&&this.right.identifier&&f.funct["(scope)"].block.modify(this.right.value,this);return this},n}function at(e,t){var n=rt(e);return n.type=e,n.nud=t,n}function ft(e,t){var n=at(e,t);return n.identifier=!0,n.reserved=!0,n}function lt(e,t){var n=at(e,t&&t.nud||function(){return this});return t=t||{},t.isFutureReservedWord=!0,n.value=e,n.identifier=!0,n.reserved=!0,n.meta=t,n}function ct(e,t){return ft(e,function(){return typeof t=="function"&&t(this),this})}function ht(e,t,n,r){var i=nt(e,n);return ot(i),i.infix=!0,i.led=function(i){return r||Y(f.tokens.prev,f.tokens.curr),(e==="in"||e==="instanceof")&&i.id==="!"&&F("W018",i,"!"),typeof t=="function"?t(i,this):(this.left=i,this.right=Q(n),this)},i}function pt(e){var t=nt(e,42);return t.led=function(e){return Y(f.tokens.prev,f.tokens.curr),this.left=e,this.right=Xt({type:"arrow",loneArg:e}),this},t}function dt(e,t){var n=nt(e,100);return n.led=function(e){Y(f.tokens.prev,f.tokens.curr),this.left=e;var n=this.right=Q(100);return A(e,"NaN")||A(n,"NaN")?F("W019",this):t&&t.apply(this,[e,n]),(!e||!n)&&B("E041",f.tokens.curr.line),e.id==="!"&&F("W018",e,"!"),n.id==="!"&&F("W018",n,"!"),this},n}function vt(e){return e&&(e.type==="(number)"&&+e.value===0||e.type==="(string)"&&e.value===""||e.type==="null"&&!f.option.eqnull||e.type==="true"||e.type==="false"||e.type==="undefined")}function gt(e,t,n){var i;return n.option.notypeof?!1:!e||!t?!1:(i=n.inES6()?mt.es6:mt.es3,t.type==="(identifier)"&&t.value==="typeof"&&e.type==="(string)"?!r.contains(i,e.value):!1)}function yt(e,t){var n=!1;return e.type==="this"&&t.funct["(context)"]===null?n=!0:e.type==="(identifier)"&&(t.option.node&&e.value==="global"?n=!0:t.option.browser&&(e.value==="window"||e.value==="document")&&(n=!0)),n}function bt(e){function n(e){if(typeof e!="object")return;return e.right==="prototype"?e:n(e.left)}function r(e){while(!e.identifier&&typeof e.left=="object")e=e.left;if(e.identifier&&t.indexOf(e.value)>=0)return e.value}var t=["Array","ArrayBuffer","Boolean","Collator","DataView","Date","DateTimeFormat","Error","EvalError","Float32Array","Float64Array","Function","Infinity","Intl","Int16Array","Int32Array","Int8Array","Iterator","Number","NumberFormat","Object","RangeError","ReferenceError","RegExp","StopIteration","String","SyntaxError","TypeError","Uint16Array","Uint32Array","Uint8Array","Uint8ClampedArray","URIError"],i=n(e);if(i)return r(i)}function wt(e,t,n){var r=n&&n.allowDestructuring;t=t||e;if(f.option.freeze){var i=bt(e);i&&F("W121",e,i)}return e.identifier&&!e.isMetaProperty&&f.funct["(scope)"].block.reassign(e.value,e),e.id==="."?((!e.left||e.left.value==="arguments"&&!f.isStrict())&&F("E031",t),f.nameStack.set(f.tokens.prev),!0):e.id==="{"||e.id==="["?(r&&f.tokens.curr.left.destructAssign?f.tokens.curr.left.destructAssign.forEach(function(e){e.id&&f.funct["(scope)"].block.modify(e.id,e.token)}):e.id==="{"||!e.left?F("E031",t):e.left.value==="arguments"&&!f.isStrict()&&F("E031",t),e.id==="["&&f.nameStack.set(e.right),!0):e.isMetaProperty?(q("E031",t),!0):e.identifier&&!O(e)?(f.funct["(scope)"].labeltype(e.value)==="exception"&&F("W022",e),f.nameStack.set(e),!0):(e===f.syntax["function"]&&F("W023",f.tokens.curr),!1)}function Et(e,t,n){var r=ht(e,typeof t=="function"?t:function(e,t){t.left=e;if(e&&wt(e,t,{allowDestructuring:!0}))return t.right=Q(10),t;q("E031",t)},n);return r.exps=!0,r.assign=!0,r}function St(e,t,n){var r=nt(e,n);return ot(r),r.led=typeof t=="function"?t:function(e){return f.option.bitwise&&F("W016",this,this.id),this.left=e,this.right=Q(n),this},r}function xt(e){return Et(e,function(e,t){f.option.bitwise&&F("W016",t,t.id);if(e&&wt(e,t))return t.right=Q(10),t;q("E031",t)},20)}function Tt(e){var t=nt(e,150);return t.led=function(e){return f.option.plusplus?F("W016",this,this.id):(!e.identifier||O(e))&&e.id!=="."&&e.id!=="["&&F("W017",this),e.isMetaProperty?q("E031",this):e&&e.identifier&&f.funct["(scope)"].block.modify(e.value,e),this.left=e,this},t}function Nt(e,t,n){if(!f.tokens.next.identifier)return;n||V();var r=f.tokens.curr,i=f.tokens.curr.value;return O(r)?t&&f.inES5()?i:e&&i==="undefined"?i:(F("W024",f.tokens.curr,f.tokens.curr.id),i):i}function Ct(e,t){var n=Nt(e,t,!1);if(n)return n;if(f.tokens.next.value==="..."){f.inES6(!0)||F("W119",f.tokens.next,"spread/rest operator","6"),V();if(pn(f.tokens.next,"...")){F("E024",f.tokens.next,"...");while(pn(f.tokens.next,"..."))V()}if(!f.tokens.next.identifier){F("E024",f.tokens.curr,"...");return}return Ct(e,t)}q("E030",f.tokens.next,f.tokens.next.value),f.tokens.next.id!==";"&&V()}function kt(e){var t=0,n;if(f.tokens.next.id!==";"||e.inBracelessBlock)return;for(;;){do n=W(t),t+=1;while(n.id!=="(end)"&&n.id==="(comment)");if(n.reach)return;if(n.id!=="(endline)"){if(n.id==="function"){f.option.latedef===!0&&F("W026",n);break}F("W027",n,n.value,e.value);break}}}function Lt(){if(f.tokens.next.id!==";"){if(f.tokens.next.isUnclosed)return V();var e=G(f.tokens.next)===f.tokens.curr.line&&f.tokens.next.id!=="(end)",t=pn(f.tokens.next,"}");e&&!t?R("E058",f.tokens.curr.line,f.tokens.curr.character):f.option.asi||(t&&!f.option.lastsemic||!e)&&I("W033",f.tokens.curr.line,f.tokens.curr.character)}else V(";")}function At(){var e=g,t,n=f.tokens.next,r=!1;if(n.id===";"){V(";");return}var i=O(n);i&&n.meta&&n.meta.isFutureReservedWord&&W().id===":"&&(F("W024",n,n.id),i=!1),n.identifier&&!i&&W().id===":"&&(V(),V(":"),r=!0,f.funct["(scope)"].stack(),f.funct["(scope)"].block.addBreakLabel(n.value,{token:f.tokens.curr}),!f.tokens.next.labelled&&f.tokens.next.value!=="{"&&F("W028",f.tokens.next,n.value,f.tokens.next.value),f.tokens.next.label=n.value,n=f.tokens.next);if(n.id==="{"){var s=f.funct["(verb)"]==="case"&&f.tokens.curr.value===":";_t(!0,!0,!1,!1,s);return}return t=Q(0,!0),t&&(!t.identifier||t.value!=="function")&&(t.type!=="(punctuator)"||!t.left||!t.left.identifier||t.left.value!=="function")&&!f.isStrict()&&f.option.strict==="global"&&F("E007"),n.block||(!f.option.expr&&(!t||!t.exps)?F("W030",f.tokens.curr):f.option.nonew&&t&&t.left&&t.id==="("&&t.left.id==="new"&&F("W031",n),Lt()),g=e,r&&f.funct["(scope)"].unstack(),t}function Ot(){var e=[],t;while(!f.tokens.next.reach&&f.tokens.next.id!=="(end)")f.tokens.next.id===";"?(t=W(),(!t||t.id!=="("&&t.id!=="[")&&F("W032"),V(";")):e.push(At());return e}function Mt(){var e,t,n;while(f.tokens.next.id==="(string)"){t=W(0);if(t.id==="(endline)"){e=1;do n=W(e++);while(n.id==="(endline)");if(n.id===";")t=n;else{if(n.value==="["||n.value===".")break;(!f.option.asi||n.value==="(")&&F("W033",f.tokens.next)}}else{if(t.id==="."||t.id==="[")break;t.id!==";"&&F("W033",t)}V();var r=f.tokens.curr.value;(f.directive[r]||r==="use strict"&&f.option.strict==="implied")&&F("W034",f.tokens.curr,r),f.directive[r]=!0,t.id===";"&&V(";")}f.isStrict()&&(f.option["(explicitNewcap)"]||(f.option.newcap=!0),f.option.undef=!0)}function _t(e,t,n,i,s){var o,u=m,a=g,l,c,h,p;m=e,c=f.tokens.next;var d=f.funct["(metrics)"];d.nestedBlockDepth+=1,d.verifyMaxNestedBlockDepthPerFunction();if(f.tokens.next.id==="{"){V("{"),f.funct["(scope)"].stack(),h=f.tokens.curr.line;if(f.tokens.next.id!=="}"){g+=f.option.indent;while(!e&&f.tokens.next.from>g)g+=f.option.indent;if(n){l={};for(p in f.directive)r.has(f.directive,p)&&(l[p]=f.directive[p]);Mt(),f.option.strict&&f.funct["(context)"]["(global)"]&&!l["use strict"]&&!f.isStrict()&&F("E007")}o=Ot(),d.statementCount+=o.length,g-=f.option.indent}V("}",c),n&&(f.funct["(scope)"].validateParams(),l&&(f.directive=l)),f.funct["(scope)"].unstack(),g=a}else if(!e)if(n){f.funct["(scope)"].stack(),l={},t&&!i&&!f.inMoz()&&q("W118",f.tokens.curr,"function closure expressions");if(!t)for(p in f.directive)r.has(f.directive,p)&&(l[p]=f.directive[p]);Q(10),f.option.strict&&f.funct["(context)"]["(global)"]&&!l["use strict"]&&!f.isStrict()&&F("E007"),f.funct["(scope)"].unstack()}else q("E021",f.tokens.next,"{",f.tokens.next.value);else f.funct["(noblockscopedvar)"]=f.tokens.next.id!=="for",f.funct["(scope)"].stack(),(!t||f.option.curly)&&F("W116",f.tokens.next,"{",f.tokens.next.value),f.tokens.next.inBracelessBlock=!0,g+=f.option.indent,o=[At()],g-=f.option.indent,f.funct["(scope)"].unstack(),delete f.funct["(noblockscopedvar)"];switch(f.funct["(verb)"]){case"break":case"continue":case"return":case"throw":if(s)break;default:f.funct["(verb)"]=null}return m=u,e&&f.option.noempty&&(!o||o.length===0)&&F("W035",f.tokens.prev),d.nestedBlockDepth-=1,o}function Dt(e){E&&typeof E[e]!="boolean"&&F("W036",f.tokens.curr,e),typeof w[e]=="number"?w[e]+=1:w[e]=1}function Bt(){var e={};e.exps=!0,f.funct["(comparray)"].stack();var t=!1;return f.tokens.next.value!=="for"&&(t=!0,f.inMoz()||F("W116",f.tokens.next,"for",f.tokens.next.value),f.funct["(comparray)"].setState("use"),e.right=Q(10)),V("for"),f.tokens.next.value==="each"&&(V("each"),f.inMoz()||F("W118",f.tokens.curr,"for each")),V("("),f.funct["(comparray)"].setState("define"),e.left=Q(130),r.contains(["in","of"],f.tokens.next.value)?V():q("E045",f.tokens.curr),f.funct["(comparray)"].setState("generate"),Q(10),V(")"),f.tokens.next.value==="if"&&(V("if"),V("("),f.funct["(comparray)"].setState("filter"),e.filter=Q(10),V(")")),t||(f.funct["(comparray)"].setState("use"),e.right=Q(10)),V("]"),f.funct["(comparray)"].unstack(),e}function jt(){return f.funct["(statement)"]&&f.funct["(statement)"].type==="class"||f.funct["(context)"]&&f.funct["(context)"]["(verb)"]==="class"}function Ft(e){return e.identifier||e.id==="(string)"||e.id==="(number)"}function It(e){var t,n=!0;return typeof e=="object"?t=e:(n=e,t=Nt(!1,!0,n)),t?typeof t=="object"&&(t.id==="(string)"||t.id==="(identifier)"?t=t.value:t.id==="(number)"&&(t=t.value.toString())):f.tokens.next.id==="(string)"?(t=f.tokens.next.value,n||V()):f.tokens.next.id==="(number)"&&(t=f.tokens.next.value.toString(),n||V()),t==="hasOwnProperty"&&F("W001"),t}function qt(e){function h(e){f.funct["(scope)"].addParam.apply(f.funct["(scope)"],e)}var t,n=[],i,s=[],o,u=!1,a=!1,l=0,c=e&&e.loneArg;if(c&&c.identifier===!0)return f.funct["(scope)"].addParam(c.value,c),{arity:1,params:[c.value]};t=f.tokens.next,(!e||!e.parsedOpening)&&V("(");if(f.tokens.next.id===")"){V(")");return}for(;;){l++;var p=[];if(r.contains(["{","["],f.tokens.next.id)){s=Gt();for(o in s)o=s[o],o.id&&(n.push(o.id),p.push([o.id,o.token]))}else{pn(f.tokens.next,"...")&&(a=!0),i=Ct(!0);if(i)n.push(i),p.push([i,f.tokens.curr]);else while(!hn(f.tokens.next,[",",")"]))V()}u&&f.tokens.next.id!=="="&&q("W138",f.tokens.current),f.tokens.next.id==="="&&(f.inES6()||F("W119",f.tokens.next,"default parameters","6"),V("="),u=!0,Q(10)),p.forEach(h);if(f.tokens.next.id!==",")return V(")",t),{arity:l,params:n};a&&F("W131",f.tokens.next),tt()}}function Rt(e,t,n){var i={"(name)":e,"(breakage)":0,"(loopage)":0,"(tokens)":{},"(properties)":{},"(catch)":!1,"(global)":!1,"(line)":null,"(character)":null,"(metrics)":null,"(statement)":null,"(context)":null,"(scope)":null,"(comparray)":null,"(generator)":null,"(arrow)":null,"(params)":null};return t&&r.extend(i,{"(line)":t.line,"(character)":t.character,"(metrics)":Vt(t)}),r.extend(i,n),i["(context)"]&&(i["(scope)"]=i["(context)"]["(scope)"],i["(comparray)"]=i["(context)"]["(comparray)"]),i}function Ut(e){return"(scope)"in e}function zt(e){return e["(global)"]&&!e["(verb)"]}function Wt(e){function i(){if(f.tokens.curr.template&&f.tokens.curr.tail&&f.tokens.curr.context===t)return!0;var e=f.tokens.next.template&&f.tokens.next.tail&&f.tokens.next.context===t;return e&&V(),e||f.tokens.next.isUnclosed}var t=this.context,n=this.noSubst,r=this.depth;if(!n)while(!i())!f.tokens.next.template||f.tokens.next.depth>r?Q(0):V();return{id:"(template)",type:"(template)",tag:e}}function Xt(e){var t,n,r,i,s,o,u,a,l=f.option,c=f.ignored;e&&(r=e.name,i=e.statement,s=e.classExprBinding,o=e.type==="generator",u=e.type==="arrow",a=e.ignoreLoopFunc),f.option=Object.create(f.option),f.ignored=Object.create(f.ignored),f.funct=Rt(r||f.nameStack.infer(),f.tokens.next,{"(statement)":i,"(context)":f.funct,"(arrow)":u,"(generator)":o}),t=f.funct,n=f.tokens.curr,n.funct=f.funct,v.push(f.funct),f.funct["(scope)"].stack("functionouter");var h=r||s;h&&f.funct["(scope)"].block.add(h,s?"class":"function",f.tokens.curr,!1),f.funct["(scope)"].stack("functionparams");var p=qt(e);return p?(f.funct["(params)"]=p.params,f.funct["(metrics)"].arity=p.arity,f.funct["(metrics)"].verifyMaxParametersPerFunction()):f.funct["(metrics)"].arity=0,u&&(f.inES6(!0)||F("W119",f.tokens.curr,"arrow function syntax (=>)","6"),e.loneArg||V("=>")),_t(!1,!0,!0,u),!f.option.noyield&&o&&f.funct["(generator)"]!=="yielded"&&F("W124",f.tokens.curr),f.funct["(metrics)"].verifyMaxStatementsPerFunction(),f.funct["(metrics)"].verifyMaxComplexityPerFunction(),f.funct["(unusedOption)"]=f.option.unused,f.option=l,f.ignored=c,f.funct["(last)"]=f.tokens.curr.line,f.funct["(lastcharacter)"]=f.tokens.curr.character,f.funct["(scope)"].unstack(),f.funct["(scope)"].unstack(),f.funct=f.funct["(context)"],!a&&!f.option.loopfunc&&f.funct["(loopage)"]&&t["(isCapturing)"]&&F("W083",n),t}function Vt(e){return{statementCount:0,nestedBlockDepth:-1,ComplexityCount:1,arity:0,verifyMaxStatementsPerFunction:function(){f.option.maxstatements&&this.statementCount>f.option.maxstatements&&F("W071",e,this.statementCount)},verifyMaxParametersPerFunction:function(){r.isNumber(f.option.maxparams)&&this.arity>f.option.maxparams&&F("W072",e,this.arity)},verifyMaxNestedBlockDepthPerFunction:function(){f.option.maxdepth&&this.nestedBlockDepth>0&&this.nestedBlockDepth===f.option.maxdepth+1&&F("W073",null,this.nestedBlockDepth)},verifyMaxComplexityPerFunction:function(){var t=f.option.maxcomplexity,n=this.ComplexityCount;t&&n>t&&F("W074",e,n)}}}function $t(){f.funct["(metrics)"].ComplexityCount+=1}function Jt(e){var t,n;e&&(t=e.id,n=e.paren,t===","&&(e=e.exprs[e.exprs.length-1])&&(t=e.id,n=n||e.paren));switch(t){case"=":case"+=":case"-=":case"*=":case"%=":case"&=":case"|=":case"^=":case"/=":!n&&!f.option.boss&&F("W084")}}function Kt(e){if(f.inES5())for(var t in e)e[t]&&e[t].setterToken&&!e[t].getterToken&&F("W078",e[t].setterToken)}function Qt(e,t){if(pn(f.tokens.next,".")){var n=f.tokens.curr.id;V(".");var r=Ct();return f.tokens.curr.isMetaProperty=!0,e!==r?q("E057",f.tokens.prev,n,r):t(),f.tokens.curr}}function Gt(e){var t=e&&e.assignment;return f.inES6()||F("W104",f.tokens.curr,t?"destructuring assignment":"destructuring binding","6"),Yt(e)}function Yt(e){var t,n=[],r=e&&e.openingParsed,i=e&&e.assignment,s=i?{assignment:i}:null,o=r?f.tokens.curr:f.tokens.next,u=function(){var e;if(hn(f.tokens.next,["[","{"])){t=Yt(s);for(var r in t)r=t[r],n.push({id:r.id,token:r.token})}else if(pn(f.tokens.next,","))n.push({id:null,token:f.tokens.curr});else{if(!pn(f.tokens.next,"(")){var o=pn(f.tokens.next,"...");if(i){var a=o?W(0):f.tokens.next;a.identifier||F("E030",a,a.value);var l=Q(155);l&&(wt(l),l.identifier&&(e=l.value))}else e=Ct();return e&&n.push({id:e,token:f.tokens.curr}),o}V("("),u(),V(")")}return!1},a=function(){var e;pn(f.tokens.next,"[")?(V("["),Q(10),V("]"),V(":"),u()):f.tokens.next.id==="(string)"||f.tokens.next.id==="(number)"?(V(),V(":"),u()):(e=Ct(),pn(f.tokens.next,":")?(V(":"),u()):e&&(i&&wt(f.tokens.curr),n.push({id:e,token:f.tokens.curr})))};if(pn(o,"[")){r||V("["),pn(f.tokens.next,"]")&&F("W137",f.tokens.curr);var l=!1;while(!pn(f.tokens.next,"]"))u()&&!l&&pn(f.tokens.next,",")&&(F("W130",f.tokens.next),l=!0),pn(f.tokens.next,"=")&&(pn(f.tokens.prev,"...")?V("]"):V("="),f.tokens.next.id==="undefined"&&F("W080",f.tokens.prev,f.tokens.prev.value),Q(10)),pn(f.tokens.next,"]")||V(",");V("]")}else if(pn(o,"{")){r||V("{"),pn(f.tokens.next,"}")&&F("W137",f.tokens.curr);while(!pn(f.tokens.next,"}")){a(),pn(f.tokens.next,"=")&&(V("="),f.tokens.next.id==="undefined"&&F("W080",f.tokens.prev,f.tokens.prev.value),Q(10));if(!pn(f.tokens.next,"}")){V(",");if(pn(f.tokens.next,"}"))break}}V("}")}return n}function Zt(e,t){var n=t.first;if(!n)return;r.zip(e,Array.isArray(n)?n:[n]).forEach(function(e){var t=e[0],n=e[1];t&&n?t.first=n:t&&t.first&&!n&&F("W080",t.first,t.first.value)})}function en(e,t,n){var i=n&&n.prefix,s=n&&n.inexport,o=e==="let",u=e==="const",a,l,c,h;f.inES6()||F("W104",f.tokens.curr,e,"6"),o&&f.tokens.next.value==="("?(f.inMoz()||F("W118",f.tokens.next,"let block"),V("("),f.funct["(scope)"].stack(),h=!0):f.funct["(noblockscopedvar)"]&&q("E048",f.tokens.curr,u?"Const":"Let"),t.first=[];for(;;){var p=[];r.contains(["{","["],f.tokens.next.value)?(a=Gt(),l=!1):(a=[{id:Ct(),token:f.tokens.curr}],l=!0),!i&&u&&f.tokens.next.id!=="="&&F("E012",f.tokens.curr,f.tokens.curr.value);for(var d in a)a.hasOwnProperty(d)&&(d=a[d],f.funct["(scope)"].block.isGlobal()&&S[d.id]===!1&&F("W079",d.token,d.id),d.id&&!f.funct["(noblockscopedvar)"]&&(f.funct["(scope)"].addlabel(d.id,{type:e,token:d.token}),p.push(d.token),l&&s&&f.funct["(scope)"].setExported(d.token.value,d.token)));f.tokens.next.id==="="&&(V("="),!i&&f.tokens.next.id==="undefined"&&F("W080",f.tokens.prev,f.tokens.prev.value),!i&&W(0).id==="="&&f.tokens.next.identifier&&F("W120",f.tokens.next,f.tokens.next.value),c=Q(i?120:10),l?a[0].first=c:Zt(p,c)),t.first=t.first.concat(p);if(f.tokens.next.id!==",")break;tt()}return h&&(V(")"),_t(!0,!0),t.block=!0,f.funct["(scope)"].unstack()),t}function sn(e){return f.inES6()||F("W104",f.tokens.curr,"class","6"),e?(this.name=Ct(),f.funct["(scope)"].addlabel(this.name,{type:"class",token:f.tokens.curr})):f.tokens.next.identifier&&f.tokens.next.value!=="extends"?(this.name=Ct(),this.namedExpr=!0):this.name=f.nameStack.infer(),on(this),this}function on(e){var t=f.inClassBody;f.tokens.next.value==="extends"&&(V("extends"),e.heritage=Q(10)),f.inClassBody=!0,V("{"),e.body=un(e),V("}"),f.inClassBody=t}function un(e){var t,n,r,i,s=Object.create(null),o=Object.create(null),u;for(var a=0;f.tokens.next.id!=="}";++a){t=f.tokens.next,n=!1,r=!1,i=null;if(t.id===";"){F("W032"),V(";");continue}t.id==="*"&&(r=!0,V("*"),t=f.tokens.next);if(t.id==="[")t=cn(),u=!0;else{if(!Ft(t)){F("W052",f.tokens.next,f.tokens.next.value||f.tokens.next.type),V();continue}V(),u=!1;if(t.identifier&&t.value==="static"){pn(f.tokens.next,"*")&&(r=!0,V("*"));if(Ft(f.tokens.next)||f.tokens.next.id==="[")u=f.tokens.next.id==="[",n=!0,t=f.tokens.next,f.tokens.next.id==="["?t=cn():V()}t.identifier&&(t.value==="get"||t.value==="set")&&(Ft(f.tokens.next)||f.tokens.next.id==="[")&&(u=f.tokens.next.id==="[",i=t,t=f.tokens.next,f.tokens.next.id==="["?t=cn():V())}if(!pn(f.tokens.next,"(")){q("E054",f.tokens.next,f.tokens.next.value);while(f.tokens.next.id!=="}"&&!pn(f.tokens.next,"("))V();f.tokens.next.value!=="("&&Xt({statement:e})}u||(i?ln(i.value,n?o:s,t.value,t,!0,n):(t.value==="constructor"?f.nameStack.set(e):f.nameStack.set(t),fn(n?o:s,t.value,t,!0,n)));if(i&&t.value==="constructor"){var l=i.value==="get"?"class getter method":"class setter method";q("E049",t,l,"constructor")}else t.value==="prototype"&&q("E049",t,"class method","prototype");It(t),Xt({statement:e,type:r?"generator":null,classExprBinding:e.namedExpr?e.name:null})}Kt(s)}function fn(e,t,n,r,i){var s=["key","class method","static class method"];s=s[(r||!1)+(i||!1)],n.identifier&&(t=n.value),e[t]&&t!=="__proto__"?F("W075",f.tokens.next,s,t):e[t]=Object.create(null),e[t].basic=!0,e[t].basictkn=n}function ln(e,t,n,r,i,s){var o=e==="get"?"getterToken":"setterToken",u="";i?(s&&(u+="static "),u+=e+"ter method"):u="key",f.tokens.curr.accessorType=e,f.nameStack.set(r),t[n]?(t[n].basic||t[n][o])&&n!=="__proto__"&&F("W075",f.tokens.next,u,n):t[n]=Object.create(null),t[n][o]=r}function cn(){V("["),f.inES6()||F("W119",f.tokens.curr,"computed property names","6");var e=Q(10);return V("]"),e}function hn(e,t){return e.type==="(punctuator)"?r.contains(t,e.value):!1}function pn(e,t){return e.type==="(punctuator)"&&e.value===t}function dn(){var e=an();e.notJson?(!f.inES6()&&e.isDestAssign&&F("W104",f.tokens.curr,"destructuring assignment","6"),Ot()):(f.option.laxbreak=!0,f.jsonMode=!0,mn())}function mn(){function e(){var e={},t=f.tokens.next;V("{");if(f.tokens.next.id!=="}")for(;;){if(f.tokens.next.id==="(end)")q("E026",f.tokens.next,t.line);else{if(f.tokens.next.id==="}"){F("W094",f.tokens.curr);break}f.tokens.next.id===","?q("E028",f.tokens.next):f.tokens.next.id!=="(string)"&&F("W095",f.tokens.next,f.tokens.next.value)}e[f.tokens.next.value]===!0?F("W075",f.tokens.next,"key",f.tokens.next.value):f.tokens.next.value==="__proto__"&&!f.option.proto||f.tokens.next.value==="__iterator__"&&!f.option.iterator?F("W096",f.tokens.next,f.tokens.next.value):e[f.tokens.next.value]=!0,V(),V(":"),mn();if(f.tokens.next.id!==",")break;V(",")}V("}")}function t(){var e=f.tokens.next;V("[");if(f.tokens.next.id!=="]")for(;;){if(f.tokens.next.id==="(end)")q("E027",f.tokens.next,e.line);else{if(f.tokens.next.id==="]"){F("W094",f.tokens.curr);break}f.tokens.next.id===","&&q("E028",f.tokens.next)}mn();if(f.tokens.next.id!==",")break;V(",")}V("]")}switch(f.tokens.next.id){case"{":e();break;case"[":t();break;case"true":case"false":case"null":case"(number)":case"(string)":V();break;case"-":V("-"),V("(number)");break;default:q("E003",f.tokens.next)}}var e,t={"<":!0,"<=":!0,"==":!0,"===":!0,"!==":!0,"!=":!0,">":!0,">=":!0,"+":!0,"-":!0,"*":!0,"/":!0,"%":!0},n,d=["closure","exception","global","label","outer","unused","var"],v,m,g,y,b,w,E,S,x,T,N=[],C=new i.EventEmitter,mt={};mt.legacy=["xml","unknown"],mt.es3=["undefined","boolean","number","string","function","object"],mt.es3=mt.es3.concat(mt.legacy),mt.es6=mt.es3.concat("symbol"),at("(number)",function(){return this}),at("(string)",function(){return this}),f.syntax["(identifier)"]={type:"(identifier)",lbp:0,identifier:!0,nud:function(){var e=this.value;return f.tokens.next.id==="=>"?this:(f.funct["(comparray)"].check(e)||f.funct["(scope)"].block.use(e,f.tokens.curr),this)},led:function(){q("E033",f.tokens.next,f.tokens.next.value)}};var Pt={lbp:0,identifier:!1,template:!0};f.syntax["(template)"]=r.extend({type:"(template)",nud:Wt,led:Wt,noSubst:!1},Pt),f.syntax["(template middle)"]=r.extend({type:"(template middle)",middle:!0,noSubst:!1},Pt),f.syntax["(template tail)"]=r.extend({type:"(template tail)",tail:!0,noSubst:!1},Pt),f.syntax["(no subst template)"]=r.extend({type:"(template)",nud:Wt,led:Wt,noSubst:!0,tail:!0},Pt),at("(regexp)",function(){return this}),rt("(endline)"),rt("(begin)"),rt("(end)").reach=!0,rt("(error)").reach=!0,rt("}").reach=!0,rt(")"),rt("]"),rt('"').reach=!0,rt("'").reach=!0,rt(";"),rt(":").reach=!0,rt("#"),ft("else"),ft("case").reach=!0,ft("catch"),ft("default").reach=!0,ft("finally"),ct("arguments",function(e){f.isStrict()&&f.funct["(global)"]&&F("E008",e)}),ct("eval"),ct("false"),ct("Infinity"),ct("null"),ct("this",function(e){f.isStrict()&&!jt()&&!f.option.validthis&&(f.funct["(statement)"]&&f.funct["(name)"].charAt(0)>"Z"||f.funct["(global)"])&&F("W040",e)}),ct("true"),ct("undefined"),Et("=","assign",20),Et("+=","assignadd",20),Et("-=","assignsub",20),Et("*=","assignmult",20),Et("/=","assigndiv",20).nud=function(){q("E014")},Et("%=","assignmod",20),xt("&="),xt("|="),xt("^="),xt("<<="),xt(">>="),xt(">>>="),ht(",",function(e,t){var n;t.exprs=[e],f.option.nocomma&&F("W127");if(!tt({peek:!0}))return t;for(;;){if(!(n=Q(10)))break;t.exprs.push(n);if(f.tokens.next.value!==","||!tt())break}return t},10,!0),ht("?",function(e,t){return $t(),t.left=e,t.right=Q(10),V(":"),t["else"]=Q(10),t},30);var Ht=40;ht("||",function(e,t){return $t(),t.left=e,t.right=Q(Ht),t},Ht),ht("&&","and",50),St("|","bitor",70),St("^","bitxor",80),St("&","bitand",90),dt("==",function(e,t){var n=f.option.eqnull&&((e&&e.value)==="null"||(t&&t.value)==="null");switch(!0){case!n&&f.option.eqeqeq:this.from=this.character,F("W116",this,"===","==");break;case vt(e):F("W041",this,"===",e.value);break;case vt(t):F("W041",this,"===",t.value);break;case gt(t,e,f):F("W122",this,t.value);break;case gt(e,t,f):F("W122",this,e.value)}return this}),dt("===",function(e,t){return gt(t,e,f)?F("W122",this,t.value):gt(e,t,f)&&F("W122",this,e.value),this}),dt("!=",function(e,t){var n=f.option.eqnull&&((e&&e.value)==="null"||(t&&t.value)==="null");return!n&&f.option.eqeqeq?(this.from=this.character,F("W116",this,"!==","!=")):vt(e)?F("W041",this,"!==",e.value):vt(t)?F("W041",this,"!==",t.value):gt(t,e,f)?F("W122",this,t.value):gt(e,t,f)&&F("W122",this,e.value),this}),dt("!==",function(e,t){return gt(t,e,f)?F("W122",this,t.value):gt(e,t,f)&&F("W122",this,e.value),this}),dt("<"),dt(">"),dt("<="),dt(">="),St("<<","shiftleft",120),St(">>","shiftright",120),St(">>>","shiftrightunsigned",120),ht("in","in",120),ht("instanceof","instanceof",120),ht("+",function(e,t){var n;return t.left=e,t.right=n=Q(130),e&&n&&e.id==="(string)"&&n.id==="(string)"?(e.value+=n.value,e.character=n.character,!f.option.scripturl&&a.javascriptURL.test(e.value)&&F("W050",e),e):t},130),ut("+","num"),ut("+++",function(){return F("W007"),this.arity="unary",this.right=Q(150),this}),ht("+++",function(e){return F("W007"),this.left=e,this.right=Q(130),this},130),ht("-","sub",130),ut("-","neg"),ut("---",function(){return F("W006"),this.arity="unary",this.right=Q(150),this}),ht("---",function(e){return F("W006"),this.left=e,this.right=Q(130),this},130),ht("*","mult",140),ht("/","div",140),ht("%","mod",140),Tt("++"),ut("++","preinc"),f.syntax["++"].exps=!0,Tt("--"),ut("--","predec"),f.syntax["--"].exps=!0,ut("delete",function(){var e=Q(10);return e?(e.id!=="."&&e.id!=="["&&F("W051"),this.first=e,e.identifier&&!f.isStrict()&&(e.forgiveUndef=!0),this):this}).exps=!0,ut("~",function(){return f.option.bitwise&&F("W016",this,"~"),this.arity="unary",this.right=Q(150),this}),ut("...",function(){return f.inES6(!0)||F("W119",this,"spread/rest operator","6"),!f.tokens.next.identifier&&f.tokens.next.type!=="(string)"&&!hn(f.tokens.next,["[","("])&&q("E030",f.tokens.next,f.tokens.next.value),Q(150),this}),ut("!",function(){return this.arity="unary",this.right=Q(150),this.right||B("E041",this.line||0),t[this.right.id]===!0&&F("W018",this,"!"),this}),ut("typeof",function(){var e=Q(150);return this.first=this.right=e,e||B("E041",this.line||0,this.character||0),e.identifier&&(e.forgiveUndef=!0),this}),ut("new",function(){var e=Qt("target",function(){f.inES6(!0)||F("W119",f.tokens.prev,"new.target","6");var e,t=f.funct;while(t){e=!t["(global)"];if(!t["(arrow)"])break;t=t["(context)"]}e||F("W136",f.tokens.prev,"new.target")});if(e)return e;var t=Q(155),n;if(t&&t.id!=="function")if(t.identifier){t["new"]=!0;switch(t.value){case"Number":case"String":case"Boolean":case"Math":case"JSON":F("W053",f.tokens.prev,t.value);break;case"Symbol":f.inES6()&&F("W053",f.tokens.prev,t.value);break;case"Function":f.option.evil||F("W054");break;case"Date":case"RegExp":case"this":break;default:t.id!=="function"&&(n=t.value.substr(0,1),f.option.newcap&&(n<"A"||n>"Z")&&!f.funct["(scope)"].isPredefined(t.value)&&F("W055",f.tokens.curr))}}else t.id!=="."&&t.id!=="["&&t.id!=="("&&F("W056",f.tokens.curr);else f.option.supernew||F("W057",this);return f.tokens.next.id!=="("&&!f.option.supernew&&F("W058",f.tokens.curr,f.tokens.curr.value),this.first=this.right=t,this}),f.syntax["new"].exps=!0,ut("void").exps=!0,ht(".",function(e,t){var n=Ct(!1,!0);return typeof n=="string"&&Dt(n),t.left=e,t.right=n,n&&n==="hasOwnProperty"&&f.tokens.next.value==="="&&F("W001"),!e||e.value!=="arguments"||n!=="callee"&&n!=="caller"?!f.option.evil&&e&&e.value==="document"&&(n==="write"||n==="writeln")&&F("W060",e):f.option.noarg?F("W059",e,n):f.isStrict()&&q("E008"),!f.option.evil&&(n==="eval"||n==="execScript")&&yt(e,f)&&F("W061"),t},160,!0),ht("(",function(e,t){f.option.immed&&e&&!e.immed&&e.id==="function"&&F("W062");var n=0,r=[];e&&e.type==="(identifier)"&&e.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)&&"Array Number String Boolean Date Object Error Symbol".indexOf(e.value)===-1&&(e.value==="Math"?F("W063",e):f.option.newcap&&F("W064",e));if(f.tokens.next.id!==")")for(;;){r[r.length]=Q(10),n+=1;if(f.tokens.next.id!==",")break;tt()}return V(")"),typeof e=="object"&&(!f.inES5()&&e.value==="parseInt"&&n===1&&F("W065",f.tokens.curr),f.option.evil||(e.value==="eval"||e.value==="Function"||e.value==="execScript"?(F("W061",e),r[0]&&[0].id==="(string)"&&U(e,r[0].value)):!r[0]||r[0].id!=="(string)"||e.value!=="setTimeout"&&e.value!=="setInterval"?r[0]&&r[0].id==="(string)"&&e.value==="."&&e.left.value==="window"&&(e.right==="setTimeout"||e.right==="setInterval")&&(F("W066",e),U(e,r[0].value)):(F("W066",e),U(e,r[0].value))),!e.identifier&&e.id!=="."&&e.id!=="["&&e.id!=="=>"&&e.id!=="("&&e.id!=="&&"&&e.id!=="||"&&e.id!=="?"&&(!f.inES6()||!e["(name)"])&&F("W067",t)),t.left=e,t},155,!0).exps=!0,ut("(",function(){var e=f.tokens.next,t,n=-1,r,i,s,o,u=1,a=f.tokens.curr,l=f.tokens.prev,c=!f.option.singleGroups;do e.value==="("?u+=1:e.value===")"&&(u-=1),n+=1,t=e,e=W(n);while((u!==0||t.value!==")")&&e.value!==";"&&e.type!=="(end)");f.tokens.next.id==="function"&&(i=f.tokens.next.immed=!0);if(e.value==="=>")return Xt({type:"arrow",parsedOpening:!0});var h=[];if(f.tokens.next.id!==")")for(;;){h.push(Q(10));if(f.tokens.next.id!==",")break;f.option.nocomma&&F("W127"),tt()}V(")",this),f.option.immed&&h[0]&&h[0].id==="function"&&f.tokens.next.id!=="("&&f.tokens.next.id!=="."&&f.tokens.next.id!=="["&&F("W068",this);if(!h.length)return;return h.length>1?(r=Object.create(f.syntax[","]),r.exprs=h,s=h[0],o=h[h.length-1],c||(c=l.assign||l.delim)):(r=s=o=h[0],c||(c=a.beginsStmt&&(r.id==="{"||i||Ut(r))||i&&(!J()||f.tokens.prev.id!=="}")||Ut(r)&&!J()||r.id==="{"&&l.id==="=>"||r.type==="(number)"&&pn(e,".")&&/^\d+$/.test(r.value))),r&&(!c&&(s.left||s.right||r.exprs)&&(c=!K(l)&&s.lbp<=l.lbp||!J()&&o.lbp<f.tokens.next.lbp),c||F("W126",a),r.paren=!0),r}),pt("=>"),ht("[",function(e,t){var n=Q(10),r;return n&&n.type==="(string)"&&(!f.option.evil&&(n.value==="eval"||n.value==="execScript")&&yt(e,f)&&F("W061"),Dt(n.value),!f.option.sub&&a.identifier.test(n.value)&&(r=f.syntax[n.value],(!r||!O(r))&&F("W069",f.tokens.prev,n.value))),V("]",t),n&&n.value==="hasOwnProperty"&&f.tokens.next.value==="="&&F("W001"),t.left=e,t.right=n,t},160,!0),ut("[",function(){var e=an();if(e.isCompArray)return!f.option.esnext&&!f.inMoz()&&F("W118",f.tokens.curr,"array comprehension"),Bt();if(e.isDestAssign)return this.destructAssign=Gt({openingParsed:!0,assignment:!0}),this;var t=f.tokens.curr.line!==G(f.tokens.next);this.first=[],t&&(g+=f.option.indent,f.tokens.next.from===g+f.option.indent&&(g+=f.option.indent));while(f.tokens.next.id!=="(end)"){while(f.tokens.next.id===","){if(!f.option.elision){if(!!f.inES5()){F("W128");do V(",");while(f.tokens.next.id===",");continue}F("W070")}V(",")}if(f.tokens.next.id==="]")break;this.first.push(Q(10));if(f.tokens.next.id!==",")break;tt({allowTrailing:!0});if(f.tokens.next.id==="]"&&!f.inES5()){F("W070",f.tokens.curr);break}}return t&&(g-=f.option.indent),V("]",this),this}),function(e){e.nud=function(){var e,t,n,r,i,s=!1,o,u=Object.create(null);e=f.tokens.curr.line!==G(f.tokens.next),e&&(g+=f.option.indent,f.tokens.next.from===g+f.option.indent&&(g+=f.option.indent));var a=an();if(a.isDestAssign)return this.destructAssign=Gt({openingParsed:!0,assignment:!0}),this;for(;;){if(f.tokens.next.id==="}")break;o=f.tokens.next.value;if(!f.tokens.next.identifier||X().id!==","&&X().id!=="}")if(W().id===":"||o!=="get"&&o!=="set"){f.tokens.next.value==="*"&&f.tokens.next.type==="(punctuator)"?(f.inES6()||F("W104",f.tokens.next,"generator functions","6"),V("*"),s=!0):s=!1;if(f.tokens.next.id==="[")n=cn(),f.nameStack.set(n);else{f.nameStack.set(f.tokens.next),n=It(),fn(u,n,f.tokens.next);if(typeof n!="string")break}f.tokens.next.value==="("?(f.inES6()||F("W104",f.tokens.curr,"concise methods","6"),Xt({type:s?"generator":null})):(V(":"),Q(10))}else V(o),f.inES5()||q("E034"),n=It(),!n&&!f.inES6()&&q("E035"),n&&ln(o,u,n,f.tokens.curr),i=f.tokens.next,t=Xt(),r=t["(params)"],o==="get"&&n&&r?F("W076",i,r[0],n):o==="set"&&n&&(!r||r.length!==1)&&F("W077",i,n);else f.inES6()||F("W104",f.tokens.next,"object short notation","6"),n=It(!0),fn(u,n,f.tokens.next),Q(10);Dt(n);if(f.tokens.next.id!==",")break;tt({allowTrailing:!0,property:!0}),f.tokens.next.id===","?F("W070",f.tokens.curr):f.tokens.next.id==="}"&&!f.inES5()&&F("W070",f.tokens.curr)}return e&&(g-=f.option.indent),V("}",this),Kt(u),this},e.fud=function(){q("E036",f.tokens.curr)}}(rt("{"));var tn=it("const",function(e){return en("const",this,e)});tn.exps=!0;var nn=it("let",function(e){return en("let",this,e)});nn.exps=!0;var rn=it("var",function(e){var t=e&&e.prefix,n=e&&e.inexport,i,o,u,a=e&&e.implied,l=!e||!e.ignore;this.first=[];for(;;){var c=[];r.contains(["{","["],f.tokens.next.value)?(i=Gt(),o=!1):(i=[{id:Ct(),token:f.tokens.curr}],o=!0),(!t||!a)&&l&&f.option.varstmt&&F("W132",this),this.first=this.first.concat(c);for(var h in i)i.hasOwnProperty(h)&&(h=i[h],!a&&f.funct["(global)"]&&(S[h.id]===!1?F("W079",h.token,h.id):f.option.futurehostile===!1&&(!f.inES5()&&s.ecmaIdentifiers[5][h.id]===!1||!f.inES6()&&s.ecmaIdentifiers[6][h.id]===!1)&&F("W129",h.token,h.id)),h.id&&(a==="for"?(f.funct["(scope)"].has(h.id)||l&&F("W088",h.token,h.id),f.funct["(scope)"].block.use(h.id,h.token)):(f.funct["(scope)"].addlabel(h.id,{type:"var",token:h.token}),o&&n&&f.funct["(scope)"].setExported(h.id,h.token)),c.push(h.token)));f.tokens.next.id==="="&&(f.nameStack.set(f.tokens.curr),V("="),!t&&l&&!f.funct["(loopage)"]&&f.tokens.next.id==="undefined"&&F("W080",f.tokens.prev,f.tokens.prev.value),W(0).id==="="&&f.tokens.next.identifier&&(!t&&l&&!f.funct["(params)"]||f.funct["(params)"].indexOf(f.tokens.next.value)===-1)&&F("W120",f.tokens.next,f.tokens.next.value),u=Q(t?120:10),o?i[0].first=u:Zt(c,u));if(f.tokens.next.id!==",")break;tt()}return this});rn.exps=!0,st("class",function(){return sn.call(this,!0)}),st("function",function(e){var t=e&&e.inexport,n=!1;f.tokens.next.value==="*"&&(V("*"),f.inES6({strict:!0})?n=!0:F("W119",f.tokens.curr,"function*","6")),m&&F("W082",f.tokens.curr);var r=Nt();return f.funct["(scope)"].addlabel(r,{type:"function",token:f.tokens.curr}),r===undefined?F("W025"):t&&f.funct["(scope)"].setExported(r,f.tokens.prev),Xt({name:r,statement:this,type:n?"generator":null,ignoreLoopFunc:m}),f.tokens.next.id==="("&&f.tokens.next.line===f.tokens.curr.line&&q("E039"),this}),ut("function",function(){var e=!1;f.tokens.next.value==="*"&&(f.inES6()||F("W119",f.tokens.curr,"function*","6"),V("*"),e=!0);var t=Nt();return Xt({name:t,type:e?"generator":null}),this}),st("if",function(){var e=f.tokens.next;$t(),f.condition=!0,V("(");var t=Q(0);Jt(t);var n=null;f.option.forin&&f.forinifcheckneeded&&(f.forinifcheckneeded=!1,n=f.forinifchecks[f.forinifchecks.length-1],t.type==="(punctuator)"&&t.value==="!"?n.type="(negative)":n.type="(positive)"),V(")",e),f.condition=!1;var r=_t(!0,!0);return n&&n.type==="(negative)"&&r&&r[0]&&r[0].type==="(identifier)"&&r[0].value==="continue"&&(n.type="(negative-with-continue)"),f.tokens.next.id==="else"&&(V("else"),f.tokens.next.id==="if"||f.tokens.next.id==="switch"?At():_t(!0,!0)),this}),st("try",function(){function t(){V("catch"),V("("),f.funct["(scope)"].stack("catchparams");if(hn(f.tokens.next,["[","{"])){var e=Gt();r.each(e,function(e){e.id&&f.funct["(scope)"].addParam(e.id,e,"exception")})}else f.tokens.next.type!=="(identifier)"?F("E030",f.tokens.next,f.tokens.next.value):f.funct["(scope)"].addParam(Ct(),f.tokens.curr,"exception");f.tokens.next.value==="if"&&(f.inMoz()||F("W118",f.tokens.curr,"catch filter"),V("if"),Q(0)),V(")"),_t(!1),f.funct["(scope)"].unstack()}var e;_t(!0);while(f.tokens.next.id==="catch")$t(),e&&!f.inMoz()&&F("W118",f.tokens.next,"multiple catch blocks"),t(),e=!0;if(f.tokens.next.id==="finally"){V("finally"),_t(!0);return}return e||q("E021",f.tokens.next,"catch",f.tokens.next.value),this}),st("while",function(){var e=f.tokens.next;return f.funct["(breakage)"]+=1,f.funct["(loopage)"]+=1,$t(),V("("),Jt(Q(0)),V(")",e),_t(!0,!0),f.funct["(breakage)"]-=1,f.funct["(loopage)"]-=1,this}).labelled=!0,st("with",function(){var e=f.tokens.next;return f.isStrict()?q("E010",f.tokens.curr):f.option.withstmt||F("W085",f.tokens.curr),V("("),Q(0),V(")",e),_t(!0,!0),this}),st("switch",function(){var e=f.tokens.next,t=!1,n=!1;f.funct["(breakage)"]+=1,V("("),Jt(Q(0)),V(")",e),e=f.tokens.next,V("{"),f.tokens.next.from===g&&(n=!0),n||(g+=f.option.indent),this.cases=[];for(;;)switch(f.tokens.next.id){case"case":switch(f.funct["(verb)"]){case"yield":case"break":case"case":case"continue":case"return":case"switch":case"throw":break;default:f.tokens.curr.caseFallsThrough||F("W086",f.tokens.curr,"case")}V("case"),this.cases.push(Q(0)),$t(),t=!0,V(":"),f.funct["(verb)"]="case";break;case"default":switch(f.funct["(verb)"]){case"yield":case"break":case"continue":case"return":case"throw":break;default:this.cases.length&&(f.tokens.curr.caseFallsThrough||F("W086",f.tokens.curr,"default"))}V("default"),t=!0,V(":");break;case"}":n||(g-=f.option.indent),V("}",e),f.funct["(breakage)"]-=1,f.funct["(verb)"]=undefined;return;case"(end)":q("E023",f.tokens.next,"}");return;default:g+=f.option.indent;if(t)switch(f.tokens.curr.id){case",":q("E040");return;case":":t=!1,Ot();break;default:q("E025",f.tokens.curr);return}else{if(f.tokens.curr.id!==":"){q("E021",f.tokens.next,"case",f.tokens.next.value);return}V(":"),q("E024",f.tokens.curr,":"),Ot()}g-=f.option.indent}return this}).labelled=!0,it("debugger",function(){return f.option.debug||F("W087",this),this}).exps=!0,function(){var e=it("do",function(){f.funct["(breakage)"]+=1,f.funct["(loopage)"]+=1,$t(),this.first=_t(!0,!0),V("while");var e=f.tokens.next;return V("("),Jt(Q(0)),V(")",e),f.funct["(breakage)"]-=1,f.funct["(loopage)"]-=1,this});e.labelled=!0,e.exps=!0}(),st("for",function(){var e,t=f.tokens.next,n=!1,i=null;t.value==="each"&&(i=t,V("each"),f.inMoz()||F("W118",f.tokens.curr,"for each")),$t(),V("(");var s,o=0,u=["in","of"],a=0,l,c;hn(f.tokens.next,["{","["])&&++a;do{s=W(o),++o,hn(s,["{","["])?++a:hn(s,["}","]"])&&--a;if(a<0)break;a===0&&(!l&&pn(s,",")?l=s:!c&&pn(s,"=")&&(c=s))}while(a>0||!r.contains(u,s.value)&&s.value!==";"&&s.type!=="(end)");if(r.contains(u,s.value)){!f.inES6()&&s.value==="of"&&F("W104",s,"for of","6");var h=!c&&!l;c&&q("W133",l,s.value,"initializer is forbidden"),l&&q("W133",l,s.value,"more than one ForBinding"),f.tokens.next.id==="var"?(V("var"),f.tokens.curr.fud({prefix:!0})):f.tokens.next.id==="let"||f.tokens.next.id==="const"?(V(f.tokens.next.id),n=!0,f.funct["(scope)"].stack(),f.tokens.curr.fud({prefix:!0})):Object.create(rn).fud({prefix:!0,implied:"for",ignore:!h}),V(s.value),Q(20),V(")",t),s.value==="in"&&f.option.forin&&(f.forinifcheckneeded=!0,f.forinifchecks===undefined&&(f.forinifchecks=[]),f.forinifchecks.push({type:"(none)"})),f.funct["(breakage)"]+=1,f.funct["(loopage)"]+=1,e=_t(!0,!0);if(s.value==="in"&&f.option.forin){if(f.forinifchecks&&f.forinifchecks.length>0){var p=f.forinifchecks.pop();(e&&e.length>0&&(typeof e[0]!="object"||e[0].value!=="if")||p.type==="(positive)"&&e.length>1||p.type==="(negative)")&&F("W089",this)}f.forinifcheckneeded=!1}f.funct["(breakage)"]-=1,f.funct["(loopage)"]-=1}else{i&&q("E045",i);if(f.tokens.next.id!==";")if(f.tokens.next.id==="var")V("var"),f.tokens.curr.fud();else if(f.tokens.next.id==="let")V("let"),n=!0,f.funct["(scope)"].stack(),f.tokens.curr.fud();else for(;;){Q(0,"for");if(f.tokens.next.id!==",")break;l()}Z(f.tokens.curr),V(";"),f.funct["(loopage)"]+=1,f.tokens.next.id!==";"&&Jt(Q(0)),Z(f.tokens.curr),V(";"),f.tokens.next.id===";"&&q("E021",f.tokens.next,")",";");if(f.tokens.next.id!==")")for(;;){Q(0,"for");if(f.tokens.next.id!==",")break;l()}V(")",t),f.funct["(breakage)"]+=1,_t(!0,!0),f.funct["(breakage)"]-=1,f.funct["(loopage)"]-=1}return n&&f.funct["(scope)"].unstack(),this}).labelled=!0,it("break",function(){var e=f.tokens.next.value;return f.option.asi||Z(this),f.tokens.next.id!==";"&&!f.tokens.next.reach&&f.tokens.curr.line===G(f.tokens.next)?(f.funct["(scope)"].funct.hasBreakLabel(e)||F("W090",f.tokens.next,e),this.first=f.tokens.next,V()):f.funct["(breakage)"]===0&&F("W052",f.tokens.next,this.value),kt(this),this}).exps=!0,it("continue",function(){var e=f.tokens.next.value;return f.funct["(breakage)"]===0&&F("W052",f.tokens.next,this.value),f.funct["(loopage)"]||F("W052",f.tokens.next,this.value),f.option.asi||Z(this),f.tokens.next.id!==";"&&!f.tokens.next.reach&&f.tokens.curr.line===G(f.tokens.next)&&(f.funct["(scope)"].funct.hasBreakLabel(e)||F("W090",f.tokens.next,e),this.first=f.tokens.next,V()),kt(this),this}).exps=!0,it("return",function(){return this.line===G(f.tokens.next)?f.tokens.next.id!==";"&&!f.tokens.next.reach&&(this.first=Q(0),this.first&&this.first.type==="(punctuator)"&&this.first.value==="="&&!this.first.paren&&!f.option.boss&&I("W093",this.first.line,this.first.character)):f.tokens.next.type==="(punctuator)"&&["[","{","+","-"].indexOf(f.tokens.next.value)>-1&&Z(this),kt(this),this}).exps=!0,function(e){e.exps=!0,e.lbp=25}(ut("yield",function(){var e=f.tokens.prev;f.inES6(!0)&&!f.funct["(generator)"]?("(catch)"!==f.funct["(name)"]||!f.funct["(context)"]["(generator)"])&&q("E046",f.tokens.curr,"yield"):f.inES6()||F("W104",f.tokens.curr,"yield","6"),f.funct["(generator)"]="yielded";var t=!1;f.tokens.next.value==="*"&&(t=!0,V("*"));if(this.line===G(f.tokens.next)||!f.inMoz()){if(t||f.tokens.next.id!==";"&&!f.option.asi&&!f.tokens.next.reach&&f.tokens.next.nud)Y(f.tokens.curr,f.tokens.next),this.first=Q(10),this.first.type==="(punctuator)"&&this.first.value==="="&&!this.first.paren&&!f.option.boss&&I("W093",this.first.line,this.first.character);f.inMoz()&&f.tokens.next.id!==")"&&(e.lbp>30||!e.assign&&!J()||e.id==="yield")&&q("E050",this)}else f.option.asi||Z(this);return this})),it("throw",function(){return Z(this),this.first=Q(20),kt(this),this}).exps=!0,it("import",function(){f.inES6()||F("W119",f.tokens.curr,"import","6");if(f.tokens.next.type==="(string)")return V("(string)"),this;if(f.tokens.next.identifier){this.name=Ct(),f.funct["(scope)"].addlabel(this.name,{type:"const",token:f.tokens.curr});if(f.tokens.next.value!==",")return V("from"),V("(string)"),this;V(",")}if(f.tokens.next.id==="*")V("*"),V("as"),f.tokens.next.identifier&&(this.name=Ct(),f.funct["(scope)"].addlabel(this.name,{type:"const",token:f.tokens.curr}));else{V("{");for(;;){if(f.tokens.next.value==="}"){V("}");break}var e;f.tokens.next.type==="default"?(e="default",V("default")):e=Ct(),f.tokens.next.value==="as"&&(V("as"),e=Ct()),f.funct["(scope)"].addlabel(e,{type:"const",token:f.tokens.curr});if(f.tokens.next.value!==","){if(f.tokens.next.value==="}"){V("}");break}q("E024",f.tokens.next,f.tokens.next.value);break}V(",")}}return V("from"),V("(string)"),this}).exps=!0,it("export",function(){var e=!0,t,n;f.inES6()||(F("W119",f.tokens.curr,"export","6"),e=!1),f.funct["(scope)"].block.isGlobal()||(q("E053",f.tokens.curr),e=!1);if(f.tokens.next.value==="*")return V("*"),V("from"),V("(string)"),this;if(f.tokens.next.type==="default"){f.nameStack.set(f.tokens.next),V("default");var r=f.tokens.next.id;if(r==="function"||r==="class")this.block=!0;return t=W(),Q(10),n=t.value,this.block&&(f.funct["(scope)"].addlabel(n,{type:r,token:t}),f.funct["(scope)"].setExported(n,t)),this}if(f.tokens.next.value==="{"){V("{");var i=[];for(;;){f.tokens.next.identifier||q("E030",f.tokens.next,f.tokens.next.value),V(),i.push(f.tokens.curr),f.tokens.next.value==="as"&&(V("as"),f.tokens.next.identifier||q("E030",f.tokens.next,f.tokens.next.value),V());if(f.tokens.next.value!==","){if(f.tokens.next.value==="}"){V("}");break}q("E024",f.tokens.next,f.tokens.next.value);break}V(",")}return f.tokens.next.value==="from"?(V("from"),V("(string)")):e&&i.forEach(function(e){f.funct["(scope)"].setExported(e.value,e)}),this}if(f.tokens.next.id==="var")V("var"),f.tokens.curr.fud({inexport:!0});else if(f.tokens.next.id==="let")V("let"),f.tokens.curr.fud({inexport:!0});else if(f.tokens.next.id==="const")V("const"),f.tokens.curr.fud({inexport:!0});else if(f.tokens.next.id==="function")this.block=!0,V("function"),f.syntax["function"].fud({inexport:!0});else if(f.tokens.next.id==="class"){this.block=!0,V("class");var s=f.tokens.next;f.syntax["class"].fud(),f.funct["(scope)"].setExported(s.value,s)}else q("E024",f.tokens.next,f.tokens.next.value);return this}).exps=!0,lt("abstract"),lt("boolean"),lt("byte"),lt("char"),lt("class",{es5:!0,nud:sn}),lt("double"),lt("enum",{es5:!0}),lt("export",{es5:!0}),lt("extends",{es5:!0}),lt("final"),lt("float"),lt("goto"),lt("implements",{es5:!0,strictOnly:!0}),lt("import",{es5:!0}),lt("int"),lt("interface",{es5:!0,strictOnly:!0}),lt("long"),lt("native"),lt("package",{es5:!0,strictOnly:!0}),lt("private",{es5:!0,strictOnly:!0}),lt("protected",{es5:!0,strictOnly:!0}),lt("public",{es5:!0,strictOnly:!0}),lt("short"),lt("static",{es5:!0,strictOnly:!0}),lt("super",{es5:!0}),lt("synchronized"),lt("transient"),lt("volatile");var an=function(){var e,t,n,r=-1,i=0,s={};hn(f.tokens.curr,["[","{"])&&(i+=1);do{n=r===-1?f.tokens.curr:e,e=r===-1?f.tokens.next:W(r),t=W(r+1),r+=1,hn(e,["[","{"])?i+=1:hn(e,["]","}"])&&(i-=1);if(i===1&&e.identifier&&e.value==="for"&&!pn(n,".")){s.isCompArray=!0,s.notJson=!0;break}if(i===0&&hn(e,["}","]"])){if(t.value==="="){s.isDestAssign=!0,s.notJson=!0;break}if(t.value==="."){s.notJson=!0;break}}pn(e,";")&&(s.isBlock=!0,s.notJson=!0)}while(i>0&&e.id!=="(end)");return s},vn=function(){function i(e){var t=n.variables.filter(function(t){if(t.value===e)return t.undef=!1,e}).length;return t!==0}function s(e){var t=n.variables.filter(function(t){if(t.value===e&&!t.undef)return t.unused===!0&&(t.unused=!1),e}).length;return t===0}var e=function(){this.mode="use",this.variables=[]},t=[],n;return{stack:function(){n=new e,t.push(n)},unstack:function(){n.variables.filter(function(e){e.unused&&F("W098",e.token,e.raw_text||e.value),e.undef&&f.funct["(scope)"].block.use(e.value,e.token)}),t.splice(-1,1),n=t[t.length-1]},setState:function(e){r.contains(["use","define","generate","filter"],e)&&(n.mode=e)},check:function(e){if(!n)return;return n&&n.mode==="use"?(s(e)&&n.variables.push({funct:f.funct,token:f.tokens.curr,value:e,undef:!0,unused:!1}),!0):n&&n.mode==="define"?(i(e)||n.variables.push({funct:f.funct,token:f.tokens.curr,value:e,undef:!1,unused:!0}),!0):n&&n.mode==="generate"?(f.funct["(scope)"].block.use(e,f.tokens.curr),!0):n&&n.mode==="filter"?(s(e)&&f.funct["(scope)"].block.use(e,f.tokens.curr),!0):!1}}},gn=function(e){return e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")},yn=function(t,i,o){function U(e,t){if(!e)return;!Array.isArray(e)&&typeof e=="object"&&(e=Object.keys(e)),e.forEach(t)}var a,l,c,d,A,O,M={},P={};i=r.clone(i),f.reset(),i&&i.scope?p.scope=i.scope:(p.errors=[],p.undefs=[],p.internals=[],p.blacklist={},p.scope="(main)"),S=Object.create(null),D(S,s.ecmaIdentifiers[3]),D(S,s.reservedVars),D(S,o||{}),n=Object.create(null);var j=Object.create(null);if(i){U(i.predef||null,function(e){var t,n;e[0]==="-"?(t=e.slice(1),p.blacklist[t]=t,delete S[t]):(n=Object.getOwnPropertyDescriptor(i.predef,e),S[e]=n?n.value:!1)}),U(i.exported||null,function(e){j[e]=!0}),delete i.predef,delete i.exported,O=Object.keys(i);for(c=0;c<O.length;c++)if(/^-W\d{3}$/g.test(O[c]))P[O[c].slice(1)]=!0;else{var z=O[c];M[z]=i[z],(z==="esversion"&&i[z]===5||z==="es5"&&i[z])&&F("I003"),O[c]==="newcap"&&i[z]===!1&&(M["(explicitNewcap)"]=!0)}}f.option=M,f.ignored=P,f.option.indent=f.option.indent||4,f.option.maxerr=f.option.maxerr||50,g=1;var W=h(f,S,j,n);W.on("warning",function(e){F.apply(null,[e.code,e.token].concat(e.data))}),W.on("error",function(e){q.apply(null,[e.code,e.token].concat(e.data))}),f.funct=Rt("(global)",null,{"(global)":!0,"(scope)":W,"(comparray)":vn(),"(metrics)":Vt(f.tokens.next)}),v=[f.funct],T=[],x=null,w={},E=null,m=!1,y=[];if(!L(t)&&!Array.isArray(t))return R("E004",0),!1;e={get isJSON(){return f.jsonMode},getOption:function(e){return f.option[e]||null},getCache:function(e){return f.cache[e]},setCache:function(e,t){f.cache[e]=t},warn:function(e,t){I.apply(null,[e,t.line,t.char].concat(t.data))},on:function(e,t){e.split(" ").forEach(function(e){C.on(e,t)}.bind(this))}},C.removeAllListeners(),(N||[]).forEach(function(t){t(e)}),f.tokens.prev=f.tokens.curr=f.tokens.next=f.syntax["(begin)"],i&&i.ignoreDelimiters&&(Array.isArray(i.ignoreDelimiters)||(i.ignoreDelimiters=[i.ignoreDelimiters]),i.ignoreDelimiters.forEach(function(e){if(!e.start||!e.end)return;d=gn(e.start)+"[\\s\\S]*?"+gn(e.end),A=new RegExp(d,"ig"),t=t.replace(A,function(e){return e.replace(/./g," ")})})),b=new u(t),b.on("warning",function(e){I.apply(null,[e.code,e.line,e.character].concat(e.data))}),b.on("error",function(e){R.apply(null,[e.code,e.line,e.character].concat(e.data))}),b.on("fatal",function(e){B("E041",e.line,e.from)}),b.on("Identifier",function(e){C.emit("Identifier",e)}),b.on("String",function(e){C.emit("String",e)}),b.on("Number",function(e){C.emit("Number",e)}),b.start();for(var X in i)r.has(i,X)&&k(X,f.tokens.curr);H(),D(S,o||{}),tt.first=!0;try{V();switch(f.tokens.next.id){case"{":case"[":dn();break;default:Mt(),f.directive["use strict"]&&f.option.strict!=="global"&&F("W097",f.tokens.prev),Ot()}f.tokens.next.id!=="(end)"&&B("E041",f.tokens.curr.line),f.funct["(scope)"].unstack()}catch($){if(!$||$.name!=="JSHintError")throw $;var J=f.tokens.next||{};p.errors.push({scope:"(main)",raw:$.raw,code:$.code,reason:$.message,line:$.line||J.line,character:$.character||J.from},null)}if(p.scope==="(main)"){i=i||{};for(a=0;a<p.internals.length;a+=1)l=p.internals[a],i.scope=l.elem,yn(l.value,i,o)}return p.errors.length===0};return yn.addModule=function(e){N.push(e)},yn.addModule(l.register),yn.data=function(){var e={functions:[],options:f.option},t,n,r,i,s,o;yn.errors.length&&(e.errors=yn.errors),f.jsonMode&&(e.json=!0);var u=f.funct["(scope)"].getImpliedGlobals();u.length>0&&(e.implieds=u),T.length>0&&(e.urls=T),o=f.funct["(scope)"].getUsedOrDefinedGlobals(),o.length>0&&(e.globals=o);for(r=1;r<v.length;r+=1){n=v[r],t={};for(i=0;i<d.length;i+=1)t[d[i]]=[];for(i=0;i<d.length;i+=1)t[d[i]].length===0&&delete t[d[i]];t.name=n["(name)"],t.param=n["(params)"],t.line=n["(line)"],t.character=n["(character)"],t.last=n["(last)"],t.lastcharacter=n["(lastcharacter)"],t.metrics={complexity:n["(metrics)"].ComplexityCount,parameters:n["(metrics)"].arity,statements:n["(metrics)"].statementCount},e.functions.push(t)}var a=f.funct["(scope)"].getUnuseds();a.length>0&&(e.unused=a);for(s in w)if(typeof w[s]=="number"){e.member=w;break}return e},yn.jshint=yn,yn}();typeof n=="object"&&n&&(n.JSHINT=p)},{"../lodash":"/node_modules/jshint/lodash.js","./lex.js":"/node_modules/jshint/src/lex.js","./messages.js":"/node_modules/jshint/src/messages.js","./options.js":"/node_modules/jshint/src/options.js","./reg.js":"/node_modules/jshint/src/reg.js","./scope-manager.js":"/node_modules/jshint/src/scope-manager.js","./state.js":"/node_modules/jshint/src/state.js","./style.js":"/node_modules/jshint/src/style.js","./vars.js":"/node_modules/jshint/src/vars.js",events:"/node_modules/browserify/node_modules/events/events.js"}],"/node_modules/jshint/src/lex.js":[function(e,t,n){"use strict";function h(){var e=[];return{push:function(t){e.push(t)},check:function(){for(var t=0;t<e.length;++t)e[t]();e.splice(0,e.length)}}}function p(e){var t=e;typeof t=="string"&&(t=t.replace(/\r\n/g,"\n").replace(/\r/g,"\n").split("\n")),t[0]&&t[0].substr(0,2)==="#!"&&(t[0].indexOf("node")!==-1&&(o.option.node=!0),t[0]=""),this.emitter=new i.EventEmitter,this.source=e,this.setLines(t),this.prereg=!0,this.line=0,this.char=1,this.from=1,this.input="",this.inComment=!1,this.context=[],this.templateStarts=[];for(var n=0;n<o.option.indent;n+=1)o.tab+=" ";this.ignoreLinterErrors=!1}var r=e("../lodash"),i=e("events"),s=e("./reg.js"),o=e("./state.js").state,u=e("../data/ascii-identifier-data.js"),a=u.asciiIdentifierStartTable,f=u.asciiIdentifierPartTable,l={Identifier:1,Punctuator:2,NumericLiteral:3,StringLiteral:4,Comment:5,Keyword:6,NullLiteral:7,BooleanLiteral:8,RegExp:9,TemplateHead:10,TemplateMiddle:11,TemplateTail:12,NoSubstTemplate:13},c={Block:1,Template:2};p.prototype={_lines:[],inContext:function(e){return this.context.length>0&&this.context[this.context.length-1].type===e},pushContext:function(e){this.context.push({type:e})},popContext:function(){return this.context.pop()},isContext:function(e){return this.context.length>0&&this.context[this.context.length-1]===e},currentContext:function(){return this.context.length>0&&this.context[this.context.length-1]},getLines:function(){return this._lines=o.lines,this._lines},setLines:function(e){this._lines=e,o.lines=this._lines},peek:function(e){return this.input.charAt(e||0)},skip:function(e){e=e||1,this.char+=e,this.input=this.input.slice(e)},on:function(e,t){e.split(" ").forEach(function(e){this.emitter.on(e,t)}.bind(this))},trigger:function(){this.emitter.emit.apply(this.emitter,Array.prototype.slice.call(arguments))},triggerAsync:function(e,t,n,r){n.push(function(){r()&&this.trigger(e,t)}.bind(this))},scanPunctuator:function(){var e=this.peek(),t,n,r;switch(e){case".":if(/^[0-9]$/.test(this.peek(1)))return null;if(this.peek(1)==="."&&this.peek(2)===".")return{type:l.Punctuator,value:"..."};case"(":case")":case";":case",":case"[":case"]":case":":case"~":case"?":return{type:l.Punctuator,value:e};case"{":return this.pushContext(c.Block),{type:l.Punctuator,value:e};case"}":return this.inContext(c.Block)&&this.popContext(),{type:l.Punctuator,value:e};case"#":return{type:l.Punctuator,value:e};case"":return null}return t=this.peek(1),n=this.peek(2),r=this.peek(3),e===">"&&t===">"&&n===">"&&r==="="?{type:l.Punctuator,value:">>>="}:e==="="&&t==="="&&n==="="?{type:l.Punctuator,value:"==="}:e==="!"&&t==="="&&n==="="?{type:l.Punctuator,value:"!=="}:e===">"&&t===">"&&n===">"?{type:l.Punctuator,value:">>>"}:e==="<"&&t==="<"&&n==="="?{type:l.Punctuator,value:"<<="}:e===">"&&t===">"&&n==="="?{type:l.Punctuator,value:">>="}:e==="="&&t===">"?{type:l.Punctuator,value:e+t}:e===t&&"+-<>&|".indexOf(e)>=0?{type:l.Punctuator,value:e+t}:"<>=!+-*%&|^".indexOf(e)>=0?t==="="?{type:l.Punctuator,value:e+t}:{type:l.Punctuator,value:e}:e==="/"?t==="="?{type:l.Punctuator,value:"/="}:{type:l.Punctuator,value:"/"}:null},scanComments:function(){function u(e,t,n){var r=["jshint","jslint","members","member","globals","global","exported"],i=!1,u=e+t,a="plain";return n=n||{},n.isMultiline&&(u+="*/"),t=t.replace(/\n/g," "),e==="/*"&&s.fallsThrough.test(t)&&(i=!0,a="falls through"),r.forEach(function(n){if(i)return;if(e==="//"&&n!=="jshint")return;t.charAt(n.length)===" "&&t.substr(0,n.length)===n&&(i=!0,e+=n,t=t.substr(n.length)),!i&&t.charAt(0)===" "&&t.charAt(n.length+1)===" "&&t.substr(1,n.length)===n&&(i=!0,e=e+" "+n,t=t.substr(n.length+1));if(!i)return;switch(n){case"member":a="members";break;case"global":a="globals";break;default:var r=t.split(":").map(function(e){return e.replace(/^\s+/,"").replace(/\s+$/,"")});if(r.length===2)switch(r[0]){case"ignore":switch(r[1]){case"start":o.ignoringLinterErrors=!0,i=!1;break;case"end":o.ignoringLinterErrors=!1,i=!1}}a=n}}),{type:l.Comment,commentType:a,value:u,body:t,isSpecial:i,isMultiline:n.isMultiline||!1,isMalformed:n.isMalformed||!1}}var e=this.peek(),t=this.peek(1),n=this.input.substr(2),r=this.line,i=this.char,o=this;if(e==="*"&&t==="/")return this.trigger("error",{code:"E018",line:r,character:i}),this.skip(2),null;if(e!=="/"||t!=="*"&&t!=="/")return null;if(t==="/")return this.skip(this.input.length),u("//",n);var a="";if(t==="*"){this.inComment=!0,this.skip(2);while(this.peek()!=="*"||this.peek(1)!=="/")if(this.peek()===""){a+="\n";if(!this.nextLine())return this.trigger("error",{code:"E017",line:r,character:i}),this.inComment=!1,u("/*",a,{isMultiline:!0,isMalformed:!0})}else a+=this.peek(),this.skip();return this.skip(2),this.inComment=!1,u("/*",a,{isMultiline:!0})}},scanKeyword:function(){var e=/^[a-zA-Z_$][a-zA-Z0-9_$]*/.exec(this.input),t=["if","in","do","var","for","new","try","let","this","else","case","void","with","enum","while","break","catch","throw","const","yield","class","super","return","typeof","delete","switch","export","import","default","finally","extends","function","continue","debugger","instanceof"];return e&&t.indexOf(e[0])>=0?{type:l.Keyword,value:e[0]}:null},scanIdentifier:function(){function i(e){return e>256}function s(e){return e>256}function o(e){return/^[0-9a-fA-F]$/.test(e)}function p(e){return e.replace(/\\u([0-9a-fA-F]{4})/g,function(e,t){return String.fromCharCode(parseInt(t,16))})}var e="",t=0,n,r,u=function(){t+=1;if(this.peek(t)!=="u")return null;var e=this.peek(t+1),n=this.peek(t+2),r=this.peek(t+3),i=this.peek(t+4),u;return o(e)&&o(n)&&o(r)&&o(i)?(u=parseInt(e+n+r+i,16),f[u]||s(u)?(t+=5,"\\u"+e+n+r+i):null):null}.bind(this),c=function(){var e=this.peek(t),n=e.charCodeAt(0);return n===92?u():n<128?a[n]?(t+=1,e):null:i(n)?(t+=1,e):null}.bind(this),h=function(){var e=this.peek(t),n=e.charCodeAt(0);return n===92?u():n<128?f[n]?(t+=1,e):null:s(n)?(t+=1,e):null}.bind(this);r=c();if(r===null)return null;e=r;for(;;){r=h();if(r===null)break;e+=r}switch(e){case"true":case"false":n=l.BooleanLiteral;break;case"null":n=l.NullLiteral;break;default:n=l.Identifier}return{type:n,value:p(e),text:e,tokenLength:e.length}},scanNumericLiteral:function(){function f(e){return/^[0-9]$/.test(e)}function c(e){return/^[0-7]$/.test(e)}function h(e){return/^[01]$/.test(e)}function p(e){return/^[0-9a-fA-F]$/.test(e)}function d(e){return e==="$"||e==="_"||e==="\\"||e>="a"&&e<="z"||e>="A"&&e<="Z"}var e=0,t="",n=this.input.length,r=this.peek(e),i,s=f,u=10,a=!1;if(r!=="."&&!f(r))return null;if(r!=="."){t=this.peek(e),e+=1,r=this.peek(e);if(t==="0"){if(r==="x"||r==="X")s=p,u=16,e+=1,t+=r;if(r==="o"||r==="O")s=c,u=8,o.inES6(!0)||this.trigger("warning",{code:"W119",line:this.line,character:this.char,data:["Octal integer literal","6"]}),e+=1,t+=r;if(r==="b"||r==="B")s=h,u=2,o.inES6(!0)||this.trigger("warning",{code:"W119",line:this.line,character:this.char,data:["Binary integer literal","6"]}),e+=1,t+=r;c(r)&&(s=c,u=8,a=!0,i=!1,e+=1,t+=r),!c(r)&&f(r)&&(e+=1,t+=r)}while(e<n){r=this.peek(e);if(a&&f(r))i=!0;else if(!s(r))break;t+=r,e+=1}if(s!==f){if(!a&&t.length<=2)return{type:l.NumericLiteral,value:t,isMalformed:!0};if(e<n){r=this.peek(e);if(d(r))return null}return{type:l.NumericLiteral,value:t,base:u,isLegacy:a,isMalformed:!1}}}if(r==="."){t+=r,e+=1;while(e<n){r=this.peek(e);if(!f(r))break;t+=r,e+=1}}if(r==="e"||r==="E"){t+=r,e+=1,r=this.peek(e);if(r==="+"||r==="-")t+=this.peek(e),e+=1;r=this.peek(e);if(!f(r))return null;t+=r,e+=1;while(e<n){r=this.peek(e);if(!f(r))break;t+=r,e+=1}}if(e<n){r=this.peek(e);if(d(r))return null}return{type:l.NumericLiteral,value:t,base:u,isMalformed:!isFinite(t)}},scanEscapeSequence:function(e){var t=!1,n=1;this.skip();var r=this.peek();switch(r){case"'":this.triggerAsync("warning",{code:"W114",line:this.line,character:this.char,data:["\\'"]},e,function(){return o.jsonMode});break;case"b":r="\\b";break;case"f":r="\\f";break;case"n":r="\\n";break;case"r":r="\\r";break;case"t":r="\\t";break;case"0":r="\\0";var i=parseInt(this.peek(1),10);this.triggerAsync("warning",{code:"W115",line:this.line,character:this.char},e,function(){return i>=0&&i<=7&&o.isStrict()});break;case"u":var s=this.input.substr(1,4),u=parseInt(s,16);isNaN(u)&&this.trigger("warning",{code:"W052",line:this.line,character:this.char,data:["u"+s]}),r=String.fromCharCode(u),n=5;break;case"v":this.triggerAsync("warning",{code:"W114",line:this.line,character:this.char,data:["\\v"]},e,function(){return o.jsonMode}),r="";break;case"x":var a=parseInt(this.input.substr(1,2),16);this.triggerAsync("warning",{code:"W114",line:this.line,character:this.char,data:["\\x-"]},e,function(){return o.jsonMode}),r=String.fromCharCode(a),n=3;break;case"\\":r="\\\\";break;case'"':r='\\"';break;case"/":break;case"":t=!0,r=""}return{"char":r,jump:n,allowNewLine:t}},scanTemplateLiteral:function(e){var t,n="",r,i=this.line,s=this.char,u=this.templateStarts.length;if(!o.inES6(!0))return null;if(this.peek()==="`")t=l.TemplateHead,this.templateStarts.push({line:this.line,"char":this.char}),u=this.templateStarts.length,this.skip(1),this.pushContext(c.Template);else{if(!this.inContext(c.Template)||this.peek()!=="}")return null;t=l.TemplateMiddle}while(this.peek()!=="`"){while((r=this.peek())===""){n+="\n";if(!this.nextLine()){var a=this.templateStarts.pop();return this.trigger("error",{code:"E052",line:a.line,character:a.char}),{type:t,value:n,startLine:i,startChar:s,isUnclosed:!0,depth:u,context:this.popContext()}}}if(r==="$"&&this.peek(1)==="{")return n+="${",this.skip(2),{type:t,value:n,startLine:i,startChar:s,isUnclosed:!1,depth:u,context:this.currentContext()};if(r==="\\"){var f=this.scanEscapeSequence(e);n+=f.char,this.skip(f.jump)}else r!=="`"&&(n+=r,this.skip(1))}return t=t===l.TemplateHead?l.NoSubstTemplate:l.TemplateTail,this.skip(1),this.templateStarts.pop(),{type:t,value:n,startLine:i,startChar:s,isUnclosed:!1,depth:u,context:this.popContext()}},scanStringLiteral:function(e){var t=this.peek();if(t!=='"'&&t!=="'")return null;this.triggerAsync("warning",{code:"W108",line:this.line,character:this.char},e,function(){return o.jsonMode&&t!=='"'});var n="",r=this.line,i=this.char,s=!1;this.skip();while(this.peek()!==t)if(this.peek()===""){s?(s=!1,this.triggerAsync("warning",{code:"W043",line:this.line,character:this.char},e,function(){return!o.option.multistr}),this.triggerAsync("warning",{code:"W042",line:this.line,character:this.char},e,function(){return o.jsonMode&&o.option.multistr})):this.trigger("warning",{code:"W112",line:this.line,character:this.char});if(!this.nextLine())return this.trigger("error",{code:"E029",line:r,character:i}),{type:l.StringLiteral,value:n,startLine:r,startChar:i,isUnclosed:!0,quote:t}}else{s=!1;var u=this.peek(),a=1;u<" "&&this.trigger("warning",{code:"W113",line:this.line,character:this.char,data:["<non-printable>"]});if(u==="\\"){var f=this.scanEscapeSequence(e);u=f.char,a=f.jump,s=f.allowNewLine}n+=u,this.skip(a)}return this.skip(),{type:l.StringLiteral,value:n,startLine:r,startChar:i,isUnclosed:!1,quote:t}},scanRegExp:function(){var e=0,t=this.input.length,n=this.peek(),r=n,i="",s=[],o=!1,u=!1,a,f=function(){n<" "&&(o=!0,this.trigger("warning",{code:"W048",line:this.line,character:this.char})),n==="<"&&(o=!0,this.trigger("warning",{code:"W049",line:this.line,character:this.char,data:[n]}))}.bind(this);if(!this.prereg||n!=="/")return null;e+=1,a=!1;while(e<t){n=this.peek(e),r+=n,i+=n;if(u){n==="]"&&(this.peek(e-1)!=="\\"||this.peek(e-2)==="\\")&&(u=!1),n==="\\"&&(e+=1,n=this.peek(e),i+=n,r+=n,f()),e+=1;continue}if(n==="\\"){e+=1,n=this.peek(e),i+=n,r+=n,f();if(n==="/"){e+=1;continue}if(n==="["){e+=1;continue}}if(n==="["){u=!0,e+=1;continue}if(n==="/"){i=i.substr(0,i.length-1),a=!0,e+=1;break}e+=1}if(!a)return this.trigger("error",{code:"E015",line:this.line,character:this.from}),void this.trigger("fatal",{line:this.line,from:this.from});while(e<t){n=this.peek(e);if(!/[gim]/.test(n))break;s.push(n),r+=n,e+=1}try{new RegExp(i,s.join(""))}catch(c){o=!0,this.trigger("error",{code:"E016",line:this.line,character:this.char,data:[c.message]})}return{type:l.RegExp,value:r,flags:s,isMalformed:o}},scanNonBreakingSpaces:function(){return o.option.nonbsp?this.input.search(/(\u00A0)/):-1},scanUnsafeChars:function(){return this.input.search(s.unsafeChars)},next:function(e){this.from=this.char;var t;if(/\s/.test(this.peek())){t=this.char;while(/\s/.test(this.peek()))this.from+=1,this.skip()}var n=this.scanComments()||this.scanStringLiteral(e)||this.scanTemplateLiteral(e);return n?n:(n=this.scanRegExp()||this.scanPunctuator()||this.scanKeyword()||this.scanIdentifier()||this.scanNumericLiteral(),n?(this.skip(n.tokenLength||n.value.length),n):null)},nextLine:function(){var e;if(this.line>=this.getLines().length)return!1;this.input=this.getLines()[this.line],this.line+=1,this.char=1,this.from=1;var t=this.input.trim(),n=function(){return r.some(arguments,function(e){return t.indexOf(e)===0})},i=function(){return r.some(arguments,function(e){return t.indexOf(e,t.length-e.length)!==-1})};this.ignoringLinterErrors===!0&&!n("/*","//")&&(!this.inComment||!i("*/"))&&(this.input=""),e=this.scanNonBreakingSpaces(),e>=0&&this.trigger("warning",{code:"W125",line:this.line,character:e+1}),this.input=this.input.replace(/\t/g,o.tab),e=this.scanUnsafeChars(),e>=0&&this.trigger("warning",{code:"W100",line:this.line,character:e});if(!this.ignoringLinterErrors&&o.option.maxlen&&o.option.maxlen<this.input.length){var u=this.inComment||n.call(t,"//")||n.call(t,"/*"),a=!u||!s.maxlenException.test(t);a&&this.trigger("warning",{code:"W101",line:this.line,character:this.input.length})}return!0},start:function(){this.nextLine()},token:function(){function n(e,t){if(!e.reserved)return!1;var n=e.meta;if(n&&n.isFutureReservedWord&&o.inES5()){if(!n.es5)return!1;if(n.strictOnly&&!o.option.strict&&!o.isStrict())return!1;if(t)return!1}return!0}var e=h(),t,i=function(t,i,s,u){var a;t!=="(endline)"&&t!=="(end)"&&(this.prereg=!1);if(t==="(punctuator)"){switch(i){case".":case")":case"~":case"#":case"]":case"++":case"--":this.prereg=!1;break;default:this.prereg=!0}a=Object.create(o.syntax[i]||o.syntax["(error)"])}if(t==="(identifier)"){if(i==="return"||i==="case"||i==="typeof")this.prereg=!0;r.has(o.syntax,i)&&(a=Object.create(o.syntax[i]||o.syntax["(error)"]),n(a,s&&t==="(identifier)")||(a=null))}return a||(a=Object.create(o.syntax[t])),a.identifier=t==="(identifier)",a.type=a.type||t,a.value=i,a.line=this.line,a.character=this.char,a.from=this.from,a.identifier&&u&&(a.raw_text=u.text||u.value),u&&u.startLine&&u.startLine!==this.line&&(a.startLine=u.startLine),u&&u.context&&(a.context=u.context),u&&u.depth&&(a.depth=u.depth),u&&u.isUnclosed&&(a.isUnclosed=u.isUnclosed),s&&a.identifier&&(a.isProperty=s),a.check=e.check,a}.bind(this);for(;;){if(!this.input.length)return this.nextLine()?i("(endline)",""):this.exhausted?null:(this.exhausted=!0,i("(end)",""));t=this.next(e);if(!t){this.input.length&&(this.trigger("error",{code:"E024",line:this.line,character:this.char,data:[this.peek()]}),this.input="");continue}switch(t.type){case l.StringLiteral:return this.triggerAsync("String",{line:this.line,"char":this.char,from:this.from,startLine:t.startLine,startChar:t.startChar,value:t.value,quote:t.quote},e,function(){return!0}),i("(string)",t.value,null,t);case l.TemplateHead:return this.trigger("TemplateHead",{line:this.line,"char":this.char,from:this.from,startLine:t.startLine,startChar:t.startChar,value:t.value}),i("(template)",t.value,null,t);case l.TemplateMiddle:return this.trigger("TemplateMiddle",{line:this.line,"char":this.char,from:this.from,startLine:t.startLine,startChar:t.startChar,value:t.value}),i("(template middle)",t.value,null,t);case l.TemplateTail:return this.trigger("TemplateTail",{line:this.line,"char":this.char,from:this.from,startLine:t.startLine,startChar:t.startChar,value:t.value}),i("(template tail)",t.value,null,t);case l.NoSubstTemplate:return this.trigger("NoSubstTemplate",{line:this.line,"char":this.char,from:this.from,startLine:t.startLine,startChar:t.startChar,value:t.value}),i("(no subst template)",t.value,null,t);case l.Identifier:this.triggerAsync("Identifier",{line:this.line,"char":this.char,from:this.form,name:t.value,raw_name:t.text,isProperty:o.tokens.curr.id==="."},e,function(){return!0});case l.Keyword:case l.NullLiteral:case l.BooleanLiteral:return i("(identifier)",t.value,o.tokens.curr.id===".",t);case l.NumericLiteral:return t.isMalformed&&this.trigger("warning",{code:"W045",line:this.line,character:this.char,data:[t.value]}),this.triggerAsync("warning",{code:"W114",line:this.line,character:this.char,data:["0x-"]},e,function(){return t.base===16&&o.jsonMode}),this.triggerAsync("warning",{code:"W115",line:this.line,character:this.char},e,function(){return o.isStrict()&&t.base===8&&t.isLegacy}),this.trigger("Number",{line:this.line,"char":this.char,from:this.from,value:t.value,base:t.base,isMalformed:t.malformed}),i("(number)",t.value);case l.RegExp:return i("(regexp)",t.value);case l.Comment:o.tokens.curr.comment=!0;if(t.isSpecial)return{id:"(comment)",value:t.value,body:t.body,type:t.commentType,isSpecial:t.isSpecial,line:this.line,character:this.char,from:this.from};break;case"":break;default:return i("(punctuator)",t.value)}}}},n.Lexer=p,n.Context=c},{"../data/ascii-identifier-data.js":"/node_modules/jshint/data/ascii-identifier-data.js","../lodash":"/node_modules/jshint/lodash.js","./reg.js":"/node_modules/jshint/src/reg.js","./state.js":"/node_modules/jshint/src/state.js",events:"/node_modules/browserify/node_modules/events/events.js"}],"/node_modules/jshint/src/messages.js":[function(e,t,n){"use strict";var r=e("../lodash"),i={E001:"Bad option: '{a}'.",E002:"Bad option value.",E003:"Expected a JSON value.",E004:"Input is neither a string nor an array of strings.",E005:"Input is empty.",E006:"Unexpected early end of program.",E007:'Missing "use strict" statement.',E008:"Strict violation.",E009:"Option 'validthis' can't be used in a global scope.",E010:"'with' is not allowed in strict mode.",E011:"'{a}' has already been declared.",E012:"const '{a}' is initialized to 'undefined'.",E013:"Attempting to override '{a}' which is a constant.",E014:"A regular expression literal can be confused with '/='.",E015:"Unclosed regular expression.",E016:"Invalid regular expression.",E017:"Unclosed comment.",E018:"Unbegun comment.",E019:"Unmatched '{a}'.",E020:"Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.",E021:"Expected '{a}' and instead saw '{b}'.",E022:"Line breaking error '{a}'.",E023:"Missing '{a}'.",E024:"Unexpected '{a}'.",E025:"Missing ':' on a case clause.",E026:"Missing '}' to match '{' from line {a}.",E027:"Missing ']' to match '[' from line {a}.",E028:"Illegal comma.",E029:"Unclosed string.",E030:"Expected an identifier and instead saw '{a}'.",E031:"Bad assignment.",E032:"Expected a small integer or 'false' and instead saw '{a}'.",E033:"Expected an operator and instead saw '{a}'.",E034:"get/set are ES5 features.",E035:"Missing property name.",E036:"Expected to see a statement and instead saw a block.",E037:null,E038:null,E039:"Function declarations are not invocable. Wrap the whole function invocation in parens.",E040:"Each value should have its own case label.",E041:"Unrecoverable syntax error.",E042:"Stopping.",E043:"Too many errors.",E044:null,E045:"Invalid for each loop.",E046:"A yield statement shall be within a generator function (with syntax: `function*`)",E047:null,E048:"{a} declaration not directly within block.",E049:"A {a} cannot be named '{b}'.",E050:"Mozilla requires the yield expression to be parenthesized here.",E051:null,E052:"Unclosed template literal.",E053:"Export declaration must be in global scope.",E054:"Class properties must be methods. Expected '(' but instead saw '{a}'.",E055:"The '{a}' option cannot be set after any executable code.",E056:"'{a}' was used before it was declared, which is illegal for '{b}' variables.",E057:"Invalid meta property: '{a}.{b}'.",E058:"Missing semicolon."},s={W001:"'hasOwnProperty' is a really bad name.",W002:"Value of '{a}' may be overwritten in IE 8 and earlier.",W003:"'{a}' was used before it was defined.",W004:"'{a}' is already defined.",W005:"A dot following a number can be confused with a decimal point.",W006:"Confusing minuses.",W007:"Confusing plusses.",W008:"A leading decimal point can be confused with a dot: '{a}'.",W009:"The array literal notation [] is preferable.",W010:"The object literal notation {} is preferable.",W011:null,W012:null,W013:null,W014:"Bad line breaking before '{a}'.",W015:null,W016:"Unexpected use of '{a}'.",W017:"Bad operand.",W018:"Confusing use of '{a}'.",W019:"Use the isNaN function to compare with NaN.",W020:"Read only.",W021:"Reassignment of '{a}', which is is a {b}. Use 'var' or 'let' to declare bindings that may change.",W022:"Do not assign to the exception parameter.",W023:"Expected an identifier in an assignment and instead saw a function invocation.",W024:"Expected an identifier and instead saw '{a}' (a reserved word).",W025:"Missing name in function declaration.",W026:"Inner functions should be listed at the top of the outer function.",W027:"Unreachable '{a}' after '{b}'.",W028:"Label '{a}' on {b} statement.",W030:"Expected an assignment or function call and instead saw an expression.",W031:"Do not use 'new' for side effects.",W032:"Unnecessary semicolon.",W033:"Missing semicolon.",W034:'Unnecessary directive "{a}".',W035:"Empty block.",W036:"Unexpected /*member '{a}'.",W037:"'{a}' is a statement label.",W038:"'{a}' used out of scope.",W039:"'{a}' is not allowed.",W040:"Possible strict violation.",W041:"Use '{a}' to compare with '{b}'.",W042:"Avoid EOL escaping.",W043:"Bad escaping of EOL. Use option multistr if needed.",W044:"Bad or unnecessary escaping.",W045:"Bad number '{a}'.",W046:"Don't use extra leading zeros '{a}'.",W047:"A trailing decimal point can be confused with a dot: '{a}'.",W048:"Unexpected control character in regular expression.",W049:"Unexpected escaped character '{a}' in regular expression.",W050:"JavaScript URL.",W051:"Variables should not be deleted.",W052:"Unexpected '{a}'.",W053:"Do not use {a} as a constructor.",W054:"The Function constructor is a form of eval.",W055:"A constructor name should start with an uppercase letter.",W056:"Bad constructor.",W057:"Weird construction. Is 'new' necessary?",W058:"Missing '()' invoking a constructor.",W059:"Avoid arguments.{a}.",W060:"document.write can be a form of eval.",W061:"eval can be harmful.",W062:"Wrap an immediate function invocation in parens to assist the reader in understanding that the expression is the result of a function, and not the function itself.",W063:"Math is not a function.",W064:"Missing 'new' prefix when invoking a constructor.",W065:"Missing radix parameter.",W066:"Implied eval. Consider passing a function instead of a string.",W067:"Bad invocation.",W068:"Wrapping non-IIFE function literals in parens is unnecessary.",W069:"['{a}'] is better written in dot notation.",W070:"Extra comma. (it breaks older versions of IE)",W071:"This function has too many statements. ({a})",W072:"This function has too many parameters. ({a})",W073:"Blocks are nested too deeply. ({a})",W074:"This function's cyclomatic complexity is too high. ({a})",W075:"Duplicate {a} '{b}'.",W076:"Unexpected parameter '{a}' in get {b} function.",W077:"Expected a single parameter in set {a} function.",W078:"Setter is defined without getter.",W079:"Redefinition of '{a}'.",W080:"It's not necessary to initialize '{a}' to 'undefined'.",W081:null,W082:"Function declarations should not be placed in blocks. Use a function expression or move the statement to the top of the outer function.",W083:"Don't make functions within a loop.",W084:"Assignment in conditional expression",W085:"Don't use 'with'.",W086:"Expected a 'break' statement before '{a}'.",W087:"Forgotten 'debugger' statement?",W088:"Creating global 'for' variable. Should be 'for (var {a} ...'.",W089:"The body of a for in should be wrapped in an if statement to filter unwanted properties from the prototype.",W090:"'{a}' is not a statement label.",W091:null,W093:"Did you mean to return a conditional instead of an assignment?",W094:"Unexpected comma.",W095:"Expected a string and instead saw {a}.",W096:"The '{a}' key may produce unexpected results.",W097:'Use the function form of "use strict".',W098:"'{a}' is defined but never used.",W099:null,W100:"This character may get silently deleted by one or more browsers.",W101:"Line is too long.",W102:null,W103:"The '{a}' property is deprecated.",W104:"'{a}' is available in ES{b} (use 'esversion: {b}') or Mozilla JS extensions (use moz).",W105:"Unexpected {a} in '{b}'.",W106:"Identifier '{a}' is not in camel case.",W107:"Script URL.",W108:"Strings must use doublequote.",W109:"Strings must use singlequote.",W110:"Mixed double and single quotes.",W112:"Unclosed string.",W113:"Control character in string: {a}.",W114:"Avoid {a}.",W115:"Octal literals are not allowed in strict mode.",W116:"Expected '{a}' and instead saw '{b}'.",W117:"'{a}' is not defined.",W118:"'{a}' is only available in Mozilla JavaScript extensions (use moz option).",W119:"'{a}' is only available in ES{b} (use 'esversion: {b}').",W120:"You might be leaking a variable ({a}) here.",W121:"Extending prototype of native object: '{a}'.",W122:"Invalid typeof value '{a}'",W123:"'{a}' is already defined in outer scope.",W124:"A generator function shall contain a yield statement.",W125:"This line contains non-breaking spaces: http://jshint.com/doc/options/#nonbsp",W126:"Unnecessary grouping operator.",W127:"Unexpected use of a comma operator.",W128:"Empty array elements require elision=true.",W129:"'{a}' is defined in a future version of JavaScript. Use a different variable name to avoid migration issues.",W130:"Invalid element after rest element.",W131:"Invalid parameter after rest parameter.",W132:"`var` declarations are forbidden. Use `let` or `const` instead.",W133:"Invalid for-{a} loop left-hand-side: {b}.",W134:"The '{a}' option is only available when linting ECMAScript {b} code.",W135:"{a} may not be supported by non-browser environments.",W136:"'{a}' must be in function scope.",W137:"Empty destructuring.",W138:"Regular parameters should not come after default parameters."},o={I001:"Comma warnings can be turned off with 'laxcomma'.",I002:null,I003:"ES5 option is now set per default"};n.errors={},n.warnings={},n.info={},r.each(i,function(e,t){n.errors[t]={code:t,desc:e}}),r.each(s,function(e,t){n.warnings[t]={code:t,desc:e}}),r.each(o,function(e,t){n.info[t]={code:t,desc:e}})},{"../lodash":"/node_modules/jshint/lodash.js"}],"/node_modules/jshint/src/name-stack.js":[function(e,t,n){"use strict";function r(){this._stack=[]}Object.defineProperty(r.prototype,"length",{get:function(){return this._stack.length}}),r.prototype.push=function(){this._stack.push(null)},r.prototype.pop=function(){this._stack.pop()},r.prototype.set=function(e){this._stack[this.length-1]=e},r.prototype.infer=function(){var e=this._stack[this.length-1],t="",n;if(!e||e.type==="class")e=this._stack[this.length-2];return e?(n=e.type,n!=="(string)"&&n!=="(number)"&&n!=="(identifier)"&&n!=="default"?"(expression)":(e.accessorType&&(t=e.accessorType+" "),t+e.value)):"(empty)"},t.exports=r},{}],"/node_modules/jshint/src/options.js":[function(e,t,n){"use strict";n.bool={enforcing:{bitwise:!0,freeze:!0,camelcase:!0,curly:!0,eqeqeq:!0,futurehostile:!0,notypeof:!0,es3:!0,es5:!0,forin:!0,funcscope:!0,immed:!0,iterator:!0,newcap:!0,noarg:!0,nocomma:!0,noempty:!0,nonbsp:!0,nonew:!0,undef:!0,singleGroups:!1,varstmt:!1,enforceall:!1},relaxing:{asi:!0,multistr:!0,debug:!0,boss:!0,evil:!0,globalstrict:!0,plusplus:!0,proto:!0,scripturl:!0,sub:!0,supernew:!0,laxbreak:!0,laxcomma:!0,validthis:!0,withstmt:!0,moz:!0,noyield:!0,eqnull:!0,lastsemic:!0,loopfunc:!0,expr:!0,esnext:!0,elision:!0},environments:{mootools:!0,couch:!0,jasmine:!0,jquery:!0,node:!0,qunit:!0,rhino:!0,shelljs:!0,prototypejs:!0,yui:!0,mocha:!0,module:!0,wsh:!0,worker:!0,nonstandard:!0,browser:!0,browserify:!0,devel:!0,dojo:!0,typed:!0,phantom:!0},obsolete:{onecase:!0,regexp:!0,regexdash:!0}},n.val={maxlen:!1,indent:!1,maxerr:!1,predef:!1,globals:!1,quotmark:!1,scope:!1,maxstatements:!1,maxdepth:!1,maxparams:!1,maxcomplexity:!1,shadow:!1,strict:!0,unused:!0,latedef:!1,ignore:!1,ignoreDelimiters:!1,esversion:5},n.inverted={bitwise:!0,forin:!0,newcap:!0,plusplus:!0,regexp:!0,undef:!0,eqeqeq:!0,strict:!0},n.validNames=Object.keys(n.val).concat(Object.keys(n.bool.relaxing)).concat(Object.keys(n.bool.enforcing)).concat(Object.keys(n.bool.obsolete)).concat(Object.keys(n.bool.environments)),n.renamed={eqeq:"eqeqeq",windows:"wsh",sloppy:"strict"},n.removed={nomen:!0,onevar:!0,passfail:!0,white:!0,gcl:!0,smarttabs:!0,trailing:!0},n.noenforceall={varstmt:!0,strict:!0}},{}],"/node_modules/jshint/src/reg.js":[function(e,t,n){"use strict";n.unsafeString=/@cc|<\/?|script|\]\s*\]|<\s*!|&lt/i,n.unsafeChars=/[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,n.needEsc=/[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,n.needEscGlobal=/[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,n.starSlash=/\*\//,n.identifier=/^([a-zA-Z_$][a-zA-Z0-9_$]*)$/,n.javascriptURL=/^(?:javascript|jscript|ecmascript|vbscript|livescript)\s*:/i,n.fallsThrough=/^\s*falls?\sthrough\s*$/,n.maxlenException=/^(?:(?:\/\/|\/\*|\*) ?)?[^ ]+$/},{}],"/node_modules/jshint/src/scope-manager.js":[function(e,t,n){"use strict";var r=e("../lodash"),i=e("events"),s={},o=function(e,t,n,o){function f(e){u={"(labels)":Object.create(null),"(usages)":Object.create(null),"(breakLabels)":Object.create(null),"(parent)":u,"(type)":e,"(params)":e==="functionparams"||e==="catchparams"?[]:null},a.push(u)}function v(e,t){d.emit("warning",{code:e,token:t,data:r.slice(arguments,2)})}function m(e,t){d.emit("warning",{code:e,token:t,data:r.slice(arguments,2)})}function g(e){u["(usages)"][e]||(u["(usages)"][e]={"(modified)":[],"(reassigned)":[],"(tokens)":[]})}function w(){if(u["(type)"]==="functionparams"){E();return}var e=u["(labels)"];for(var t in e)e[t]&&e[t]["(type)"]!=="exception"&&e[t]["(unused)"]&&b(t,e[t]["(token)"],"var")}function E(){var t=u["(params)"];if(!t)return;var n=t.pop(),r;while(n){var i=u["(labels)"][n];r=y(e.funct["(unusedOption)"]);if(n==="undefined")return;if(i["(unused)"])b(n,i["(token)"],"param",e.funct["(unusedOption)"]);else if(r==="last-param")return;n=t.pop()}}function S(e){for(var t=a.length-1;t>=0;--t){var n=a[t]["(labels)"];if(n[e])return n}}function x(e){for(var t=a.length-1;t>=0;t--){var n=a[t];if(n["(usages)"][e])return n["(usages)"][e];if(n===l)break}return!1}function T(t,n){if(e.option.shadow!=="outer")return;var r=l["(type)"]==="global",i=u["(type)"]==="functionparams",s=!r;for(var o=0;o<a.length;o++){var f=a[o];!i&&a[o+1]===l&&(s=!1),s&&f["(labels)"][t]&&v("W123",n,t),f["(breakLabels)"][t]&&v("W123",n,t)}}function N(t,n,r){e.option.latedef&&(e.option.latedef===!0&&t==="function"||t!=="function")&&v("W003",r,n)}var u,a=[];f("global"),u["(predefined)"]=t;var l=u,c=Object.create(null),h=Object.create(null),p=[],d=new i.EventEmitter,y=function(t){return t===undefined&&(t=e.option.unused),t===!0&&(t="last-param"),t},b=function(e,t,n,r){var i=t.line,s=t.from,o=t.raw_text||e;r=y(r);var u={vars:["var"],"last-param":["var","param"],strict:["var","param","last-param"]};r&&u[r]&&u[r].indexOf(n)!==-1&&v("W098",{line:i,from:s},o),(r||n==="var")&&p.push({name:e,line:i,character:s})},C={on:function(e,t){e.split(" ").forEach(function(e){d.on(e,t)})},isPredefined:function(e){return!this.has(e)&&r.has(a[0]["(predefined)"],e)},stack:function(e){var t=u;f(e),!e&&t["(type)"]==="functionparams"&&(u["(isFuncBody)"]=!0,u["(context)"]=l,l=u)},unstack:function(){var t=a.length>1?a[a.length-2]:null,n=u===l,i=u["(type)"]==="functionparams",f=u["(type)"]==="functionouter",p,d,g=u["(usages)"],y=u["(labels)"],E=Object.keys(g);g.__proto__&&E.indexOf("__proto__")===-1&&E.push("__proto__");for(p=0;p<E.length;p++){var S=E[p],x=g[S],T=y[S];if(T){var N=T["(type)"];if(T["(useOutsideOfScope)"]&&!e.option.funcscope){var C=x["(tokens)"];if(C)for(d=0;d<C.length;d++)T["(function)"]===C[d]["(function)"]&&m("W038",C[d],S)}u["(labels)"][S]["(unused)"]=!1;if(N==="const"&&x["(modified)"])for(d=0;d<x["(modified)"].length;d++)m("E013",x["(modified)"][d],S);if((N==="function"||N==="class")&&x["(reassigned)"])for(d=0;d<x["(reassigned)"].length;d++)m("W021",x["(reassigned)"][d],S,N);continue}f&&(e.funct["(isCapturing)"]=!0);if(t)if(!t["(usages)"][S])t["(usages)"][S]=x,n&&(t["(usages)"][S]["(onlyUsedSubFunction)"]=!0);else{var k=t["(usages)"][S];k["(modified)"]=k["(modified)"].concat(x["(modified)"]),k["(tokens)"]=k["(tokens)"].concat(x["(tokens)"]),k["(reassigned)"]=k["(reassigned)"].concat(x["(reassigned)"]),k["(onlyUsedSubFunction)"]=!1}else if(typeof u["(predefined)"][S]=="boolean"){delete o[S],c[S]=s;if(u["(predefined)"][S]===!1&&x["(reassigned)"])for(d=0;d<x["(reassigned)"].length;d++)v("W020",x["(reassigned)"][d])}else if(x["(tokens)"])for(d=0;d<x["(tokens)"].length;d++){var L=x["(tokens)"][d];L.forgiveUndef||(e.option.undef&&!L.ignoreUndef&&v("W117",L,S),h[S]?h[S].line.push(L.line):h[S]={name:S,line:[L.line]})}}t||Object.keys(o).forEach(function(e){b(e,o[e],"var")});if(t&&!n&&!i&&!f){var A=Object.keys(y);for(p=0;p<A.length;p++){var O=A[p];!y[O]["(blockscoped)"]&&y[O]["(type)"]!=="exception"&&!this.funct.has(O,{excludeCurrent:!0})&&(t["(labels)"][O]=y[O],l["(type)"]!=="global"&&(t["(labels)"][O]["(useOutsideOfScope)"]=!0),delete y[O])}}w(),a.pop(),n&&(l=a[r.findLastIndex(a,function(e){return e["(isFuncBody)"]||e["(type)"]==="global"})]),u=t},addParam:function(t,n,i){i=i||"param";if(i==="exception"){var s=this.funct.labeltype(t);s&&s!=="exception"&&(e.option.node||v("W002",e.tokens.next,t))}r.has(u["(labels)"],t)?u["(labels)"][t].duplicated=!0:(T(t,n,i),u["(labels)"][t]={"(type)":i,"(token)":n,"(unused)":!0},u["(params)"].push(t));if(r.has(u["(usages)"],t)){var o=u["(usages)"][t];o["(onlyUsedSubFunction)"]?N(i,t,n):v("E056",n,t,i)}},validateParams:function(){if(l["(type)"]==="global")return;var t=e.isStrict(),n=l["(parent)"];if(!n["(params)"])return;n["(params)"].forEach(function(r){var i=n["(labels)"][r];i&&i.duplicated&&(t?v("E011",i["(token)"],r):e.option.shadow!==!0&&v("W004",i["(token)"],r))})},getUsedOrDefinedGlobals:function(){var e=Object.keys(c);return c.__proto__===s&&e.indexOf("__proto__")===-1&&e.push("__proto__"),e},getImpliedGlobals:function(){var e=r.values(h),t=!1;return h.__proto__&&(t=e.some(function(e){return e.name==="__proto__"}),t||e.push(h.__proto__)),e},getUnuseds:function(){return p},has:function(e){return Boolean(S(e))},labeltype:function(e){var t=S(e);return t?t[e]["(type)"]:null},addExported:function(e){var t=a[0]["(labels)"];if(r.has(o,e))delete o[e];else if(r.has(t,e))t[e]["(unused)"]=!1;else{for(var i=1;i<a.length;i++){var s=a[i];if(!!s["(type)"])break;if(r.has(s["(labels)"],e)&&!s["(labels)"][e]["(blockscoped)"]){s["(labels)"][e]["(unused)"]=!1;return}}n[e]=!0}},setExported:function(e,t){this.block.use(e,t)},addlabel:function(t,i){var o=i.type,a=i.token,f=o==="let"||o==="const"||o==="class",h=(f?u:l)["(type)"]==="global"&&r.has(n,t);T(t,a,o);if(f){var p=u["(labels)"][t];!p&&u===l&&u["(type)"]!=="global"&&(p=!!l["(parent)"]["(labels)"][t]);if(!p&&u["(usages)"][t]){var d=u["(usages)"][t];d["(onlyUsedSubFunction)"]?N(o,t,a):v("E056",a,t,o)}p?v("E011",a,t):e.option.shadow==="outer"&&C.funct.has(t)&&v("W004",a,t),C.block.add(t,o,a,!h)}else{var m=C.funct.has(t);!m&&x(t)&&N(o,t,a),C.funct.has(t,{onlyBlockscoped:!0})?v("E011",a,t):e.option.shadow!==!0&&m&&t!=="__proto__"&&l["(type)"]!=="global"&&v("W004",a,t),C.funct.add(t,o,a,!h),l["(type)"]==="global"&&(c[t]=s)}},funct:{labeltype:function(e,t){var n=t&&t.onlyBlockscoped,r=t&&t.excludeParams,i=a.length-(t&&t.excludeCurrent?2:1);for(var s=i;s>=0;s--){var o=a[s];if(o["(labels)"][e]&&(!n||o["(labels)"][e]["(blockscoped)"]))return o["(labels)"][e]["(type)"];var u=r?a[s-1]:o;if(u&&u["(type)"]==="functionparams")return null}return null},hasBreakLabel:function(e){for(var t=a.length-1;t>=0;t--){var n=a[t];if(n["(breakLabels)"][e])return!0;if(n["(type)"]==="functionparams")return!1}return!1},has:function(e,t){return Boolean(this.labeltype(e,t))},add:function(e,t,n,r){u["(labels)"][e]={"(type)":t,"(token)":n,"(blockscoped)":!1,"(function)":l,"(unused)":r}}},block:{isGlobal:function(){return u["(type)"]==="global"},use:function(t,n){var r=l["(parent)"];r&&r["(labels)"][t]&&r["(labels)"][t]["(type)"]==="param"&&(C.funct.has(t,{excludeParams:!0,onlyBlockscoped:!0})||(r["(labels)"][t]["(unused)"]=!1)),n&&(e.ignored.W117||e.option.undef===!1)&&(n.ignoreUndef=!0),g(t),n&&(n["(function)"]=l,u["(usages)"][t]["(tokens)"].push(n))},reassign:function(e,t){this.modify(e,t),u["(usages)"][e]["(reassigned)"].push(t)},modify:function(e,t){g(e),u["(usages)"][e]["(modified)"].push(t)},add:function(e,t,n,r){u["(labels)"][e]={"(type)":t,"(token)":n,"(blockscoped)":!0,"(unused)":r}},addBreakLabel:function(t,n){var r=n.token;C.funct.hasBreakLabel(t)?v("E011",r,t):e.option.shadow==="outer"&&(C.funct.has(t)?v("W004",r,t):T(t,r)),u["(breakLabels)"][t]=r}}};return C};t.exports=o},{"../lodash":"/node_modules/jshint/lodash.js",events:"/node_modules/browserify/node_modules/events/events.js"}],"/node_modules/jshint/src/state.js":[function(e,t,n){"use strict";var r=e("./name-stack.js"),i={syntax:{},isStrict:function(){return this.directive["use strict"]||this.inClassBody||this.option.module||this.option.strict==="implied"},inMoz:function(){return this.option.moz},inES6:function(){return this.option.moz||this.option.esversion>=6},inES5:function(e){return e?(!this.option.esversion||this.option.esversion===5)&&!this.option.moz:!this.option.esversion||this.option.esversion>=5||this.option.moz},reset:function(){this.tokens={prev:null,next:null,curr:null},this.option={},this.funct=null,this.ignored={},this.directive={},this.jsonMode=!1,this.jsonWarnings=[],this.lines=[],this.tab="",this.cache={},this.ignoredLines={},this.forinifcheckneeded=!1,this.nameStack=new r,this.inClassBody=!1}};n.state=i},{"./name-stack.js":"/node_modules/jshint/src/name-stack.js"}],"/node_modules/jshint/src/style.js":[function(e,t,n){"use strict";n.register=function(e){e.on("Identifier",function(n){if(e.getOption("proto"))return;n.name==="__proto__"&&e.warn("W103",{line:n.line,"char":n.char,data:[n.name,"6"]})}),e.on("Identifier",function(n){if(e.getOption("iterator"))return;n.name==="__iterator__"&&e.warn("W103",{line:n.line,"char":n.char,data:[n.name]})}),e.on("Identifier",function(n){if(!e.getOption("camelcase"))return;n.name.replace(/^_+|_+$/g,"").indexOf("_")>-1&&!n.name.match(/^[A-Z0-9_]*$/)&&e.warn("W106",{line:n.line,"char":n.from,data:[n.name]})}),e.on("String",function(n){var r=e.getOption("quotmark"),i;if(!r)return;r==="single"&&n.quote!=="'"&&(i="W109"),r==="double"&&n.quote!=='"'&&(i="W108"),r===!0&&(e.getCache("quotmark")||e.setCache("quotmark",n.quote),e.getCache("quotmark")!==n.quote&&(i="W110")),i&&e.warn(i,{line:n.line,"char":n.char})}),e.on("Number",function(n){n.value.charAt(0)==="."&&e.warn("W008",{line:n.line,"char":n.char,data:[n.value]}),n.value.substr(n.value.length-1)==="."&&e.warn("W047",{line:n.line,"char":n.char,data:[n.value]}),/^00+/.test(n.value)&&e.warn("W046",{line:n.line,"char":n.char,data:[n.value]})}),e.on("String",function(n){var r=/^(?:javascript|jscript|ecmascript|vbscript|livescript)\s*:/i;if(e.getOption("scripturl"))return;r.test(n.value)&&e.warn("W107",{line:n.line,"char":n.char})})}},{}],"/node_modules/jshint/src/vars.js":[function(e,t,n){"use strict";n.reservedVars={arguments:!1,NaN:!1},n.ecmaIdentifiers={3:{Array:!1,Boolean:!1,Date:!1,decodeURI:!1,decodeURIComponent:!1,encodeURI:!1,encodeURIComponent:!1,Error:!1,eval:!1,EvalError:!1,Function:!1,hasOwnProperty:!1,isFinite:!1,isNaN:!1,Math:!1,Number:!1,Object:!1,parseInt:!1,parseFloat:!1,RangeError:!1,ReferenceError:!1,RegExp:!1,String:!1,SyntaxError:!1,TypeError:!1,URIError:!1},5:{JSON:!1},6:{Map:!1,Promise:!1,Proxy:!1,Reflect:!1,Set:!1,Symbol:!1,WeakMap:!1,WeakSet:!1}},n.browser={Audio:!1,Blob:!1,addEventListener:!1,applicationCache:!1,atob:!1,blur:!1,btoa:!1,cancelAnimationFrame:!1,CanvasGradient:!1,CanvasPattern:!1,CanvasRenderingContext2D:!1,CSS:!1,clearInterval:!1,clearTimeout:!1,close:!1,closed:!1,Comment:!1,CustomEvent:!1,DOMParser:!1,defaultStatus:!1,Document:!1,document:!1,DocumentFragment:!1,Element:!1,ElementTimeControl:!1,Event:!1,event:!1,fetch:!1,FileReader:!1,FormData:!1,focus:!1,frames:!1,getComputedStyle:!1,HTMLElement:!1,HTMLAnchorElement:!1,HTMLBaseElement:!1,HTMLBlockquoteElement:!1,HTMLBodyElement:!1,HTMLBRElement:!1,HTMLButtonElement:!1,HTMLCanvasElement:!1,HTMLCollection:!1,HTMLDirectoryElement:!1,HTMLDivElement:!1,HTMLDListElement:!1,HTMLFieldSetElement:!1,HTMLFontElement:!1,HTMLFormElement:!1,HTMLFrameElement:!1,HTMLFrameSetElement:!1,HTMLHeadElement:!1,HTMLHeadingElement:!1,HTMLHRElement:!1,HTMLHtmlElement:!1,HTMLIFrameElement:!1,HTMLImageElement:!1,HTMLInputElement:!1,HTMLIsIndexElement:!1,HTMLLabelElement:!1,HTMLLayerElement:!1,HTMLLegendElement:!1,HTMLLIElement:!1,HTMLLinkElement:!1,HTMLMapElement:!1,HTMLMenuElement:!1,HTMLMetaElement:!1,HTMLModElement:!1,HTMLObjectElement:!1,HTMLOListElement:!1,HTMLOptGroupElement:!1,HTMLOptionElement:!1,HTMLParagraphElement:!1,HTMLParamElement:!1,HTMLPreElement:!1,HTMLQuoteElement:!1,HTMLScriptElement:!1,HTMLSelectElement:!1,HTMLStyleElement:!1,HTMLTableCaptionElement:!1,HTMLTableCellElement:!1,HTMLTableColElement:!1,HTMLTableElement:!1,HTMLTableRowElement:!1,HTMLTableSectionElement:!1,HTMLTemplateElement:!1,HTMLTextAreaElement:!1,HTMLTitleElement:!1,HTMLUListElement:!1,HTMLVideoElement:!1,history:!1,Image:!1,Intl:!1,length:!1,localStorage:!1,location:!1,matchMedia:!1,MessageChannel:!1,MessageEvent:!1,MessagePort:!1,MouseEvent:!1,moveBy:!1,moveTo:!1,MutationObserver:!1,name:!1,Node:!1,NodeFilter:!1,NodeList:!1,Notification:!1,navigator:!1,onbeforeunload:!0,onblur:!0,onerror:!0,onfocus:!0,onload:!0,onresize:!0,onunload:!0,open:!1,openDatabase:!1,opener:!1,Option:!1,parent:!1,performance:!1,print:!1,Range:!1,requestAnimationFrame:!1,removeEventListener:!1,resizeBy:!1,resizeTo:!1,screen:!1,scroll:!1,scrollBy:!1,scrollTo:!1,sessionStorage:!1,setInterval:!1,setTimeout:!1,SharedWorker:!1,status:!1,SVGAElement:!1,SVGAltGlyphDefElement:!1,SVGAltGlyphElement:!1,SVGAltGlyphItemElement:!1,SVGAngle:!1,SVGAnimateColorElement:!1,SVGAnimateElement:!1,SVGAnimateMotionElement:!1,SVGAnimateTransformElement:!1,SVGAnimatedAngle:!1,SVGAnimatedBoolean:!1,SVGAnimatedEnumeration:!1,SVGAnimatedInteger:!1,SVGAnimatedLength:!1,SVGAnimatedLengthList:!1,SVGAnimatedNumber:!1,SVGAnimatedNumberList:!1,SVGAnimatedPathData:!1,SVGAnimatedPoints:!1,SVGAnimatedPreserveAspectRatio:!1,SVGAnimatedRect:!1,SVGAnimatedString:!1,SVGAnimatedTransformList:!1,SVGAnimationElement:!1,SVGCSSRule:!1,SVGCircleElement:!1,SVGClipPathElement:!1,SVGColor:!1,SVGColorProfileElement:!1,SVGColorProfileRule:!1,SVGComponentTransferFunctionElement:!1,SVGCursorElement:!1,SVGDefsElement:!1,SVGDescElement:!1,SVGDocument:!1,SVGElement:!1,SVGElementInstance:!1,SVGElementInstanceList:!1,SVGEllipseElement:!1,SVGExternalResourcesRequired:!1,SVGFEBlendElement:!1,SVGFEColorMatrixElement:!1,SVGFEComponentTransferElement:!1,SVGFECompositeElement:!1,SVGFEConvolveMatrixElement:!1,SVGFEDiffuseLightingElement:!1,SVGFEDisplacementMapElement:!1,SVGFEDistantLightElement:!1,SVGFEFloodElement:!1,SVGFEFuncAElement:!1,SVGFEFuncBElement:!1,SVGFEFuncGElement:!1,SVGFEFuncRElement:!1,SVGFEGaussianBlurElement:!1,SVGFEImageElement:!1,SVGFEMergeElement:!1,SVGFEMergeNodeElement:!1,SVGFEMorphologyElement:!1,SVGFEOffsetElement:!1,SVGFEPointLightElement:!1,SVGFESpecularLightingElement:!1,SVGFESpotLightElement:!1,SVGFETileElement:!1,SVGFETurbulenceElement:!1,SVGFilterElement:!1,SVGFilterPrimitiveStandardAttributes:!1,SVGFitToViewBox:!1,SVGFontElement:!1,SVGFontFaceElement:!1,SVGFontFaceFormatElement:!1,SVGFontFaceNameElement:!1,SVGFontFaceSrcElement:!1,SVGFontFaceUriElement:!1,SVGForeignObjectElement:!1,SVGGElement:!1,SVGGlyphElement:!1,SVGGlyphRefElement:!1,SVGGradientElement:!1,SVGHKernElement:!1,SVGICCColor:!1,SVGImageElement:!1,SVGLangSpace:!1,SVGLength:!1,SVGLengthList:!1,SVGLineElement:!1,SVGLinearGradientElement:!1,SVGLocatable:!1,SVGMPathElement:!1,SVGMarkerElement:!1,SVGMaskElement:!1,SVGMatrix:!1,SVGMetadataElement:!1,SVGMissingGlyphElement:!1,SVGNumber:!1,SVGNumberList:!1,SVGPaint:!1,SVGPathElement:!1,SVGPathSeg:!1,SVGPathSegArcAbs:!1,SVGPathSegArcRel:!1,SVGPathSegClosePath:!1,SVGPathSegCurvetoCubicAbs:!1,SVGPathSegCurvetoCubicRel:!1,SVGPathSegCurvetoCubicSmoothAbs:!1,SVGPathSegCurvetoCubicSmoothRel:!1,SVGPathSegCurvetoQuadraticAbs:!1,SVGPathSegCurvetoQuadraticRel:!1,SVGPathSegCurvetoQuadraticSmoothAbs:!1,SVGPathSegCurvetoQuadraticSmoothRel:!1,SVGPathSegLinetoAbs:!1,SVGPathSegLinetoHorizontalAbs:!1,SVGPathSegLinetoHorizontalRel:!1,SVGPathSegLinetoRel:!1,SVGPathSegLinetoVerticalAbs:!1,SVGPathSegLinetoVerticalRel:!1,SVGPathSegList:!1,SVGPathSegMovetoAbs:!1,SVGPathSegMovetoRel:!1,SVGPatternElement:!1,SVGPoint:!1,SVGPointList:!1,SVGPolygonElement:!1,SVGPolylineElement:!1,SVGPreserveAspectRatio:!1,SVGRadialGradientElement:!1,SVGRect:!1,SVGRectElement:!1,SVGRenderingIntent:!1,SVGSVGElement:!1,SVGScriptElement:!1,SVGSetElement:!1,SVGStopElement:!1,SVGStringList:!1,SVGStylable:!1,SVGStyleElement:!1,SVGSwitchElement:!1,SVGSymbolElement:!1,SVGTRefElement:!1,SVGTSpanElement:!1,SVGTests:!1,SVGTextContentElement:!1,SVGTextElement:!1,SVGTextPathElement:!1,SVGTextPositioningElement:!1,SVGTitleElement:!1,SVGTransform:!1,SVGTransformList:!1,SVGTransformable:!1,SVGURIReference:!1,SVGUnitTypes:!1,SVGUseElement:!1,SVGVKernElement:!1,SVGViewElement:!1,SVGViewSpec:!1,SVGZoomAndPan:!1,Text:!1,TextDecoder:!1,TextEncoder:!1,TimeEvent:!1,top:!1,URL:!1,WebGLActiveInfo:!1,WebGLBuffer:!1,WebGLContextEvent:!1,WebGLFramebuffer:!1,WebGLProgram:!1,WebGLRenderbuffer:!1,WebGLRenderingContext:!1,WebGLShader:!1,WebGLShaderPrecisionFormat:!1,WebGLTexture:!1,WebGLUniformLocation:!1,WebSocket:!1,window:!1,Window:!1,Worker:!1,XDomainRequest:!1,XMLHttpRequest:!1,XMLSerializer:!1,XPathEvaluator:!1,XPathException:!1,XPathExpression:!1,XPathNamespace:!1,XPathNSResolver:!1,XPathResult:!1},n.devel={alert:!1,confirm:!1,console:!1,Debug:!1,opera:!1,prompt:!1},n.worker={importScripts:!0,postMessage:!0,self:!0,FileReaderSync:!0},n.nonstandard={escape:!1,unescape:!1},n.couch={require:!1,respond:!1,getRow:!1,emit:!1,send:!1,start:!1,sum:!1,log:!1,exports:!1,module:!1,provides:!1},n.node={__filename:!1,__dirname:!1,GLOBAL:!1,global:!1,module:!1,require:!1,Buffer:!0,console:!0,exports:!0,process:!0,setTimeout:!0,clearTimeout:!0,setInterval:!0,clearInterval:!0,setImmediate:!0,clearImmediate:!0},n.browserify={__filename:!1,__dirname:!1,global:!1,module:!1,require:!1,Buffer:!0,exports:!0,process:!0},n.phantom={phantom:!0,require:!0,WebPage:!0,console:!0,exports:!0},n.qunit={asyncTest:!1,deepEqual:!1,equal:!1,expect:!1,module:!1,notDeepEqual:!1,notEqual:!1,notPropEqual:!1,notStrictEqual:!1,ok:!1,propEqual:!1,QUnit:!1,raises:!1,start:!1,stop:!1,strictEqual:!1,test:!1,"throws":!1},n.rhino={defineClass:!1,deserialize:!1,gc:!1,help:!1,importClass:!1,importPackage:!1,java:!1,load:!1,loadClass:!1,Packages:!1,print:!1,quit:!1,readFile:!1,readUrl:!1,runCommand:!1,seal:!1,serialize:!1,spawn:!1,sync:!1,toint32:!1,version:!1},n.shelljs={target:!1,echo:!1,exit:!1,cd:!1,pwd:!1,ls:!1,find:!1,cp:!1,rm:!1,mv:!1,mkdir:!1,test:!1,cat:!1,sed:!1,grep:!1,which:!1,dirs:!1,pushd:!1,popd:!1,env:!1,exec:!1,chmod:!1,config:!1,error:!1,tempdir:!1},n.typed={ArrayBuffer:!1,ArrayBufferView:!1,DataView:!1,Float32Array:!1,Float64Array:!1,Int16Array:!1,Int32Array:!1,Int8Array:!1,Uint16Array:!1,Uint32Array:!1,Uint8Array:!1,Uint8ClampedArray:!1},n.wsh={ActiveXObject:!0,Enumerator:!0,GetObject:!0,ScriptEngine:!0,ScriptEngineBuildVersion:!0,ScriptEngineMajorVersion:!0,ScriptEngineMinorVersion:!0,VBArray:!0,WSH:!0,WScript:!0,XDomainRequest:!0},n.dojo={dojo:!1,dijit:!1,dojox:!1,define:!1,require:!1},n.jquery={$:!1,jQuery:!1},n.mootools={$:!1,$$:!1,Asset:!1,Browser:!1,Chain:!1,Class:!1,Color:!1,Cookie:!1,Core:!1,Document:!1,DomReady:!1,DOMEvent:!1,DOMReady:!1,Drag:!1,Element:!1,Elements:!1,Event:!1,Events:!1,Fx:!1,Group:!1,Hash:!1,HtmlTable:!1,IFrame:!1,IframeShim:!1,InputValidator:!1,instanceOf:!1,Keyboard:!1,Locale:!1,Mask:!1,MooTools:!1,Native:!1,Options:!1,OverText:!1,Request:!1,Scroller:!1,Slick:!1,Slider:!1,Sortables:!1,Spinner:!1,Swiff:!1,Tips:!1,Type:!1,typeOf:!1,URI:!1,Window:!1},n.prototypejs={$:!1,$$:!1,$A:!1,$F:!1,$H:!1,$R:!1,$break:!1,$continue:!1,$w:!1,Abstract:!1,Ajax:!1,Class:!1,Enumerable:!1,Element:!1,Event:!1,Field:!1,Form:!1,Hash:!1,Insertion:!1,ObjectRange:!1,PeriodicalExecuter:!1,Position:!1,Prototype:!1,Selector:!1,Template:!1,Toggle:!1,Try:!1,Autocompleter:!1,Builder:!1,Control:!1,Draggable:!1,Draggables:!1,Droppables:!1,Effect:!1,Sortable:!1,SortableObserver:!1,Sound:!1,Scriptaculous:!1},n.yui={YUI:!1,Y:!1,YUI_config:!1},n.mocha={mocha:!1,describe:!1,xdescribe:!1,it:!1,xit:!1,context:!1,xcontext:!1,before:!1,after:!1,beforeEach:!1,afterEach:!1,suite:!1,test:!1,setup:!1,teardown:!1,suiteSetup:!1,suiteTeardown:!1},n.jasmine={jasmine:!1,describe:!1,xdescribe:!1,it:!1,xit:!1,beforeEach:!1,afterEach:!1,setFixtures:!1,loadFixtures:!1,spyOn:!1,expect:!1,runs:!1,waitsFor:!1,waits:!1,beforeAll:!1,afterAll:!1,fail:!1,fdescribe:!1,fit:!1,pending:!1}},{}]},{},["/node_modules/jshint/src/jshint.js"])}),ace.define("ace/mode/javascript_worker",["require","exports","module","ace/lib/oop","ace/worker/mirror","ace/mode/javascript/jshint"],function(require,exports,module){"use strict";function startRegex(e){return RegExp("^("+e.join("|")+")")}var oop=require("../lib/oop"),Mirror=require("../worker/mirror").Mirror,lint=require("./javascript/jshint").JSHINT,disabledWarningsRe=startRegex(["Bad for in variable '(.+)'.",'Missing "use strict"']),errorsRe=startRegex(["Unexpected","Expected ","Confusing (plus|minus)","\\{a\\} unterminated regular expression","Unclosed ","Unmatched ","Unbegun comment","Bad invocation","Missing space after","Missing operator at"]),infoRe=startRegex(["Expected an assignment","Bad escapement of EOL","Unexpected comma","Unexpected space","Missing radix parameter.","A leading decimal point can","\\['{a}'\\] is better written in dot notation.","'{a}' used out of scope"]),JavaScriptWorker=exports.JavaScriptWorker=function(e){Mirror.call(this,e),this.setTimeout(500),this.setOptions()};oop.inherits(JavaScriptWorker,Mirror),function(){this.setOptions=function(e){this.options=e||{esnext:!0,moz:!0,devel:!0,browser:!0,node:!0,laxcomma:!0,laxbreak:!0,lastsemic:!0,onevar:!1,passfail:!1,maxerr:100,expr:!0,multistr:!0,globalstrict:!0},this.doc.getValue()&&this.deferredUpdate.schedule(100)},this.changeOptions=function(e){oop.mixin(this.options,e),this.doc.getValue()&&this.deferredUpdate.schedule(100)},this.isValidJS=function(str){try{eval("throw 0;"+str)}catch(e){if(e===0)return!0}return!1},this.onUpdate=function(){var e=this.doc.getValue();e=e.replace(/^#!.*\n/,"\n");if(!e)return this.sender.emit("annotate",[]);var t=[],n=this.isValidJS(e)?"warning":"error";lint(e,this.options);var r=lint.errors,i=!1;for(var s=0;s<r.length;s++){var o=r[s];if(!o)continue;var u=o.raw,a="warning";if(u=="Missing semicolon."){var f=o.evidence.substr(o.character);f=f.charAt(f.search(/\S/)),n=="error"&&f&&/[\w\d{(['"]/.test(f)?(o.reason='Missing ";" before statement',a="error"):a="info"}else{if(disabledWarningsRe.test(u))continue;infoRe.test(u)?a="info":errorsRe.test(u)?(i=!0,a=n):u=="'{a}' is not defined."?a="warning":u=="'{a}' is defined but never used."&&(a="info")}t.push({row:o.line-1,column:o.character-1,text:o.reason,type:a,raw:u}),i}this.sender.emit("annotate",t)}}.call(JavaScriptWorker.prototype)}),ace.define("ace/lib/es5-shim",["require","exports","module"],function(e,t,n){function r(){}function w(e){try{return Object.defineProperty(e,"sentinel",{}),"sentinel"in e}catch(t){}}function H(e){return e=+e,e!==e?e=0:e!==0&&e!==1/0&&e!==-1/0&&(e=(e>0||-1)*Math.floor(Math.abs(e))),e}function B(e){var t=typeof e;return e===null||t==="undefined"||t==="boolean"||t==="number"||t==="string"}function j(e){var t,n,r;if(B(e))return e;n=e.valueOf;if(typeof n=="function"){t=n.call(e);if(B(t))return t}r=e.toString;if(typeof r=="function"){t=r.call(e);if(B(t))return t}throw new TypeError}Function.prototype.bind||(Function.prototype.bind=function(t){var n=this;if(typeof n!="function")throw new TypeError("Function.prototype.bind called on incompatible "+n);var i=u.call(arguments,1),s=function(){if(this instanceof s){var e=n.apply(this,i.concat(u.call(arguments)));return Object(e)===e?e:this}return n.apply(t,i.concat(u.call(arguments)))};return n.prototype&&(r.prototype=n.prototype,s.prototype=new r,r.prototype=null),s});var i=Function.prototype.call,s=Array.prototype,o=Object.prototype,u=s.slice,a=i.bind(o.toString),f=i.bind(o.hasOwnProperty),l,c,h,p,d;if(d=f(o,"__defineGetter__"))l=i.bind(o.__defineGetter__),c=i.bind(o.__defineSetter__),h=i.bind(o.__lookupGetter__),p=i.bind(o.__lookupSetter__);if([1,2].splice(0).length!=2)if(!function(){function e(e){var t=new Array(e+2);return t[0]=t[1]=0,t}var t=[],n;t.splice.apply(t,e(20)),t.splice.apply(t,e(26)),n=t.length,t.splice(5,0,"XXX"),n+1==t.length;if(n+1==t.length)return!0}())Array.prototype.splice=function(e,t){var n=this.length;e>0?e>n&&(e=n):e==void 0?e=0:e<0&&(e=Math.max(n+e,0)),e+t<n||(t=n-e);var r=this.slice(e,e+t),i=u.call(arguments,2),s=i.length;if(e===n)s&&this.push.apply(this,i);else{var o=Math.min(t,n-e),a=e+o,f=a+s-o,l=n-a,c=n-o;if(f<a)for(var h=0;h<l;++h)this[f+h]=this[a+h];else if(f>a)for(h=l;h--;)this[f+h]=this[a+h];if(s&&e===c)this.length=c,this.push.apply(this,i);else{this.length=c+s;for(h=0;h<s;++h)this[e+h]=i[h]}}return r};else{var v=Array.prototype.splice;Array.prototype.splice=function(e,t){return arguments.length?v.apply(this,[e===void 0?0:e,t===void 0?this.length-e:t].concat(u.call(arguments,2))):[]}}Array.isArray||(Array.isArray=function(t){return a(t)=="[object Array]"});var m=Object("a"),g=m[0]!="a"||!(0 in m);Array.prototype.forEach||(Array.prototype.forEach=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=arguments[1],s=-1,o=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError;while(++s<o)s in r&&t.call(i,r[s],s,n)}),Array.prototype.map||(Array.prototype.map=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=Array(i),o=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var u=0;u<i;u++)u in r&&(s[u]=t.call(o,r[u],u,n));return s}),Array.prototype.filter||(Array.prototype.filter=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=[],o,u=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var f=0;f<i;f++)f in r&&(o=r[f],t.call(u,o,f,n)&&s.push(o));return s}),Array.prototype.every||(Array.prototype.every=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&!t.call(s,r[o],o,n))return!1;return!0}),Array.prototype.some||(Array.prototype.some=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&t.call(s,r[o],o,n))return!0;return!1}),Array.prototype.reduce||(Array.prototype.reduce=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduce of empty array with no initial value");var s=0,o;if(arguments.length>=2)o=arguments[1];else do{if(s in r){o=r[s++];break}if(++s>=i)throw new TypeError("reduce of empty array with no initial value")}while(!0);for(;s<i;s++)s in r&&(o=t.call(void 0,o,r[s],s,n));return o}),Array.prototype.reduceRight||(Array.prototype.reduceRight=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduceRight of empty array with no initial value");var s,o=i-1;if(arguments.length>=2)s=arguments[1];else do{if(o in r){s=r[o--];break}if(--o<0)throw new TypeError("reduceRight of empty array with no initial value")}while(!0);do o in this&&(s=t.call(void 0,s,r[o],o,n));while(o--);return s});if(!Array.prototype.indexOf||[0,1].indexOf(1,2)!=-1)Array.prototype.indexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=0;arguments.length>1&&(i=H(arguments[1])),i=i>=0?i:Math.max(0,r+i);for(;i<r;i++)if(i in n&&n[i]===t)return i;return-1};if(!Array.prototype.lastIndexOf||[0,1].lastIndexOf(0,-3)!=-1)Array.prototype.lastIndexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=r-1;arguments.length>1&&(i=Math.min(i,H(arguments[1]))),i=i>=0?i:r-Math.abs(i);for(;i>=0;i--)if(i in n&&t===n[i])return i;return-1};Object.getPrototypeOf||(Object.getPrototypeOf=function(t){return t.__proto__||(t.constructor?t.constructor.prototype:o)});if(!Object.getOwnPropertyDescriptor){var y="Object.getOwnPropertyDescriptor called on a non-object: ";Object.getOwnPropertyDescriptor=function(t,n){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(y+t);if(!f(t,n))return;var r,i,s;r={enumerable:!0,configurable:!0};if(d){var u=t.__proto__;t.__proto__=o;var i=h(t,n),s=p(t,n);t.__proto__=u;if(i||s)return i&&(r.get=i),s&&(r.set=s),r}return r.value=t[n],r}}Object.getOwnPropertyNames||(Object.getOwnPropertyNames=function(t){return Object.keys(t)});if(!Object.create){var b;Object.prototype.__proto__===null?b=function(){return{__proto__:null}}:b=function(){var e={};for(var t in e)e[t]=null;return e.constructor=e.hasOwnProperty=e.propertyIsEnumerable=e.isPrototypeOf=e.toLocaleString=e.toString=e.valueOf=e.__proto__=null,e},Object.create=function(t,n){var r;if(t===null)r=b();else{if(typeof t!="object")throw new TypeError("typeof prototype["+typeof t+"] != 'object'");var i=function(){};i.prototype=t,r=new i,r.__proto__=t}return n!==void 0&&Object.defineProperties(r,n),r}}if(Object.defineProperty){var E=w({}),S=typeof document=="undefined"||w(document.createElement("div"));if(!E||!S)var x=Object.defineProperty}if(!Object.defineProperty||x){var T="Property description must be an object: ",N="Object.defineProperty called on non-object: ",C="getters & setters can not be defined on this javascript engine";Object.defineProperty=function(t,n,r){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(N+t);if(typeof r!="object"&&typeof r!="function"||r===null)throw new TypeError(T+r);if(x)try{return x.call(Object,t,n,r)}catch(i){}if(f(r,"value"))if(d&&(h(t,n)||p(t,n))){var s=t.__proto__;t.__proto__=o,delete t[n],t[n]=r.value,t.__proto__=s}else t[n]=r.value;else{if(!d)throw new TypeError(C);f(r,"get")&&l(t,n,r.get),f(r,"set")&&c(t,n,r.set)}return t}}Object.defineProperties||(Object.defineProperties=function(t,n){for(var r in n)f(n,r)&&Object.defineProperty(t,r,n[r]);return t}),Object.seal||(Object.seal=function(t){return t}),Object.freeze||(Object.freeze=function(t){return t});try{Object.freeze(function(){})}catch(k){Object.freeze=function(t){return function(n){return typeof n=="function"?n:t(n)}}(Object.freeze)}Object.preventExtensions||(Object.preventExtensions=function(t){return t}),Object.isSealed||(Object.isSealed=function(t){return!1}),Object.isFrozen||(Object.isFrozen=function(t){return!1}),Object.isExtensible||(Object.isExtensible=function(t){if(Object(t)===t)throw new TypeError;var n="";while(f(t,n))n+="?";t[n]=!0;var r=f(t,n);return delete t[n],r});if(!Object.keys){var L=!0,A=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],O=A.length;for(var M in{toString:null})L=!1;Object.keys=function I(e){if(typeof e!="object"&&typeof e!="function"||e===null)throw new TypeError("Object.keys called on a non-object");var I=[];for(var t in e)f(e,t)&&I.push(t);if(L)for(var n=0,r=O;n<r;n++){var i=A[n];f(e,i)&&I.push(i)}return I}}Date.now||(Date.now=function(){return(new Date).getTime()});var _="	\n\f\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\ufeff";if(!String.prototype.trim||_.trim()){_="["+_+"]";var D=new RegExp("^"+_+_+"*"),P=new RegExp(_+_+"*$");String.prototype.trim=function(){return String(this).replace(D,"").replace(P,"")}}var F=function(e){if(e==null)throw new TypeError("can't convert "+e+" to object");return Object(e)}})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-json.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-json.js
new file mode 100644
index 0000000..604ffd7
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-json.js
@@ -0,0 +1 @@
+"no use strict";(function(e){function t(e,t){var n=e,r="";while(n){var i=t[n];if(typeof i=="string")return i+r;if(i)return i.location.replace(/\/*$/,"/")+(r||i.main||i.name);if(i===!1)return"";var s=n.lastIndexOf("/");if(s===-1)break;r=n.substr(s)+r,n=n.slice(0,s)}return e}if(typeof e.window!="undefined"&&e.document)return;if(e.require&&e.define)return;e.console||(e.console=function(){var e=Array.prototype.slice.call(arguments,0);postMessage({type:"log",data:e})},e.console.error=e.console.warn=e.console.log=e.console.trace=e.console),e.window=e,e.ace=e,e.onerror=function(e,t,n,r,i){postMessage({type:"error",data:{message:e,data:i.data,file:t,line:n,col:r,stack:i.stack}})},e.normalizeModule=function(t,n){if(n.indexOf("!")!==-1){var r=n.split("!");return e.normalizeModule(t,r[0])+"!"+e.normalizeModule(t,r[1])}if(n.charAt(0)=="."){var i=t.split("/").slice(0,-1).join("/");n=(i?i+"/":"")+n;while(n.indexOf(".")!==-1&&s!=n){var s=n;n=n.replace(/^\.\//,"").replace(/\/\.\//,"/").replace(/[^\/]+\/\.\.\//,"")}}return n},e.require=function(r,i){i||(i=r,r=null);if(!i.charAt)throw new Error("worker.js require() accepts only (parentId, id) as arguments");i=e.normalizeModule(r,i);var s=e.require.modules[i];if(s)return s.initialized||(s.initialized=!0,s.exports=s.factory().exports),s.exports;if(!e.require.tlns)return console.log("unable to load "+i);var o=t(i,e.require.tlns);return o.slice(-3)!=".js"&&(o+=".js"),e.require.id=i,e.require.modules[i]={},importScripts(o),e.require(r,i)},e.require.modules={},e.require.tlns={},e.define=function(t,n,r){arguments.length==2?(r=n,typeof t!="string"&&(n=t,t=e.require.id)):arguments.length==1&&(r=t,n=[],t=e.require.id);if(typeof r!="function"){e.require.modules[t]={exports:r,initialized:!0};return}n.length||(n=["require","exports","module"]);var i=function(n){return e.require(t,n)};e.require.modules[t]={exports:{},factory:function(){var e=this,t=r.apply(this,n.map(function(t){switch(t){case"require":return i;case"exports":return e.exports;case"module":return e;default:return i(t)}}));return t&&(e.exports=t),e}}},e.define.amd={},require.tlns={},e.initBaseUrls=function(t){for(var n in t)require.tlns[n]=t[n]},e.initSender=function(){var n=e.require("ace/lib/event_emitter").EventEmitter,r=e.require("ace/lib/oop"),i=function(){};return function(){r.implement(this,n),this.callback=function(e,t){postMessage({type:"call",id:t,data:e})},this.emit=function(e,t){postMessage({type:"event",name:e,data:t})}}.call(i.prototype),new i};var n=e.main=null,r=e.sender=null;e.onmessage=function(t){var i=t.data;if(i.event&&r)r._signal(i.event,i.data);else if(i.command)if(n[i.command])n[i.command].apply(n,i.args);else{if(!e[i.command])throw new Error("Unknown command:"+i.command);e[i.command].apply(e,i.args)}else if(i.init){e.initBaseUrls(i.tlns),require("ace/lib/es5-shim"),r=e.sender=e.initSender();var s=require(i.module)[i.classname];n=e.main=new s(r)}}})(this),ace.define("ace/lib/oop",["require","exports","module"],function(e,t,n){"use strict";t.inherits=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})},t.mixin=function(e,t){for(var n in t)e[n]=t[n];return e},t.implement=function(e,n){t.mixin(e,n)}}),ace.define("ace/range",["require","exports","module"],function(e,t,n){"use strict";var r=function(e,t){return e.row-t.row||e.column-t.column},i=function(e,t,n,r){this.start={row:e,column:t},this.end={row:n,column:r}};(function(){this.isEqual=function(e){return this.start.row===e.start.row&&this.end.row===e.end.row&&this.start.column===e.start.column&&this.end.column===e.end.column},this.toString=function(){return"Range: ["+this.start.row+"/"+this.start.column+"] -> ["+this.end.row+"/"+this.end.column+"]"},this.contains=function(e,t){return this.compare(e,t)==0},this.compareRange=function(e){var t,n=e.end,r=e.start;return t=this.compare(n.row,n.column),t==1?(t=this.compare(r.row,r.column),t==1?2:t==0?1:0):t==-1?-2:(t=this.compare(r.row,r.column),t==-1?-1:t==1?42:0)},this.comparePoint=function(e){return this.compare(e.row,e.column)},this.containsRange=function(e){return this.comparePoint(e.start)==0&&this.comparePoint(e.end)==0},this.intersects=function(e){var t=this.compareRange(e);return t==-1||t==0||t==1},this.isEnd=function(e,t){return this.end.row==e&&this.end.column==t},this.isStart=function(e,t){return this.start.row==e&&this.start.column==t},this.setStart=function(e,t){typeof e=="object"?(this.start.column=e.column,this.start.row=e.row):(this.start.row=e,this.start.column=t)},this.setEnd=function(e,t){typeof e=="object"?(this.end.column=e.column,this.end.row=e.row):(this.end.row=e,this.end.column=t)},this.inside=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)||this.isStart(e,t)?!1:!0:!1},this.insideStart=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)?!1:!0:!1},this.insideEnd=function(e,t){return this.compare(e,t)==0?this.isStart(e,t)?!1:!0:!1},this.compare=function(e,t){return!this.isMultiLine()&&e===this.start.row?t<this.start.column?-1:t>this.end.column?1:0:e<this.start.row?-1:e>this.end.row?1:this.start.row===e?t>=this.start.column?0:-1:this.end.row===e?t<=this.end.column?0:1:0},this.compareStart=function(e,t){return this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.compareEnd=function(e,t){return this.end.row==e&&this.end.column==t?1:this.compare(e,t)},this.compareInside=function(e,t){return this.end.row==e&&this.end.column==t?1:this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.clipRows=function(e,t){if(this.end.row>t)var n={row:t+1,column:0};else if(this.end.row<e)var n={row:e,column:0};if(this.start.row>t)var r={row:t+1,column:0};else if(this.start.row<e)var r={row:e,column:0};return i.fromPoints(r||this.start,n||this.end)},this.extend=function(e,t){var n=this.compare(e,t);if(n==0)return this;if(n==-1)var r={row:e,column:t};else var s={row:e,column:t};return i.fromPoints(r||this.start,s||this.end)},this.isEmpty=function(){return this.start.row===this.end.row&&this.start.column===this.end.column},this.isMultiLine=function(){return this.start.row!==this.end.row},this.clone=function(){return i.fromPoints(this.start,this.end)},this.collapseRows=function(){return this.end.column==0?new i(this.start.row,0,Math.max(this.start.row,this.end.row-1),0):new i(this.start.row,0,this.end.row,0)},this.toScreenRange=function(e){var t=e.documentToScreenPosition(this.start),n=e.documentToScreenPosition(this.end);return new i(t.row,t.column,n.row,n.column)},this.moveBy=function(e,t){this.start.row+=e,this.start.column+=t,this.end.row+=e,this.end.column+=t}}).call(i.prototype),i.fromPoints=function(e,t){return new i(e.row,e.column,t.row,t.column)},i.comparePoints=r,i.comparePoints=function(e,t){return e.row-t.row||e.column-t.column},t.Range=i}),ace.define("ace/apply_delta",["require","exports","module"],function(e,t,n){"use strict";function r(e,t){throw console.log("Invalid Delta:",e),"Invalid Delta: "+t}function i(e,t){return t.row>=0&&t.row<e.length&&t.column>=0&&t.column<=e[t.row].length}function s(e,t){t.action!="insert"&&t.action!="remove"&&r(t,"delta.action must be 'insert' or 'remove'"),t.lines instanceof Array||r(t,"delta.lines must be an Array"),(!t.start||!t.end)&&r(t,"delta.start/end must be an present");var n=t.start;i(e,t.start)||r(t,"delta.start must be contained in document");var s=t.end;t.action=="remove"&&!i(e,s)&&r(t,"delta.end must contained in document for 'remove' actions");var o=s.row-n.row,u=s.column-(o==0?n.column:0);(o!=t.lines.length-1||t.lines[o].length!=u)&&r(t,"delta.range must match delta lines")}t.applyDelta=function(e,t,n){var r=t.start.row,i=t.start.column,s=e[r]||"";switch(t.action){case"insert":var o=t.lines;if(o.length===1)e[r]=s.substring(0,i)+t.lines[0]+s.substring(i);else{var u=[r,1].concat(t.lines);e.splice.apply(e,u),e[r]=s.substring(0,i)+e[r],e[r+t.lines.length-1]+=s.substring(i)}break;case"remove":var a=t.end.column,f=t.end.row;r===f?e[r]=s.substring(0,i)+s.substring(a):e.splice(r,f-r+1,s.substring(0,i)+e[f].substring(a))}}}),ace.define("ace/lib/event_emitter",["require","exports","module"],function(e,t,n){"use strict";var r={},i=function(){this.propagationStopped=!0},s=function(){this.defaultPrevented=!0};r._emit=r._dispatchEvent=function(e,t){this._eventRegistry||(this._eventRegistry={}),this._defaultHandlers||(this._defaultHandlers={});var n=this._eventRegistry[e]||[],r=this._defaultHandlers[e];if(!n.length&&!r)return;if(typeof t!="object"||!t)t={};t.type||(t.type=e),t.stopPropagation||(t.stopPropagation=i),t.preventDefault||(t.preventDefault=s),n=n.slice();for(var o=0;o<n.length;o++){n[o](t,this);if(t.propagationStopped)break}if(r&&!t.defaultPrevented)return r(t,this)},r._signal=function(e,t){var n=(this._eventRegistry||{})[e];if(!n)return;n=n.slice();for(var r=0;r<n.length;r++)n[r](t,this)},r.once=function(e,t){var n=this;t&&this.addEventListener(e,function r(){n.removeEventListener(e,r),t.apply(null,arguments)})},r.setDefaultHandler=function(e,t){var n=this._defaultHandlers;n||(n=this._defaultHandlers={_disabled_:{}});if(n[e]){var r=n[e],i=n._disabled_[e];i||(n._disabled_[e]=i=[]),i.push(r);var s=i.indexOf(t);s!=-1&&i.splice(s,1)}n[e]=t},r.removeDefaultHandler=function(e,t){var n=this._defaultHandlers;if(!n)return;var r=n._disabled_[e];if(n[e]==t){var i=n[e];r&&this.setDefaultHandler(e,r.pop())}else if(r){var s=r.indexOf(t);s!=-1&&r.splice(s,1)}},r.on=r.addEventListener=function(e,t,n){this._eventRegistry=this._eventRegistry||{};var r=this._eventRegistry[e];return r||(r=this._eventRegistry[e]=[]),r.indexOf(t)==-1&&r[n?"unshift":"push"](t),t},r.off=r.removeListener=r.removeEventListener=function(e,t){this._eventRegistry=this._eventRegistry||{};var n=this._eventRegistry[e];if(!n)return;var r=n.indexOf(t);r!==-1&&n.splice(r,1)},r.removeAllListeners=function(e){this._eventRegistry&&(this._eventRegistry[e]=[])},t.EventEmitter=r}),ace.define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=t.Anchor=function(e,t,n){this.$onChange=this.onChange.bind(this),this.attach(e),typeof n=="undefined"?this.setPosition(t.row,t.column):this.setPosition(t,n)};(function(){function e(e,t,n){var r=n?e.column<=t.column:e.column<t.column;return e.row<t.row||e.row==t.row&&r}function t(t,n,r){var i=t.action=="insert",s=(i?1:-1)*(t.end.row-t.start.row),o=(i?1:-1)*(t.end.column-t.start.column),u=t.start,a=i?u:t.end;return e(n,u,r)?{row:n.row,column:n.column}:e(a,n,!r)?{row:n.row+s,column:n.column+(n.row==a.row?o:0)}:{row:u.row,column:u.column}}r.implement(this,i),this.getPosition=function(){return this.$clipPositionToDocument(this.row,this.column)},this.getDocument=function(){return this.document},this.$insertRight=!1,this.onChange=function(e){if(e.start.row==e.end.row&&e.start.row!=this.row)return;if(e.start.row>this.row)return;var n=t(e,{row:this.row,column:this.column},this.$insertRight);this.setPosition(n.row,n.column,!0)},this.setPosition=function(e,t,n){var r;n?r={row:e,column:t}:r=this.$clipPositionToDocument(e,t);if(this.row==r.row&&this.column==r.column)return;var i={row:this.row,column:this.column};this.row=r.row,this.column=r.column,this._signal("change",{old:i,value:r})},this.detach=function(){this.document.removeEventListener("change",this.$onChange)},this.attach=function(e){this.document=e||this.document,this.document.on("change",this.$onChange)},this.$clipPositionToDocument=function(e,t){var n={};return e>=this.document.getLength()?(n.row=Math.max(0,this.document.getLength()-1),n.column=this.document.getLine(n.row).length):e<0?(n.row=0,n.column=0):(n.row=e,n.column=Math.min(this.document.getLine(n.row).length,Math.max(0,t))),t<0&&(n.column=0),n}}).call(s.prototype)}),ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./apply_delta").applyDelta,s=e("./lib/event_emitter").EventEmitter,o=e("./range").Range,u=e("./anchor").Anchor,a=function(e){this.$lines=[""],e.length===0?this.$lines=[""]:Array.isArray(e)?this.insertMergedLines({row:0,column:0},e):this.insert({row:0,column:0},e)};(function(){r.implement(this,s),this.setValue=function(e){var t=this.getLength()-1;this.remove(new o(0,0,t,this.getLine(t).length)),this.insert({row:0,column:0},e)},this.getValue=function(){return this.getAllLines().join(this.getNewLineCharacter())},this.createAnchor=function(e,t){return new u(this,e,t)},"aaa".split(/a/).length===0?this.$split=function(e){return e.replace(/\r\n|\r/g,"\n").split("\n")}:this.$split=function(e){return e.split(/\r\n|\r|\n/)},this.$detectNewLine=function(e){var t=e.match(/^.*?(\r\n|\r|\n)/m);this.$autoNewLine=t?t[1]:"\n",this._signal("changeNewLineMode")},this.getNewLineCharacter=function(){switch(this.$newLineMode){case"windows":return"\r\n";case"unix":return"\n";default:return this.$autoNewLine||"\n"}},this.$autoNewLine="",this.$newLineMode="auto",this.setNewLineMode=function(e){if(this.$newLineMode===e)return;this.$newLineMode=e,this._signal("changeNewLineMode")},this.getNewLineMode=function(){return this.$newLineMode},this.isNewLine=function(e){return e=="\r\n"||e=="\r"||e=="\n"},this.getLine=function(e){return this.$lines[e]||""},this.getLines=function(e,t){return this.$lines.slice(e,t+1)},this.getAllLines=function(){return this.getLines(0,this.getLength())},this.getLength=function(){return this.$lines.length},this.getTextRange=function(e){return this.getLinesForRange(e).join(this.getNewLineCharacter())},this.getLinesForRange=function(e){var t;if(e.start.row===e.end.row)t=[this.getLine(e.start.row).substring(e.start.column,e.end.column)];else{t=this.getLines(e.start.row,e.end.row),t[0]=(t[0]||"").substring(e.start.column);var n=t.length-1;e.end.row-e.start.row==n&&(t[n]=t[n].substring(0,e.end.column))}return t},this.insertLines=function(e,t){return console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."),this.insertFullLines(e,t)},this.removeLines=function(e,t){return console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."),this.removeFullLines(e,t)},this.insertNewLine=function(e){return console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead."),this.insertMergedLines(e,["",""])},this.insert=function(e,t){return this.getLength()<=1&&this.$detectNewLine(t),this.insertMergedLines(e,this.$split(t))},this.insertInLine=function(e,t){var n=this.clippedPos(e.row,e.column),r=this.pos(e.row,e.column+t.length);return this.applyDelta({start:n,end:r,action:"insert",lines:[t]},!0),this.clonePos(r)},this.clippedPos=function(e,t){var n=this.getLength();e===undefined?e=n:e<0?e=0:e>=n&&(e=n-1,t=undefined);var r=this.getLine(e);return t==undefined&&(t=r.length),t=Math.min(Math.max(t,0),r.length),{row:e,column:t}},this.clonePos=function(e){return{row:e.row,column:e.column}},this.pos=function(e,t){return{row:e,column:t}},this.$clipPosition=function(e){var t=this.getLength();return e.row>=t?(e.row=Math.max(0,t-1),e.column=this.getLine(t-1).length):(e.row=Math.max(0,e.row),e.column=Math.min(Math.max(e.column,0),this.getLine(e.row).length)),e},this.insertFullLines=function(e,t){e=Math.min(Math.max(e,0),this.getLength());var n=0;e<this.getLength()?(t=t.concat([""]),n=0):(t=[""].concat(t),e--,n=this.$lines[e].length),this.insertMergedLines({row:e,column:n},t)},this.insertMergedLines=function(e,t){var n=this.clippedPos(e.row,e.column),r={row:n.row+t.length-1,column:(t.length==1?n.column:0)+t[t.length-1].length};return this.applyDelta({start:n,end:r,action:"insert",lines:t}),this.clonePos(r)},this.remove=function(e){var t=this.clippedPos(e.start.row,e.start.column),n=this.clippedPos(e.end.row,e.end.column);return this.applyDelta({start:t,end:n,action:"remove",lines:this.getLinesForRange({start:t,end:n})}),this.clonePos(t)},this.removeInLine=function(e,t,n){var r=this.clippedPos(e,t),i=this.clippedPos(e,n);return this.applyDelta({start:r,end:i,action:"remove",lines:this.getLinesForRange({start:r,end:i})},!0),this.clonePos(r)},this.removeFullLines=function(e,t){e=Math.min(Math.max(0,e),this.getLength()-1),t=Math.min(Math.max(0,t),this.getLength()-1);var n=t==this.getLength()-1&&e>0,r=t<this.getLength()-1,i=n?e-1:e,s=n?this.getLine(i).length:0,u=r?t+1:t,a=r?0:this.getLine(u).length,f=new o(i,s,u,a),l=this.$lines.slice(e,t+1);return this.applyDelta({start:f.start,end:f.end,action:"remove",lines:this.getLinesForRange(f)}),l},this.removeNewLine=function(e){e<this.getLength()-1&&e>=0&&this.applyDelta({start:this.pos(e,this.getLine(e).length),end:this.pos(e+1,0),action:"remove",lines:["",""]})},this.replace=function(e,t){e instanceof o||(e=o.fromPoints(e.start,e.end));if(t.length===0&&e.isEmpty())return e.start;if(t==this.getTextRange(e))return e.end;this.remove(e);var n;return t?n=this.insert(e.start,t):n=e.start,n},this.applyDeltas=function(e){for(var t=0;t<e.length;t++)this.applyDelta(e[t])},this.revertDeltas=function(e){for(var t=e.length-1;t>=0;t--)this.revertDelta(e[t])},this.applyDelta=function(e,t){var n=e.action=="insert";if(n?e.lines.length<=1&&!e.lines[0]:!o.comparePoints(e.start,e.end))return;n&&e.lines.length>2e4&&this.$splitAndapplyLargeDelta(e,2e4),i(this.$lines,e,t),this._signal("change",e)},this.$splitAndapplyLargeDelta=function(e,t){var n=e.lines,r=n.length,i=e.start.row,s=e.start.column,o=0,u=0;do{o=u,u+=t-1;var a=n.slice(o,u);if(u>r){e.lines=a,e.start.row=i+o,e.start.column=s;break}a.push(""),this.applyDelta({start:this.pos(i+o,s),end:this.pos(i+u,s=0),action:e.action,lines:a},!0)}while(!0)},this.revertDelta=function(e){this.applyDelta({start:this.clonePos(e.start),end:this.clonePos(e.end),action:e.action=="insert"?"remove":"insert",lines:e.lines.slice()})},this.indexToPosition=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length;for(var i=t||0,s=n.length;i<s;i++){e-=n[i].length+r;if(e<0)return{row:i,column:e+n[i].length+r}}return{row:s-1,column:n[s-1].length}},this.positionToIndex=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length,i=0,s=Math.min(e.row,n.length);for(var o=t||0;o<s;++o)i+=n[o].length+r;return i+e.column}}).call(a.prototype),t.Document=a}),ace.define("ace/lib/lang",["require","exports","module"],function(e,t,n){"use strict";t.last=function(e){return e[e.length-1]},t.stringReverse=function(e){return e.split("").reverse().join("")},t.stringRepeat=function(e,t){var n="";while(t>0){t&1&&(n+=e);if(t>>=1)e+=e}return n};var r=/^\s\s*/,i=/\s\s*$/;t.stringTrimLeft=function(e){return e.replace(r,"")},t.stringTrimRight=function(e){return e.replace(i,"")},t.copyObject=function(e){var t={};for(var n in e)t[n]=e[n];return t},t.copyArray=function(e){var t=[];for(var n=0,r=e.length;n<r;n++)e[n]&&typeof e[n]=="object"?t[n]=this.copyObject(e[n]):t[n]=e[n];return t},t.deepCopy=function s(e){if(typeof e!="object"||!e)return e;var t;if(Array.isArray(e)){t=[];for(var n=0;n<e.length;n++)t[n]=s(e[n]);return t}var r=e.constructor;if(r===RegExp)return e;t=r();for(var n in e)t[n]=s(e[n]);return t},t.arrayToMap=function(e){var t={};for(var n=0;n<e.length;n++)t[e[n]]=1;return t},t.createMap=function(e){var t=Object.create(null);for(var n in e)t[n]=e[n];return t},t.arrayRemove=function(e,t){for(var n=0;n<=e.length;n++)t===e[n]&&e.splice(n,1)},t.escapeRegExp=function(e){return e.replace(/([.*+?^${}()|[\]\/\\])/g,"\\$1")},t.escapeHTML=function(e){return e.replace(/&/g,"&#38;").replace(/"/g,"&#34;").replace(/'/g,"&#39;").replace(/</g,"&#60;")},t.getMatchOffsets=function(e,t){var n=[];return e.replace(t,function(e){n.push({offset:arguments[arguments.length-2],length:e.length})}),n},t.deferredCall=function(e){var t=null,n=function(){t=null,e()},r=function(e){return r.cancel(),t=setTimeout(n,e||0),r};return r.schedule=r,r.call=function(){return this.cancel(),e(),r},r.cancel=function(){return clearTimeout(t),t=null,r},r.isPending=function(){return t},r},t.delayedCall=function(e,t){var n=null,r=function(){n=null,e()},i=function(e){n==null&&(n=setTimeout(r,e||t))};return i.delay=function(e){n&&clearTimeout(n),n=setTimeout(r,e||t)},i.schedule=i,i.call=function(){this.cancel(),e()},i.cancel=function(){n&&clearTimeout(n),n=null},i.isPending=function(){return n},i}}),ace.define("ace/worker/mirror",["require","exports","module","ace/range","ace/document","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../range").Range,i=e("../document").Document,s=e("../lib/lang"),o=t.Mirror=function(e){this.sender=e;var t=this.doc=new i(""),n=this.deferredUpdate=s.delayedCall(this.onUpdate.bind(this)),r=this;e.on("change",function(e){var i=e.data;if(i[0].start)t.applyDeltas(i);else for(var s=0;s<i.length;s+=2){if(Array.isArray(i[s+1]))var o={action:"insert",start:i[s],lines:i[s+1]};else var o={action:"remove",start:i[s],end:i[s+1]};t.applyDelta(o,!0)}if(r.$timeout)return n.schedule(r.$timeout);r.onUpdate()})};(function(){this.$timeout=500,this.setTimeout=function(e){this.$timeout=e},this.setValue=function(e){this.doc.setValue(e),this.deferredUpdate.schedule(this.$timeout)},this.getValue=function(e){this.sender.callback(this.doc.getValue(),e)},this.onUpdate=function(){},this.isPending=function(){return this.deferredUpdate.isPending()}}).call(o.prototype)}),ace.define("ace/mode/json/json_parse",["require","exports","module"],function(e,t,n){"use strict";var r,i,s={'"':'"',"\\":"\\","/":"/",b:"\b",f:"\f",n:"\n",r:"\r",t:"	"},o,u=function(e){throw{name:"SyntaxError",message:e,at:r,text:o}},a=function(e){return e&&e!==i&&u("Expected '"+e+"' instead of '"+i+"'"),i=o.charAt(r),r+=1,i},f=function(){var e,t="";i==="-"&&(t="-",a("-"));while(i>="0"&&i<="9")t+=i,a();if(i==="."){t+=".";while(a()&&i>="0"&&i<="9")t+=i}if(i==="e"||i==="E"){t+=i,a();if(i==="-"||i==="+")t+=i,a();while(i>="0"&&i<="9")t+=i,a()}e=+t;if(!isNaN(e))return e;u("Bad number")},l=function(){var e,t,n="",r;if(i==='"')while(a()){if(i==='"')return a(),n;if(i==="\\"){a();if(i==="u"){r=0;for(t=0;t<4;t+=1){e=parseInt(a(),16);if(!isFinite(e))break;r=r*16+e}n+=String.fromCharCode(r)}else{if(typeof s[i]!="string")break;n+=s[i]}}else n+=i}u("Bad string")},c=function(){while(i&&i<=" ")a()},h=function(){switch(i){case"t":return a("t"),a("r"),a("u"),a("e"),!0;case"f":return a("f"),a("a"),a("l"),a("s"),a("e"),!1;case"n":return a("n"),a("u"),a("l"),a("l"),null}u("Unexpected '"+i+"'")},p,d=function(){var e=[];if(i==="["){a("["),c();if(i==="]")return a("]"),e;while(i){e.push(p()),c();if(i==="]")return a("]"),e;a(","),c()}}u("Bad array")},v=function(){var e,t={};if(i==="{"){a("{"),c();if(i==="}")return a("}"),t;while(i){e=l(),c(),a(":"),Object.hasOwnProperty.call(t,e)&&u('Duplicate key "'+e+'"'),t[e]=p(),c();if(i==="}")return a("}"),t;a(","),c()}}u("Bad object")};return p=function(){c();switch(i){case"{":return v();case"[":return d();case'"':return l();case"-":return f();default:return i>="0"&&i<="9"?f():h()}},function(e,t){var n;return o=e,r=0,i=" ",n=p(),c(),i&&u("Syntax error"),typeof t=="function"?function s(e,n){var r,i,o=e[n];if(o&&typeof o=="object")for(r in o)Object.hasOwnProperty.call(o,r)&&(i=s(o,r),i!==undefined?o[r]=i:delete o[r]);return t.call(e,n,o)}({"":n},""):n}}),ace.define("ace/mode/json_worker",["require","exports","module","ace/lib/oop","ace/worker/mirror","ace/mode/json/json_parse"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../worker/mirror").Mirror,s=e("./json/json_parse"),o=t.JsonWorker=function(e){i.call(this,e),this.setTimeout(200)};r.inherits(o,i),function(){this.onUpdate=function(){var e=this.doc.getValue(),t=[];try{e&&s(e)}catch(n){var r=this.doc.indexToPosition(n.at-1);t.push({row:r.row,column:r.column,text:n.message,type:"error"})}this.sender.emit("annotate",t)}}.call(o.prototype)}),ace.define("ace/lib/es5-shim",["require","exports","module"],function(e,t,n){function r(){}function w(e){try{return Object.defineProperty(e,"sentinel",{}),"sentinel"in e}catch(t){}}function H(e){return e=+e,e!==e?e=0:e!==0&&e!==1/0&&e!==-1/0&&(e=(e>0||-1)*Math.floor(Math.abs(e))),e}function B(e){var t=typeof e;return e===null||t==="undefined"||t==="boolean"||t==="number"||t==="string"}function j(e){var t,n,r;if(B(e))return e;n=e.valueOf;if(typeof n=="function"){t=n.call(e);if(B(t))return t}r=e.toString;if(typeof r=="function"){t=r.call(e);if(B(t))return t}throw new TypeError}Function.prototype.bind||(Function.prototype.bind=function(t){var n=this;if(typeof n!="function")throw new TypeError("Function.prototype.bind called on incompatible "+n);var i=u.call(arguments,1),s=function(){if(this instanceof s){var e=n.apply(this,i.concat(u.call(arguments)));return Object(e)===e?e:this}return n.apply(t,i.concat(u.call(arguments)))};return n.prototype&&(r.prototype=n.prototype,s.prototype=new r,r.prototype=null),s});var i=Function.prototype.call,s=Array.prototype,o=Object.prototype,u=s.slice,a=i.bind(o.toString),f=i.bind(o.hasOwnProperty),l,c,h,p,d;if(d=f(o,"__defineGetter__"))l=i.bind(o.__defineGetter__),c=i.bind(o.__defineSetter__),h=i.bind(o.__lookupGetter__),p=i.bind(o.__lookupSetter__);if([1,2].splice(0).length!=2)if(!function(){function e(e){var t=new Array(e+2);return t[0]=t[1]=0,t}var t=[],n;t.splice.apply(t,e(20)),t.splice.apply(t,e(26)),n=t.length,t.splice(5,0,"XXX"),n+1==t.length;if(n+1==t.length)return!0}())Array.prototype.splice=function(e,t){var n=this.length;e>0?e>n&&(e=n):e==void 0?e=0:e<0&&(e=Math.max(n+e,0)),e+t<n||(t=n-e);var r=this.slice(e,e+t),i=u.call(arguments,2),s=i.length;if(e===n)s&&this.push.apply(this,i);else{var o=Math.min(t,n-e),a=e+o,f=a+s-o,l=n-a,c=n-o;if(f<a)for(var h=0;h<l;++h)this[f+h]=this[a+h];else if(f>a)for(h=l;h--;)this[f+h]=this[a+h];if(s&&e===c)this.length=c,this.push.apply(this,i);else{this.length=c+s;for(h=0;h<s;++h)this[e+h]=i[h]}}return r};else{var v=Array.prototype.splice;Array.prototype.splice=function(e,t){return arguments.length?v.apply(this,[e===void 0?0:e,t===void 0?this.length-e:t].concat(u.call(arguments,2))):[]}}Array.isArray||(Array.isArray=function(t){return a(t)=="[object Array]"});var m=Object("a"),g=m[0]!="a"||!(0 in m);Array.prototype.forEach||(Array.prototype.forEach=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=arguments[1],s=-1,o=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError;while(++s<o)s in r&&t.call(i,r[s],s,n)}),Array.prototype.map||(Array.prototype.map=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=Array(i),o=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var u=0;u<i;u++)u in r&&(s[u]=t.call(o,r[u],u,n));return s}),Array.prototype.filter||(Array.prototype.filter=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=[],o,u=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var f=0;f<i;f++)f in r&&(o=r[f],t.call(u,o,f,n)&&s.push(o));return s}),Array.prototype.every||(Array.prototype.every=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&!t.call(s,r[o],o,n))return!1;return!0}),Array.prototype.some||(Array.prototype.some=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&t.call(s,r[o],o,n))return!0;return!1}),Array.prototype.reduce||(Array.prototype.reduce=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduce of empty array with no initial value");var s=0,o;if(arguments.length>=2)o=arguments[1];else do{if(s in r){o=r[s++];break}if(++s>=i)throw new TypeError("reduce of empty array with no initial value")}while(!0);for(;s<i;s++)s in r&&(o=t.call(void 0,o,r[s],s,n));return o}),Array.prototype.reduceRight||(Array.prototype.reduceRight=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduceRight of empty array with no initial value");var s,o=i-1;if(arguments.length>=2)s=arguments[1];else do{if(o in r){s=r[o--];break}if(--o<0)throw new TypeError("reduceRight of empty array with no initial value")}while(!0);do o in this&&(s=t.call(void 0,s,r[o],o,n));while(o--);return s});if(!Array.prototype.indexOf||[0,1].indexOf(1,2)!=-1)Array.prototype.indexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=0;arguments.length>1&&(i=H(arguments[1])),i=i>=0?i:Math.max(0,r+i);for(;i<r;i++)if(i in n&&n[i]===t)return i;return-1};if(!Array.prototype.lastIndexOf||[0,1].lastIndexOf(0,-3)!=-1)Array.prototype.lastIndexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=r-1;arguments.length>1&&(i=Math.min(i,H(arguments[1]))),i=i>=0?i:r-Math.abs(i);for(;i>=0;i--)if(i in n&&t===n[i])return i;return-1};Object.getPrototypeOf||(Object.getPrototypeOf=function(t){return t.__proto__||(t.constructor?t.constructor.prototype:o)});if(!Object.getOwnPropertyDescriptor){var y="Object.getOwnPropertyDescriptor called on a non-object: ";Object.getOwnPropertyDescriptor=function(t,n){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(y+t);if(!f(t,n))return;var r,i,s;r={enumerable:!0,configurable:!0};if(d){var u=t.__proto__;t.__proto__=o;var i=h(t,n),s=p(t,n);t.__proto__=u;if(i||s)return i&&(r.get=i),s&&(r.set=s),r}return r.value=t[n],r}}Object.getOwnPropertyNames||(Object.getOwnPropertyNames=function(t){return Object.keys(t)});if(!Object.create){var b;Object.prototype.__proto__===null?b=function(){return{__proto__:null}}:b=function(){var e={};for(var t in e)e[t]=null;return e.constructor=e.hasOwnProperty=e.propertyIsEnumerable=e.isPrototypeOf=e.toLocaleString=e.toString=e.valueOf=e.__proto__=null,e},Object.create=function(t,n){var r;if(t===null)r=b();else{if(typeof t!="object")throw new TypeError("typeof prototype["+typeof t+"] != 'object'");var i=function(){};i.prototype=t,r=new i,r.__proto__=t}return n!==void 0&&Object.defineProperties(r,n),r}}if(Object.defineProperty){var E=w({}),S=typeof document=="undefined"||w(document.createElement("div"));if(!E||!S)var x=Object.defineProperty}if(!Object.defineProperty||x){var T="Property description must be an object: ",N="Object.defineProperty called on non-object: ",C="getters & setters can not be defined on this javascript engine";Object.defineProperty=function(t,n,r){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(N+t);if(typeof r!="object"&&typeof r!="function"||r===null)throw new TypeError(T+r);if(x)try{return x.call(Object,t,n,r)}catch(i){}if(f(r,"value"))if(d&&(h(t,n)||p(t,n))){var s=t.__proto__;t.__proto__=o,delete t[n],t[n]=r.value,t.__proto__=s}else t[n]=r.value;else{if(!d)throw new TypeError(C);f(r,"get")&&l(t,n,r.get),f(r,"set")&&c(t,n,r.set)}return t}}Object.defineProperties||(Object.defineProperties=function(t,n){for(var r in n)f(n,r)&&Object.defineProperty(t,r,n[r]);return t}),Object.seal||(Object.seal=function(t){return t}),Object.freeze||(Object.freeze=function(t){return t});try{Object.freeze(function(){})}catch(k){Object.freeze=function(t){return function(n){return typeof n=="function"?n:t(n)}}(Object.freeze)}Object.preventExtensions||(Object.preventExtensions=function(t){return t}),Object.isSealed||(Object.isSealed=function(t){return!1}),Object.isFrozen||(Object.isFrozen=function(t){return!1}),Object.isExtensible||(Object.isExtensible=function(t){if(Object(t)===t)throw new TypeError;var n="";while(f(t,n))n+="?";t[n]=!0;var r=f(t,n);return delete t[n],r});if(!Object.keys){var L=!0,A=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],O=A.length;for(var M in{toString:null})L=!1;Object.keys=function I(e){if(typeof e!="object"&&typeof e!="function"||e===null)throw new TypeError("Object.keys called on a non-object");var I=[];for(var t in e)f(e,t)&&I.push(t);if(L)for(var n=0,r=O;n<r;n++){var i=A[n];f(e,i)&&I.push(i)}return I}}Date.now||(Date.now=function(){return(new Date).getTime()});var _="	\n\f\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\ufeff";if(!String.prototype.trim||_.trim()){_="["+_+"]";var D=new RegExp("^"+_+_+"*"),P=new RegExp(_+_+"*$");String.prototype.trim=function(){return String(this).replace(D,"").replace(P,"")}}var F=function(e){if(e==null)throw new TypeError("can't convert "+e+" to object");return Object(e)}})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-lua.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-lua.js
new file mode 100644
index 0000000..274f2f4
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-lua.js
@@ -0,0 +1 @@
+"no use strict";(function(e){function t(e,t){var n=e,r="";while(n){var i=t[n];if(typeof i=="string")return i+r;if(i)return i.location.replace(/\/*$/,"/")+(r||i.main||i.name);if(i===!1)return"";var s=n.lastIndexOf("/");if(s===-1)break;r=n.substr(s)+r,n=n.slice(0,s)}return e}if(typeof e.window!="undefined"&&e.document)return;if(e.require&&e.define)return;e.console||(e.console=function(){var e=Array.prototype.slice.call(arguments,0);postMessage({type:"log",data:e})},e.console.error=e.console.warn=e.console.log=e.console.trace=e.console),e.window=e,e.ace=e,e.onerror=function(e,t,n,r,i){postMessage({type:"error",data:{message:e,data:i.data,file:t,line:n,col:r,stack:i.stack}})},e.normalizeModule=function(t,n){if(n.indexOf("!")!==-1){var r=n.split("!");return e.normalizeModule(t,r[0])+"!"+e.normalizeModule(t,r[1])}if(n.charAt(0)=="."){var i=t.split("/").slice(0,-1).join("/");n=(i?i+"/":"")+n;while(n.indexOf(".")!==-1&&s!=n){var s=n;n=n.replace(/^\.\//,"").replace(/\/\.\//,"/").replace(/[^\/]+\/\.\.\//,"")}}return n},e.require=function(r,i){i||(i=r,r=null);if(!i.charAt)throw new Error("worker.js require() accepts only (parentId, id) as arguments");i=e.normalizeModule(r,i);var s=e.require.modules[i];if(s)return s.initialized||(s.initialized=!0,s.exports=s.factory().exports),s.exports;if(!e.require.tlns)return console.log("unable to load "+i);var o=t(i,e.require.tlns);return o.slice(-3)!=".js"&&(o+=".js"),e.require.id=i,e.require.modules[i]={},importScripts(o),e.require(r,i)},e.require.modules={},e.require.tlns={},e.define=function(t,n,r){arguments.length==2?(r=n,typeof t!="string"&&(n=t,t=e.require.id)):arguments.length==1&&(r=t,n=[],t=e.require.id);if(typeof r!="function"){e.require.modules[t]={exports:r,initialized:!0};return}n.length||(n=["require","exports","module"]);var i=function(n){return e.require(t,n)};e.require.modules[t]={exports:{},factory:function(){var e=this,t=r.apply(this,n.map(function(t){switch(t){case"require":return i;case"exports":return e.exports;case"module":return e;default:return i(t)}}));return t&&(e.exports=t),e}}},e.define.amd={},require.tlns={},e.initBaseUrls=function(t){for(var n in t)require.tlns[n]=t[n]},e.initSender=function(){var n=e.require("ace/lib/event_emitter").EventEmitter,r=e.require("ace/lib/oop"),i=function(){};return function(){r.implement(this,n),this.callback=function(e,t){postMessage({type:"call",id:t,data:e})},this.emit=function(e,t){postMessage({type:"event",name:e,data:t})}}.call(i.prototype),new i};var n=e.main=null,r=e.sender=null;e.onmessage=function(t){var i=t.data;if(i.event&&r)r._signal(i.event,i.data);else if(i.command)if(n[i.command])n[i.command].apply(n,i.args);else{if(!e[i.command])throw new Error("Unknown command:"+i.command);e[i.command].apply(e,i.args)}else if(i.init){e.initBaseUrls(i.tlns),require("ace/lib/es5-shim"),r=e.sender=e.initSender();var s=require(i.module)[i.classname];n=e.main=new s(r)}}})(this),ace.define("ace/lib/oop",["require","exports","module"],function(e,t,n){"use strict";t.inherits=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})},t.mixin=function(e,t){for(var n in t)e[n]=t[n];return e},t.implement=function(e,n){t.mixin(e,n)}}),ace.define("ace/range",["require","exports","module"],function(e,t,n){"use strict";var r=function(e,t){return e.row-t.row||e.column-t.column},i=function(e,t,n,r){this.start={row:e,column:t},this.end={row:n,column:r}};(function(){this.isEqual=function(e){return this.start.row===e.start.row&&this.end.row===e.end.row&&this.start.column===e.start.column&&this.end.column===e.end.column},this.toString=function(){return"Range: ["+this.start.row+"/"+this.start.column+"] -> ["+this.end.row+"/"+this.end.column+"]"},this.contains=function(e,t){return this.compare(e,t)==0},this.compareRange=function(e){var t,n=e.end,r=e.start;return t=this.compare(n.row,n.column),t==1?(t=this.compare(r.row,r.column),t==1?2:t==0?1:0):t==-1?-2:(t=this.compare(r.row,r.column),t==-1?-1:t==1?42:0)},this.comparePoint=function(e){return this.compare(e.row,e.column)},this.containsRange=function(e){return this.comparePoint(e.start)==0&&this.comparePoint(e.end)==0},this.intersects=function(e){var t=this.compareRange(e);return t==-1||t==0||t==1},this.isEnd=function(e,t){return this.end.row==e&&this.end.column==t},this.isStart=function(e,t){return this.start.row==e&&this.start.column==t},this.setStart=function(e,t){typeof e=="object"?(this.start.column=e.column,this.start.row=e.row):(this.start.row=e,this.start.column=t)},this.setEnd=function(e,t){typeof e=="object"?(this.end.column=e.column,this.end.row=e.row):(this.end.row=e,this.end.column=t)},this.inside=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)||this.isStart(e,t)?!1:!0:!1},this.insideStart=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)?!1:!0:!1},this.insideEnd=function(e,t){return this.compare(e,t)==0?this.isStart(e,t)?!1:!0:!1},this.compare=function(e,t){return!this.isMultiLine()&&e===this.start.row?t<this.start.column?-1:t>this.end.column?1:0:e<this.start.row?-1:e>this.end.row?1:this.start.row===e?t>=this.start.column?0:-1:this.end.row===e?t<=this.end.column?0:1:0},this.compareStart=function(e,t){return this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.compareEnd=function(e,t){return this.end.row==e&&this.end.column==t?1:this.compare(e,t)},this.compareInside=function(e,t){return this.end.row==e&&this.end.column==t?1:this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.clipRows=function(e,t){if(this.end.row>t)var n={row:t+1,column:0};else if(this.end.row<e)var n={row:e,column:0};if(this.start.row>t)var r={row:t+1,column:0};else if(this.start.row<e)var r={row:e,column:0};return i.fromPoints(r||this.start,n||this.end)},this.extend=function(e,t){var n=this.compare(e,t);if(n==0)return this;if(n==-1)var r={row:e,column:t};else var s={row:e,column:t};return i.fromPoints(r||this.start,s||this.end)},this.isEmpty=function(){return this.start.row===this.end.row&&this.start.column===this.end.column},this.isMultiLine=function(){return this.start.row!==this.end.row},this.clone=function(){return i.fromPoints(this.start,this.end)},this.collapseRows=function(){return this.end.column==0?new i(this.start.row,0,Math.max(this.start.row,this.end.row-1),0):new i(this.start.row,0,this.end.row,0)},this.toScreenRange=function(e){var t=e.documentToScreenPosition(this.start),n=e.documentToScreenPosition(this.end);return new i(t.row,t.column,n.row,n.column)},this.moveBy=function(e,t){this.start.row+=e,this.start.column+=t,this.end.row+=e,this.end.column+=t}}).call(i.prototype),i.fromPoints=function(e,t){return new i(e.row,e.column,t.row,t.column)},i.comparePoints=r,i.comparePoints=function(e,t){return e.row-t.row||e.column-t.column},t.Range=i}),ace.define("ace/apply_delta",["require","exports","module"],function(e,t,n){"use strict";function r(e,t){throw console.log("Invalid Delta:",e),"Invalid Delta: "+t}function i(e,t){return t.row>=0&&t.row<e.length&&t.column>=0&&t.column<=e[t.row].length}function s(e,t){t.action!="insert"&&t.action!="remove"&&r(t,"delta.action must be 'insert' or 'remove'"),t.lines instanceof Array||r(t,"delta.lines must be an Array"),(!t.start||!t.end)&&r(t,"delta.start/end must be an present");var n=t.start;i(e,t.start)||r(t,"delta.start must be contained in document");var s=t.end;t.action=="remove"&&!i(e,s)&&r(t,"delta.end must contained in document for 'remove' actions");var o=s.row-n.row,u=s.column-(o==0?n.column:0);(o!=t.lines.length-1||t.lines[o].length!=u)&&r(t,"delta.range must match delta lines")}t.applyDelta=function(e,t,n){var r=t.start.row,i=t.start.column,s=e[r]||"";switch(t.action){case"insert":var o=t.lines;if(o.length===1)e[r]=s.substring(0,i)+t.lines[0]+s.substring(i);else{var u=[r,1].concat(t.lines);e.splice.apply(e,u),e[r]=s.substring(0,i)+e[r],e[r+t.lines.length-1]+=s.substring(i)}break;case"remove":var a=t.end.column,f=t.end.row;r===f?e[r]=s.substring(0,i)+s.substring(a):e.splice(r,f-r+1,s.substring(0,i)+e[f].substring(a))}}}),ace.define("ace/lib/event_emitter",["require","exports","module"],function(e,t,n){"use strict";var r={},i=function(){this.propagationStopped=!0},s=function(){this.defaultPrevented=!0};r._emit=r._dispatchEvent=function(e,t){this._eventRegistry||(this._eventRegistry={}),this._defaultHandlers||(this._defaultHandlers={});var n=this._eventRegistry[e]||[],r=this._defaultHandlers[e];if(!n.length&&!r)return;if(typeof t!="object"||!t)t={};t.type||(t.type=e),t.stopPropagation||(t.stopPropagation=i),t.preventDefault||(t.preventDefault=s),n=n.slice();for(var o=0;o<n.length;o++){n[o](t,this);if(t.propagationStopped)break}if(r&&!t.defaultPrevented)return r(t,this)},r._signal=function(e,t){var n=(this._eventRegistry||{})[e];if(!n)return;n=n.slice();for(var r=0;r<n.length;r++)n[r](t,this)},r.once=function(e,t){var n=this;t&&this.addEventListener(e,function r(){n.removeEventListener(e,r),t.apply(null,arguments)})},r.setDefaultHandler=function(e,t){var n=this._defaultHandlers;n||(n=this._defaultHandlers={_disabled_:{}});if(n[e]){var r=n[e],i=n._disabled_[e];i||(n._disabled_[e]=i=[]),i.push(r);var s=i.indexOf(t);s!=-1&&i.splice(s,1)}n[e]=t},r.removeDefaultHandler=function(e,t){var n=this._defaultHandlers;if(!n)return;var r=n._disabled_[e];if(n[e]==t){var i=n[e];r&&this.setDefaultHandler(e,r.pop())}else if(r){var s=r.indexOf(t);s!=-1&&r.splice(s,1)}},r.on=r.addEventListener=function(e,t,n){this._eventRegistry=this._eventRegistry||{};var r=this._eventRegistry[e];return r||(r=this._eventRegistry[e]=[]),r.indexOf(t)==-1&&r[n?"unshift":"push"](t),t},r.off=r.removeListener=r.removeEventListener=function(e,t){this._eventRegistry=this._eventRegistry||{};var n=this._eventRegistry[e];if(!n)return;var r=n.indexOf(t);r!==-1&&n.splice(r,1)},r.removeAllListeners=function(e){this._eventRegistry&&(this._eventRegistry[e]=[])},t.EventEmitter=r}),ace.define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=t.Anchor=function(e,t,n){this.$onChange=this.onChange.bind(this),this.attach(e),typeof n=="undefined"?this.setPosition(t.row,t.column):this.setPosition(t,n)};(function(){function e(e,t,n){var r=n?e.column<=t.column:e.column<t.column;return e.row<t.row||e.row==t.row&&r}function t(t,n,r){var i=t.action=="insert",s=(i?1:-1)*(t.end.row-t.start.row),o=(i?1:-1)*(t.end.column-t.start.column),u=t.start,a=i?u:t.end;return e(n,u,r)?{row:n.row,column:n.column}:e(a,n,!r)?{row:n.row+s,column:n.column+(n.row==a.row?o:0)}:{row:u.row,column:u.column}}r.implement(this,i),this.getPosition=function(){return this.$clipPositionToDocument(this.row,this.column)},this.getDocument=function(){return this.document},this.$insertRight=!1,this.onChange=function(e){if(e.start.row==e.end.row&&e.start.row!=this.row)return;if(e.start.row>this.row)return;var n=t(e,{row:this.row,column:this.column},this.$insertRight);this.setPosition(n.row,n.column,!0)},this.setPosition=function(e,t,n){var r;n?r={row:e,column:t}:r=this.$clipPositionToDocument(e,t);if(this.row==r.row&&this.column==r.column)return;var i={row:this.row,column:this.column};this.row=r.row,this.column=r.column,this._signal("change",{old:i,value:r})},this.detach=function(){this.document.removeEventListener("change",this.$onChange)},this.attach=function(e){this.document=e||this.document,this.document.on("change",this.$onChange)},this.$clipPositionToDocument=function(e,t){var n={};return e>=this.document.getLength()?(n.row=Math.max(0,this.document.getLength()-1),n.column=this.document.getLine(n.row).length):e<0?(n.row=0,n.column=0):(n.row=e,n.column=Math.min(this.document.getLine(n.row).length,Math.max(0,t))),t<0&&(n.column=0),n}}).call(s.prototype)}),ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./apply_delta").applyDelta,s=e("./lib/event_emitter").EventEmitter,o=e("./range").Range,u=e("./anchor").Anchor,a=function(e){this.$lines=[""],e.length===0?this.$lines=[""]:Array.isArray(e)?this.insertMergedLines({row:0,column:0},e):this.insert({row:0,column:0},e)};(function(){r.implement(this,s),this.setValue=function(e){var t=this.getLength()-1;this.remove(new o(0,0,t,this.getLine(t).length)),this.insert({row:0,column:0},e)},this.getValue=function(){return this.getAllLines().join(this.getNewLineCharacter())},this.createAnchor=function(e,t){return new u(this,e,t)},"aaa".split(/a/).length===0?this.$split=function(e){return e.replace(/\r\n|\r/g,"\n").split("\n")}:this.$split=function(e){return e.split(/\r\n|\r|\n/)},this.$detectNewLine=function(e){var t=e.match(/^.*?(\r\n|\r|\n)/m);this.$autoNewLine=t?t[1]:"\n",this._signal("changeNewLineMode")},this.getNewLineCharacter=function(){switch(this.$newLineMode){case"windows":return"\r\n";case"unix":return"\n";default:return this.$autoNewLine||"\n"}},this.$autoNewLine="",this.$newLineMode="auto",this.setNewLineMode=function(e){if(this.$newLineMode===e)return;this.$newLineMode=e,this._signal("changeNewLineMode")},this.getNewLineMode=function(){return this.$newLineMode},this.isNewLine=function(e){return e=="\r\n"||e=="\r"||e=="\n"},this.getLine=function(e){return this.$lines[e]||""},this.getLines=function(e,t){return this.$lines.slice(e,t+1)},this.getAllLines=function(){return this.getLines(0,this.getLength())},this.getLength=function(){return this.$lines.length},this.getTextRange=function(e){return this.getLinesForRange(e).join(this.getNewLineCharacter())},this.getLinesForRange=function(e){var t;if(e.start.row===e.end.row)t=[this.getLine(e.start.row).substring(e.start.column,e.end.column)];else{t=this.getLines(e.start.row,e.end.row),t[0]=(t[0]||"").substring(e.start.column);var n=t.length-1;e.end.row-e.start.row==n&&(t[n]=t[n].substring(0,e.end.column))}return t},this.insertLines=function(e,t){return console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."),this.insertFullLines(e,t)},this.removeLines=function(e,t){return console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."),this.removeFullLines(e,t)},this.insertNewLine=function(e){return console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead."),this.insertMergedLines(e,["",""])},this.insert=function(e,t){return this.getLength()<=1&&this.$detectNewLine(t),this.insertMergedLines(e,this.$split(t))},this.insertInLine=function(e,t){var n=this.clippedPos(e.row,e.column),r=this.pos(e.row,e.column+t.length);return this.applyDelta({start:n,end:r,action:"insert",lines:[t]},!0),this.clonePos(r)},this.clippedPos=function(e,t){var n=this.getLength();e===undefined?e=n:e<0?e=0:e>=n&&(e=n-1,t=undefined);var r=this.getLine(e);return t==undefined&&(t=r.length),t=Math.min(Math.max(t,0),r.length),{row:e,column:t}},this.clonePos=function(e){return{row:e.row,column:e.column}},this.pos=function(e,t){return{row:e,column:t}},this.$clipPosition=function(e){var t=this.getLength();return e.row>=t?(e.row=Math.max(0,t-1),e.column=this.getLine(t-1).length):(e.row=Math.max(0,e.row),e.column=Math.min(Math.max(e.column,0),this.getLine(e.row).length)),e},this.insertFullLines=function(e,t){e=Math.min(Math.max(e,0),this.getLength());var n=0;e<this.getLength()?(t=t.concat([""]),n=0):(t=[""].concat(t),e--,n=this.$lines[e].length),this.insertMergedLines({row:e,column:n},t)},this.insertMergedLines=function(e,t){var n=this.clippedPos(e.row,e.column),r={row:n.row+t.length-1,column:(t.length==1?n.column:0)+t[t.length-1].length};return this.applyDelta({start:n,end:r,action:"insert",lines:t}),this.clonePos(r)},this.remove=function(e){var t=this.clippedPos(e.start.row,e.start.column),n=this.clippedPos(e.end.row,e.end.column);return this.applyDelta({start:t,end:n,action:"remove",lines:this.getLinesForRange({start:t,end:n})}),this.clonePos(t)},this.removeInLine=function(e,t,n){var r=this.clippedPos(e,t),i=this.clippedPos(e,n);return this.applyDelta({start:r,end:i,action:"remove",lines:this.getLinesForRange({start:r,end:i})},!0),this.clonePos(r)},this.removeFullLines=function(e,t){e=Math.min(Math.max(0,e),this.getLength()-1),t=Math.min(Math.max(0,t),this.getLength()-1);var n=t==this.getLength()-1&&e>0,r=t<this.getLength()-1,i=n?e-1:e,s=n?this.getLine(i).length:0,u=r?t+1:t,a=r?0:this.getLine(u).length,f=new o(i,s,u,a),l=this.$lines.slice(e,t+1);return this.applyDelta({start:f.start,end:f.end,action:"remove",lines:this.getLinesForRange(f)}),l},this.removeNewLine=function(e){e<this.getLength()-1&&e>=0&&this.applyDelta({start:this.pos(e,this.getLine(e).length),end:this.pos(e+1,0),action:"remove",lines:["",""]})},this.replace=function(e,t){e instanceof o||(e=o.fromPoints(e.start,e.end));if(t.length===0&&e.isEmpty())return e.start;if(t==this.getTextRange(e))return e.end;this.remove(e);var n;return t?n=this.insert(e.start,t):n=e.start,n},this.applyDeltas=function(e){for(var t=0;t<e.length;t++)this.applyDelta(e[t])},this.revertDeltas=function(e){for(var t=e.length-1;t>=0;t--)this.revertDelta(e[t])},this.applyDelta=function(e,t){var n=e.action=="insert";if(n?e.lines.length<=1&&!e.lines[0]:!o.comparePoints(e.start,e.end))return;n&&e.lines.length>2e4&&this.$splitAndapplyLargeDelta(e,2e4),i(this.$lines,e,t),this._signal("change",e)},this.$splitAndapplyLargeDelta=function(e,t){var n=e.lines,r=n.length,i=e.start.row,s=e.start.column,o=0,u=0;do{o=u,u+=t-1;var a=n.slice(o,u);if(u>r){e.lines=a,e.start.row=i+o,e.start.column=s;break}a.push(""),this.applyDelta({start:this.pos(i+o,s),end:this.pos(i+u,s=0),action:e.action,lines:a},!0)}while(!0)},this.revertDelta=function(e){this.applyDelta({start:this.clonePos(e.start),end:this.clonePos(e.end),action:e.action=="insert"?"remove":"insert",lines:e.lines.slice()})},this.indexToPosition=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length;for(var i=t||0,s=n.length;i<s;i++){e-=n[i].length+r;if(e<0)return{row:i,column:e+n[i].length+r}}return{row:s-1,column:n[s-1].length}},this.positionToIndex=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length,i=0,s=Math.min(e.row,n.length);for(var o=t||0;o<s;++o)i+=n[o].length+r;return i+e.column}}).call(a.prototype),t.Document=a}),ace.define("ace/lib/lang",["require","exports","module"],function(e,t,n){"use strict";t.last=function(e){return e[e.length-1]},t.stringReverse=function(e){return e.split("").reverse().join("")},t.stringRepeat=function(e,t){var n="";while(t>0){t&1&&(n+=e);if(t>>=1)e+=e}return n};var r=/^\s\s*/,i=/\s\s*$/;t.stringTrimLeft=function(e){return e.replace(r,"")},t.stringTrimRight=function(e){return e.replace(i,"")},t.copyObject=function(e){var t={};for(var n in e)t[n]=e[n];return t},t.copyArray=function(e){var t=[];for(var n=0,r=e.length;n<r;n++)e[n]&&typeof e[n]=="object"?t[n]=this.copyObject(e[n]):t[n]=e[n];return t},t.deepCopy=function s(e){if(typeof e!="object"||!e)return e;var t;if(Array.isArray(e)){t=[];for(var n=0;n<e.length;n++)t[n]=s(e[n]);return t}var r=e.constructor;if(r===RegExp)return e;t=r();for(var n in e)t[n]=s(e[n]);return t},t.arrayToMap=function(e){var t={};for(var n=0;n<e.length;n++)t[e[n]]=1;return t},t.createMap=function(e){var t=Object.create(null);for(var n in e)t[n]=e[n];return t},t.arrayRemove=function(e,t){for(var n=0;n<=e.length;n++)t===e[n]&&e.splice(n,1)},t.escapeRegExp=function(e){return e.replace(/([.*+?^${}()|[\]\/\\])/g,"\\$1")},t.escapeHTML=function(e){return e.replace(/&/g,"&#38;").replace(/"/g,"&#34;").replace(/'/g,"&#39;").replace(/</g,"&#60;")},t.getMatchOffsets=function(e,t){var n=[];return e.replace(t,function(e){n.push({offset:arguments[arguments.length-2],length:e.length})}),n},t.deferredCall=function(e){var t=null,n=function(){t=null,e()},r=function(e){return r.cancel(),t=setTimeout(n,e||0),r};return r.schedule=r,r.call=function(){return this.cancel(),e(),r},r.cancel=function(){return clearTimeout(t),t=null,r},r.isPending=function(){return t},r},t.delayedCall=function(e,t){var n=null,r=function(){n=null,e()},i=function(e){n==null&&(n=setTimeout(r,e||t))};return i.delay=function(e){n&&clearTimeout(n),n=setTimeout(r,e||t)},i.schedule=i,i.call=function(){this.cancel(),e()},i.cancel=function(){n&&clearTimeout(n),n=null},i.isPending=function(){return n},i}}),ace.define("ace/worker/mirror",["require","exports","module","ace/range","ace/document","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../range").Range,i=e("../document").Document,s=e("../lib/lang"),o=t.Mirror=function(e){this.sender=e;var t=this.doc=new i(""),n=this.deferredUpdate=s.delayedCall(this.onUpdate.bind(this)),r=this;e.on("change",function(e){var i=e.data;if(i[0].start)t.applyDeltas(i);else for(var s=0;s<i.length;s+=2){if(Array.isArray(i[s+1]))var o={action:"insert",start:i[s],lines:i[s+1]};else var o={action:"remove",start:i[s],end:i[s+1]};t.applyDelta(o,!0)}if(r.$timeout)return n.schedule(r.$timeout);r.onUpdate()})};(function(){this.$timeout=500,this.setTimeout=function(e){this.$timeout=e},this.setValue=function(e){this.doc.setValue(e),this.deferredUpdate.schedule(this.$timeout)},this.getValue=function(e){this.sender.callback(this.doc.getValue(),e)},this.onUpdate=function(){},this.isPending=function(){return this.deferredUpdate.isPending()}}).call(o.prototype)}),ace.define("ace/mode/lua/luaparse",["require","exports","module"],function(e,t,n){(function(e,n,r){r(t)})(this,"luaparse",function(e){"use strict";function m(e){if(mt){var t=vt.pop();t.complete(),n.locations&&(e.loc=t.loc),n.ranges&&(e.range=t.range)}return e}function w(e,t,n){for(var r=0,i=e.length;r<i;r++)if(e[r][t]===n)return r;return-1}function E(e){var t=g.call(arguments,1);return e=e.replace(/%(\d)/g,function(e,n){return""+t[n-1]||""}),e}function S(){var e=g.call(arguments),t={},n,r;for(var i=0,s=e.length;i<s;i++){n=e[i];for(r in n)n.hasOwnProperty(r)&&(t[r]=n[r])}return t}function x(e){var t=E.apply(null,g.call(arguments,1)),n,r;throw"undefined"!=typeof e.line?(r=e.range[0]-e.lineStart,n=new SyntaxError(E("[%1:%2] %3",e.line,r,t)),n.line=e.line,n.index=e.range[0],n.column=r):(r=C-D+1,n=new SyntaxError(E("[%1:%2] %3",_,r,t)),n.index=C,n.line=_,n.column=r),n}function T(e,t){x(t,d.expectedToken,e,t.value)}function N(e,t){"undefined"==typeof t&&(t=A.value);if("undefined"!=typeof e.type){var n;switch(e.type){case o:n="string";break;case u:n="keyword";break;case a:n="identifier";break;case f:n="number";break;case l:n="symbol";break;case c:n="boolean";break;case h:return x(e,d.unexpected,"symbol","nil",t)}return x(e,d.unexpected,n,e.value,t)}return x(e,d.unexpected,"symbol",e,t)}function P(){H();while(45===t.charCodeAt(C)&&45===t.charCodeAt(C+1))X(),H();if(C>=r)return{type:s,value:"<eof>",line:_,lineStart:D,range:[C,C]};var e=t.charCodeAt(C),n=t.charCodeAt(C+1);M=C;if(et(e))return B();switch(e){case 39:case 34:return I();case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return R();case 46:if(Y(n))return R();if(46===n)return 46===t.charCodeAt(C+2)?F():j("..");return j(".");case 61:if(61===n)return j("==");return j("=");case 62:if(61===n)return j(">=");return j(">");case 60:if(61===n)return j("<=");return j("<");case 126:if(61===n)return j("~=");return x({},d.expected,"=","~");case 58:if(58===n)return j("::");return j(":");case 91:if(91===n||61===n)return q();return j("[");case 42:case 47:case 94:case 37:case 44:case 123:case 125:case 93:case 40:case 41:case 59:case 35:case 45:case 43:return j(t.charAt(C))}return N(t.charAt(C))}function H(){while(C<r){var e=t.charCodeAt(C);if(Q(e))C++;else{if(!G(e))break;_++,D=++C}}}function B(){var e,n;while(tt(t.charCodeAt(++C)));return e=t.slice(M,C),nt(e)?n=u:"true"===e||"false"===e?(n=c,e="true"===e):"nil"===e?(n=h,e=null):n=a,{type:n,value:e,line:_,lineStart:D,range:[M,C]}}function j(e){return C+=e.length,{type:l,value:e,line:_,lineStart:D,range:[M,C]}}function F(){return C+=3,{type:p,value:"...",line:_,lineStart:D,range:[M,C]}}function I(){var e=t.charCodeAt(C++),n=C,i="",s;while(C<r){s=t.charCodeAt(C++);if(e===s)break;if(92===s)i+=t.slice(n,C-1)+W(),n=C;else if(C>=r||G(s))i+=t.slice(n,C-1),x({},d.unfinishedString,i+String.fromCharCode(s))}return i+=t.slice(n,C-1),{type:o,value:i,line:_,lineStart:D,range:[M,C]}}function q(){var e=V();return!1===e&&x(k,d.expected,"[",k.value),{type:o,value:e,line:_,lineStart:D,range:[M,C]}}function R(){var e=t.charAt(C),n=t.charAt(C+1),r="0"===e&&"xX".indexOf(n||null)>=0?U():z();return{type:f,value:r,line:_,lineStart:D,range:[M,C]}}function U(){var e=0,n=1,r=1,i,s,o,u;u=C+=2,Z(t.charCodeAt(C))||x({},d.malformedNumber,t.slice(M,C));while(Z(t.charCodeAt(C)))C++;i=parseInt(t.slice(u,C),16);if("."===t.charAt(C)){s=++C;while(Z(t.charCodeAt(C)))C++;e=t.slice(s,C),e=s===C?0:parseInt(e,16)/Math.pow(16,C-s)}if("pP".indexOf(t.charAt(C)||null)>=0){C++,"+-".indexOf(t.charAt(C)||null)>=0&&(r="+"===t.charAt(C++)?1:-1),o=C,Y(t.charCodeAt(C))||x({},d.malformedNumber,t.slice(M,C));while(Y(t.charCodeAt(C)))C++;n=t.slice(o,C),n=Math.pow(2,n*r)}return(i+e)*n}function z(){while(Y(t.charCodeAt(C)))C++;if("."===t.charAt(C)){C++;while(Y(t.charCodeAt(C)))C++}if("eE".indexOf(t.charAt(C)||null)>=0){C++,"+-".indexOf(t.charAt(C)||null)>=0&&C++,Y(t.charCodeAt(C))||x({},d.malformedNumber,t.slice(M,C));while(Y(t.charCodeAt(C)))C++}return parseFloat(t.slice(M,C))}function W(){var e=C;switch(t.charAt(C)){case"n":return C++,"\n";case"r":return C++,"\r";case"t":return C++,"	";case"v":return C++,"";case"b":return C++,"\b";case"f":return C++,"\f";case"z":return C++,H(),"";case"x":if(Z(t.charCodeAt(C+1))&&Z(t.charCodeAt(C+2)))return C+=3,"\\"+t.slice(e,C);return"\\"+t.charAt(C++);default:if(Y(t.charCodeAt(C))){while(Y(t.charCodeAt(++C)));return"\\"+t.slice(e,C)}return t.charAt(C++)}}function X(){M=C,C+=2;var e=t.charAt(C),i="",s=!1,o=C,u=D,a=_;"["===e&&(i=V(),!1===i?i=e:s=!0);if(!s){while(C<r){if(G(t.charCodeAt(C)))break;C++}n.comments&&(i=t.slice(o,C))}if(n.comments){var f=v.comment(i,t.slice(M,C));n.locations&&(f.loc={start:{line:a,column:M-u},end:{line:_,column:C-D}}),n.ranges&&(f.range=[M,C]),O.push(f)}}function V(){var e=0,n="",i=!1,s,o;C++;while("="===t.charAt(C+e))e++;if("["!==t.charAt(C+e))return!1;C+=e+1,G(t.charCodeAt(C))&&(_++,D=C++),o=C;while(C<r){s=t.charAt(C++),G(s.charCodeAt(0))&&(_++,D=C);if("]"===s){i=!0;for(var u=0;u<e;u++)"="!==t.charAt(C+u)&&(i=!1);"]"!==t.charAt(C+e)&&(i=!1)}if(i)break}return n+=t.slice(o,C-1),C+=e+1,n}function $(){L=k,k=A,A=P()}function J(e){return e===k.value?($(),!0):!1}function K(e){e===k.value?$():x(k,d.expected,e,k.value)}function Q(e){return 9===e||32===e||11===e||12===e}function G(e){return 10===e||13===e}function Y(e){return e>=48&&e<=57}function Z(e){return e>=48&&e<=57||e>=97&&e<=102||e>=65&&e<=70}function et(e){return e>=65&&e<=90||e>=97&&e<=122||95===e}function tt(e){return e>=65&&e<=90||e>=97&&e<=122||95===e||e>=48&&e<=57}function nt(e){switch(e.length){case 2:return"do"===e||"if"===e||"in"===e||"or"===e;case 3:return"and"===e||"end"===e||"for"===e||"not"===e;case 4:return"else"===e||"goto"===e||"then"===e;case 5:return"break"===e||"local"===e||"until"===e||"while"===e;case 6:return"elseif"===e||"repeat"===e||"return"===e;case 8:return"function"===e}return!1}function rt(e){return l===e.type?"#-".indexOf(e.value)>=0:u===e.type?"not"===e.value:!1}function it(e){switch(e.type){case"CallExpression":case"TableCallExpression":case"StringCallExpression":return!0}return!1}function st(e){if(s===e.type)return!0;if(u!==e.type)return!1;switch(e.value){case"else":case"elseif":case"end":case"until":return!0;default:return!1}}function ft(){ot.push(Array.apply(null,ot[ut++]))}function lt(){ot.pop(),ut--}function ct(e){if(-1!==b(ot[ut],e))return;ot[ut].push(e)}function ht(e){ct(e.name),pt(e,!0)}function pt(e,t){!t&&-1===w(at,"name",e.name)&&at.push(e),e.isLocal=t}function dt(e){return-1!==b(ot[ut],e)}function gt(){return new yt(k)}function yt(e){n.locations&&(this.loc={start:{line:e.line,column:e.range[0]-e.lineStart},end:{line:0,column:0}}),n.ranges&&(this.range=[e.range[0],0])}function bt(){mt&&vt.push(gt())}function wt(e){mt&&vt.push(e)}function Et(){$(),bt();var e=St();return s!==k.type&&N(k),mt&&!e.length&&(L=k),m(v.chunk(e))}function St(e){var t=[],r;n.scope&&ft();while(!st(k)){if("return"===k.value){t.push(xt());break}r=xt(),r&&t.push(r)}return n.scope&&lt(),t}function xt(){bt();if(u===k.type)switch(k.value){case"local":return $(),Dt();case"if":return $(),Mt();case"return":return $(),Ot();case"function":$();var e=jt();return Bt(e);case"while":return $(),Lt();case"for":return $(),_t();case"repeat":return $(),At();case"break":return $(),Nt();case"do":return $(),kt();case"goto":return $(),Ct()}if(l===k.type&&J("::"))return Tt();mt&&vt.pop();if(J(";"))return;return Pt()}function Tt(){var e=k.value,t=Ht();return n.scope&&(ct("::"+e+"::"),pt(t,!0)),K("::"),m(v.labelStatement(t))}function Nt(){return m(v.breakStatement())}function Ct(){var e=k.value,t=Ht();return n.scope&&(t.isLabel=dt("::"+e+"::")),m(v.gotoStatement(t))}function kt(){var e=St();return K("end"),m(v.doStatement(e))}function Lt(){var e=qt();K("do");var t=St();return K("end"),m(v.whileStatement(e,t))}function At(){var e=St();K("until");var t=qt();return m(v.repeatStatement(t,e))}function Ot(){var e=[];if("end"!==k.value){var t=It();null!=t&&e.push(t);while(J(","))t=qt(),e.push(t);J(";")}return m(v.returnStatement(e))}function Mt(){var e=[],t,n,r;mt&&(r=vt[vt.length-1],vt.push(r)),t=qt(),K("then"),n=St(),e.push(m(v.ifClause(t,n))),mt&&(r=gt());while(J("elseif"))wt(r),t=qt(),K("then"),n=St(),e.push(m(v.elseifClause(t,n))),mt&&(r=gt());return J("else")&&(mt&&(r=new yt(L),vt.push(r)),n=St(),e.push(m(v.elseClause(n)))),K("end"),m(v.ifStatement(e))}function _t(){var e=Ht(),t;n.scope&&ht(e);if(J("=")){var r=qt();K(",");var i=qt(),s=J(",")?qt():null;return K("do"),t=St(),K("end"),m(v.forNumericStatement(e,r,i,s,t))}var o=[e];while(J(","))e=Ht(),n.scope&&ht(e),o.push(e);K("in");var u=[];do{var a=qt();u.push(a)}while(J(","));return K("do"),t=St(),K("end"),m(v.forGenericStatement(o,u,t))}function Dt(){var e;if(a===k.type){var t=[],r=[];do e=Ht(),t.push(e);while(J(","));if(J("="))do{var i=qt();r.push(i)}while(J(","));if(n.scope)for(var s=0,o=t.length;s<o;s++)ht(t[s]);return m(v.localStatement(t,r))}if(J("function"))return e=Ht(),n.scope&&ht(e),Bt(e,!0);T("<name>",k)}function Pt(){var e=k,t,n;mt&&(n=gt()),t=zt();if(null==t)return N(k);if(",=".indexOf(k.value)>=0){var r=[t],i=[],s;while(J(","))s=zt(),null==s&&T("<expression>",k),r.push(s);K("=");do s=qt(),i.push(s);while(J(","));return wt(n),m(v.assignmentStatement(r,i))}return it(t)?(wt(n),m(v.callStatement(t))):N(e)}function Ht(){bt();var e=k.value;return a!==k.type&&T("<name>",k),$(),m(v.identifier(e))}function Bt(e,t){var r=[];K("(");if(!J(")"))for(;;)if(a===k.type){var i=Ht();n.scope&&ht(i),r.push(i);if(J(","))continue;if(J(")"))break}else{if(p===k.type){r.push(Xt()),K(")");break}T("<name> or '...'",k)}var s=St();return K("end"),t=t||!1,m(v.functionStatement(e,r,t,s))}function jt(){var e,t,r;mt&&(r=gt()),e=Ht(),n.scope&&pt(e,!1);while(J("."))wt(r),t=Ht(),n.scope&&pt(t,!1),e=m(v.memberExpression(e,".",t));return J(":")&&(wt(r),t=Ht(),n.scope&&pt(t,!1),e=m(v.memberExpression(e,":",t))),e}function Ft(){var e=[],t,n;for(;;){bt();if(l===k.type&&J("["))t=qt(),K("]"),K("="),n=qt(),e.push(m(v.tableKey(t,n)));else if(a===k.type)t=qt(),J("=")?(n=qt(),e.push(m(v.tableKeyString(t,n)))):e.push(m(v.tableValue(t)));else{if(null==(n=It())){vt.pop();break}e.push(m(v.tableValue(n)))}if(",;".indexOf(k.value)>=0){$();continue}if("}"===k.value)break}return K("}"),m(v.tableConstructorExpression(e))}function It(){var e=Ut(0);return e}function qt(){var e=It();if(null!=e)return e;T("<expression>",k)}function Rt(e){var t=e.charCodeAt(0),n=e.length;if(1===n)switch(t){case 94:return 10;case 42:case 47:case 37:return 7;case 43:case 45:return 6;case 60:case 62:return 3}else if(2===n)switch(t){case 46:return 5;case 60:case 62:case 61:case 126:return 3;case 111:return 1}else if(97===t&&"and"===e)return 2;return 0}function Ut(e){var t=k.value,n,r;mt&&(r=gt());if(rt(k)){bt(),$();var i=Ut(8);i==null&&T("<expression>",k),n=m(v.unaryExpression(t,i))}null==n&&(n=Xt(),null==n&&(n=zt()));if(null==n)return null;var s;for(;;){t=k.value,s=l===k.type||u===k.type?Rt(t):0;if(s===0||s<=e)break;("^"===t||".."===t)&&s--,$();var o=Ut(s);null==o&&T("<expression>",k),mt&&vt.push(r),n=m(v.binaryExpression(t,n,o))}return n}function zt(){var e,t,r,i;mt&&(r=gt());if(a===k.type)t=k.value,e=Ht(),n.scope&&pt(e,i=dt(t));else{if(!J("("))return null;e=qt(),K(")"),n.scope&&(i=e.isLocal)}var s,u;for(;;)if(l===k.type)switch(k.value){case"[":wt(r),$(),s=qt(),e=m(v.indexExpression(e,s)),K("]");break;case".":wt(r),$(),u=Ht(),n.scope&&pt(u,i),e=m(v.memberExpression(e,".",u));break;case":":wt(r),$(),u=Ht(),n.scope&&pt(u,i),e=m(v.memberExpression(e,":",u)),wt(r),e=Wt(e);break;case"(":case"{":wt(r),e=Wt(e);break;default:return e}else{if(o!==k.type)break;wt(r),e=Wt(e)}return e}function Wt(e){if(l===k.type)switch(k.value){case"(":$();var t=[],n=It();null!=n&&t.push(n);while(J(","))n=qt(),t.push(n);return K(")"),m(v.callExpression(e,t));case"{":bt(),$();var r=Ft();return m(v.tableCallExpression(e,r))}else if(o===k.type)return m(v.stringCallExpression(e,Xt()));T("function arguments",k)}function Xt(){var e=o|f|c|h|p,n=k.value,r=k.type,i;mt&&(i=gt());if(r&e){wt(i);var s=t.slice(k.range[0],k.range[1]);return $(),m(v.literal(r,n,s))}if(u===r&&"function"===n)return wt(i),$(),Bt(null);if(J("{"))return wt(i),Ft()}function Vt(s,o){return"undefined"==typeof o&&"object"==typeof s&&(o=s,s=undefined),o||(o={}),t=s||"",n=S(i,o),C=0,_=1,D=0,r=t.length,ot=[[]],ut=0,at=[],vt=[],n.comments&&(O=[]),n.wait?e:Jt()}function $t(n){return t+=String(n),r=t.length,e}function Jt(e){"undefined"!=typeof e&&$t(e),r=t.length,mt=n.locations||n.ranges,A=P();var i=Et();n.comments&&(i.comments=O),n.scope&&(i.globals=at);if(vt.length>0)throw new Error("Location tracking failed. This is most likely a bug in luaparse");return i}e.version="0.1.4";var t,n,r,i=e.defaultOptions={wait:!1,comments:!0,scope:!1,locations:!1,ranges:!1},s=1,o=2,u=4,a=8,f=16,l=32,c=64,h=128,p=256;e.tokenTypes={EOF:s,StringLiteral:o,Keyword:u,Identifier:a,NumericLiteral:f,Punctuator:l,BooleanLiteral:c,NilLiteral:h,VarargLiteral:p};var d=e.errors={unexpected:"Unexpected %1 '%2' near '%3'",expected:"'%1' expected near '%2'",expectedToken:"%1 expected near '%2'",unfinishedString:"unfinished string near '%1'",malformedNumber:"malformed number near '%1'"},v=e.ast={labelStatement:function(e){return{type:"LabelStatement",label:e}},breakStatement:function(){return{type:"BreakStatement"}},gotoStatement:function(e){return{type:"GotoStatement",label:e}},returnStatement:function(e){return{type:"ReturnStatement",arguments:e}},ifStatement:function(e){return{type:"IfStatement",clauses:e}},ifClause:function(e,t){return{type:"IfClause",condition:e,body:t}},elseifClause:function(e,t){return{type:"ElseifClause",condition:e,body:t}},elseClause:function(e){return{type:"ElseClause",body:e}},whileStatement:function(e,t){return{type:"WhileStatement",condition:e,body:t}},doStatement:function(e){return{type:"DoStatement",body:e}},repeatStatement:function(e,t){return{type:"RepeatStatement",condition:e,body:t}},localStatement:function(e,t){return{type:"LocalStatement",variables:e,init:t}},assignmentStatement:function(e,t){return{type:"AssignmentStatement",variables:e,init:t}},callStatement:function(e){return{type:"CallStatement",expression:e}},functionStatement:function(e,t,n,r){return{type:"FunctionDeclaration",identifier:e,isLocal:n,parameters:t,body:r}},forNumericStatement:function(e,t,n,r,i){return{type:"ForNumericStatement",variable:e,start:t,end:n,step:r,body:i}},forGenericStatement:function(e,t,n){return{type:"ForGenericStatement",variables:e,iterators:t,body:n}},chunk:function(e){return{type:"Chunk",body:e}},identifier:function(e){return{type:"Identifier",name:e}},literal:function(e,t,n){return e=e===o?"StringLiteral":e===f?"NumericLiteral":e===c?"BooleanLiteral":e===h?"NilLiteral":"VarargLiteral",{type:e,value:t,raw:n}},tableKey:function(e,t){return{type:"TableKey",key:e,value:t}},tableKeyString:function(e,t){return{type:"TableKeyString",key:e,value:t}},tableValue:function(e){return{type:"TableValue",value:e}},tableConstructorExpression:function(e){return{type:"TableConstructorExpression",fields:e}},binaryExpression:function(e,t,n){var r="and"===e||"or"===e?"LogicalExpression":"BinaryExpression";return{type:r,operator:e,left:t,right:n}},unaryExpression:function(e,t){return{type:"UnaryExpression",operator:e,argument:t}},memberExpression:function(e,t,n){return{type:"MemberExpression",indexer:t,identifier:n,base:e}},indexExpression:function(e,t){return{type:"IndexExpression",base:e,index:t}},callExpression:function(e,t){return{type:"CallExpression",base:e,arguments:t}},tableCallExpression:function(e,t){return{type:"TableCallExpression",base:e,arguments:t}},stringCallExpression:function(e,t){return{type:"StringCallExpression",base:e,argument:t}},comment:function(e,t){return{type:"Comment",value:e,raw:t}}},g=Array.prototype.slice,y=Object.prototype.toString,b=function(t,n){for(var r=0,i=t.length;r<i;r++)if(t[r]===n)return r;return-1},C,k,L,A,O,M,_,D;e.lex=P;var ot,ut,at,vt=[],mt;yt.prototype.complete=function(){n.locations&&(this.loc.end.line=L.line,this.loc.end.column=L.range[1]-L.lineStart),n.ranges&&(this.range[1]=L.range[1])},e.parse=Vt,e.write=$t,e.end=Jt})}),ace.define("ace/mode/lua_worker",["require","exports","module","ace/lib/oop","ace/worker/mirror","ace/mode/lua/luaparse"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../worker/mirror").Mirror,s=e("../mode/lua/luaparse"),o=t.Worker=function(e){i.call(this,e),this.setTimeout(500)};r.inherits(o,i),function(){this.onUpdate=function(){var e=this.doc.getValue(),t=[];try{s.parse(e)}catch(n){n instanceof SyntaxError&&t.push({row:n.line-1,column:n.column,text:n.message,type:"error"})}this.sender.emit("annotate",t)}}.call(o.prototype)}),ace.define("ace/lib/es5-shim",["require","exports","module"],function(e,t,n){function r(){}function w(e){try{return Object.defineProperty(e,"sentinel",{}),"sentinel"in e}catch(t){}}function H(e){return e=+e,e!==e?e=0:e!==0&&e!==1/0&&e!==-1/0&&(e=(e>0||-1)*Math.floor(Math.abs(e))),e}function B(e){var t=typeof e;return e===null||t==="undefined"||t==="boolean"||t==="number"||t==="string"}function j(e){var t,n,r;if(B(e))return e;n=e.valueOf;if(typeof n=="function"){t=n.call(e);if(B(t))return t}r=e.toString;if(typeof r=="function"){t=r.call(e);if(B(t))return t}throw new TypeError}Function.prototype.bind||(Function.prototype.bind=function(t){var n=this;if(typeof n!="function")throw new TypeError("Function.prototype.bind called on incompatible "+n);var i=u.call(arguments,1),s=function(){if(this instanceof s){var e=n.apply(this,i.concat(u.call(arguments)));return Object(e)===e?e:this}return n.apply(t,i.concat(u.call(arguments)))};return n.prototype&&(r.prototype=n.prototype,s.prototype=new r,r.prototype=null),s});var i=Function.prototype.call,s=Array.prototype,o=Object.prototype,u=s.slice,a=i.bind(o.toString),f=i.bind(o.hasOwnProperty),l,c,h,p,d;if(d=f(o,"__defineGetter__"))l=i.bind(o.__defineGetter__),c=i.bind(o.__defineSetter__),h=i.bind(o.__lookupGetter__),p=i.bind(o.__lookupSetter__);if([1,2].splice(0).length!=2)if(!function(){function e(e){var t=new Array(e+2);return t[0]=t[1]=0,t}var t=[],n;t.splice.apply(t,e(20)),t.splice.apply(t,e(26)),n=t.length,t.splice(5,0,"XXX"),n+1==t.length;if(n+1==t.length)return!0}())Array.prototype.splice=function(e,t){var n=this.length;e>0?e>n&&(e=n):e==void 0?e=0:e<0&&(e=Math.max(n+e,0)),e+t<n||(t=n-e);var r=this.slice(e,e+t),i=u.call(arguments,2),s=i.length;if(e===n)s&&this.push.apply(this,i);else{var o=Math.min(t,n-e),a=e+o,f=a+s-o,l=n-a,c=n-o;if(f<a)for(var h=0;h<l;++h)this[f+h]=this[a+h];else if(f>a)for(h=l;h--;)this[f+h]=this[a+h];if(s&&e===c)this.length=c,this.push.apply(this,i);else{this.length=c+s;for(h=0;h<s;++h)this[e+h]=i[h]}}return r};else{var v=Array.prototype.splice;Array.prototype.splice=function(e,t){return arguments.length?v.apply(this,[e===void 0?0:e,t===void 0?this.length-e:t].concat(u.call(arguments,2))):[]}}Array.isArray||(Array.isArray=function(t){return a(t)=="[object Array]"});var m=Object("a"),g=m[0]!="a"||!(0 in m);Array.prototype.forEach||(Array.prototype.forEach=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=arguments[1],s=-1,o=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError;while(++s<o)s in r&&t.call(i,r[s],s,n)}),Array.prototype.map||(Array.prototype.map=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=Array(i),o=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var u=0;u<i;u++)u in r&&(s[u]=t.call(o,r[u],u,n));return s}),Array.prototype.filter||(Array.prototype.filter=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=[],o,u=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var f=0;f<i;f++)f in r&&(o=r[f],t.call(u,o,f,n)&&s.push(o));return s}),Array.prototype.every||(Array.prototype.every=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&!t.call(s,r[o],o,n))return!1;return!0}),Array.prototype.some||(Array.prototype.some=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&t.call(s,r[o],o,n))return!0;return!1}),Array.prototype.reduce||(Array.prototype.reduce=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduce of empty array with no initial value");var s=0,o;if(arguments.length>=2)o=arguments[1];else do{if(s in r){o=r[s++];break}if(++s>=i)throw new TypeError("reduce of empty array with no initial value")}while(!0);for(;s<i;s++)s in r&&(o=t.call(void 0,o,r[s],s,n));return o}),Array.prototype.reduceRight||(Array.prototype.reduceRight=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduceRight of empty array with no initial value");var s,o=i-1;if(arguments.length>=2)s=arguments[1];else do{if(o in r){s=r[o--];break}if(--o<0)throw new TypeError("reduceRight of empty array with no initial value")}while(!0);do o in this&&(s=t.call(void 0,s,r[o],o,n));while(o--);return s});if(!Array.prototype.indexOf||[0,1].indexOf(1,2)!=-1)Array.prototype.indexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=0;arguments.length>1&&(i=H(arguments[1])),i=i>=0?i:Math.max(0,r+i);for(;i<r;i++)if(i in n&&n[i]===t)return i;return-1};if(!Array.prototype.lastIndexOf||[0,1].lastIndexOf(0,-3)!=-1)Array.prototype.lastIndexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=r-1;arguments.length>1&&(i=Math.min(i,H(arguments[1]))),i=i>=0?i:r-Math.abs(i);for(;i>=0;i--)if(i in n&&t===n[i])return i;return-1};Object.getPrototypeOf||(Object.getPrototypeOf=function(t){return t.__proto__||(t.constructor?t.constructor.prototype:o)});if(!Object.getOwnPropertyDescriptor){var y="Object.getOwnPropertyDescriptor called on a non-object: ";Object.getOwnPropertyDescriptor=function(t,n){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(y+t);if(!f(t,n))return;var r,i,s;r={enumerable:!0,configurable:!0};if(d){var u=t.__proto__;t.__proto__=o;var i=h(t,n),s=p(t,n);t.__proto__=u;if(i||s)return i&&(r.get=i),s&&(r.set=s),r}return r.value=t[n],r}}Object.getOwnPropertyNames||(Object.getOwnPropertyNames=function(t){return Object.keys(t)});if(!Object.create){var b;Object.prototype.__proto__===null?b=function(){return{__proto__:null}}:b=function(){var e={};for(var t in e)e[t]=null;return e.constructor=e.hasOwnProperty=e.propertyIsEnumerable=e.isPrototypeOf=e.toLocaleString=e.toString=e.valueOf=e.__proto__=null,e},Object.create=function(t,n){var r;if(t===null)r=b();else{if(typeof t!="object")throw new TypeError("typeof prototype["+typeof t+"] != 'object'");var i=function(){};i.prototype=t,r=new i,r.__proto__=t}return n!==void 0&&Object.defineProperties(r,n),r}}if(Object.defineProperty){var E=w({}),S=typeof document=="undefined"||w(document.createElement("div"));if(!E||!S)var x=Object.defineProperty}if(!Object.defineProperty||x){var T="Property description must be an object: ",N="Object.defineProperty called on non-object: ",C="getters & setters can not be defined on this javascript engine";Object.defineProperty=function(t,n,r){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(N+t);if(typeof r!="object"&&typeof r!="function"||r===null)throw new TypeError(T+r);if(x)try{return x.call(Object,t,n,r)}catch(i){}if(f(r,"value"))if(d&&(h(t,n)||p(t,n))){var s=t.__proto__;t.__proto__=o,delete t[n],t[n]=r.value,t.__proto__=s}else t[n]=r.value;else{if(!d)throw new TypeError(C);f(r,"get")&&l(t,n,r.get),f(r,"set")&&c(t,n,r.set)}return t}}Object.defineProperties||(Object.defineProperties=function(t,n){for(var r in n)f(n,r)&&Object.defineProperty(t,r,n[r]);return t}),Object.seal||(Object.seal=function(t){return t}),Object.freeze||(Object.freeze=function(t){return t});try{Object.freeze(function(){})}catch(k){Object.freeze=function(t){return function(n){return typeof n=="function"?n:t(n)}}(Object.freeze)}Object.preventExtensions||(Object.preventExtensions=function(t){return t}),Object.isSealed||(Object.isSealed=function(t){return!1}),Object.isFrozen||(Object.isFrozen=function(t){return!1}),Object.isExtensible||(Object.isExtensible=function(t){if(Object(t)===t)throw new TypeError;var n="";while(f(t,n))n+="?";t[n]=!0;var r=f(t,n);return delete t[n],r});if(!Object.keys){var L=!0,A=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],O=A.length;for(var M in{toString:null})L=!1;Object.keys=function I(e){if(typeof e!="object"&&typeof e!="function"||e===null)throw new TypeError("Object.keys called on a non-object");var I=[];for(var t in e)f(e,t)&&I.push(t);if(L)for(var n=0,r=O;n<r;n++){var i=A[n];f(e,i)&&I.push(i)}return I}}Date.now||(Date.now=function(){return(new Date).getTime()});var _="	\n\f\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\ufeff";if(!String.prototype.trim||_.trim()){_="["+_+"]";var D=new RegExp("^"+_+_+"*"),P=new RegExp(_+_+"*$");String.prototype.trim=function(){return String(this).replace(D,"").replace(P,"")}}var F=function(e){if(e==null)throw new TypeError("can't convert "+e+" to object");return Object(e)}})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-php.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-php.js
new file mode 100644
index 0000000..edea3d1
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-php.js
@@ -0,0 +1 @@
+"no use strict";(function(e){function t(e,t){var n=e,r="";while(n){var i=t[n];if(typeof i=="string")return i+r;if(i)return i.location.replace(/\/*$/,"/")+(r||i.main||i.name);if(i===!1)return"";var s=n.lastIndexOf("/");if(s===-1)break;r=n.substr(s)+r,n=n.slice(0,s)}return e}if(typeof e.window!="undefined"&&e.document)return;if(e.require&&e.define)return;e.console||(e.console=function(){var e=Array.prototype.slice.call(arguments,0);postMessage({type:"log",data:e})},e.console.error=e.console.warn=e.console.log=e.console.trace=e.console),e.window=e,e.ace=e,e.onerror=function(e,t,n,r,i){postMessage({type:"error",data:{message:e,data:i.data,file:t,line:n,col:r,stack:i.stack}})},e.normalizeModule=function(t,n){if(n.indexOf("!")!==-1){var r=n.split("!");return e.normalizeModule(t,r[0])+"!"+e.normalizeModule(t,r[1])}if(n.charAt(0)=="."){var i=t.split("/").slice(0,-1).join("/");n=(i?i+"/":"")+n;while(n.indexOf(".")!==-1&&s!=n){var s=n;n=n.replace(/^\.\//,"").replace(/\/\.\//,"/").replace(/[^\/]+\/\.\.\//,"")}}return n},e.require=function(r,i){i||(i=r,r=null);if(!i.charAt)throw new Error("worker.js require() accepts only (parentId, id) as arguments");i=e.normalizeModule(r,i);var s=e.require.modules[i];if(s)return s.initialized||(s.initialized=!0,s.exports=s.factory().exports),s.exports;if(!e.require.tlns)return console.log("unable to load "+i);var o=t(i,e.require.tlns);return o.slice(-3)!=".js"&&(o+=".js"),e.require.id=i,e.require.modules[i]={},importScripts(o),e.require(r,i)},e.require.modules={},e.require.tlns={},e.define=function(t,n,r){arguments.length==2?(r=n,typeof t!="string"&&(n=t,t=e.require.id)):arguments.length==1&&(r=t,n=[],t=e.require.id);if(typeof r!="function"){e.require.modules[t]={exports:r,initialized:!0};return}n.length||(n=["require","exports","module"]);var i=function(n){return e.require(t,n)};e.require.modules[t]={exports:{},factory:function(){var e=this,t=r.apply(this,n.map(function(t){switch(t){case"require":return i;case"exports":return e.exports;case"module":return e;default:return i(t)}}));return t&&(e.exports=t),e}}},e.define.amd={},require.tlns={},e.initBaseUrls=function(t){for(var n in t)require.tlns[n]=t[n]},e.initSender=function(){var n=e.require("ace/lib/event_emitter").EventEmitter,r=e.require("ace/lib/oop"),i=function(){};return function(){r.implement(this,n),this.callback=function(e,t){postMessage({type:"call",id:t,data:e})},this.emit=function(e,t){postMessage({type:"event",name:e,data:t})}}.call(i.prototype),new i};var n=e.main=null,r=e.sender=null;e.onmessage=function(t){var i=t.data;if(i.event&&r)r._signal(i.event,i.data);else if(i.command)if(n[i.command])n[i.command].apply(n,i.args);else{if(!e[i.command])throw new Error("Unknown command:"+i.command);e[i.command].apply(e,i.args)}else if(i.init){e.initBaseUrls(i.tlns),require("ace/lib/es5-shim"),r=e.sender=e.initSender();var s=require(i.module)[i.classname];n=e.main=new s(r)}}})(this),ace.define("ace/lib/oop",["require","exports","module"],function(e,t,n){"use strict";t.inherits=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})},t.mixin=function(e,t){for(var n in t)e[n]=t[n];return e},t.implement=function(e,n){t.mixin(e,n)}}),ace.define("ace/range",["require","exports","module"],function(e,t,n){"use strict";var r=function(e,t){return e.row-t.row||e.column-t.column},i=function(e,t,n,r){this.start={row:e,column:t},this.end={row:n,column:r}};(function(){this.isEqual=function(e){return this.start.row===e.start.row&&this.end.row===e.end.row&&this.start.column===e.start.column&&this.end.column===e.end.column},this.toString=function(){return"Range: ["+this.start.row+"/"+this.start.column+"] -> ["+this.end.row+"/"+this.end.column+"]"},this.contains=function(e,t){return this.compare(e,t)==0},this.compareRange=function(e){var t,n=e.end,r=e.start;return t=this.compare(n.row,n.column),t==1?(t=this.compare(r.row,r.column),t==1?2:t==0?1:0):t==-1?-2:(t=this.compare(r.row,r.column),t==-1?-1:t==1?42:0)},this.comparePoint=function(e){return this.compare(e.row,e.column)},this.containsRange=function(e){return this.comparePoint(e.start)==0&&this.comparePoint(e.end)==0},this.intersects=function(e){var t=this.compareRange(e);return t==-1||t==0||t==1},this.isEnd=function(e,t){return this.end.row==e&&this.end.column==t},this.isStart=function(e,t){return this.start.row==e&&this.start.column==t},this.setStart=function(e,t){typeof e=="object"?(this.start.column=e.column,this.start.row=e.row):(this.start.row=e,this.start.column=t)},this.setEnd=function(e,t){typeof e=="object"?(this.end.column=e.column,this.end.row=e.row):(this.end.row=e,this.end.column=t)},this.inside=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)||this.isStart(e,t)?!1:!0:!1},this.insideStart=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)?!1:!0:!1},this.insideEnd=function(e,t){return this.compare(e,t)==0?this.isStart(e,t)?!1:!0:!1},this.compare=function(e,t){return!this.isMultiLine()&&e===this.start.row?t<this.start.column?-1:t>this.end.column?1:0:e<this.start.row?-1:e>this.end.row?1:this.start.row===e?t>=this.start.column?0:-1:this.end.row===e?t<=this.end.column?0:1:0},this.compareStart=function(e,t){return this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.compareEnd=function(e,t){return this.end.row==e&&this.end.column==t?1:this.compare(e,t)},this.compareInside=function(e,t){return this.end.row==e&&this.end.column==t?1:this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.clipRows=function(e,t){if(this.end.row>t)var n={row:t+1,column:0};else if(this.end.row<e)var n={row:e,column:0};if(this.start.row>t)var r={row:t+1,column:0};else if(this.start.row<e)var r={row:e,column:0};return i.fromPoints(r||this.start,n||this.end)},this.extend=function(e,t){var n=this.compare(e,t);if(n==0)return this;if(n==-1)var r={row:e,column:t};else var s={row:e,column:t};return i.fromPoints(r||this.start,s||this.end)},this.isEmpty=function(){return this.start.row===this.end.row&&this.start.column===this.end.column},this.isMultiLine=function(){return this.start.row!==this.end.row},this.clone=function(){return i.fromPoints(this.start,this.end)},this.collapseRows=function(){return this.end.column==0?new i(this.start.row,0,Math.max(this.start.row,this.end.row-1),0):new i(this.start.row,0,this.end.row,0)},this.toScreenRange=function(e){var t=e.documentToScreenPosition(this.start),n=e.documentToScreenPosition(this.end);return new i(t.row,t.column,n.row,n.column)},this.moveBy=function(e,t){this.start.row+=e,this.start.column+=t,this.end.row+=e,this.end.column+=t}}).call(i.prototype),i.fromPoints=function(e,t){return new i(e.row,e.column,t.row,t.column)},i.comparePoints=r,i.comparePoints=function(e,t){return e.row-t.row||e.column-t.column},t.Range=i}),ace.define("ace/apply_delta",["require","exports","module"],function(e,t,n){"use strict";function r(e,t){throw console.log("Invalid Delta:",e),"Invalid Delta: "+t}function i(e,t){return t.row>=0&&t.row<e.length&&t.column>=0&&t.column<=e[t.row].length}function s(e,t){t.action!="insert"&&t.action!="remove"&&r(t,"delta.action must be 'insert' or 'remove'"),t.lines instanceof Array||r(t,"delta.lines must be an Array"),(!t.start||!t.end)&&r(t,"delta.start/end must be an present");var n=t.start;i(e,t.start)||r(t,"delta.start must be contained in document");var s=t.end;t.action=="remove"&&!i(e,s)&&r(t,"delta.end must contained in document for 'remove' actions");var o=s.row-n.row,u=s.column-(o==0?n.column:0);(o!=t.lines.length-1||t.lines[o].length!=u)&&r(t,"delta.range must match delta lines")}t.applyDelta=function(e,t,n){var r=t.start.row,i=t.start.column,s=e[r]||"";switch(t.action){case"insert":var o=t.lines;if(o.length===1)e[r]=s.substring(0,i)+t.lines[0]+s.substring(i);else{var u=[r,1].concat(t.lines);e.splice.apply(e,u),e[r]=s.substring(0,i)+e[r],e[r+t.lines.length-1]+=s.substring(i)}break;case"remove":var a=t.end.column,f=t.end.row;r===f?e[r]=s.substring(0,i)+s.substring(a):e.splice(r,f-r+1,s.substring(0,i)+e[f].substring(a))}}}),ace.define("ace/lib/event_emitter",["require","exports","module"],function(e,t,n){"use strict";var r={},i=function(){this.propagationStopped=!0},s=function(){this.defaultPrevented=!0};r._emit=r._dispatchEvent=function(e,t){this._eventRegistry||(this._eventRegistry={}),this._defaultHandlers||(this._defaultHandlers={});var n=this._eventRegistry[e]||[],r=this._defaultHandlers[e];if(!n.length&&!r)return;if(typeof t!="object"||!t)t={};t.type||(t.type=e),t.stopPropagation||(t.stopPropagation=i),t.preventDefault||(t.preventDefault=s),n=n.slice();for(var o=0;o<n.length;o++){n[o](t,this);if(t.propagationStopped)break}if(r&&!t.defaultPrevented)return r(t,this)},r._signal=function(e,t){var n=(this._eventRegistry||{})[e];if(!n)return;n=n.slice();for(var r=0;r<n.length;r++)n[r](t,this)},r.once=function(e,t){var n=this;t&&this.addEventListener(e,function r(){n.removeEventListener(e,r),t.apply(null,arguments)})},r.setDefaultHandler=function(e,t){var n=this._defaultHandlers;n||(n=this._defaultHandlers={_disabled_:{}});if(n[e]){var r=n[e],i=n._disabled_[e];i||(n._disabled_[e]=i=[]),i.push(r);var s=i.indexOf(t);s!=-1&&i.splice(s,1)}n[e]=t},r.removeDefaultHandler=function(e,t){var n=this._defaultHandlers;if(!n)return;var r=n._disabled_[e];if(n[e]==t){var i=n[e];r&&this.setDefaultHandler(e,r.pop())}else if(r){var s=r.indexOf(t);s!=-1&&r.splice(s,1)}},r.on=r.addEventListener=function(e,t,n){this._eventRegistry=this._eventRegistry||{};var r=this._eventRegistry[e];return r||(r=this._eventRegistry[e]=[]),r.indexOf(t)==-1&&r[n?"unshift":"push"](t),t},r.off=r.removeListener=r.removeEventListener=function(e,t){this._eventRegistry=this._eventRegistry||{};var n=this._eventRegistry[e];if(!n)return;var r=n.indexOf(t);r!==-1&&n.splice(r,1)},r.removeAllListeners=function(e){this._eventRegistry&&(this._eventRegistry[e]=[])},t.EventEmitter=r}),ace.define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=t.Anchor=function(e,t,n){this.$onChange=this.onChange.bind(this),this.attach(e),typeof n=="undefined"?this.setPosition(t.row,t.column):this.setPosition(t,n)};(function(){function e(e,t,n){var r=n?e.column<=t.column:e.column<t.column;return e.row<t.row||e.row==t.row&&r}function t(t,n,r){var i=t.action=="insert",s=(i?1:-1)*(t.end.row-t.start.row),o=(i?1:-1)*(t.end.column-t.start.column),u=t.start,a=i?u:t.end;return e(n,u,r)?{row:n.row,column:n.column}:e(a,n,!r)?{row:n.row+s,column:n.column+(n.row==a.row?o:0)}:{row:u.row,column:u.column}}r.implement(this,i),this.getPosition=function(){return this.$clipPositionToDocument(this.row,this.column)},this.getDocument=function(){return this.document},this.$insertRight=!1,this.onChange=function(e){if(e.start.row==e.end.row&&e.start.row!=this.row)return;if(e.start.row>this.row)return;var n=t(e,{row:this.row,column:this.column},this.$insertRight);this.setPosition(n.row,n.column,!0)},this.setPosition=function(e,t,n){var r;n?r={row:e,column:t}:r=this.$clipPositionToDocument(e,t);if(this.row==r.row&&this.column==r.column)return;var i={row:this.row,column:this.column};this.row=r.row,this.column=r.column,this._signal("change",{old:i,value:r})},this.detach=function(){this.document.removeEventListener("change",this.$onChange)},this.attach=function(e){this.document=e||this.document,this.document.on("change",this.$onChange)},this.$clipPositionToDocument=function(e,t){var n={};return e>=this.document.getLength()?(n.row=Math.max(0,this.document.getLength()-1),n.column=this.document.getLine(n.row).length):e<0?(n.row=0,n.column=0):(n.row=e,n.column=Math.min(this.document.getLine(n.row).length,Math.max(0,t))),t<0&&(n.column=0),n}}).call(s.prototype)}),ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./apply_delta").applyDelta,s=e("./lib/event_emitter").EventEmitter,o=e("./range").Range,u=e("./anchor").Anchor,a=function(e){this.$lines=[""],e.length===0?this.$lines=[""]:Array.isArray(e)?this.insertMergedLines({row:0,column:0},e):this.insert({row:0,column:0},e)};(function(){r.implement(this,s),this.setValue=function(e){var t=this.getLength()-1;this.remove(new o(0,0,t,this.getLine(t).length)),this.insert({row:0,column:0},e)},this.getValue=function(){return this.getAllLines().join(this.getNewLineCharacter())},this.createAnchor=function(e,t){return new u(this,e,t)},"aaa".split(/a/).length===0?this.$split=function(e){return e.replace(/\r\n|\r/g,"\n").split("\n")}:this.$split=function(e){return e.split(/\r\n|\r|\n/)},this.$detectNewLine=function(e){var t=e.match(/^.*?(\r\n|\r|\n)/m);this.$autoNewLine=t?t[1]:"\n",this._signal("changeNewLineMode")},this.getNewLineCharacter=function(){switch(this.$newLineMode){case"windows":return"\r\n";case"unix":return"\n";default:return this.$autoNewLine||"\n"}},this.$autoNewLine="",this.$newLineMode="auto",this.setNewLineMode=function(e){if(this.$newLineMode===e)return;this.$newLineMode=e,this._signal("changeNewLineMode")},this.getNewLineMode=function(){return this.$newLineMode},this.isNewLine=function(e){return e=="\r\n"||e=="\r"||e=="\n"},this.getLine=function(e){return this.$lines[e]||""},this.getLines=function(e,t){return this.$lines.slice(e,t+1)},this.getAllLines=function(){return this.getLines(0,this.getLength())},this.getLength=function(){return this.$lines.length},this.getTextRange=function(e){return this.getLinesForRange(e).join(this.getNewLineCharacter())},this.getLinesForRange=function(e){var t;if(e.start.row===e.end.row)t=[this.getLine(e.start.row).substring(e.start.column,e.end.column)];else{t=this.getLines(e.start.row,e.end.row),t[0]=(t[0]||"").substring(e.start.column);var n=t.length-1;e.end.row-e.start.row==n&&(t[n]=t[n].substring(0,e.end.column))}return t},this.insertLines=function(e,t){return console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."),this.insertFullLines(e,t)},this.removeLines=function(e,t){return console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."),this.removeFullLines(e,t)},this.insertNewLine=function(e){return console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead."),this.insertMergedLines(e,["",""])},this.insert=function(e,t){return this.getLength()<=1&&this.$detectNewLine(t),this.insertMergedLines(e,this.$split(t))},this.insertInLine=function(e,t){var n=this.clippedPos(e.row,e.column),r=this.pos(e.row,e.column+t.length);return this.applyDelta({start:n,end:r,action:"insert",lines:[t]},!0),this.clonePos(r)},this.clippedPos=function(e,t){var n=this.getLength();e===undefined?e=n:e<0?e=0:e>=n&&(e=n-1,t=undefined);var r=this.getLine(e);return t==undefined&&(t=r.length),t=Math.min(Math.max(t,0),r.length),{row:e,column:t}},this.clonePos=function(e){return{row:e.row,column:e.column}},this.pos=function(e,t){return{row:e,column:t}},this.$clipPosition=function(e){var t=this.getLength();return e.row>=t?(e.row=Math.max(0,t-1),e.column=this.getLine(t-1).length):(e.row=Math.max(0,e.row),e.column=Math.min(Math.max(e.column,0),this.getLine(e.row).length)),e},this.insertFullLines=function(e,t){e=Math.min(Math.max(e,0),this.getLength());var n=0;e<this.getLength()?(t=t.concat([""]),n=0):(t=[""].concat(t),e--,n=this.$lines[e].length),this.insertMergedLines({row:e,column:n},t)},this.insertMergedLines=function(e,t){var n=this.clippedPos(e.row,e.column),r={row:n.row+t.length-1,column:(t.length==1?n.column:0)+t[t.length-1].length};return this.applyDelta({start:n,end:r,action:"insert",lines:t}),this.clonePos(r)},this.remove=function(e){var t=this.clippedPos(e.start.row,e.start.column),n=this.clippedPos(e.end.row,e.end.column);return this.applyDelta({start:t,end:n,action:"remove",lines:this.getLinesForRange({start:t,end:n})}),this.clonePos(t)},this.removeInLine=function(e,t,n){var r=this.clippedPos(e,t),i=this.clippedPos(e,n);return this.applyDelta({start:r,end:i,action:"remove",lines:this.getLinesForRange({start:r,end:i})},!0),this.clonePos(r)},this.removeFullLines=function(e,t){e=Math.min(Math.max(0,e),this.getLength()-1),t=Math.min(Math.max(0,t),this.getLength()-1);var n=t==this.getLength()-1&&e>0,r=t<this.getLength()-1,i=n?e-1:e,s=n?this.getLine(i).length:0,u=r?t+1:t,a=r?0:this.getLine(u).length,f=new o(i,s,u,a),l=this.$lines.slice(e,t+1);return this.applyDelta({start:f.start,end:f.end,action:"remove",lines:this.getLinesForRange(f)}),l},this.removeNewLine=function(e){e<this.getLength()-1&&e>=0&&this.applyDelta({start:this.pos(e,this.getLine(e).length),end:this.pos(e+1,0),action:"remove",lines:["",""]})},this.replace=function(e,t){e instanceof o||(e=o.fromPoints(e.start,e.end));if(t.length===0&&e.isEmpty())return e.start;if(t==this.getTextRange(e))return e.end;this.remove(e);var n;return t?n=this.insert(e.start,t):n=e.start,n},this.applyDeltas=function(e){for(var t=0;t<e.length;t++)this.applyDelta(e[t])},this.revertDeltas=function(e){for(var t=e.length-1;t>=0;t--)this.revertDelta(e[t])},this.applyDelta=function(e,t){var n=e.action=="insert";if(n?e.lines.length<=1&&!e.lines[0]:!o.comparePoints(e.start,e.end))return;n&&e.lines.length>2e4&&this.$splitAndapplyLargeDelta(e,2e4),i(this.$lines,e,t),this._signal("change",e)},this.$splitAndapplyLargeDelta=function(e,t){var n=e.lines,r=n.length,i=e.start.row,s=e.start.column,o=0,u=0;do{o=u,u+=t-1;var a=n.slice(o,u);if(u>r){e.lines=a,e.start.row=i+o,e.start.column=s;break}a.push(""),this.applyDelta({start:this.pos(i+o,s),end:this.pos(i+u,s=0),action:e.action,lines:a},!0)}while(!0)},this.revertDelta=function(e){this.applyDelta({start:this.clonePos(e.start),end:this.clonePos(e.end),action:e.action=="insert"?"remove":"insert",lines:e.lines.slice()})},this.indexToPosition=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length;for(var i=t||0,s=n.length;i<s;i++){e-=n[i].length+r;if(e<0)return{row:i,column:e+n[i].length+r}}return{row:s-1,column:n[s-1].length}},this.positionToIndex=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length,i=0,s=Math.min(e.row,n.length);for(var o=t||0;o<s;++o)i+=n[o].length+r;return i+e.column}}).call(a.prototype),t.Document=a}),ace.define("ace/lib/lang",["require","exports","module"],function(e,t,n){"use strict";t.last=function(e){return e[e.length-1]},t.stringReverse=function(e){return e.split("").reverse().join("")},t.stringRepeat=function(e,t){var n="";while(t>0){t&1&&(n+=e);if(t>>=1)e+=e}return n};var r=/^\s\s*/,i=/\s\s*$/;t.stringTrimLeft=function(e){return e.replace(r,"")},t.stringTrimRight=function(e){return e.replace(i,"")},t.copyObject=function(e){var t={};for(var n in e)t[n]=e[n];return t},t.copyArray=function(e){var t=[];for(var n=0,r=e.length;n<r;n++)e[n]&&typeof e[n]=="object"?t[n]=this.copyObject(e[n]):t[n]=e[n];return t},t.deepCopy=function s(e){if(typeof e!="object"||!e)return e;var t;if(Array.isArray(e)){t=[];for(var n=0;n<e.length;n++)t[n]=s(e[n]);return t}var r=e.constructor;if(r===RegExp)return e;t=r();for(var n in e)t[n]=s(e[n]);return t},t.arrayToMap=function(e){var t={};for(var n=0;n<e.length;n++)t[e[n]]=1;return t},t.createMap=function(e){var t=Object.create(null);for(var n in e)t[n]=e[n];return t},t.arrayRemove=function(e,t){for(var n=0;n<=e.length;n++)t===e[n]&&e.splice(n,1)},t.escapeRegExp=function(e){return e.replace(/([.*+?^${}()|[\]\/\\])/g,"\\$1")},t.escapeHTML=function(e){return e.replace(/&/g,"&#38;").replace(/"/g,"&#34;").replace(/'/g,"&#39;").replace(/</g,"&#60;")},t.getMatchOffsets=function(e,t){var n=[];return e.replace(t,function(e){n.push({offset:arguments[arguments.length-2],length:e.length})}),n},t.deferredCall=function(e){var t=null,n=function(){t=null,e()},r=function(e){return r.cancel(),t=setTimeout(n,e||0),r};return r.schedule=r,r.call=function(){return this.cancel(),e(),r},r.cancel=function(){return clearTimeout(t),t=null,r},r.isPending=function(){return t},r},t.delayedCall=function(e,t){var n=null,r=function(){n=null,e()},i=function(e){n==null&&(n=setTimeout(r,e||t))};return i.delay=function(e){n&&clearTimeout(n),n=setTimeout(r,e||t)},i.schedule=i,i.call=function(){this.cancel(),e()},i.cancel=function(){n&&clearTimeout(n),n=null},i.isPending=function(){return n},i}}),ace.define("ace/worker/mirror",["require","exports","module","ace/range","ace/document","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../range").Range,i=e("../document").Document,s=e("../lib/lang"),o=t.Mirror=function(e){this.sender=e;var t=this.doc=new i(""),n=this.deferredUpdate=s.delayedCall(this.onUpdate.bind(this)),r=this;e.on("change",function(e){var i=e.data;if(i[0].start)t.applyDeltas(i);else for(var s=0;s<i.length;s+=2){if(Array.isArray(i[s+1]))var o={action:"insert",start:i[s],lines:i[s+1]};else var o={action:"remove",start:i[s],end:i[s+1]};t.applyDelta(o,!0)}if(r.$timeout)return n.schedule(r.$timeout);r.onUpdate()})};(function(){this.$timeout=500,this.setTimeout=function(e){this.$timeout=e},this.setValue=function(e){this.doc.setValue(e),this.deferredUpdate.schedule(this.$timeout)},this.getValue=function(e){this.sender.callback(this.doc.getValue(),e)},this.onUpdate=function(){},this.isPending=function(){return this.deferredUpdate.isPending()}}).call(o.prototype)}),ace.define("ace/mode/php/php",["require","exports","module"],function(e,t,n){var r={Constants:{}};r.Constants.T_INCLUDE=262,r.Constants.T_INCLUDE_ONCE=261,r.Constants.T_EVAL=260,r.Constants.T_REQUIRE=259,r.Constants.T_REQUIRE_ONCE=258,r.Constants.T_LOGICAL_OR=263,r.Constants.T_LOGICAL_XOR=264,r.Constants.T_LOGICAL_AND=265,r.Constants.T_PRINT=266,r.Constants.T_PLUS_EQUAL=277,r.Constants.T_MINUS_EQUAL=276,r.Constants.T_MUL_EQUAL=275,r.Constants.T_DIV_EQUAL=274,r.Constants.T_CONCAT_EQUAL=273,r.Constants.T_MOD_EQUAL=272,r.Constants.T_AND_EQUAL=271,r.Constants.T_OR_EQUAL=270,r.Constants.T_XOR_EQUAL=269,r.Constants.T_SL_EQUAL=268,r.Constants.T_SR_EQUAL=267,r.Constants.T_BOOLEAN_OR=278,r.Constants.T_BOOLEAN_AND=279,r.Constants.T_IS_EQUAL=283,r.Constants.T_IS_NOT_EQUAL=282,r.Constants.T_IS_IDENTICAL=281,r.Constants.T_IS_NOT_IDENTICAL=280,r.Constants.T_IS_SMALLER_OR_EQUAL=285,r.Constants.T_IS_GREATER_OR_EQUAL=284,r.Constants.T_SL=287,r.Constants.T_SR=286,r.Constants.T_INSTANCEOF=288,r.Constants.T_INC=297,r.Constants.T_DEC=296,r.Constants.T_INT_CAST=295,r.Constants.T_DOUBLE_CAST=294,r.Constants.T_STRING_CAST=293,r.Constants.T_ARRAY_CAST=292,r.Constants.T_OBJECT_CAST=291,r.Constants.T_BOOL_CAST=290,r.Constants.T_UNSET_CAST=289,r.Constants.T_NEW=299,r.Constants.T_CLONE=298,r.Constants.T_EXIT=300,r.Constants.T_IF=301,r.Constants.T_ELSEIF=302,r.Constants.T_ELSE=303,r.Constants.T_ENDIF=304,r.Constants.T_LNUMBER=305,r.Constants.T_DNUMBER=306,r.Constants.T_STRING=307,r.Constants.T_STRING_VARNAME=308,r.Constants.T_VARIABLE=309,r.Constants.T_NUM_STRING=310,r.Constants.T_INLINE_HTML=311,r.Constants.T_CHARACTER=312,r.Constants.T_BAD_CHARACTER=313,r.Constants.T_ENCAPSED_AND_WHITESPACE=314,r.Constants.T_CONSTANT_ENCAPSED_STRING=315,r.Constants.T_ECHO=316,r.Constants.T_DO=317,r.Constants.T_WHILE=318,r.Constants.T_ENDWHILE=319,r.Constants.T_FOR=320,r.Constants.T_ENDFOR=321,r.Constants.T_FOREACH=322,r.Constants.T_ENDFOREACH=323,r.Constants.T_DECLARE=324,r.Constants.T_ENDDECLARE=325,r.Constants.T_AS=326,r.Constants.T_SWITCH=327,r.Constants.T_ENDSWITCH=328,r.Constants.T_CASE=329,r.Constants.T_DEFAULT=330,r.Constants.T_BREAK=331,r.Constants.T_CONTINUE=332,r.Constants.T_GOTO=333,r.Constants.T_FUNCTION=334,r.Constants.T_CONST=335,r.Constants.T_RETURN=336,r.Constants.T_TRY=337,r.Constants.T_CATCH=338,r.Constants.T_THROW=339,r.Constants.T_USE=340,r.Constants.T_GLOBAL=341,r.Constants.T_STATIC=347,r.Constants.T_ABSTRACT=346,r.Constants.T_FINAL=345,r.Constants.T_PRIVATE=344,r.Constants.T_PROTECTED=343,r.Constants.T_PUBLIC=342,r.Constants.T_VAR=348,r.Constants.T_UNSET=349,r.Constants.T_ISSET=350,r.Constants.T_EMPTY=351,r.Constants.T_HALT_COMPILER=352,r.Constants.T_CLASS=353,r.Constants.T_TRAIT=382,r.Constants.T_INTERFACE=354,r.Constants.T_EXTENDS=355,r.Constants.T_IMPLEMENTS=356,r.Constants.T_OBJECT_OPERATOR=357,r.Constants.T_DOUBLE_ARROW=358,r.Constants.T_LIST=359,r.Constants.T_ARRAY=360,r.Constants.T_CLASS_C=361,r.Constants.T_TRAIT_C=381,r.Constants.T_METHOD_C=362,r.Constants.T_FUNC_C=363,r.Constants.T_LINE=364,r.Constants.T_FILE=365,r.Constants.T_COMMENT=366,r.Constants.T_DOC_COMMENT=367,r.Constants.T_OPEN_TAG=368,r.Constants.T_OPEN_TAG_WITH_ECHO=369,r.Constants.T_CLOSE_TAG=370,r.Constants.T_WHITESPACE=371,r.Constants.T_START_HEREDOC=372,r.Constants.T_END_HEREDOC=373,r.Constants.T_DOLLAR_OPEN_CURLY_BRACES=374,r.Constants.T_CURLY_OPEN=375,r.Constants.T_PAAMAYIM_NEKUDOTAYIM=376,r.Constants.T_DOUBLE_COLON=376,r.Constants.T_NAMESPACE=377,r.Constants.T_NS_C=378,r.Constants.T_DIR=379,r.Constants.T_NS_SEPARATOR=380,r.Lexer=function(e,t){var n,i=function(e){if(e.match(/\n/)!==null){var t=e.substring(0,1);e="["+e.split(/\n/).join(t+","+t)+'].join("\\n")'}return e},s,o=t===undefined||/^(on|true|1)$/i.test(t.short_open_tag)?/(\<\?php\s|\<\?|\<\%|\<script language\=('|")?php('|")?\>)/i:/(\<\?php\s|<\?=|\<script language\=('|")?php('|")?\>)/i,u=t===undefined||/^(on|true|1)$/i.test(t.short_open_tag)?/^(\<\?php\s|\<\?|\<\%|\<script language\=('|")?php('|")?\>)/i:/^(\<\?php\s|<\?=|\<script language\=('|")?php('|")?\>)/i,a=[{value:r.Constants.T_NAMESPACE,re:/^namespace(?=\s)/i},{value:r.Constants.T_USE,re:/^use(?=\s)/i},{value:r.Constants.T_ABSTRACT,re:/^abstract(?=\s)/i},{value:r.Constants.T_IMPLEMENTS,re:/^implements(?=\s)/i},{value:r.Constants.T_INTERFACE,re:/^interface(?=\s)/i},{value:r.Constants.T_CONST,re:/^const(?=\s)/i},{value:r.Constants.T_STATIC,re:/^static(?=\s)/i},{value:r.Constants.T_FINAL,re:/^final(?=\s)/i},{value:r.Constants.T_VAR,re:/^var(?=\s)/i},{value:r.Constants.T_GLOBAL,re:/^global(?=\s)/i},{value:r.Constants.T_CLONE,re:/^clone(?=\s)/i},{value:r.Constants.T_THROW,re:/^throw(?=\s)/i},{value:r.Constants.T_EXTENDS,re:/^extends(?=\s)/i},{value:r.Constants.T_AND_EQUAL,re:/^&=/},{value:r.Constants.T_AS,re:/^as(?=\s)/i},{value:r.Constants.T_ARRAY_CAST,re:/^\(array\)/i},{value:r.Constants.T_BOOL_CAST,re:/^\((bool|boolean)\)/i},{value:r.Constants.T_DOUBLE_CAST,re:/^\((real|float|double)\)/i},{value:r.Constants.T_INT_CAST,re:/^\((int|integer)\)/i},{value:r.Constants.T_OBJECT_CAST,re:/^\(object\)/i},{value:r.Constants.T_STRING_CAST,re:/^\(string\)/i},{value:r.Constants.T_UNSET_CAST,re:/^\(unset\)/i},{value:r.Constants.T_TRY,re:/^try(?=\s*{)/i},{value:r.Constants.T_CATCH,re:/^catch(?=\s*\()/i},{value:r.Constants.T_INSTANCEOF,re:/^instanceof(?=\s)/i},{value:r.Constants.T_LOGICAL_OR,re:/^or(?=\s)/i},{value:r.Constants.T_LOGICAL_AND,re:/^and(?=\s)/i},{value:r.Constants.T_LOGICAL_XOR,re:/^xor(?=\s)/i},{value:r.Constants.T_BOOLEAN_AND,re:/^&&/},{value:r.Constants.T_BOOLEAN_OR,re:/^\|\|/},{value:r.Constants.T_CONTINUE,re:/^continue(?=\s|;)/i},{value:r.Constants.T_BREAK,re:/^break(?=\s|;)/i},{value:r.Constants.T_ENDDECLARE,re:/^enddeclare(?=\s|;)/i},{value:r.Constants.T_ENDFOR,re:/^endfor(?=\s|;)/i},{value:r.Constants.T_ENDFOREACH,re:/^endforeach(?=\s|;)/i},{value:r.Constants.T_ENDIF,re:/^endif(?=\s|;)/i},{value:r.Constants.T_ENDSWITCH,re:/^endswitch(?=\s|;)/i},{value:r.Constants.T_ENDWHILE,re:/^endwhile(?=\s|;)/i},{value:r.Constants.T_CASE,re:/^case(?=\s)/i},{value:r.Constants.T_DEFAULT,re:/^default(?=\s|:)/i},{value:r.Constants.T_SWITCH,re:/^switch(?=[ (])/i},{value:r.Constants.T_EXIT,re:/^(exit|die)(?=[ \(;])/i},{value:r.Constants.T_CLOSE_TAG,re:/^(\?\>|\%\>|\<\/script\>)\s?\s?/i,func:function(e){return c=!1,e}},{value:r.Constants.T_DOUBLE_ARROW,re:/^\=\>/},{value:r.Constants.T_DOUBLE_COLON,re:/^\:\:/},{value:r.Constants.T_METHOD_C,re:/^__METHOD__/},{value:r.Constants.T_LINE,re:/^__LINE__/},{value:r.Constants.T_FILE,re:/^__FILE__/},{value:r.Constants.T_FUNC_C,re:/^__FUNCTION__/},{value:r.Constants.T_NS_C,re:/^__NAMESPACE__/},{value:r.Constants.T_TRAIT_C,re:/^__TRAIT__/},{value:r.Constants.T_DIR,re:/^__DIR__/},{value:r.Constants.T_CLASS_C,re:/^__CLASS__/},{value:r.Constants.T_INC,re:/^\+\+/},{value:r.Constants.T_DEC,re:/^\-\-/},{value:r.Constants.T_CONCAT_EQUAL,re:/^\.\=/},{value:r.Constants.T_DIV_EQUAL,re:/^\/\=/},{value:r.Constants.T_XOR_EQUAL,re:/^\^\=/},{value:r.Constants.T_MUL_EQUAL,re:/^\*\=/},{value:r.Constants.T_MOD_EQUAL,re:/^\%\=/},{value:r.Constants.T_SL_EQUAL,re:/^<<=/},{value:r.Constants.T_START_HEREDOC,re:/^<<<[A-Z_0-9]+\s/i,func:function(e){return n=e.substring(3,e.length-1),e}},{value:r.Constants.T_SL,re:/^<</},{value:r.Constants.T_IS_SMALLER_OR_EQUAL,re:/^<=/},{value:r.Constants.T_SR_EQUAL,re:/^>>=/},{value:r.Constants.T_SR,re:/^>>/},{value:r.Constants.T_IS_GREATER_OR_EQUAL,re:/^>=/},{value:r.Constants.T_OR_EQUAL,re:/^\|\=/},{value:r.Constants.T_PLUS_EQUAL,re:/^\+\=/},{value:r.Constants.T_MINUS_EQUAL,re:/^-\=/},{value:r.Constants.T_OBJECT_OPERATOR,re:/^\-\>/i},{value:r.Constants.T_CLASS,re:/^class(?=[\s\{])/i,afterWhitespace:!0},{value:r.Constants.T_TRAIT,re:/^trait(?=[\s]+[A-Za-z])/i},{value:r.Constants.T_PUBLIC,re:/^public(?=[\s])/i},{value:r.Constants.T_PRIVATE,re:/^private(?=[\s])/i},{value:r.Constants.T_PROTECTED,re:/^protected(?=[\s])/i},{value:r.Constants.T_ARRAY,re:/^array(?=\s*?\()/i},{value:r.Constants.T_EMPTY,re:/^empty(?=[ \(])/i},{value:r.Constants.T_ISSET,re:/^isset(?=[ \(])/i},{value:r.Constants.T_UNSET,re:/^unset(?=[ \(])/i},{value:r.Constants.T_RETURN,re:/^return(?=[ "'(;])/i},{value:r.Constants.T_FUNCTION,re:/^function(?=[ "'(;])/i},{value:r.Constants.T_ECHO,re:/^echo(?=[ "'(;])/i},{value:r.Constants.T_LIST,re:/^list(?=\s*?\()/i},{value:r.Constants.T_PRINT,re:/^print(?=[ "'(;])/i},{value:r.Constants.T_INCLUDE,re:/^include(?=[ "'(;])/i},{value:r.Constants.T_INCLUDE_ONCE,re:/^include_once(?=[ "'(;])/i},{value:r.Constants.T_REQUIRE,re:/^require(?=[ "'(;])/i},{value:r.Constants.T_REQUIRE_ONCE,re:/^require_once(?=[ "'(;])/i},{value:r.Constants.T_NEW,re:/^new(?=[ ])/i},{value:r.Constants.T_COMMENT,re:/^\/\*([\S\s]*?)(?:\*\/|$)/},{value:r.Constants.T_COMMENT,re:/^\/\/.*(\s)?/},{value:r.Constants.T_COMMENT,re:/^\#.*(\s)?/},{value:r.Constants.T_ELSEIF,re:/^elseif(?=[\s(])/i},{value:r.Constants.T_GOTO,re:/^goto(?=[\s(])/i},{value:r.Constants.T_ELSE,re:/^else(?=[\s{:])/i},{value:r.Constants.T_IF,re:/^if(?=[\s(])/i},{value:r.Constants.T_DO,re:/^do(?=[ {])/i},{value:r.Constants.T_WHILE,re:/^while(?=[ (])/i},{value:r.Constants.T_FOREACH,re:/^foreach(?=[ (])/i},{value:r.Constants.T_ISSET,re:/^isset(?=[ (])/i},{value:r.Constants.T_IS_IDENTICAL,re:/^===/},{value:r.Constants.T_IS_EQUAL,re:/^==/},{value:r.Constants.T_IS_NOT_IDENTICAL,re:/^\!==/},{value:r.Constants.T_IS_NOT_EQUAL,re:/^(\!=|\<\>)/},{value:r.Constants.T_FOR,re:/^for(?=[ (])/i},{value:r.Constants.T_DNUMBER,re:/^[0-9]*\.[0-9]+([eE][-]?[0-9]*)?/},{value:r.Constants.T_LNUMBER,re:/^(0x[0-9A-F]+|[0-9]+)/i},{value:r.Constants.T_OPEN_TAG_WITH_ECHO,re:/^(\<\?=|\<\%=)/i},{value:r.Constants.T_OPEN_TAG,re:u},{value:r.Constants.T_VARIABLE,re:/^\$[a-zA-Z_\x7f-\uffff][a-zA-Z0-9_\x7f-\uffff]*/},{value:r.Constants.T_WHITESPACE,re:/^\s+/},{value:r.Constants.T_CONSTANT_ENCAPSED_STRING,re:/^("(?:[^"\\]|\\[\s\S])*"|'(?:[^'\\]|\\[\s\S])*')/,func:function(e,t){var n=0,i,s=0;if(e.substring(0,1)==="'")return e;var o=e.match(/(?:[^\\]|\\.)*[^\\]\$[a-zA-Z_\x7f-\uffff][a-zA-Z0-9_\x7f-\uffff]*/g);if(o!==null){while(e.length>0){i=e.length,o=e.match(/^[\[\]\;\:\?\(\)\!\.\,\>\<\=\+\-\/\*\|\&\@\^\%\"\'\{\}]/),o!==null&&(f.push(o[0]),e=e.substring(1),n>0&&o[0]==="}"&&n--,o[0]==="["&&s++,o[0]==="]"&&s--),o=e.match(/^\$[a-zA-Z_\x7f-\uffff][a-zA-Z0-9_\x7f-\uffff]*/);if(o!==null){f.push([parseInt(r.Constants.T_VARIABLE,10),o[0],l]),e=e.substring(o[0].length),o=e.match(/^(\-\>)\s*([a-zA-Z_\x7f-\uffff][a-zA-Z0-9_\x7f-\uffff]*)\s*(\()/),o!==null&&(f.push([parseInt(r.Constants.T_OBJECT_OPERATOR,10),o[1],l]),f.push([parseInt(r.Constants.T_STRING,10),o[2],l]),o[3]&&f.push(o[3]),e=e.substring(o[0].length));if(e.match(/^\[/g)!==null)continue}var u;n>0?u=/^([^\\\$"{}\]\(\)\->]|\\.)+/g:u=/^([^\\\$"{]|\\.|{[^\$]|\$(?=[^a-zA-Z_\x7f-\uffff]))+/g;var a,c;while((o=e.match(u))!==null){if(e.length===1)throw new Error(o);a=0,n>0?(c=o[0].match(/^[\[\]\;\:\?\(\)\!\.\,\>\<\=\+\-\/\*\|\&\{\}\@\^\%\$\~]/))?f.push(c[0]):a=r.Constants.T_STRING:a=r.Constants.T_ENCAPSED_AND_WHITESPACE,a&&f.push([parseInt(a,10),o[0].replace(/\n/g,"\\n").replace(/\r/g,""),l]),l+=o[0].split("\n").length-1,e=e.substring(o[0].length)}n>0&&e.match(/^\->/)!==null&&(f.push([parseInt(r.Constants.T_OBJECT_OPERATOR,10),"->",l]),e=e.substring(2)),e.match(/^{\$/)!==null&&(f.push([parseInt(r.Constants.T_CURLY_OPEN,10),"{",l]),e=e.substring(1),n++);if(i===e.length&&(o=e.match(/^(([^\\]|\\.)*?[^\\]\$[a-zA-Z_\x7f-\uffff][a-zA-Z0-9_\x7f-\uffff]*)/g))!==null)return}return undefined}return e=e.replace(/\r/g,""),e}},{value:r.Constants.T_NS_SEPARATOR,re:/^\\(?=[a-zA-Z_])/},{value:r.Constants.T_STRING,re:/^[a-zA-Z_\x7f-\uffff][a-zA-Z0-9_\x7f-\uffff]*/},{value:-1,re:/^[\[\]\;\:\?\(\)\!\.\,\>\<\=\+\-\/\*\|\&\{\}\@\^\%\"\'\$\~]/}],f=[],l=1,c=!1,h=!0;if(e===null)return f;typeof e!="string"&&(e=e.toString());while(e.length>0&&h===!0)if(c===!0)if(n!==undefined){var p=new RegExp("([\\S\\s]*?)(\\r\\n|\\n|\\r)("+n+")(;|\\r\\n|\\n)","i"),d=e.match(p);d!==null&&(f.push([parseInt(r.Constants.T_ENCAPSED_AND_WHITESPACE,10),d[1].replace(/^\n/g,"").replace(/\\\$/g,"$")+"\n",l]),l+=d[1].split("\n").length,f.push([parseInt(r.Constants.T_END_HEREDOC,10),d[3],l]),e=e.substring(d[1].length+d[2].length+d[3].length),n=undefined);if(d===null)throw Error("sup")}else h=a.some(function(t){if(t.afterWhitespace===!0){var n=f[f.length-1];if(!Array.isArray(n)||n[0]!==r.Constants.T_WHITESPACE&&n[0]!==r.Constants.T_OPEN_TAG&&n[0]!==r.Constants.T_COMMENT)return!1}var i=e.match(t.re);if(i!==null){if(t.value!==-1){var s=i[0];t.func!==undefined&&(s=t.func(s,t)),s!==undefined&&(f.push([parseInt(t.value,10),s,l]),l+=s.split("\n").length-1)}else f.push(i[0]);return e=e.substring(i[0].length),!0}return!1});else{var d=o.exec(e);if(d===null)return f.push([parseInt(r.Constants.T_INLINE_HTML,10),e.replace(/^\n/,""),l]),f;if(d.index>0){var v=e.substring(0,d.index);f.push([parseInt(r.Constants.T_INLINE_HTML,10),v,l]),l+=v.split("\n").length-1,e=e.substring(d.index)}c=!0}return f},r.Parser=function(e,t){var n=this.yybase,i=this.yydefault,s=this.yycheck,o=this.yyaction,u=this.yylen,a=this.yygbase,f=this.yygcheck,l=this.yyp,c=this.yygoto,h=this.yylhs,p=this.terminals,d=this.translate,v=this.yygdefault;this.pos=-1,this.line=1,this.tokenMap=this.createTokenMap(),this.dropTokens={},this.dropTokens[r.Constants.T_WHITESPACE]=1,this.dropTokens[r.Constants.T_OPEN_TAG]=1;var m=[];e.forEach(function(e,t){typeof e=="object"&&e[0]===r.Constants.T_OPEN_TAG_WITH_ECHO?(m.push([r.Constants.T_OPEN_TAG,e[1],e[2]]),m.push([r.Constants.T_ECHO,e[1],e[2]])):m.push(e)}),this.tokens=m;var g=this.TOKEN_NONE;this.startAttributes={startLine:1},this.endAttributes={};var y=[this.startAttributes],b=0,w=[b];this.yyastk=[],this.stackPos=0;var E,S;for(;;){if(n[b]===0)E=i[b];else{g===this.TOKEN_NONE&&(S=this.getNextToken(),g=S>=0&&S<this.TOKEN_MAP_SIZE?d[S]:this.TOKEN_INVALID,y[this.stackPos]=this.startAttributes);if(((E=n[b]+g)>=0&&E<this.YYLAST&&s[E]===g||b<this.YY2TBLSTATE&&(E=n[b+this.YYNLSTATES]+g)>=0&&E<this.YYLAST&&s[E]===g)&&(E=o[E])!==this.YYDEFAULT)if(E>0){++this.stackPos,w[this.stackPos]=b=E,this.yyastk[this.stackPos]=this.tokenValue,y[this.stackPos]=this.startAttributes,g=this.TOKEN_NONE;if(E<this.YYNLSTATES)continue;E-=this.YYNLSTATES}else E=-E;else E=i[b]}for(;;){if(E===0)return this.yyval;if(E===this.YYUNEXPECTED){if(t!==!0){var N=[];for(var C=0;C<this.TOKEN_MAP_SIZE;++C)if((E=n[b]+C)>=0&&E<this.YYLAST&&s[E]==C||b<this.YY2TBLSTATE&&(E=n[b+this.YYNLSTATES]+C)&&E<this.YYLAST&&s[E]==C)if(o[E]!=this.YYUNEXPECTED){if(N.length==4){N=[];break}N.push(this.terminals[C])}var k="";throw N.length&&(k=", expecting "+N.join(" or ")),new r.ParseError("syntax error, unexpected "+p[g]+k,this.startAttributes.startLine)}return this.startAttributes.startLine}for(var x in this.endAttributes)y[this.stackPos-u[E]][x]=this.endAttributes[x];try{this["yyn"+E](y[this.stackPos-u[E]])}catch(T){throw T}this.stackPos-=u[E],E=h[E],(l=a[E]+w[this.stackPos])>=0&&l<this.YYGLAST&&f[l]===E?b=c[l]:b=v[E],++this.stackPos,w[this.stackPos]=b,this.yyastk[this.stackPos]=this.yyval,y[this.stackPos]=this.startAttributes;if(b<this.YYNLSTATES)break;E=b-this.YYNLSTATES}}},r.ParseError=function(e,t){this.message=e,this.line=t},r.Parser.prototype.MODIFIER_PUBLIC=1,r.Parser.prototype.MODIFIER_PROTECTED=2,r.Parser.prototype.MODIFIER_PRIVATE=4,r.Parser.prototype.MODIFIER_STATIC=8,r.Parser.prototype.MODIFIER_ABSTRACT=16,r.Parser.prototype.MODIFIER_FINAL=32,r.Parser.prototype.getNextToken=function(){this.startAttributes={},this.endAttributes={};var e,t;while(this.tokens[++this.pos]!==undefined){e=this.tokens[this.pos];if(typeof e=="string")return this.startAttributes.startLine=this.line,this.endAttributes.endLine=this.line,'b"'===e?(this.tokenValue='b"','"'.charCodeAt(0)):(this.tokenValue=e,e.charCodeAt(0));this.line+=(t=e[1].match(/\n/g))===null?0:t.length;if(r.Constants.T_COMMENT===e[0])Array.isArray(this.startAttributes.comments)||(this.startAttributes.comments=[]),this.startAttributes.comments.push({type:"comment",comment:e[1],line:e[2]});else if(r.Constants.T_DOC_COMMENT===e[0])this.startAttributes.comments.push(new PHPParser_Comment_Doc(e[1],e[2]));else if(this.dropTokens[e[0]]===undefined)return this.tokenValue=e[1],this.startAttributes.startLine=e[2],this.endAttributes.endLine=this.line,this.tokenMap[e[0]]}return this.startAttributes.startLine=this.line,0},r.Parser.prototype.tokenName=function(e){var t=["T_INCLUDE","T_INCLUDE_ONCE","T_EVAL","T_REQUIRE","T_REQUIRE_ONCE","T_LOGICAL_OR","T_LOGICAL_XOR","T_LOGICAL_AND","T_PRINT","T_PLUS_EQUAL","T_MINUS_EQUAL","T_MUL_EQUAL","T_DIV_EQUAL","T_CONCAT_EQUAL","T_MOD_EQUAL","T_AND_EQUAL","T_OR_EQUAL","T_XOR_EQUAL","T_SL_EQUAL","T_SR_EQUAL","T_BOOLEAN_OR","T_BOOLEAN_AND","T_IS_EQUAL","T_IS_NOT_EQUAL","T_IS_IDENTICAL","T_IS_NOT_IDENTICAL","T_IS_SMALLER_OR_EQUAL","T_IS_GREATER_OR_EQUAL","T_SL","T_SR","T_INSTANCEOF","T_INC","T_DEC","T_INT_CAST","T_DOUBLE_CAST","T_STRING_CAST","T_ARRAY_CAST","T_OBJECT_CAST","T_BOOL_CAST","T_UNSET_CAST","T_NEW","T_CLONE","T_EXIT","T_IF","T_ELSEIF","T_ELSE","T_ENDIF","T_LNUMBER","T_DNUMBER","T_STRING","T_STRING_VARNAME","T_VARIABLE","T_NUM_STRING","T_INLINE_HTML","T_CHARACTER","T_BAD_CHARACTER","T_ENCAPSED_AND_WHITESPACE","T_CONSTANT_ENCAPSED_STRING","T_ECHO","T_DO","T_WHILE","T_ENDWHILE","T_FOR","T_ENDFOR","T_FOREACH","T_ENDFOREACH","T_DECLARE","T_ENDDECLARE","T_AS","T_SWITCH","T_ENDSWITCH","T_CASE","T_DEFAULT","T_BREAK","T_CONTINUE","T_GOTO","T_FUNCTION","T_CONST","T_RETURN","T_TRY","T_CATCH","T_THROW","T_USE","T_INSTEADOF","T_GLOBAL","T_STATIC","T_ABSTRACT","T_FINAL","T_PRIVATE","T_PROTECTED","T_PUBLIC","T_VAR","T_UNSET","T_ISSET","T_EMPTY","T_HALT_COMPILER","T_CLASS","T_TRAIT","T_INTERFACE","T_EXTENDS","T_IMPLEMENTS","T_OBJECT_OPERATOR","T_DOUBLE_ARROW","T_LIST","T_ARRAY","T_CALLABLE","T_CLASS_C","T_TRAIT_C","T_METHOD_C","T_FUNC_C","T_LINE","T_FILE","T_COMMENT","T_DOC_COMMENT","T_OPEN_TAG","T_OPEN_TAG_WITH_ECHO","T_CLOSE_TAG","T_WHITESPACE","T_START_HEREDOC","T_END_HEREDOC","T_DOLLAR_OPEN_CURLY_BRACES","T_CURLY_OPEN","T_PAAMAYIM_NEKUDOTAYIM","T_DOUBLE_COLON","T_NAMESPACE","T_NS_C","T_DIR","T_NS_SEPARATOR"],n="UNKNOWN";return t.some(function(t){return r.Constants[t]===e?(n=t,!0):!1}),n},r.Parser.prototype.createTokenMap=function(){var e={},t,n,i=r.Constants.T_PAAMAYIM_NEKUDOTAYIM;for(n=256;n<1e3;++n)i===n?e[n]=this.T_PAAMAYIM_NEKUDOTAYIM:r.Constants.T_OPEN_TAG_WITH_ECHO===n?e[n]=r.Constants.T_ECHO:r.Constants.T_CLOSE_TAG===n?e[n]=59:"UNKNOWN"!==(t=this.tokenName(n))&&(e[n]=this[t]);return e};var i=function(){this.yyval=this.yyastk[this.stackPos-0]};r.Parser.prototype.MakeArray=function(e){return Array.isArray(e)?e:[e]},r.Parser.prototype.parseString=function(e){var t=0;return"b"===e[0]&&(t=1),"'"===e[t]?e=e.replace(["\\\\","\\'"],["\\","'"]):e=this.parseEscapeSequences(e,'"'),e},r.Parser.prototype.parseEscapeSequences=function(e,t){undefined!==t&&(e=e.replace(new RegExp("\\"+t,"g"),t));var n={"\\":"\\",$:"$",n:"\n",r:"\r",t:"	",f:"\f",v:"",e:""};return e.replace(/~\\\\([\\\\$nrtfve]|[xX][0-9a-fA-F]{1,2}|[0-7]{1,3})~/g,function(e){var t=e[1];return n[t]!==undefined?n[t]:"x"===t[0]||"X"===t[0]?chr(hexdec(t)):chr(octdec(t))})},r.Parser.prototype.TOKEN_NONE=-1,r.Parser.prototype.TOKEN_INVALID=149,r.Parser.prototype.TOKEN_MAP_SIZE=384,r.Parser.prototype.YYLAST=913,r.Parser.prototype.YY2TBLSTATE=328,r.Parser.prototype.YYGLAST=415,r.Parser.prototype.YYNLSTATES=544,r.Parser.prototype.YYUNEXPECTED=32767,r.Parser.prototype.YYDEFAULT=-32766,r.Parser.prototype.YYERRTOK=256,r.Parser.prototype.T_INCLUDE=257,r.Parser.prototype.T_INCLUDE_ONCE=258,r.Parser.prototype.T_EVAL=259,r.Parser.prototype.T_REQUIRE=260,r.Parser.prototype.T_REQUIRE_ONCE=261,r.Parser.prototype.T_LOGICAL_OR=262,r.Parser.prototype.T_LOGICAL_XOR=263,r.Parser.prototype.T_LOGICAL_AND=264,r.Parser.prototype.T_PRINT=265,r.Parser.prototype.T_PLUS_EQUAL=266,r.Parser.prototype.T_MINUS_EQUAL=267,r.Parser.prototype.T_MUL_EQUAL=268,r.Parser.prototype.T_DIV_EQUAL=269,r.Parser.prototype.T_CONCAT_EQUAL=270,r.Parser.prototype.T_MOD_EQUAL=271,r.Parser.prototype.T_AND_EQUAL=272,r.Parser.prototype.T_OR_EQUAL=273,r.Parser.prototype.T_XOR_EQUAL=274,r.Parser.prototype.T_SL_EQUAL=275,r.Parser.prototype.T_SR_EQUAL=276,r.Parser.prototype.T_BOOLEAN_OR=277,r.Parser.prototype.T_BOOLEAN_AND=278,r.Parser.prototype.T_IS_EQUAL=279,r.Parser.prototype.T_IS_NOT_EQUAL=280,r.Parser.prototype.T_IS_IDENTICAL=281,r.Parser.prototype.T_IS_NOT_IDENTICAL=282,r.Parser.prototype.T_IS_SMALLER_OR_EQUAL=283,r.Parser.prototype.T_IS_GREATER_OR_EQUAL=284,r.Parser.prototype.T_SL=285,r.Parser.prototype.T_SR=286,r.Parser.prototype.T_INSTANCEOF=287,r.Parser.prototype.T_INC=288,r.Parser.prototype.T_DEC=289,r.Parser.prototype.T_INT_CAST=290,r.Parser.prototype.T_DOUBLE_CAST=291,r.Parser.prototype.T_STRING_CAST=292,r.Parser.prototype.T_ARRAY_CAST=293,r.Parser.prototype.T_OBJECT_CAST=294,r.Parser.prototype.T_BOOL_CAST=295,r.Parser.prototype.T_UNSET_CAST=296,r.Parser.prototype.T_NEW=297,r.Parser.prototype.T_CLONE=298,r.Parser.prototype.T_EXIT=299,r.Parser.prototype.T_IF=300,r.Parser.prototype.T_ELSEIF=301,r.Parser.prototype.T_ELSE=302,r.Parser.prototype.T_ENDIF=303,r.Parser.prototype.T_LNUMBER=304,r.Parser.prototype.T_DNUMBER=305,r.Parser.prototype.T_STRING=306,r.Parser.prototype.T_STRING_VARNAME=307,r.Parser.prototype.T_VARIABLE=308,r.Parser.prototype.T_NUM_STRING=309,r.Parser.prototype.T_INLINE_HTML=310,r.Parser.prototype.T_CHARACTER=311,r.Parser.prototype.T_BAD_CHARACTER=312,r.Parser.prototype.T_ENCAPSED_AND_WHITESPACE=313,r.Parser.prototype.T_CONSTANT_ENCAPSED_STRING=314,r.Parser.prototype.T_ECHO=315,r.Parser.prototype.T_DO=316,r.Parser.prototype.T_WHILE=317,r.Parser.prototype.T_ENDWHILE=318,r.Parser.prototype.T_FOR=319,r.Parser.prototype.T_ENDFOR=320,r.Parser.prototype.T_FOREACH=321,r.Parser.prototype.T_ENDFOREACH=322,r.Parser.prototype.T_DECLARE=323,r.Parser.prototype.T_ENDDECLARE=324,r.Parser.prototype.T_AS=325,r.Parser.prototype.T_SWITCH=326,r.Parser.prototype.T_ENDSWITCH=327,r.Parser.prototype.T_CASE=328,r.Parser.prototype.T_DEFAULT=329,r.Parser.prototype.T_BREAK=330,r.Parser.prototype.T_CONTINUE=331,r.Parser.prototype.T_GOTO=332,r.Parser.prototype.T_FUNCTION=333,r.Parser.prototype.T_CONST=334,r.Parser.prototype.T_RETURN=335,r.Parser.prototype.T_TRY=336,r.Parser.prototype.T_CATCH=337,r.Parser.prototype.T_THROW=338,r.Parser.prototype.T_USE=339,r.Parser.prototype.T_INSTEADOF=340,r.Parser.prototype.T_GLOBAL=341,r.Parser.prototype.T_STATIC=342,r.Parser.prototype.T_ABSTRACT=343,r.Parser.prototype.T_FINAL=344,r.Parser.prototype.T_PRIVATE=345,r.Parser.prototype.T_PROTECTED=346,r.Parser.prototype.T_PUBLIC=347,r.Parser.prototype.T_VAR=348,r.Parser.prototype.T_UNSET=349,r.Parser.prototype.T_ISSET=350,r.Parser.prototype.T_EMPTY=351,r.Parser.prototype.T_HALT_COMPILER=352,r.Parser.prototype.T_CLASS=353,r.Parser.prototype.T_TRAIT=354,r.Parser.prototype.T_INTERFACE=355,r.Parser.prototype.T_EXTENDS=356,r.Parser.prototype.T_IMPLEMENTS=357,r.Parser.prototype.T_OBJECT_OPERATOR=358,r.Parser.prototype.T_DOUBLE_ARROW=359,r.Parser.prototype.T_LIST=360,r.Parser.prototype.T_ARRAY=361,r.Parser.prototype.T_CALLABLE=362,r.Parser.prototype.T_CLASS_C=363,r.Parser.prototype.T_TRAIT_C=364,r.Parser.prototype.T_METHOD_C=365,r.Parser.prototype.T_FUNC_C=366,r.Parser.prototype.T_LINE=367,r.Parser.prototype.T_FILE=368,r.Parser.prototype.T_COMMENT=369,r.Parser.prototype.T_DOC_COMMENT=370,r.Parser.prototype.T_OPEN_TAG=371,r.Parser.prototype.T_OPEN_TAG_WITH_ECHO=372,r.Parser.prototype.T_CLOSE_TAG=373,r.Parser.prototype.T_WHITESPACE=374,r.Parser.prototype.T_START_HEREDOC=375,r.Parser.prototype.T_END_HEREDOC=376,r.Parser.prototype.T_DOLLAR_OPEN_CURLY_BRACES=377,r.Parser.prototype.T_CURLY_OPEN=378,r.Parser.prototype.T_PAAMAYIM_NEKUDOTAYIM=379,r.Parser.prototype.T_NAMESPACE=380,r.Parser.prototype.T_NS_C=381,r.Parser.prototype.T_DIR=382,r.Parser.prototype.T_NS_SEPARATOR=383,r.Parser.prototype.terminals=["$EOF","error","T_INCLUDE","T_INCLUDE_ONCE","T_EVAL","T_REQUIRE","T_REQUIRE_ONCE","','","T_LOGICAL_OR","T_LOGICAL_XOR","T_LOGICAL_AND","T_PRINT","'='","T_PLUS_EQUAL","T_MINUS_EQUAL","T_MUL_EQUAL","T_DIV_EQUAL","T_CONCAT_EQUAL","T_MOD_EQUAL","T_AND_EQUAL","T_OR_EQUAL","T_XOR_EQUAL","T_SL_EQUAL","T_SR_EQUAL","'?'","':'","T_BOOLEAN_OR","T_BOOLEAN_AND","'|'","'^'","'&'","T_IS_EQUAL","T_IS_NOT_EQUAL","T_IS_IDENTICAL","T_IS_NOT_IDENTICAL","'<'","T_IS_SMALLER_OR_EQUAL","'>'","T_IS_GREATER_OR_EQUAL","T_SL","T_SR","'+'","'-'","'.'","'*'","'/'","'%'","'!'","T_INSTANCEOF","'~'","T_INC","T_DEC","T_INT_CAST","T_DOUBLE_CAST","T_STRING_CAST","T_ARRAY_CAST","T_OBJECT_CAST","T_BOOL_CAST","T_UNSET_CAST","'@'","'['","T_NEW","T_CLONE","T_EXIT","T_IF","T_ELSEIF","T_ELSE","T_ENDIF","T_LNUMBER","T_DNUMBER","T_STRING","T_STRING_VARNAME","T_VARIABLE","T_NUM_STRING","T_INLINE_HTML","T_ENCAPSED_AND_WHITESPACE","T_CONSTANT_ENCAPSED_STRING","T_ECHO","T_DO","T_WHILE","T_ENDWHILE","T_FOR","T_ENDFOR","T_FOREACH","T_ENDFOREACH","T_DECLARE","T_ENDDECLARE","T_AS","T_SWITCH","T_ENDSWITCH","T_CASE","T_DEFAULT","T_BREAK","T_CONTINUE","T_GOTO","T_FUNCTION","T_CONST","T_RETURN","T_TRY","T_CATCH","T_THROW","T_USE","T_INSTEADOF","T_GLOBAL","T_STATIC","T_ABSTRACT","T_FINAL","T_PRIVATE","T_PROTECTED","T_PUBLIC","T_VAR","T_UNSET","T_ISSET","T_EMPTY","T_HALT_COMPILER","T_CLASS","T_TRAIT","T_INTERFACE","T_EXTENDS","T_IMPLEMENTS","T_OBJECT_OPERATOR","T_DOUBLE_ARROW","T_LIST","T_ARRAY","T_CALLABLE","T_CLASS_C","T_TRAIT_C","T_METHOD_C","T_FUNC_C","T_LINE","T_FILE","T_START_HEREDOC","T_END_HEREDOC","T_DOLLAR_OPEN_CURLY_BRACES","T_CURLY_OPEN","T_PAAMAYIM_NEKUDOTAYIM","T_NAMESPACE","T_NS_C","T_DIR","T_NS_SEPARATOR","';'","'{'","'}'","'('","')'","'$'","']'","'`'","'\"'","???"],r.Parser.prototype.translate=[0,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,47,148,149,145,46,30,149,143,144,44,41,7,42,43,45,149,149,149,149,149,149,149,149,149,149,25,140,35,12,37,24,59,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,60,149,146,29,149,147,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,141,28,142,49,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,1,2,3,4,5,6,8,9,10,11,13,14,15,16,17,18,19,20,21,22,23,26,27,31,32,33,34,36,38,39,40,48,50,51,52,53,54,55,56,57,58,61,62,63,64,65,66,67,68,69,70,71,72,73,74,149,149,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,149,149,149,149,149,149,131,132,133,134,135,136,137,138,139],r.Parser.prototype.yyaction=[61,62,363,63,64,-32766,-32766,-32766,509,65,708,709,710,707,706,705,-32766,-32766,-32766,-32766,-32766,-32766,132,-32766,-32766,-32766,-32766,-32766,-32767,-32767,-32767,-32767,-32766,335,-32766,-32766,-32766,-32766,-32766,66,67,351,663,664,40,68,548,69,232,233,70,71,72,73,74,75,76,77,30,246,78,336,364,-112,0,469,833,834,365,641,890,436,590,41,835,53,27,366,294,367,687,368,921,369,923,922,370,-32766,-32766,-32766,42,43,371,339,126,44,372,337,79,297,349,292,293,-32766,918,-32766,-32766,373,374,375,376,377,391,199,361,338,573,613,378,379,380,381,845,839,840,841,842,836,837,253,-32766,87,88,89,391,843,838,338,597,519,128,80,129,273,332,257,261,47,673,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,799,247,884,108,109,110,226,247,21,-32766,310,-32766,-32766,-32766,642,548,-32766,-32766,-32766,-32766,56,353,-32766,-32766,-32766,55,-32766,-32766,-32766,-32766,-32766,58,-32766,-32766,-32766,-32766,-32766,-32766,-32766,-32766,-32766,557,-32766,-32766,518,-32766,548,890,-32766,390,-32766,228,252,-32766,-32766,-32766,-32766,-32766,275,-32766,234,-32766,587,588,-32766,-32766,-32766,-32766,-32766,-32766,-32766,46,236,-32766,-32766,281,-32766,682,348,-32766,390,-32766,346,333,521,-32766,-32766,-32766,271,911,262,237,446,911,-32766,894,59,700,358,135,548,123,538,35,-32766,333,122,-32766,-32766,-32766,271,-32766,124,-32766,692,-32766,-32766,-32766,-32766,700,273,22,-32766,-32766,-32766,-32766,239,-32766,-32766,612,-32766,548,134,-32766,390,-32766,462,354,-32766,-32766,-32766,-32766,-32766,227,-32766,238,-32766,845,542,-32766,856,611,200,-32766,-32766,-32766,259,280,-32766,-32766,201,-32766,855,129,-32766,390,130,202,333,206,-32766,-32766,-32766,271,-32766,-32766,-32766,125,601,-32766,136,299,700,489,28,548,105,106,107,-32766,498,499,-32766,-32766,-32766,207,-32766,133,-32766,525,-32766,-32766,-32766,-32766,663,664,527,-32766,-32766,-32766,-32766,528,-32766,-32766,610,-32766,548,427,-32766,390,-32766,532,539,-32766,-32766,-32766,-32766,-32766,240,-32766,247,-32766,697,543,-32766,554,523,608,-32766,-32766,-32766,686,535,-32766,-32766,54,-32766,57,60,-32766,390,246,-155,278,345,-32766,-32766,-32766,506,347,-152,471,402,403,-32766,405,404,272,493,416,548,318,417,505,-32766,517,548,-32766,-32766,-32766,549,-32766,562,-32766,916,-32766,-32766,-32766,-32766,564,826,848,-32766,-32766,-32766,-32766,694,-32766,-32766,485,-32766,548,487,-32766,390,-32766,504,802,-32766,-32766,-32766,-32766,-32766,279,-32766,911,-32766,502,492,-32766,413,483,269,-32766,-32766,-32766,243,337,-32766,-32766,418,-32766,454,229,-32766,390,274,373,374,344,-32766,-32766,-32766,360,614,-32766,573,613,378,379,-274,548,615,-332,844,-32766,258,51,-32766,-32766,-32766,270,-32766,346,-32766,52,-32766,260,0,-32766,-333,-32766,-32766,-32766,-32766,-32766,-32766,205,-32766,-32766,49,-32766,548,424,-32766,390,-32766,-266,264,-32766,-32766,-32766,-32766,-32766,409,-32766,343,-32766,265,312,-32766,470,513,-275,-32766,-32766,-32766,920,337,-32766,-32766,530,-32766,531,600,-32766,390,592,373,374,578,581,-32766,-32766,644,629,-32766,573,613,378,379,635,548,636,576,627,-32766,625,693,-32766,-32766,-32766,691,-32766,591,-32766,582,-32766,203,204,-32766,584,583,-32766,-32766,-32766,-32766,586,599,-32766,-32766,589,-32766,690,558,-32766,390,197,683,919,86,520,522,-32766,524,833,834,529,533,-32766,534,537,541,835,48,111,112,113,114,115,116,117,118,119,120,121,127,31,633,337,330,634,585,-32766,32,291,337,330,478,373,374,917,291,891,889,875,373,374,553,613,378,379,737,739,887,553,613,378,379,824,451,675,839,840,841,842,836,837,320,895,277,885,23,33,843,838,556,277,337,330,-32766,34,-32766,555,291,36,37,38,373,374,39,45,50,81,82,83,84,553,613,378,379,-32767,-32767,-32767,-32767,103,104,105,106,107,337,85,131,137,337,138,198,224,225,277,373,374,-332,230,373,374,24,337,231,573,613,378,379,573,613,378,379,373,374,235,248,249,250,337,251,0,573,613,378,379,276,329,331,373,374,-32766,337,574,490,792,337,609,573,613,378,379,373,374,25,300,373,374,319,337,795,573,613,378,379,573,613,378,379,373,374,516,355,359,445,482,796,507,573,613,378,379,508,548,337,890,775,791,337,604,803,808,806,698,373,374,888,807,373,374,-32766,-32766,-32766,573,613,378,379,573,613,378,379,873,832,804,872,851,-32766,809,-32766,-32766,-32766,-32766,805,20,26,29,298,480,515,770,778,827,457,0,900,455,774,0,0,0,874,870,886,823,915,852,869,488,0,391,793,0,338,0,0,0,340,0,273],r.Parser.prototype.yycheck=[2,3,4,5,6,8,9,10,70,11,104,105,106,107,108,109,8,9,10,8,9,24,60,26,27,28,29,30,31,32,33,34,24,7,26,27,28,29,30,41,42,7,123,124,7,47,70,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,144,0,75,68,69,70,25,72,70,74,7,76,77,78,79,7,81,142,83,70,85,72,73,88,8,9,10,92,93,94,95,7,97,98,95,100,7,7,103,104,24,142,26,27,105,106,111,112,113,136,7,7,139,114,115,116,117,122,123,132,125,126,127,128,129,130,131,8,8,9,10,136,137,138,139,140,141,25,143,141,145,142,147,148,24,72,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,144,48,72,44,45,46,30,48,144,64,72,8,9,10,140,70,8,9,10,74,60,25,77,78,79,60,81,24,83,26,85,60,24,88,26,27,28,92,93,94,64,140,97,98,70,100,70,72,103,104,74,145,7,77,78,79,111,81,7,83,30,85,140,140,88,8,9,10,92,93,94,133,134,97,98,145,100,140,7,103,104,24,139,96,141,140,141,111,101,75,75,30,70,75,64,70,60,110,121,12,70,141,25,143,74,96,141,77,78,79,101,81,141,83,140,85,140,141,88,110,145,144,92,93,94,64,7,97,98,142,100,70,141,103,104,74,145,141,77,78,79,111,81,7,83,30,85,132,25,88,132,142,12,92,93,94,120,60,97,98,12,100,148,141,103,104,141,12,96,12,140,141,111,101,8,9,10,141,25,64,90,91,110,65,66,70,41,42,43,74,65,66,77,78,79,12,81,25,83,25,85,140,141,88,123,124,25,92,93,94,64,25,97,98,142,100,70,120,103,104,74,25,25,77,78,79,111,81,30,83,48,85,140,141,88,140,141,30,92,93,94,140,141,97,98,60,100,60,60,103,104,61,72,75,70,140,141,111,67,70,87,99,70,70,64,70,72,102,89,70,70,71,70,70,74,70,70,77,78,79,70,81,70,83,70,85,140,141,88,70,144,70,92,93,94,64,70,97,98,72,100,70,72,103,104,74,72,72,77,78,79,111,81,75,83,75,85,89,86,88,79,101,118,92,93,94,87,95,97,98,87,100,87,87,103,104,118,105,106,95,140,141,111,95,115,64,114,115,116,117,135,70,115,120,132,74,120,140,77,78,79,119,81,139,83,140,85,120,-1,88,120,140,141,92,93,94,64,121,97,98,121,100,70,122,103,104,74,135,135,77,78,79,111,81,139,83,139,85,135,135,88,135,135,135,92,93,94,142,95,97,98,140,100,140,140,103,104,140,105,106,140,140,141,111,140,140,64,114,115,116,117,140,70,140,140,140,74,140,140,77,78,79,140,81,140,83,140,85,41,42,88,140,140,141,92,93,94,140,140,97,98,140,100,140,140,103,104,60,140,142,141,141,141,111,141,68,69,141,141,72,141,141,141,76,12,13,14,15,16,17,18,19,20,21,22,23,141,143,142,95,96,142,140,141,143,101,95,96,142,105,106,142,101,142,142,142,105,106,114,115,116,117,50,51,142,114,115,116,117,142,123,142,125,126,127,128,129,130,131,142,136,142,144,143,137,138,142,136,95,96,143,143,145,142,101,143,143,143,105,106,143,143,143,143,143,143,143,114,115,116,117,35,36,37,38,39,40,41,42,43,95,143,143,143,95,143,143,143,143,136,105,106,120,143,105,106,144,95,143,114,115,116,117,114,115,116,117,105,106,143,143,143,143,95,143,-1,114,115,116,117,143,143,143,105,106,143,95,142,80,146,95,142,114,115,116,117,105,106,144,144,105,106,144,95,142,114,115,116,117,114,115,116,117,105,106,82,144,144,144,144,142,84,114,115,116,117,144,70,95,72,144,144,95,142,144,146,144,142,105,106,146,144,105,106,8,9,10,114,115,116,117,114,115,116,117,144,144,144,144,144,24,104,26,27,28,29,144,144,144,144,144,144,144,144,144,144,144,-1,144,144,144,-1,-1,-1,146,146,146,146,146,146,146,146,-1,136,147,-1,139,-1,-1,-1,143,-1,145],r.Parser.prototype.yybase=[0,574,581,623,655,2,718,402,747,659,672,688,743,701,705,483,483,483,483,483,351,356,366,366,367,366,344,-2,-2,-2,200,200,231,231,231,231,231,231,231,231,200,231,451,482,532,316,370,115,146,285,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,401,44,474,429,476,481,487,488,739,740,741,734,733,416,736,539,541,342,542,543,552,557,559,536,567,737,755,569,735,738,123,123,123,123,123,123,123,123,123,122,11,336,336,336,336,336,336,336,336,336,336,336,336,336,336,336,227,227,173,577,577,577,577,577,577,577,577,577,577,577,79,178,846,8,-3,-3,-3,-3,642,706,706,706,706,157,179,242,431,431,360,431,525,368,767,767,767,767,767,767,767,767,767,767,767,767,350,375,315,315,652,652,-81,-81,-81,-81,251,185,188,184,-62,348,195,195,195,408,392,410,1,192,129,129,129,-24,-24,-24,-24,499,-24,-24,-24,113,108,108,12,161,349,526,271,398,529,438,130,206,265,427,76,414,427,288,295,76,166,44,262,422,141,491,372,494,413,71,92,93,267,135,100,34,415,745,746,742,-38,420,-10,135,147,744,498,107,26,493,144,377,363,369,332,363,400,377,588,377,376,377,360,37,582,376,377,374,376,388,363,364,412,369,377,441,443,390,106,332,377,390,377,400,64,590,591,323,592,589,593,649,608,362,500,399,407,620,625,636,365,354,614,524,425,359,355,423,570,578,357,406,414,394,352,403,531,433,403,653,434,385,417,411,444,310,318,501,425,668,757,380,637,684,403,609,387,87,325,638,382,403,639,403,696,503,615,403,697,384,435,425,352,352,352,700,66,699,583,702,707,704,748,721,749,584,750,358,583,722,751,682,215,613,422,436,389,447,221,257,752,403,403,506,499,403,395,685,397,426,753,392,391,647,683,403,418,754,221,723,587,724,450,568,507,648,509,327,725,353,497,610,454,622,455,461,404,510,373,732,612,247,361,664,463,405,692,641,464,465,511,343,437,335,409,396,665,293,467,468,472,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,0,0,0,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,0,0,0,0,0,0,0,0,0,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,767,767,767,767,767,767,767,767,767,767,767,123,123,123,123,123,123,123,123,0,129,129,129,129,-94,-94,-94,767,767,767,767,767,767,0,0,0,0,0,0,0,0,0,0,0,0,-94,-94,129,129,767,767,-24,-24,-24,-24,-24,108,108,108,-24,108,145,145,145,108,108,108,100,100,0,0,0,0,0,0,0,145,0,0,0,376,0,0,0,145,260,260,221,260,260,135,0,0,425,376,0,364,376,0,0,0,0,0,0,531,0,87,637,241,425,0,0,0,0,0,0,0,425,289,289,306,0,358,0,0,0,306,241,0,0,221],r.Parser.prototype.yydefault=[3,32767,32767,1,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,104,96,110,95,106,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,358,358,122,122,122,122,122,122,122,122,316,32767,32767,32767,32767,32767,32767,32767,32767,32767,173,173,173,32767,348,348,348,348,348,348,348,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,363,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,232,233,235,236,172,125,349,362,171,199,201,250,200,177,182,183,184,185,186,187,188,189,190,191,192,176,229,228,197,313,313,316,32767,32767,32767,32767,32767,32767,32767,32767,198,202,204,203,219,220,217,218,175,221,222,223,224,157,157,157,357,357,32767,357,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,158,32767,211,212,276,276,117,117,117,117,117,32767,32767,32767,32767,284,32767,32767,32767,32767,32767,286,32767,32767,206,207,205,32767,32767,32767,32767,32767,32767,32767,32767,32767,285,32767,32767,32767,32767,32767,32767,32767,32767,334,321,272,32767,32767,32767,265,32767,107,109,32767,32767,32767,32767,302,339,32767,32767,32767,17,32767,32767,32767,370,334,32767,32767,19,32767,32767,32767,32767,227,32767,338,332,32767,32767,32767,32767,32767,32767,63,32767,32767,32767,32767,32767,63,281,63,32767,63,32767,315,287,32767,63,74,32767,72,32767,32767,76,32767,63,93,93,254,315,54,63,254,63,32767,32767,32767,32767,4,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,267,32767,323,32767,337,336,324,32767,265,32767,215,194,266,32767,196,32767,32767,270,273,32767,32767,32767,134,32767,268,180,32767,32767,32767,32767,365,32767,32767,174,32767,32767,32767,130,32767,61,332,32767,32767,355,32767,32767,332,269,208,209,210,32767,121,32767,310,32767,32767,32767,32767,32767,32767,327,32767,333,32767,32767,32767,32767,111,32767,302,32767,32767,32767,75,32767,32767,178,126,32767,32767,364,32767,32767,32767,320,32767,32767,32767,32767,32767,62,32767,32767,77,32767,32767,32767,32767,332,32767,32767,32767,115,32767,169,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,332,32767,32767,32767,32767,32767,32767,32767,4,32767,151,32767,32767,32767,32767,32767,32767,32767,25,25,3,137,3,137,25,101,25,25,137,93,93,25,25,25,144,25,25,25,25,25,25,25,25],r.Parser.prototype.yygoto=[141,141,173,173,173,173,173,173,173,173,141,173,142,143,144,148,153,155,181,175,172,172,172,172,174,174,174,174,174,174,174,168,169,170,171,179,757,758,392,760,781,782,783,784,785,786,787,789,725,145,146,147,149,150,151,152,154,177,178,180,196,208,209,210,211,212,213,214,215,217,218,219,220,244,245,266,267,268,430,431,432,182,183,184,185,186,187,188,189,190,191,192,156,157,158,159,176,160,194,161,162,163,164,195,165,193,139,166,167,452,452,452,452,452,452,452,452,452,452,452,453,453,453,453,453,453,453,453,453,453,453,551,551,551,464,491,394,394,394,394,394,394,394,394,394,394,394,394,394,394,394,394,394,394,407,552,552,552,810,810,662,662,662,662,662,594,283,595,510,399,399,567,679,632,849,850,863,660,714,426,222,622,622,622,622,223,617,623,494,395,395,395,395,395,395,395,395,395,395,395,395,395,395,395,395,395,395,465,472,514,904,398,398,425,425,459,425,419,322,421,421,393,396,412,422,428,460,463,473,481,501,5,476,284,327,1,15,2,6,7,550,550,550,8,9,10,668,16,11,17,12,18,13,19,14,704,328,881,881,643,628,626,626,624,626,526,401,652,647,847,847,847,847,847,847,847,847,847,847,847,437,438,441,447,477,479,497,290,910,910,400,400,486,880,880,263,913,910,303,255,723,306,822,821,306,896,896,896,861,304,323,410,913,913,897,316,420,769,658,559,879,671,536,324,466,565,311,311,311,801,241,676,496,439,440,442,444,448,475,631,858,311,285,286,603,495,712,0,406,321,0,0,0,314,0,0,429,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,411],r.Parser.prototype.yygcheck=[15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35,35,35,35,35,35,35,35,35,35,35,86,86,86,86,86,86,86,86,86,86,86,6,6,6,21,21,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,71,7,7,7,35,35,35,35,35,35,35,29,44,29,35,86,86,12,12,12,12,12,12,12,12,75,40,35,35,35,35,40,35,35,35,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,36,36,36,104,82,82,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,13,42,42,42,2,13,2,13,13,5,5,5,13,13,13,54,13,13,13,13,13,13,13,13,67,67,83,83,5,5,5,5,5,5,5,5,5,5,93,93,93,93,93,93,93,93,93,93,93,52,52,52,52,52,52,52,4,105,105,89,89,94,84,84,92,105,105,26,92,71,4,91,91,4,84,84,84,97,30,70,30,105,105,102,27,30,72,50,10,84,55,46,9,30,11,90,90,90,80,30,56,30,85,85,85,85,85,85,43,96,90,44,44,34,77,69,-1,4,90,-1,-1,-1,4,-1,-1,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,71],r.Parser.prototype.yygbase=[0,0,-286,0,10,239,130,154,0,-10,25,-23,-29,-289,0,-30,0,0,0,0,0,83,0,0,0,0,245,84,-11,142,-28,0,0,0,-13,-88,-42,0,0,0,-344,0,-38,-12,-188,0,23,0,0,0,66,0,247,0,205,24,-18,0,0,0,0,0,0,0,0,0,0,13,0,-15,85,74,70,0,0,148,0,-14,0,0,-6,0,-35,11,47,278,-77,0,0,44,68,43,38,72,94,0,-16,109,0,0,0,0,87,0,170,34,0],r.Parser.prototype.yygdefault=[-32768,362,3,546,382,570,571,572,307,305,560,566,467,4,568,140,295,575,296,500,577,414,579,580,308,309,415,315,216,593,503,313,596,357,602,301,449,383,350,461,221,423,456,630,282,638,540,646,649,450,657,352,433,434,667,672,677,680,334,325,474,684,685,256,689,511,512,703,242,711,317,724,342,788,790,397,408,484,797,326,800,384,385,386,387,435,818,815,289,866,287,443,254,853,468,356,903,862,288,388,389,302,898,341,905,912,458],r.Parser.prototype.yylhs=[0,1,2,2,4,4,3,3,3,3,3,3,3,3,3,8,8,10,10,10,10,9,9,11,13,13,14,14,14,14,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,33,33,34,27,27,30,30,6,7,7,7,37,37,37,38,38,41,41,39,39,42,42,22,22,29,29,32,32,31,31,43,23,23,23,23,44,44,45,45,46,46,20,20,16,16,47,18,18,48,17,17,19,19,36,36,49,49,50,50,51,51,51,51,52,52,53,53,54,54,24,24,55,55,55,25,25,56,56,40,40,57,57,57,57,62,62,63,63,64,64,64,64,65,66,66,61,61,58,58,60,60,68,68,67,67,67,67,67,67,59,59,69,69,26,26,21,21,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,71,77,77,79,79,80,81,81,81,81,81,81,86,86,35,35,35,72,72,87,87,82,82,88,88,88,88,88,73,73,73,76,76,76,78,78,93,93,93,93,93,93,93,93,93,93,93,93,93,93,12,12,12,12,12,12,74,74,74,74,94,94,96,96,95,95,97,97,28,28,28,28,99,99,98,98,98,98,98,100,100,84,84,89,89,83,83,101,101,101,101,90,90,90,90,85,85,91,91,91,70,70,102,102,102,75,75,103,103,104,104,104,104,92,92,92,92,105,105,105,105,105,105,105,106,106,106],r.Parser.prototype.yylen=[1,1,2,0,1,3,1,1,1,1,3,5,4,3,3,3,1,1,3,2,4,3,1,3,2,0,1,1,1,1,3,7,10,5,7,9,5,2,3,2,3,2,3,3,3,3,1,2,5,7,8,10,5,1,5,3,3,2,1,2,8,1,3,0,1,9,7,6,5,1,2,2,0,2,0,2,0,2,1,3,1,4,1,4,1,4,1,3,3,3,4,4,5,0,2,4,3,1,1,1,4,0,2,5,0,2,6,0,2,0,3,1,0,1,3,3,5,0,1,1,1,1,0,1,3,1,2,3,1,1,2,4,3,1,1,3,2,0,3,3,8,3,1,3,0,2,4,5,4,4,3,1,1,1,3,1,1,0,1,1,2,1,1,1,1,1,1,1,3,1,3,3,1,0,1,1,6,3,4,4,1,2,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,5,4,4,4,2,2,4,2,2,2,2,2,2,2,2,2,2,2,1,4,3,3,2,9,10,3,0,4,1,3,2,4,6,8,4,4,4,1,1,1,2,3,1,1,1,1,1,1,0,3,3,4,4,0,2,3,0,1,1,0,3,1,1,1,1,1,1,1,1,1,1,1,3,2,1,1,3,2,2,4,3,1,3,3,3,0,2,0,1,3,1,3,1,1,1,1,1,6,4,3,6,4,4,4,1,3,1,2,1,1,4,1,3,6,4,4,4,4,1,4,0,1,1,3,1,3,1,1,4,0,0,2,3,1,3,1,4,2,2,2,1,2,1,4,3,3,3,6,3,1,1,1],r.Parser.prototype.yyn0=function(){this.yyval=this.yyastk[this.stackPos]},r.Parser.prototype.yyn1=function(e){this.yyval=this.Stmt_Namespace_postprocess(this.yyastk[this.stackPos-0])},r.Parser.prototype.yyn2=function(e){Array.isArray(this.yyastk[this.stackPos-0])?this.yyval=this.yyastk[this.stackPos-1].concat(this.yyastk[this.stackPos-0]):(this.yyastk[this.stackPos-1].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-1])},r.Parser.prototype.yyn3=function(e){this.yyval=[]},r.Parser.prototype.yyn4=function(e){this.yyval=[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn5=function(e){this.yyastk[this.stackPos-2].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn6=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn7=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn8=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn9=function(e){this.yyval=this.Node_Stmt_HaltCompiler(e)},r.Parser.prototype.yyn10=function(e){this.yyval=this.Node_Stmt_Namespace(this.Node_Name(this.yyastk[this.stackPos-1],e),null,e)},r.Parser.prototype.yyn11=function(e){this.yyval=this.Node_Stmt_Namespace(this.Node_Name(this.yyastk[this.stackPos-3],e),this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn12=function(e){this.yyval=this.Node_Stmt_Namespace(null,this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn13=function(e){this.yyval=this.Node_Stmt_Use(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn14=function(e){this.yyval=this.Node_Stmt_Const(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn15=function(e){this.yyastk[this.stackPos-2].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn16=function(e){this.yyval=[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn17=function(e){this.yyval=this.Node_Stmt_UseUse(this.Node_Name(this.yyastk[this.stackPos-0],e),null,e)},r.Parser.prototype.yyn18=function(e){this.yyval=this.Node_Stmt_UseUse(this.Node_Name(this.yyastk[this.stackPos-2],e),this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn19=function(e){this.yyval=this.Node_Stmt_UseUse(this.Node_Name(this.yyastk[this.stackPos-0],e),null,e)},r.Parser.prototype.yyn20=function(e){this.yyval=this.Node_Stmt_UseUse(this.Node_Name(this.yyastk[this.stackPos-2],e),this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn21=function(e){this.yyastk[this.stackPos-2].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn22=function(e){this.yyval=[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn23=function(e){this.yyval=this.Node_Const(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn24=function(e){Array.isArray(this.yyastk[this.stackPos-0])?this.yyval=this.yyastk[this.stackPos-1].concat(this.yyastk[this.stackPos-0]):(this.yyastk[this.stackPos-1].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-1])},r.Parser.prototype.yyn25=function(e){this.yyval=[]},r.Parser.prototype.yyn26=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn27=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn28=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn29=function(e){throw new Error("__halt_compiler() can only be used from the outermost scope")},r.Parser.prototype.yyn30=function(e){this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn31=function(e){this.yyval=this.Node_Stmt_If(this.yyastk[this.stackPos-4],{stmts:Array.isArray(this.yyastk[this.stackPos-2])?this.yyastk[this.stackPos-2]:[this.yyastk[this.stackPos-2]],elseifs:this.yyastk[this.stackPos-1],Else:this.yyastk[this.stackPos-0]},e)},r.Parser.prototype.yyn32=function(e){this.yyval=this.Node_Stmt_If(this.yyastk[this.stackPos-7],{stmts:this.yyastk[this.stackPos-4],elseifs:this.yyastk[this.stackPos-3],"else":this.yyastk[this.stackPos-2]},e)},r.Parser.prototype.yyn33=function(e){this.yyval=this.Node_Stmt_While(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn34=function(e){this.yyval=this.Node_Stmt_Do(this.yyastk[this.stackPos-2],Array.isArray(this.yyastk[this.stackPos-5])?this.yyastk[this.stackPos-5]:[this.yyastk[this.stackPos-5]],e)},r.Parser.prototype.yyn35=function(e){this.yyval=this.Node_Stmt_For({init:this.yyastk[this.stackPos-6],cond:this.yyastk[this.stackPos-4],loop:this.yyastk[this.stackPos-2],stmts:this.yyastk[this.stackPos-0]},e)},r.Parser.prototype.yyn36=function(e){this.yyval=this.Node_Stmt_Switch(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn37=function(e){this.yyval=this.Node_Stmt_Break(null,e)},r.Parser.prototype.yyn38=function(e){this.yyval=this.Node_Stmt_Break(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn39=function(e){this.yyval=this.Node_Stmt_Continue(null,e)},r.Parser.prototype.yyn40=function(e){this.yyval=this.Node_Stmt_Continue(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn41=function(e){this.yyval=this.Node_Stmt_Return(null,e)},r.Parser.prototype.yyn42=function(e){this.yyval=this.Node_Stmt_Return(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn43=function(e){this.yyval=this.Node_Stmt_Global(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn44=function(e){this.yyval=this.Node_Stmt_Static(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn45=function(e){this.yyval=this.Node_Stmt_Echo(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn46=function(e){this.yyval=this.Node_Stmt_InlineHTML(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn47=function(e){this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn48=function(e){this.yyval=this.Node_Stmt_Unset(this.yyastk[this.stackPos-2],e)},r.Parser.prototype.yyn49=function(e){this.yyval=this.Node_Stmt_Foreach(this.yyastk[this.stackPos-4],this.yyastk[this.stackPos-2],{keyVar:null,byRef:!1,stmts:this.yyastk[this.stackPos-0]},e)},r.Parser.prototype.yyn50=function(e){this.yyval=this.Node_Stmt_Foreach(this.yyastk[this.stackPos-5],this.yyastk[this.stackPos-2],{keyVar:null,byRef:!0,stmts:this.yyastk[this.stackPos-0]},e)},r.Parser.prototype.yyn51=function(e){this.yyval=this.Node_Stmt_Foreach(this.yyastk[this.stackPos-7],this.yyastk[this.stackPos-2],{keyVar:this.yyastk[this.stackPos-5],byRef:this.yyastk[this.stackPos-3],stmts:this.yyastk[this.stackPos-0]},e)},r.Parser.prototype.yyn52=function(e){this.yyval=this.Node_Stmt_Declare(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn53=function(e){this.yyval=[]},r.Parser.prototype.yyn54=function(e){this.yyval=this.Node_Stmt_TryCatch(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn55=function(e){this.yyval=this.Node_Stmt_Throw(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn56=function(e){this.yyval=this.Node_Stmt_Goto(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn57=function(e){this.yyval=this.Node_Stmt_Label(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn58=function(e){this.yyval=[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn59=function(e){this.yyastk[this.stackPos-1].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn60=function(e){this.yyval=this.Node_Stmt_Catch(this.yyastk[this.stackPos-5],this.yyastk[this.stackPos-4].substring(1),this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn61=function(e){this.yyval=[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn62=function(e){this.yyastk[this.stackPos-2].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn63=function(e){this.yyval=!1},r.Parser.prototype.yyn64=function(e){this.yyval=!0},r.Parser.prototype.yyn65=function(e){this.yyval=this.Node_Stmt_Function(this.yyastk[this.stackPos-6],{byRef:this.yyastk[this.stackPos-7],params:this.yyastk[this.stackPos-4],stmts:this.yyastk[this.stackPos-1]},e)},r.Parser.prototype.yyn66=function(e){this.yyval=this.Node_Stmt_Class(this.yyastk[this.stackPos-5],{type:this.yyastk[this.stackPos-6],Extends:this.yyastk[this.stackPos-4],Implements:this.yyastk[this.stackPos-3],stmts:this.yyastk[this.stackPos-1]},e)},r.Parser.prototype.yyn67=function(e){this.yyval=this.Node_Stmt_Interface(this.yyastk[this.stackPos-4],{Extends:this.yyastk[this.stackPos-3],stmts:this.yyastk[this.stackPos-1]},e)},r.Parser.prototype.yyn68=function(e){this.yyval=this.Node_Stmt_Trait(this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn69=function(e){this.yyval=0},r.Parser.prototype.yyn70=function(e){this.yyval=this.MODIFIER_ABSTRACT},r.Parser.prototype.yyn71=function(e){this.yyval=this.MODIFIER_FINAL},r.Parser.prototype.yyn72=function(e){this.yyval=null},r.Parser.prototype.yyn73=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn74=function(e){this.yyval=[]},r.Parser.prototype.yyn75=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn76=function(e){this.yyval=[]},r.Parser.prototype.yyn77=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn78=function(e){this.yyval=[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn79=function(e){this.yyastk[this.stackPos-2].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn80=function(e){this.yyval=Array.isArray(this.yyastk[this.stackPos-0])?this.yyastk[this.stackPos-0]:[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn81=function(e){this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn82=function(e){this.yyval=Array.isArray(this.yyastk[this.stackPos-0])?this.yyastk[this.stackPos-0]:[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn83=function(e){this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn84=function(e){this.yyval=Array.isArray(this.yyastk[this.stackPos-0])?this.yyastk[this.stackPos-0]:[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn85=function(e){this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn86=function(e){this.yyval=[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn87=function(e){this.yyastk[this.stackPos-2].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn88=function(e){this.yyval=this.Node_Stmt_DeclareDeclare(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn89=function(e){this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn90=function(e){this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn91=function(e){this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn92=function(e){this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn93=function(e){this.yyval=[]},r.Parser.prototype.yyn94=function(e){this.yyastk[this.stackPos-1].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn95=function(e){this.yyval=this.Node_Stmt_Case(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn96=function(e){this.yyval=this.Node_Stmt_Case(null,this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn97=function(){this.yyval=this.yyastk[this.stackPos]},r.Parser.prototype.yyn98=function(){this.yyval=this.yyastk[this.stackPos]},r.Parser.prototype.yyn99=function(e){this.yyval=Array.isArray(this.yyastk[this.stackPos-0])?this.yyastk[this.stackPos-0]:[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn100=function(e){this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn101=function(e){this.yyval=[]},r.Parser.prototype.yyn102=function(e){this.yyastk[this.stackPos-1].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn103=function(e){this.yyval=this.Node_Stmt_ElseIf(this.yyastk[this.stackPos-2],Array.isArray(this.yyastk[this.stackPos-0])?this.yyastk[this.stackPos-0]:[this.yyastk[this.stackPos-0]],e)},r.Parser.prototype.yyn104=function(e){this.yyval=[]},r.Parser.prototype.yyn105=function(e){this.yyastk[this.stackPos-1].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn106=function(e){this.yyval=this.Node_Stmt_ElseIf(this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn107=function(e){this.yyval=null},r.Parser.prototype.yyn108=function(e){this.yyval=this.Node_Stmt_Else(Array.isArray(this.yyastk[this.stackPos-0])?this.yyastk[this.stackPos-0]:[this.yyastk[this.stackPos-0]],e)},r.Parser.prototype.yyn109=function(e){this.yyval=null},r.Parser.prototype.yyn110=function(e){this.yyval=this.Node_Stmt_Else(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn111=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn112=function(e){this.yyval=[]},r.Parser.prototype.yyn113=function(e){this.yyval=[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn114=function(e){this.yyastk[this.stackPos-2].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn115=function(e){this.yyval=this.Node_Param(this.yyastk[this.stackPos-0].substring(1),null,this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn116=function(e){this.yyval=this.Node_Param(this.yyastk[this.stackPos-2].substring(1),this.yyastk[this.stackPos-0],this.yyastk[this.stackPos-4],this.yyastk[this.stackPos-3],e)},r.Parser.prototype.yyn117=function(e){this.yyval=null},r.Parser.prototype.yyn118=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn119=function(e){this.yyval="array"},r.Parser.prototype.yyn120=function(e){this.yyval="callable"},r.Parser.prototype.yyn121=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn122=function(e){this.yyval=[]},r.Parser.prototype.yyn123=function(e){this.yyval=[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn124=function(e){this.yyastk[this.stackPos-2].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn125=function(e){this.yyval=this.Node_Arg(this.yyastk[this.stackPos-0],!1,e)},r.Parser.prototype.yyn126=function(e){this.yyval=this.Node_Arg(this.yyastk[this.stackPos-0],!0,e)},r.Parser.prototype.yyn127=function(e){this.yyastk[this.stackPos-2].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn128=function(e){this.yyval=[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn129=function(e){this.yyval=this.Node_Expr_Variable(this.yyastk[this.stackPos-0].substring(1),e)},r.Parser.prototype.yyn130=function(e){this.yyval=this.Node_Expr_Variable(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn131=function(e){this.yyval=this.Node_Expr_Variable(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn132=function(e){this.yyastk[this.stackPos-2].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn133=function(e){this.yyval=[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn134=function(e){this.yyval=this.Node_Stmt_StaticVar(this.yyastk[this.stackPos-0].substring(1),null,e)},r.Parser.prototype.yyn135=function(e){this.yyval=this.Node_Stmt_StaticVar(this.yyastk[this.stackPos-2].substring(1),this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn136=function(e){this.yyastk[this.stackPos-1].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn137=function(e){this.yyval=[]},r.Parser.prototype.yyn138=function(e){this.yyval=this.Node_Stmt_Property(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn139=function(e){this.yyval=this.Node_Stmt_ClassConst(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn140=function(e){this.yyval=this.Node_Stmt_ClassMethod(this.yyastk[this.stackPos-4],{type:this.yyastk[this.stackPos-7],byRef:this.yyastk[this.stackPos-5],params:this.yyastk[this.stackPos-2],stmts:this.yyastk[this.stackPos-0]},e)},r.Parser.prototype.yyn141=function(e){this.yyval=this.Node_Stmt_TraitUse(this.yyastk[this.stackPos-1],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn142=function(e){this.yyval=[]},r.Parser.prototype.yyn143=function(e){this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn144=function(e){this.yyval=[]},r.Parser.prototype.yyn145=function(e){this.yyastk[this.stackPos-1].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn146=function(e){this.yyval=this.Node_Stmt_TraitUseAdaptation_Precedence(this.yyastk[this.stackPos-3][0],this.yyastk[this.stackPos-3][1],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn147=function(e){this.yyval=this.Node_Stmt_TraitUseAdaptation_Alias(this.yyastk[this.stackPos-4][0],this.yyastk[this.stackPos-4][1],this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn148=function(e){this.yyval=this.Node_Stmt_TraitUseAdaptation_Alias(this.yyastk[this.stackPos-3][0],this.yyastk[this.stackPos-3][1],this.yyastk[this.stackPos-1],null,e)},r.Parser.prototype.yyn149=function(e){this.yyval=this.Node_Stmt_TraitUseAdaptation_Alias(this.yyastk[this.stackPos-3][0],this.yyastk[this.stackPos-3][1],null,this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn150=function(e){this.yyval=array(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0])},r.Parser.prototype.yyn151=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn152=function(e){this.yyval=array(null,this.yyastk[this.stackPos-0])},r.Parser.prototype.yyn153=function(e){this.yyval=null},r.Parser.prototype.yyn154=function(e){this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn155=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn156=function(e){this.yyval=this.MODIFIER_PUBLIC},r.Parser.prototype.yyn157=function(e){this.yyval=this.MODIFIER_PUBLIC},r.Parser.prototype.yyn158=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn159=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn160=function(e){this.Stmt_Class_verifyModifier(this.yyastk[this.stackPos-1],this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-1]|this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn161=function(e){this.yyval=this.MODIFIER_PUBLIC},r.Parser.prototype.yyn162=function(e){this.yyval=this.MODIFIER_PROTECTED},r.Parser.prototype.yyn163=function(e){this.yyval=this.MODIFIER_PRIVATE},r.Parser.prototype.yyn164=function(e){this.yyval=this.MODIFIER_STATIC},r.Parser.prototype.yyn165=function(e){this.yyval=this.MODIFIER_ABSTRACT},r.Parser.prototype.yyn166=function(e){this.yyval=this.MODIFIER_FINAL},r.Parser.prototype.yyn167=function(e){this.yyval=[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn168=function(e){this.yyastk[this.stackPos-2].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn169=function(e){this.yyval=this.Node_Stmt_PropertyProperty(this.yyastk[this.stackPos-0].substring(1),null,e)},r.Parser.prototype.yyn170=function(e){this.yyval=this.Node_Stmt_PropertyProperty(this.yyastk[this.stackPos-2].substring(1),this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn171=function(e){this.yyastk[this.stackPos-2].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn172=function(e){this.yyval=[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn173=function(e){this.yyval=[]},r.Parser.prototype.yyn174=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn175=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn176=function(e){this.yyval=this.Node_Expr_AssignList(this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn177=function(e){this.yyval=this.Node_Expr_Assign(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn178=function(e){this.yyval=this.Node_Expr_AssignRef(this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn179=function(e){this.yyval=this.Node_Expr_AssignRef(this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn180=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn181=function(e){this.yyval=this.Node_Expr_Clone(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn182=function(e){this.yyval=this.Node_Expr_AssignPlus(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn183=function(e){this.yyval=this.Node_Expr_AssignMinus(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn184=function(e){this.yyval=this.Node_Expr_AssignMul(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn185=function(e){this.yyval=this.Node_Expr_AssignDiv(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn186=function(e){this.yyval=this.Node_Expr_AssignConcat(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn187=function(e){this.yyval=this.Node_Expr_AssignMod(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn188=function(e){this.yyval=this.Node_Expr_AssignBitwiseAnd(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn189=function(e){this.yyval=this.Node_Expr_AssignBitwiseOr(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn190=function(e){this.yyval=this.Node_Expr_AssignBitwiseXor(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn191=function(e){this.yyval=this.Node_Expr_AssignShiftLeft(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn192=function(e){this.yyval=this.Node_Expr_AssignShiftRight(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn193=function(e){this.yyval=this.Node_Expr_PostInc(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn194=function(e){this.yyval=this.Node_Expr_PreInc(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn195=function(e){this.yyval=this.Node_Expr_PostDec(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn196=function(e){this.yyval=this.Node_Expr_PreDec(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn197=function(e){this.yyval=this.Node_Expr_BooleanOr(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn198=function(e){this.yyval=this.Node_Expr_BooleanAnd(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn199=function(e){this.yyval=this.Node_Expr_LogicalOr(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn200=function(e){this.yyval=this.Node_Expr_LogicalAnd(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn201=function(e){this.yyval=this.Node_Expr_LogicalXor(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn202=function(e){this.yyval=this.Node_Expr_BitwiseOr(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn203=function(e){this.yyval=this.Node_Expr_BitwiseAnd(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn204=function(e){this.yyval=this.Node_Expr_BitwiseXor(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn205=function(e){this.yyval=this.Node_Expr_Concat(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn206=function(e){this.yyval=this.Node_Expr_Plus(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn207=function(e){this.yyval=this.Node_Expr_Minus(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn208=function(e){this.yyval=this.Node_Expr_Mul(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn209=function(e){this.yyval=this.Node_Expr_Div(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn210=function(e){this.yyval=this.Node_Expr_Mod(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn211=function(e){this.yyval=this.Node_Expr_ShiftLeft(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn212=function(e){this.yyval=this.Node_Expr_ShiftRight(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn213=function(e){this.yyval=this.Node_Expr_UnaryPlus(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn214=function(e){this.yyval=this.Node_Expr_UnaryMinus(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn215=function(e){this.yyval=this.Node_Expr_BooleanNot(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn216=function(e){this.yyval=this.Node_Expr_BitwiseNot(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn217=function(e){this.yyval=this.Node_Expr_Identical(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn218=function(e){this.yyval=this.Node_Expr_NotIdentical(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn219=function(e){this.yyval=this.Node_Expr_Equal(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn220=function(e){this.yyval=this.Node_Expr_NotEqual(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn221=function(e){this.yyval=this.Node_Expr_Smaller(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn222=function(e){this.yyval=this.Node_Expr_SmallerOrEqual(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn223=function(e){this.yyval=this.Node_Expr_Greater(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn224=function(e){this.yyval=this.Node_Expr_GreaterOrEqual(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn225=function(e){this.yyval=this.Node_Expr_Instanceof(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn226=function(e){this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn227=function(e){this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn228=function(e){this.yyval=this.Node_Expr_Ternary(this.yyastk[this.stackPos-4],this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn229=function(e){this.yyval=this.Node_Expr_Ternary(this.yyastk[this.stackPos-3],null,this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn230=function(e){this.yyval=this.Node_Expr_Isset(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn231=function(e){this.yyval=this.Node_Expr_Empty(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn232=function(e){this.yyval=this.Node_Expr_Include(this.yyastk[this.stackPos-0],"Node_Expr_Include",e)},r.Parser.prototype.yyn233=function(e){this.yyval=this.Node_Expr_Include(this.yyastk[this.stackPos-0],"Node_Expr_IncludeOnce",e)},r.Parser.prototype.yyn234=function(e){this.yyval=this.Node_Expr_Eval(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn235=function(e){this.yyval=this.Node_Expr_Include(this.yyastk[this.stackPos-0],"Node_Expr_Require",e)},r.Parser.prototype.yyn236=function(e){this.yyval=this.Node_Expr_Include(this.yyastk[this.stackPos-0],"Node_Expr_RequireOnce",e)},r.Parser.prototype.yyn237=function(e){this.yyval=this.Node_Expr_Cast_Int(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn238=function(e){this.yyval=this.Node_Expr_Cast_Double(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn239=function(e){this.yyval=this.Node_Expr_Cast_String(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn240=function(e){this.yyval=this.Node_Expr_Cast_Array(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn241=function(e){this.yyval=this.Node_Expr_Cast_Object(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn242=function(e){this.yyval=this.Node_Expr_Cast_Bool(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn243=function(e){this.yyval=this.Node_Expr_Cast_Unset(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn244=function(e){this.yyval=this.Node_Expr_Exit(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn245=function(e){this.yyval=this.Node_Expr_ErrorSuppress(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn246=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn247=function(e){this.yyval=this.Node_Expr_Array(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn248=function(e){this.yyval=this.Node_Expr_Array(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn249=function(e){this.yyval=this.Node_Expr_ShellExec(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn250=function(e){this.yyval=this.Node_Expr_Print(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn251=function(e){this.yyval=this.Node_Expr_Closure({"static":!1,byRef:this.yyastk[this.stackPos-7],params:this.yyastk[this.stackPos-5],uses:this.yyastk[this.stackPos-3],stmts:this.yyastk[this.stackPos-1]},e)},r.Parser.prototype.yyn252=function(e){this.yyval=this.Node_Expr_Closure({"static":!0,byRef:this.yyastk[this.stackPos-7],params:this.yyastk[this.stackPos-5],uses:this.yyastk[this.stackPos-3],stmts:this.yyastk[this.stackPos-1]},e)},r.Parser.prototype.yyn253=function(e){this.yyval=this.Node_Expr_New(this.yyastk[this.stackPos-1],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn254=function(e){this.yyval=[]},r.Parser.prototype.yyn255=function(e){this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn256=function(e){this.yyval=[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn257=function(e){this.yyastk[this.stackPos-2].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn258=function(e){this.yyval=this.Node_Expr_ClosureUse(this.yyastk[this.stackPos-0].substring(1),this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn259=function(e){this.yyval=this.Node_Expr_FuncCall(this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn260=function(e){this.yyval=this.Node_Expr_StaticCall(this.yyastk[this.stackPos-5],this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn261=function(e){this.yyval=this.Node_Expr_StaticCall(this.yyastk[this.stackPos-7],this.yyastk[this.stackPos-4],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn262=function(e){if(this.yyastk[this.stackPos-3].type==="Node_Expr_StaticPropertyFetch")this.yyval=this.Node_Expr_StaticCall(this.yyastk[this.stackPos-3].Class,this.Node_Expr_Variable(this.yyastk[this.stackPos-3].name,e),this.yyastk[this.stackPos-1],e);else{if(this.yyastk[this.stackPos-3].type!=="Node_Expr_ArrayDimFetch")throw new Exception;var t=this.yyastk[this.stackPos-3];while(t.variable.type==="Node_Expr_ArrayDimFetch")t=t.variable;this.yyval=this.Node_Expr_StaticCall(t.variable.Class,this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-1],e),t.variable=this.Node_Expr_Variable(t.variable.name,e)}},r.Parser.prototype.yyn263=function(e){this.yyval=this.Node_Expr_FuncCall(this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn264=function(e){this.yyval=this.Node_Expr_ArrayDimFetch(this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn265=function(e){this.yyval=this.Node_Name("static",e)},r.Parser.prototype.yyn266=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn267=function(e){this.yyval=this.Node_Name(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn268=function(e){this.yyval=this.Node_Name_FullyQualified(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn269=function(e){this.yyval=this.Node_Name_Relative(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn270=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn271=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn272=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn273=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn274=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn275=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn276=function(){this.yyval=this.yyastk[this.stackPos]},r.Parser.prototype.yyn277=function(e){this.yyval=this.Node_Expr_PropertyFetch(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn278=function(e){this.yyval=this.Node_Expr_PropertyFetch(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn279=function(e){this.yyval=this.Node_Expr_ArrayDimFetch(this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn280=function(e){this.yyval=this.Node_Expr_ArrayDimFetch(this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn281=function(e){this.yyval=null},r.Parser.prototype.yyn282=function(e){this.yyval=null},r.Parser.prototype.yyn283=function(e){this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn284=function(e){this.yyval=[]},r.Parser.prototype.yyn285=function(e){this.yyval=[this.Scalar_String_parseEscapeSequences(this.yyastk[this.stackPos-0],"`")]},r.Parser.prototype.yyn286=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn287=function(e){this.yyval=[]},r.Parser.prototype.yyn288=function(e){this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn289=function(e){this.yyval=this.Node_Scalar_LNumber(this.Scalar_LNumber_parse(this.yyastk[this.stackPos-0]),e)},r.Parser.prototype.yyn290=function(e){this.yyval=this.Node_Scalar_DNumber(this.Scalar_DNumber_parse(this.yyastk[this.stackPos-0]),e)},r.Parser.prototype.yyn291=function(e){this.yyval=this.Scalar_String_create(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn292=function(e){this.yyval={type:"Node_Scalar_LineConst",attributes:e}},r.Parser.prototype.yyn293=function(e){this.yyval={type:"Node_Scalar_FileConst",attributes:e}},r.Parser.prototype.yyn294=function(e){this.yyval={type:"Node_Scalar_DirConst",attributes:e}},r.Parser.prototype.yyn295=function(e){this.yyval={type:"Node_Scalar_ClassConst",attributes:e}},r.Parser.prototype.yyn296=function(e){this.yyval={type:"Node_Scalar_TraitConst",attributes:e}},r.Parser.prototype.yyn297=function(e){this.yyval={type:"Node_Scalar_MethodConst",attributes:e}},r.Parser.prototype.yyn298=function(e){this.yyval={type:"Node_Scalar_FuncConst",attributes:e}},r.Parser.prototype.yyn299=function(e){this.yyval={type:"Node_Scalar_NSConst",attributes:e}},r.Parser.prototype.yyn300=function(e){this.yyval=this.Node_Scalar_String(this.Scalar_String_parseDocString(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-1]),e)},r.Parser.prototype.yyn301=function(e){this.yyval=this.Node_Scalar_String("",e)},r.Parser.prototype.yyn302=function(e){this.yyval=this.Node_Expr_ConstFetch(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn303=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn304=function(e){this.yyval=this.Node_Expr_ClassConstFetch(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn305=function(e){this.yyval=this.Node_Expr_UnaryPlus(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn306=function(e){this.yyval=this.Node_Expr_UnaryMinus(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn307=function(e){this.yyval=this.Node_Expr_Array(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn308=function(e){this.yyval=this.Node_Expr_Array(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn309=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn310=function(e){this.yyval=this.Node_Expr_ClassConstFetch(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn311=function(e){this.yyval=this.Node_Scalar_Encapsed(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn312=function(e){this.yyval=this.Node_Scalar_Encapsed(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn313=function(e){this.yyval=[]},r.Parser.prototype.yyn314=function(e){this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn315=function(){this.yyval=this.yyastk[this.stackPos]},r.Parser.prototype.yyn316=function(){this.yyval=this.yyastk[this.stackPos]},r.Parser.prototype.yyn317=function(e){this.yyastk[this.stackPos-2].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn318=function(e){this.yyval=[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn319=function(e){this.yyval=this.Node_Expr_ArrayItem(this.yyastk[this.stackPos-0],this.yyastk[this.stackPos-2],!1,e)},r.Parser.prototype.yyn320=function(e){this.yyval=this.Node_Expr_ArrayItem(this.yyastk[this.stackPos-0],null,!1,e)},r.Parser.prototype.yyn321=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn322=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn323=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn324=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn325=function(e){this.yyval=this.Node_Expr_ArrayDimFetch(this.yyastk[this.stackPos-4],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn326=function(e){this.yyval=this.Node_Expr_ArrayDimFetch(this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn327=function(e){this.yyval=this.Node_Expr_PropertyFetch(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn328=function(e){this.yyval=this.Node_Expr_MethodCall(this.yyastk[this.stackPos-5],this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn329=function(e){this.yyval=this.Node_Expr_FuncCall(this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn330=function(e){this.yyval=this.Node_Expr_ArrayDimFetch(this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn331=function(e){this.yyval=this.Node_Expr_ArrayDimFetch(this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn332=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn333=function(e){this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn334=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn335=function(e){this.yyval=this.Node_Expr_Variable(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn336=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn337=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn338=function(e){this.yyval=this.Node_Expr_StaticPropertyFetch(this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn339=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn340=function(e){this.yyval=this.Node_Expr_StaticPropertyFetch(this.yyastk[this.stackPos-2],this.yyastk[this.stackPos-0].substring(1),e)},r.Parser.prototype.yyn341=function(e){this.yyval=this.Node_Expr_StaticPropertyFetch(this.yyastk[this.stackPos-5],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn342=function(e){this.yyval=this.Node_Expr_ArrayDimFetch(this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn343=function(e){this.yyval=this.Node_Expr_ArrayDimFetch(this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn344=function(e){this.yyval=this.Node_Expr_ArrayDimFetch(this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn345=function(e){this.yyval=this.Node_Expr_ArrayDimFetch(this.yyastk[this.stackPos-3],this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn346=function(e){this.yyval=this.Node_Expr_Variable(this.yyastk[this.stackPos-0].substring(1),e)},r.Parser.prototype.yyn347=function(e){this.yyval=this.Node_Expr_Variable(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn348=function(e){this.yyval=null},r.Parser.prototype.yyn349=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn350=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn351=function(e){this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn352=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn353=function(e){this.yyastk[this.stackPos-2].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn354=function(e){this.yyval=[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn355=function(e){this.yyval=this.yyastk[this.stackPos-0]},r.Parser.prototype.yyn356=function(e){this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn357=function(e){this.yyval=null},r.Parser.prototype.yyn358=function(e){this.yyval=[]},r.Parser.prototype.yyn359=function(e){this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn360=function(e){this.yyastk[this.stackPos-2].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-2]},r.Parser.prototype.yyn361=function(e){this.yyval=[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn362=function(e){this.yyval=this.Node_Expr_ArrayItem(this.yyastk[this.stackPos-0],this.yyastk[this.stackPos-2],!1,e)},r.Parser.prototype.yyn363=function(e){this.yyval=this.Node_Expr_ArrayItem(this.yyastk[this.stackPos-0],null,!1,e)},r.Parser.prototype.yyn364=function(e){this.yyval=this.Node_Expr_ArrayItem(this.yyastk[this.stackPos-0],this.yyastk[this.stackPos-3],!0,e)},r.Parser.prototype.yyn365=function(e){this.yyval=this.Node_Expr_ArrayItem(this.yyastk[this.stackPos-0],null,!0,e)},r.Parser.prototype.yyn366=function(e){this.yyastk[this.stackPos-1].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn367=function(e){this.yyastk[this.stackPos-1].push(this.yyastk[this.stackPos-0]),this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn368=function(e){this.yyval=[this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn369=function(e){this.yyval=[this.yyastk[this.stackPos-1],this.yyastk[this.stackPos-0]]},r.Parser.prototype.yyn370=function(e){this.yyval=this.Node_Expr_Variable(this.yyastk[this.stackPos-0].substring(1),e)},r.Parser.prototype.yyn371=function(e){this.yyval=this.Node_Expr_ArrayDimFetch(this.Node_Expr_Variable(this.yyastk[this.stackPos-3].substring(1),e),this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn372=function(e){this.yyval=this.Node_Expr_PropertyFetch(this.Node_Expr_Variable(this.yyastk[this.stackPos-2].substring(1),e),this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn373=function(e){this.yyval=this.Node_Expr_Variable(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn374=function(e){this.yyval=this.Node_Expr_Variable(this.yyastk[this.stackPos-1],e)},r.Parser.prototype.yyn375=function(e){this.yyval=this.Node_Expr_ArrayDimFetch(this.Node_Expr_Variable(this.yyastk[this.stackPos-4],e),this.yyastk[this.stackPos-2],e)},r.Parser.prototype.yyn376=function(e){this.yyval=this.yyastk[this.stackPos-1]},r.Parser.prototype.yyn377=function(e){this.yyval=this.Node_Scalar_String(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn378=function(e){this.yyval=this.Node_Scalar_String(this.yyastk[this.stackPos-0],e)},r.Parser.prototype.yyn379=function(e){this.yyval=this.Node_Expr_Variable(this.yyastk[this.stackPos-0].substring(1),e)},r.Parser.prototype.Stmt_Namespace_postprocess=function(e){return e},r.Parser.prototype.Node_Stmt_Echo=function(){return{type:"Node_Stmt_Echo",exprs:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Stmt_If=function(){return{type:"Node_Stmt_If",cond:arguments[0],stmts:arguments[1].stmts,elseifs:arguments[1].elseifs,Else:arguments[1].Else||null,attributes:arguments[2]}},r.Parser.prototype.Node_Stmt_For=function(){return{type:"Node_Stmt_For",init:arguments[0].init,cond:arguments[0].cond,loop:arguments[0].loop,stmts:arguments[0].stmts,attributes:arguments[1]}},r.Parser.prototype.Node_Stmt_Function=function(){return{type:"Node_Stmt_Function",name:arguments[0],byRef:arguments[1].byRef,params:arguments[1].params,stmts:arguments[1].stmts,attributes:arguments[2]}},r.Parser.prototype.Stmt_Class_verifyModifier=function(){},r.Parser.prototype.Node_Stmt_Namespace=function(){return{type:"Node_Stmt_Namespace",name:arguments[0],attributes:arguments[2]}},r.Parser.prototype.Node_Stmt_Use=function(){return{type:"Node_Stmt_Use",name:arguments[0],attributes:arguments[2]}},r.Parser.prototype.Node_Stmt_UseUse=function(){return{type:"Node_Stmt_UseUse",name:arguments[0],as:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Stmt_TraitUseAdaptation_Precedence=function(){return{type:"Node_Stmt_TraitUseAdaptation_Precedence",name:arguments[0],attributes:arguments[2]}},r.Parser.prototype.Node_Stmt_TraitUseAdaptation_Alias=function(){return{type:"Node_Stmt_TraitUseAdaptation_Alias",name:arguments[0],attributes:arguments[2]}},r.Parser.prototype.Node_Stmt_Trait=function(){return{type:"Node_Stmt_Trait",name:arguments[0],attributes:arguments[2]}},r.Parser.prototype.Node_Stmt_TraitUse=function(){return{type:"Node_Stmt_TraitUse",name:arguments[0],attributes:arguments[2]}},r.Parser.prototype.Node_Stmt_Class=function(){return{type:"Node_Stmt_Class",name:arguments[0],Type:arguments[1].type,Extends:arguments[1].Extends,Implements:arguments[1].Implements,stmts:arguments[1].stmts,attributes:arguments[2]}},r.Parser.prototype.Node_Stmt_ClassMethod=function(){return{type:"Node_Stmt_ClassMethod",name:arguments[0],Type:arguments[1].type,byRef:arguments[1].byRef,params:arguments[1].params,stmts:arguments[1].stmts,attributes:arguments[2]}},r.Parser.prototype.Node_Stmt_ClassConst=function(){return{type:"Node_Stmt_ClassConst",consts:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Stmt_Interface=function(){return{type:"Node_Stmt_Interface",name:arguments[0],Extends:arguments[1].Extends,stmts:arguments[1].stmts,attributes:arguments[2]}},r.Parser.prototype.Node_Stmt_Throw=function(){return{type:"Node_Stmt_Throw",expr:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Stmt_Catch=function(){return{type:"Node_Stmt_Catch",Type:arguments[0],variable:arguments[1],stmts:arguments[2],attributes:arguments[3]}},r.Parser.prototype.Node_Stmt_TryCatch=function(){return{type:"Node_Stmt_TryCatch",stmts:arguments[0],catches:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Stmt_Foreach=function(){return{type:"Node_Stmt_Foreach",expr:arguments[0],valueVar:arguments[1],keyVar:arguments[2].keyVar,byRef:arguments[2].byRef,stmts:arguments[2].stmts,attributes:arguments[3]}},r.Parser.prototype.Node_Stmt_While=function(){return{type:"Node_Stmt_While",cond:arguments[0],stmts:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Stmt_Do=function(){return{type:"Node_Stmt_Do",cond:arguments[0],stmts:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Stmt_Break=function(){return{type:"Node_Stmt_Break",num:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Stmt_Continue=function(){return{type:"Node_Stmt_Continue",num:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Stmt_Return=function(){return{type:"Node_Stmt_Return",expr:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Stmt_Case=function(){return{type:"Node_Stmt_Case",cond:arguments[0],stmts:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Stmt_Switch=function(){return{type:"Node_Stmt_Switch",cond:arguments[0],cases:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Stmt_Else=function(){return{type:"Node_Stmt_Else",stmts:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Stmt_ElseIf=function(){return{type:"Node_Stmt_ElseIf",cond:arguments[0],stmts:arguments[1],attributes:arguments[1]}},r.Parser.prototype.Node_Stmt_InlineHTML=function(){return{type:"Node_Stmt_InlineHTML",value:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Stmt_StaticVar=function(){return{type:"Node_Stmt_StaticVar",name:arguments[0],def:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Stmt_Static=function(){return{type:"Node_Stmt_Static",vars:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Stmt_Global=function(){return{type:"Node_Stmt_Global",vars:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Stmt_PropertyProperty=function(){return{type:"Node_Stmt_PropertyProperty",name:arguments[0],def:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Stmt_Property=function(){return{type:"Node_Stmt_Property",Type:arguments[0],props:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Stmt_Unset=function(){return{type:"Node_Stmt_Unset",variables:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_Variable=function(e){return{type:"Node_Expr_Variable",name:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_FuncCall=function(){return{type:"Node_Expr_FuncCall",func:arguments[0],args:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_MethodCall=function(){return{type:"Node_Expr_MethodCall",variable:arguments[0],name:arguments[1],args:arguments[2],attributes:arguments[3]}},r.Parser.prototype.Node_Expr_StaticCall=function(){return{type:"Node_Expr_StaticCall",Class:arguments[0],func:arguments[1],args:arguments[2],attributes:arguments[3]}},r.Parser.prototype.Node_Expr_Ternary=function(){return{type:"Node_Expr_Ternary",cond:arguments[0],If:arguments[1],Else:arguments[2],attributes:arguments[3]}},r.Parser.prototype.Node_Expr_AssignList=function(){return{type:"Node_Expr_AssignList",assignList:arguments[0],expr:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_Assign=function(){return{type:"Node_Expr_Assign",variable:arguments[0],expr:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_AssignConcat=function(){return{type:"Node_Expr_AssignConcat",variable:arguments[0],expr:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_AssignMinus=function(){return{type:"Node_Expr_AssignMinus",variable:arguments[0],expr:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_AssignPlus=function(){return{type:"Node_Expr_AssignPlus",variable:arguments[0],expr:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_AssignDiv=function(){return{type:"Node_Expr_AssignDiv",variable:arguments[0],expr:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_AssignRef=function(){return{type:"Node_Expr_AssignRef",variable:arguments[0],refVar:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_AssignMul=function(){return{type:"Node_Expr_AssignMul",variable:arguments[0],expr:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_AssignMod=function(){return{type:"Node_Expr_AssignMod",variable:arguments[0],expr:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_Plus=function(){return{type:"Node_Expr_Plus",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_Minus=function(){return{type:"Node_Expr_Minus",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_Mul=function(){return{type:"Node_Expr_Mul",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_Div=function(){return{type:"Node_Expr_Div",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_Mod=function(){return{type:"Node_Expr_Mod",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_Greater=function(){return{type:"Node_Expr_Greater",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_Equal=function(){return{type:"Node_Expr_Equal",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_NotEqual=function(){return{type:"Node_Expr_NotEqual",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_Identical=function(){return{type:"Node_Expr_Identical",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_NotIdentical=function(){return{type:"Node_Expr_NotIdentical",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_GreaterOrEqual=function(){return{type:"Node_Expr_GreaterOrEqual",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_SmallerOrEqual=function(){return{type:"Node_Expr_SmallerOrEqual",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_Concat=function(){return{type:"Node_Expr_Concat",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_Smaller=function(){return{type:"Node_Expr_Smaller",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_PostInc=function(){return{type:"Node_Expr_PostInc",variable:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_PostDec=function(){return{type:"Node_Expr_PostDec",variable:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_PreInc=function(){return{type:"Node_Expr_PreInc",variable:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_PreDec=function(){return{type:"Node_Expr_PreDec",variable:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_Include=function(){return{expr:arguments[0],type:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_ArrayDimFetch=function(){return{type:"Node_Expr_ArrayDimFetch",variable:arguments[0],dim:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_StaticPropertyFetch=function(){return{type:"Node_Expr_StaticPropertyFetch",Class:arguments[0],name:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_ClassConstFetch=function(){return{type:"Node_Expr_ClassConstFetch",Class:arguments[0],name:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_StaticPropertyFetch=function(){return{type:"Node_Expr_StaticPropertyFetch",Class:arguments[0],name:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_ConstFetch=function(){return{type:"Node_Expr_ConstFetch",name:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_ArrayItem=function(){return{type:"Node_Expr_ArrayItem",value:arguments[0],key:arguments[1],byRef:arguments[2],attributes:arguments[3]}},r.Parser.prototype.Node_Expr_Array=function(){return{type:"Node_Expr_Array",items:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_PropertyFetch=function(){return{type:"Node_Expr_PropertyFetch",variable:arguments[0],name:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_New=function(){return{type:"Node_Expr_New",Class:arguments[0],args:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_Print=function(){return{type:"Node_Expr_Print",expr:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_Exit=function(){return{type:"Node_Expr_Exit",expr:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_Cast_Bool=function(){return{type:"Node_Expr_Cast_Bool",expr:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_Cast_Int=function(){return{type:"Node_Expr_Cast_Int",expr:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_Cast_String=function(){return{type:"Node_Expr_Cast_String",expr:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_Cast_Double=function(){return{type:"Node_Expr_Cast_Double",expr:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_Cast_Array=function(){return{type:"Node_Expr_Cast_Array",expr:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_Cast_Object=function(){return{type:"Node_Expr_Cast_Object",expr:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_ErrorSuppress=function(){return{type:"Node_Expr_ErrorSuppress",expr:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_Isset=function(){return{type:"Node_Expr_Isset",variables:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_UnaryMinus=function(){return{type:"Node_Expr_UnaryMinus",expr:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_UnaryPlus=function(){return{type:"Node_Expr_UnaryPlus",expr:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_Empty=function(){return{type:"Node_Expr_Empty",variable:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_BooleanOr=function(){return{type:"Node_Expr_BooleanOr",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_LogicalOr=function(){return{type:"Node_Expr_LogicalOr",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_LogicalAnd=function(){return{type:"Node_Expr_LogicalAnd",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_LogicalXor=function(){return{type:"Node_Expr_LogicalXor",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_BitwiseAnd=function(){return{type:"Node_Expr_BitwiseAnd",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_BitwiseOr=function(){return{type:"Node_Expr_BitwiseOr",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_BitwiseXor=function(){return{type:"Node_Expr_BitwiseXor",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_BitwiseNot=function(){return{type:"Node_Expr_BitwiseNot",expr:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_BooleanNot=function(){return{type:"Node_Expr_BooleanNot",expr:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Expr_BooleanAnd=function(){return{type:"Node_Expr_BooleanAnd",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_Instanceof=function(){return{type:"Node_Expr_Instanceof",left:arguments[0],right:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Expr_Clone=function(){return{type:"Node_Expr_Clone",expr:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Scalar_LNumber_parse=function(e){return e},r.Parser.prototype.Scalar_DNumber_parse=function(e){return e},r.Parser.prototype.Scalar_String_parseDocString=function(){return'"'+arguments[1].replace(/([^"\\]*(?:\\.[^"\\]*)*)"/g,'$1\\"')+'"'},r.Parser.prototype.Node_Scalar_String=function(){return{type:"Node_Scalar_String",value:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Scalar_String_create=function(){return{type:"Node_Scalar_String",value:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Scalar_LNumber=function(){return{type:"Node_Scalar_LNumber",value:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Scalar_DNumber=function(){return{type:"Node_Scalar_DNumber",value:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Scalar_Encapsed=function(){return{type:"Node_Scalar_Encapsed",parts:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Name=function(){return{type:"Node_Name",parts:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Name_FullyQualified=function(){return{type:"Node_Name_FullyQualified",parts:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Name_Relative=function(){return{type:"Node_Name_Relative",parts:arguments[0],attributes:arguments[1]}},r.Parser.prototype.Node_Param=function(){return{type:"Node_Param",name:arguments[0],def:arguments[1],Type:arguments[2],byRef:arguments[3],attributes:arguments[4]}},r.Parser.prototype.Node_Arg=function(){return{type:"Node_Name",value:arguments[0],byRef:arguments[1],attributes:arguments[2]}},r.Parser.prototype.Node_Const=function(){return{type:"Node_Const",name:arguments[0],value:arguments[1],attributes:arguments[2]}},t.PHP=r}),ace.define("ace/mode/php_worker",["require","exports","module","ace/lib/oop","ace/worker/mirror","ace/mode/php/php"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../worker/mirror").Mirror,s=e("./php/php").PHP,o=t.PhpWorker=function(e){i.call(this,e),this.setTimeout(500)};r.inherits(o,i),function(){this.setOptions=function(e){this.inlinePhp=e&&e.inline},this.onUpdate=function(){var e=this.doc.getValue(),t=[];this.inlinePhp&&(e="<?"+e+"?>");var n=s.Lexer(e,{short_open_tag:1});try{new s.Parser(n)}catch(r){t.push({row:r.line-1,column:null,text:r.message.charAt(0).toUpperCase()+r.message.substring(1),type:"error"})}this.sender.emit("annotate",t)}}.call(o.prototype)}),ace.define("ace/lib/es5-shim",["require","exports","module"],function(e,t,n){function r(){}function w(e){try{return Object.defineProperty(e,"sentinel",{}),"sentinel"in e}catch(t){}}function H(e){return e=+e,e!==e?e=0:e!==0&&e!==1/0&&e!==-1/0&&(e=(e>0||-1)*Math.floor(Math.abs(e))),e}function B(e){var t=typeof e;return e===null||t==="undefined"||t==="boolean"||t==="number"||t==="string"}function j(e){var t,n,r;if(B(e))return e;n=e.valueOf;if(typeof n=="function"){t=n.call(e);if(B(t))return t}r=e.toString;if(typeof r=="function"){t=r.call(e);if(B(t))return t}throw new TypeError}Function.prototype.bind||(Function.prototype.bind=function(t){var n=this;if(typeof n!="function")throw new TypeError("Function.prototype.bind called on incompatible "+n);var i=u.call(arguments,1),s=function(){if(this instanceof s){var e=n.apply(this,i.concat(u.call(arguments)));return Object(e)===e?e:this}return n.apply(t,i.concat(u.call(arguments)))};return n.prototype&&(r.prototype=n.prototype,s.prototype=new r,r.prototype=null),s});var i=Function.prototype.call,s=Array.prototype,o=Object.prototype,u=s.slice,a=i.bind(o.toString),f=i.bind(o.hasOwnProperty),l,c,h,p,d;if(d=f(o,"__defineGetter__"))l=i.bind(o.__defineGetter__),c=i.bind(o.__defineSetter__),h=i.bind(o.__lookupGetter__),p=i.bind(o.__lookupSetter__);if([1,2].splice(0).length!=2)if(!function(){function e(e){var t=new Array(e+2);return t[0]=t[1]=0,t}var t=[],n;t.splice.apply(t,e(20)),t.splice.apply(t,e(26)),n=t.length,t.splice(5,0,"XXX"),n+1==t.length;if(n+1==t.length)return!0}())Array.prototype.splice=function(e,t){var n=this.length;e>0?e>n&&(e=n):e==void 0?e=0:e<0&&(e=Math.max(n+e,0)),e+t<n||(t=n-e);var r=this.slice(e,e+t),i=u.call(arguments,2),s=i.length;if(e===n)s&&this.push.apply(this,i);else{var o=Math.min(t,n-e),a=e+o,f=a+s-o,l=n-a,c=n-o;if(f<a)for(var h=0;h<l;++h)this[f+h]=this[a+h];else if(f>a)for(h=l;h--;)this[f+h]=this[a+h];if(s&&e===c)this.length=c,this.push.apply(this,i);else{this.length=c+s;for(h=0;h<s;++h)this[e+h]=i[h]}}return r};else{var v=Array.prototype.splice;Array.prototype.splice=function(e,t){return arguments.length?v.apply(this,[e===void 0?0:e,t===void 0?this.length-e:t].concat(u.call(arguments,2))):[]}}Array.isArray||(Array.isArray=function(t){return a(t)=="[object Array]"});var m=Object("a"),g=m[0]!="a"||!(0 in m);Array.prototype.forEach||(Array.prototype.forEach=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=arguments[1],s=-1,o=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError;while(++s<o)s in r&&t.call(i,r[s],s,n)}),Array.prototype.map||(Array.prototype.map=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=Array(i),o=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var u=0;u<i;u++)u in r&&(s[u]=t.call(o,r[u],u,n));return s}),Array.prototype.filter||(Array.prototype.filter=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=[],o,u=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var f=0;f<i;f++)f in r&&(o=r[f],t.call(u,o,f,n)&&s.push(o));return s}),Array.prototype.every||(Array.prototype.every=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&!t.call(s,r[o],o,n))return!1;return!0}),Array.prototype.some||(Array.prototype.some=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&t.call(s,r[o],o,n))return!0;return!1}),Array.prototype.reduce||(Array.prototype.reduce=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduce of empty array with no initial value");var s=0,o;if(arguments.length>=2)o=arguments[1];else do{if(s in r){o=r[s++];break}if(++s>=i)throw new TypeError("reduce of empty array with no initial value")}while(!0);for(;s<i;s++)s in r&&(o=t.call(void 0,o,r[s],s,n));return o}),Array.prototype.reduceRight||(Array.prototype.reduceRight=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduceRight of empty array with no initial value");var s,o=i-1;if(arguments.length>=2)s=arguments[1];else do{if(o in r){s=r[o--];break}if(--o<0)throw new TypeError("reduceRight of empty array with no initial value")}while(!0);do o in this&&(s=t.call(void 0,s,r[o],o,n));while(o--);return s});if(!Array.prototype.indexOf||[0,1].indexOf(1,2)!=-1)Array.prototype.indexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=0;arguments.length>1&&(i=H(arguments[1])),i=i>=0?i:Math.max(0,r+i);for(;i<r;i++)if(i in n&&n[i]===t)return i;return-1};if(!Array.prototype.lastIndexOf||[0,1].lastIndexOf(0,-3)!=-1)Array.prototype.lastIndexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=r-1;arguments.length>1&&(i=Math.min(i,H(arguments[1]))),i=i>=0?i:r-Math.abs(i);for(;i>=0;i--)if(i in n&&t===n[i])return i;return-1};Object.getPrototypeOf||(Object.getPrototypeOf=function(t){return t.__proto__||(t.constructor?t.constructor.prototype:o)});if(!Object.getOwnPropertyDescriptor){var y="Object.getOwnPropertyDescriptor called on a non-object: ";Object.getOwnPropertyDescriptor=function(t,n){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(y+t);if(!f(t,n))return;var r,i,s;r={enumerable:!0,configurable:!0};if(d){var u=t.__proto__;t.__proto__=o;var i=h(t,n),s=p(t,n);t.__proto__=u;if(i||s)return i&&(r.get=i),s&&(r.set=s),r}return r.value=t[n],r}}Object.getOwnPropertyNames||(Object.getOwnPropertyNames=function(t){return Object.keys(t)});if(!Object.create){var b;Object.prototype.__proto__===null?b=function(){return{__proto__:null}}:b=function(){var e={};for(var t in e)e[t]=null;return e.constructor=e.hasOwnProperty=e.propertyIsEnumerable=e.isPrototypeOf=e.toLocaleString=e.toString=e.valueOf=e.__proto__=null,e},Object.create=function(t,n){var r;if(t===null)r=b();else{if(typeof t!="object")throw new TypeError("typeof prototype["+typeof t+"] != 'object'");var i=function(){};i.prototype=t,r=new i,r.__proto__=t}return n!==void 0&&Object.defineProperties(r,n),r}}if(Object.defineProperty){var E=w({}),S=typeof document=="undefined"||w(document.createElement("div"));if(!E||!S)var x=Object.defineProperty}if(!Object.defineProperty||x){var T="Property description must be an object: ",N="Object.defineProperty called on non-object: ",C="getters & setters can not be defined on this javascript engine";Object.defineProperty=function(t,n,r){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(N+t);if(typeof r!="object"&&typeof r!="function"||r===null)throw new TypeError(T+r);if(x)try{return x.call(Object,t,n,r)}catch(i){}if(f(r,"value"))if(d&&(h(t,n)||p(t,n))){var s=t.__proto__;t.__proto__=o,delete t[n],t[n]=r.value,t.__proto__=s}else t[n]=r.value;else{if(!d)throw new TypeError(C);f(r,"get")&&l(t,n,r.get),f(r,"set")&&c(t,n,r.set)}return t}}Object.defineProperties||(Object.defineProperties=function(t,n){for(var r in n)f(n,r)&&Object.defineProperty(t,r,n[r]);return t}),Object.seal||(Object.seal=function(t){return t}),Object.freeze||(Object.freeze=function(t){return t});try{Object.freeze(function(){})}catch(k){Object.freeze=function(t){return function(n){return typeof n=="function"?n:t(n)}}(Object.freeze)}Object.preventExtensions||(Object.preventExtensions=function(t){return t}),Object.isSealed||(Object.isSealed=function(t){return!1}),Object.isFrozen||(Object.isFrozen=function(t){return!1}),Object.isExtensible||(Object.isExtensible=function(t){if(Object(t)===t)throw new TypeError;var n="";while(f(t,n))n+="?";t[n]=!0;var r=f(t,n);return delete t[n],r});if(!Object.keys){var L=!0,A=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],O=A.length;for(var M in{toString:null})L=!1;Object.keys=function I(e){if(typeof e!="object"&&typeof e!="function"||e===null)throw new TypeError("Object.keys called on a non-object");var I=[];for(var t in e)f(e,t)&&I.push(t);if(L)for(var n=0,r=O;n<r;n++){var i=A[n];f(e,i)&&I.push(i)}return I}}Date.now||(Date.now=function(){return(new Date).getTime()});var _="	\n\f\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\ufeff";if(!String.prototype.trim||_.trim()){_="["+_+"]";var D=new RegExp("^"+_+_+"*"),P=new RegExp(_+_+"*$");String.prototype.trim=function(){return String(this).replace(D,"").replace(P,"")}}var F=function(e){if(e==null)throw new TypeError("can't convert "+e+" to object");return Object(e)}})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-xml.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-xml.js
new file mode 100644
index 0000000..f6635f7
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-xml.js
@@ -0,0 +1 @@
+"no use strict";(function(e){function t(e,t){var n=e,r="";while(n){var i=t[n];if(typeof i=="string")return i+r;if(i)return i.location.replace(/\/*$/,"/")+(r||i.main||i.name);if(i===!1)return"";var s=n.lastIndexOf("/");if(s===-1)break;r=n.substr(s)+r,n=n.slice(0,s)}return e}if(typeof e.window!="undefined"&&e.document)return;if(e.require&&e.define)return;e.console||(e.console=function(){var e=Array.prototype.slice.call(arguments,0);postMessage({type:"log",data:e})},e.console.error=e.console.warn=e.console.log=e.console.trace=e.console),e.window=e,e.ace=e,e.onerror=function(e,t,n,r,i){postMessage({type:"error",data:{message:e,data:i.data,file:t,line:n,col:r,stack:i.stack}})},e.normalizeModule=function(t,n){if(n.indexOf("!")!==-1){var r=n.split("!");return e.normalizeModule(t,r[0])+"!"+e.normalizeModule(t,r[1])}if(n.charAt(0)=="."){var i=t.split("/").slice(0,-1).join("/");n=(i?i+"/":"")+n;while(n.indexOf(".")!==-1&&s!=n){var s=n;n=n.replace(/^\.\//,"").replace(/\/\.\//,"/").replace(/[^\/]+\/\.\.\//,"")}}return n},e.require=function(r,i){i||(i=r,r=null);if(!i.charAt)throw new Error("worker.js require() accepts only (parentId, id) as arguments");i=e.normalizeModule(r,i);var s=e.require.modules[i];if(s)return s.initialized||(s.initialized=!0,s.exports=s.factory().exports),s.exports;if(!e.require.tlns)return console.log("unable to load "+i);var o=t(i,e.require.tlns);return o.slice(-3)!=".js"&&(o+=".js"),e.require.id=i,e.require.modules[i]={},importScripts(o),e.require(r,i)},e.require.modules={},e.require.tlns={},e.define=function(t,n,r){arguments.length==2?(r=n,typeof t!="string"&&(n=t,t=e.require.id)):arguments.length==1&&(r=t,n=[],t=e.require.id);if(typeof r!="function"){e.require.modules[t]={exports:r,initialized:!0};return}n.length||(n=["require","exports","module"]);var i=function(n){return e.require(t,n)};e.require.modules[t]={exports:{},factory:function(){var e=this,t=r.apply(this,n.map(function(t){switch(t){case"require":return i;case"exports":return e.exports;case"module":return e;default:return i(t)}}));return t&&(e.exports=t),e}}},e.define.amd={},require.tlns={},e.initBaseUrls=function(t){for(var n in t)require.tlns[n]=t[n]},e.initSender=function(){var n=e.require("ace/lib/event_emitter").EventEmitter,r=e.require("ace/lib/oop"),i=function(){};return function(){r.implement(this,n),this.callback=function(e,t){postMessage({type:"call",id:t,data:e})},this.emit=function(e,t){postMessage({type:"event",name:e,data:t})}}.call(i.prototype),new i};var n=e.main=null,r=e.sender=null;e.onmessage=function(t){var i=t.data;if(i.event&&r)r._signal(i.event,i.data);else if(i.command)if(n[i.command])n[i.command].apply(n,i.args);else{if(!e[i.command])throw new Error("Unknown command:"+i.command);e[i.command].apply(e,i.args)}else if(i.init){e.initBaseUrls(i.tlns),require("ace/lib/es5-shim"),r=e.sender=e.initSender();var s=require(i.module)[i.classname];n=e.main=new s(r)}}})(this),ace.define("ace/lib/oop",["require","exports","module"],function(e,t,n){"use strict";t.inherits=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})},t.mixin=function(e,t){for(var n in t)e[n]=t[n];return e},t.implement=function(e,n){t.mixin(e,n)}}),ace.define("ace/lib/lang",["require","exports","module"],function(e,t,n){"use strict";t.last=function(e){return e[e.length-1]},t.stringReverse=function(e){return e.split("").reverse().join("")},t.stringRepeat=function(e,t){var n="";while(t>0){t&1&&(n+=e);if(t>>=1)e+=e}return n};var r=/^\s\s*/,i=/\s\s*$/;t.stringTrimLeft=function(e){return e.replace(r,"")},t.stringTrimRight=function(e){return e.replace(i,"")},t.copyObject=function(e){var t={};for(var n in e)t[n]=e[n];return t},t.copyArray=function(e){var t=[];for(var n=0,r=e.length;n<r;n++)e[n]&&typeof e[n]=="object"?t[n]=this.copyObject(e[n]):t[n]=e[n];return t},t.deepCopy=function s(e){if(typeof e!="object"||!e)return e;var t;if(Array.isArray(e)){t=[];for(var n=0;n<e.length;n++)t[n]=s(e[n]);return t}var r=e.constructor;if(r===RegExp)return e;t=r();for(var n in e)t[n]=s(e[n]);return t},t.arrayToMap=function(e){var t={};for(var n=0;n<e.length;n++)t[e[n]]=1;return t},t.createMap=function(e){var t=Object.create(null);for(var n in e)t[n]=e[n];return t},t.arrayRemove=function(e,t){for(var n=0;n<=e.length;n++)t===e[n]&&e.splice(n,1)},t.escapeRegExp=function(e){return e.replace(/([.*+?^${}()|[\]\/\\])/g,"\\$1")},t.escapeHTML=function(e){return e.replace(/&/g,"&#38;").replace(/"/g,"&#34;").replace(/'/g,"&#39;").replace(/</g,"&#60;")},t.getMatchOffsets=function(e,t){var n=[];return e.replace(t,function(e){n.push({offset:arguments[arguments.length-2],length:e.length})}),n},t.deferredCall=function(e){var t=null,n=function(){t=null,e()},r=function(e){return r.cancel(),t=setTimeout(n,e||0),r};return r.schedule=r,r.call=function(){return this.cancel(),e(),r},r.cancel=function(){return clearTimeout(t),t=null,r},r.isPending=function(){return t},r},t.delayedCall=function(e,t){var n=null,r=function(){n=null,e()},i=function(e){n==null&&(n=setTimeout(r,e||t))};return i.delay=function(e){n&&clearTimeout(n),n=setTimeout(r,e||t)},i.schedule=i,i.call=function(){this.cancel(),e()},i.cancel=function(){n&&clearTimeout(n),n=null},i.isPending=function(){return n},i}}),ace.define("ace/range",["require","exports","module"],function(e,t,n){"use strict";var r=function(e,t){return e.row-t.row||e.column-t.column},i=function(e,t,n,r){this.start={row:e,column:t},this.end={row:n,column:r}};(function(){this.isEqual=function(e){return this.start.row===e.start.row&&this.end.row===e.end.row&&this.start.column===e.start.column&&this.end.column===e.end.column},this.toString=function(){return"Range: ["+this.start.row+"/"+this.start.column+"] -> ["+this.end.row+"/"+this.end.column+"]"},this.contains=function(e,t){return this.compare(e,t)==0},this.compareRange=function(e){var t,n=e.end,r=e.start;return t=this.compare(n.row,n.column),t==1?(t=this.compare(r.row,r.column),t==1?2:t==0?1:0):t==-1?-2:(t=this.compare(r.row,r.column),t==-1?-1:t==1?42:0)},this.comparePoint=function(e){return this.compare(e.row,e.column)},this.containsRange=function(e){return this.comparePoint(e.start)==0&&this.comparePoint(e.end)==0},this.intersects=function(e){var t=this.compareRange(e);return t==-1||t==0||t==1},this.isEnd=function(e,t){return this.end.row==e&&this.end.column==t},this.isStart=function(e,t){return this.start.row==e&&this.start.column==t},this.setStart=function(e,t){typeof e=="object"?(this.start.column=e.column,this.start.row=e.row):(this.start.row=e,this.start.column=t)},this.setEnd=function(e,t){typeof e=="object"?(this.end.column=e.column,this.end.row=e.row):(this.end.row=e,this.end.column=t)},this.inside=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)||this.isStart(e,t)?!1:!0:!1},this.insideStart=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)?!1:!0:!1},this.insideEnd=function(e,t){return this.compare(e,t)==0?this.isStart(e,t)?!1:!0:!1},this.compare=function(e,t){return!this.isMultiLine()&&e===this.start.row?t<this.start.column?-1:t>this.end.column?1:0:e<this.start.row?-1:e>this.end.row?1:this.start.row===e?t>=this.start.column?0:-1:this.end.row===e?t<=this.end.column?0:1:0},this.compareStart=function(e,t){return this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.compareEnd=function(e,t){return this.end.row==e&&this.end.column==t?1:this.compare(e,t)},this.compareInside=function(e,t){return this.end.row==e&&this.end.column==t?1:this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.clipRows=function(e,t){if(this.end.row>t)var n={row:t+1,column:0};else if(this.end.row<e)var n={row:e,column:0};if(this.start.row>t)var r={row:t+1,column:0};else if(this.start.row<e)var r={row:e,column:0};return i.fromPoints(r||this.start,n||this.end)},this.extend=function(e,t){var n=this.compare(e,t);if(n==0)return this;if(n==-1)var r={row:e,column:t};else var s={row:e,column:t};return i.fromPoints(r||this.start,s||this.end)},this.isEmpty=function(){return this.start.row===this.end.row&&this.start.column===this.end.column},this.isMultiLine=function(){return this.start.row!==this.end.row},this.clone=function(){return i.fromPoints(this.start,this.end)},this.collapseRows=function(){return this.end.column==0?new i(this.start.row,0,Math.max(this.start.row,this.end.row-1),0):new i(this.start.row,0,this.end.row,0)},this.toScreenRange=function(e){var t=e.documentToScreenPosition(this.start),n=e.documentToScreenPosition(this.end);return new i(t.row,t.column,n.row,n.column)},this.moveBy=function(e,t){this.start.row+=e,this.start.column+=t,this.end.row+=e,this.end.column+=t}}).call(i.prototype),i.fromPoints=function(e,t){return new i(e.row,e.column,t.row,t.column)},i.comparePoints=r,i.comparePoints=function(e,t){return e.row-t.row||e.column-t.column},t.Range=i}),ace.define("ace/apply_delta",["require","exports","module"],function(e,t,n){"use strict";function r(e,t){throw console.log("Invalid Delta:",e),"Invalid Delta: "+t}function i(e,t){return t.row>=0&&t.row<e.length&&t.column>=0&&t.column<=e[t.row].length}function s(e,t){t.action!="insert"&&t.action!="remove"&&r(t,"delta.action must be 'insert' or 'remove'"),t.lines instanceof Array||r(t,"delta.lines must be an Array"),(!t.start||!t.end)&&r(t,"delta.start/end must be an present");var n=t.start;i(e,t.start)||r(t,"delta.start must be contained in document");var s=t.end;t.action=="remove"&&!i(e,s)&&r(t,"delta.end must contained in document for 'remove' actions");var o=s.row-n.row,u=s.column-(o==0?n.column:0);(o!=t.lines.length-1||t.lines[o].length!=u)&&r(t,"delta.range must match delta lines")}t.applyDelta=function(e,t,n){var r=t.start.row,i=t.start.column,s=e[r]||"";switch(t.action){case"insert":var o=t.lines;if(o.length===1)e[r]=s.substring(0,i)+t.lines[0]+s.substring(i);else{var u=[r,1].concat(t.lines);e.splice.apply(e,u),e[r]=s.substring(0,i)+e[r],e[r+t.lines.length-1]+=s.substring(i)}break;case"remove":var a=t.end.column,f=t.end.row;r===f?e[r]=s.substring(0,i)+s.substring(a):e.splice(r,f-r+1,s.substring(0,i)+e[f].substring(a))}}}),ace.define("ace/lib/event_emitter",["require","exports","module"],function(e,t,n){"use strict";var r={},i=function(){this.propagationStopped=!0},s=function(){this.defaultPrevented=!0};r._emit=r._dispatchEvent=function(e,t){this._eventRegistry||(this._eventRegistry={}),this._defaultHandlers||(this._defaultHandlers={});var n=this._eventRegistry[e]||[],r=this._defaultHandlers[e];if(!n.length&&!r)return;if(typeof t!="object"||!t)t={};t.type||(t.type=e),t.stopPropagation||(t.stopPropagation=i),t.preventDefault||(t.preventDefault=s),n=n.slice();for(var o=0;o<n.length;o++){n[o](t,this);if(t.propagationStopped)break}if(r&&!t.defaultPrevented)return r(t,this)},r._signal=function(e,t){var n=(this._eventRegistry||{})[e];if(!n)return;n=n.slice();for(var r=0;r<n.length;r++)n[r](t,this)},r.once=function(e,t){var n=this;t&&this.addEventListener(e,function r(){n.removeEventListener(e,r),t.apply(null,arguments)})},r.setDefaultHandler=function(e,t){var n=this._defaultHandlers;n||(n=this._defaultHandlers={_disabled_:{}});if(n[e]){var r=n[e],i=n._disabled_[e];i||(n._disabled_[e]=i=[]),i.push(r);var s=i.indexOf(t);s!=-1&&i.splice(s,1)}n[e]=t},r.removeDefaultHandler=function(e,t){var n=this._defaultHandlers;if(!n)return;var r=n._disabled_[e];if(n[e]==t){var i=n[e];r&&this.setDefaultHandler(e,r.pop())}else if(r){var s=r.indexOf(t);s!=-1&&r.splice(s,1)}},r.on=r.addEventListener=function(e,t,n){this._eventRegistry=this._eventRegistry||{};var r=this._eventRegistry[e];return r||(r=this._eventRegistry[e]=[]),r.indexOf(t)==-1&&r[n?"unshift":"push"](t),t},r.off=r.removeListener=r.removeEventListener=function(e,t){this._eventRegistry=this._eventRegistry||{};var n=this._eventRegistry[e];if(!n)return;var r=n.indexOf(t);r!==-1&&n.splice(r,1)},r.removeAllListeners=function(e){this._eventRegistry&&(this._eventRegistry[e]=[])},t.EventEmitter=r}),ace.define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=t.Anchor=function(e,t,n){this.$onChange=this.onChange.bind(this),this.attach(e),typeof n=="undefined"?this.setPosition(t.row,t.column):this.setPosition(t,n)};(function(){function e(e,t,n){var r=n?e.column<=t.column:e.column<t.column;return e.row<t.row||e.row==t.row&&r}function t(t,n,r){var i=t.action=="insert",s=(i?1:-1)*(t.end.row-t.start.row),o=(i?1:-1)*(t.end.column-t.start.column),u=t.start,a=i?u:t.end;return e(n,u,r)?{row:n.row,column:n.column}:e(a,n,!r)?{row:n.row+s,column:n.column+(n.row==a.row?o:0)}:{row:u.row,column:u.column}}r.implement(this,i),this.getPosition=function(){return this.$clipPositionToDocument(this.row,this.column)},this.getDocument=function(){return this.document},this.$insertRight=!1,this.onChange=function(e){if(e.start.row==e.end.row&&e.start.row!=this.row)return;if(e.start.row>this.row)return;var n=t(e,{row:this.row,column:this.column},this.$insertRight);this.setPosition(n.row,n.column,!0)},this.setPosition=function(e,t,n){var r;n?r={row:e,column:t}:r=this.$clipPositionToDocument(e,t);if(this.row==r.row&&this.column==r.column)return;var i={row:this.row,column:this.column};this.row=r.row,this.column=r.column,this._signal("change",{old:i,value:r})},this.detach=function(){this.document.removeEventListener("change",this.$onChange)},this.attach=function(e){this.document=e||this.document,this.document.on("change",this.$onChange)},this.$clipPositionToDocument=function(e,t){var n={};return e>=this.document.getLength()?(n.row=Math.max(0,this.document.getLength()-1),n.column=this.document.getLine(n.row).length):e<0?(n.row=0,n.column=0):(n.row=e,n.column=Math.min(this.document.getLine(n.row).length,Math.max(0,t))),t<0&&(n.column=0),n}}).call(s.prototype)}),ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./apply_delta").applyDelta,s=e("./lib/event_emitter").EventEmitter,o=e("./range").Range,u=e("./anchor").Anchor,a=function(e){this.$lines=[""],e.length===0?this.$lines=[""]:Array.isArray(e)?this.insertMergedLines({row:0,column:0},e):this.insert({row:0,column:0},e)};(function(){r.implement(this,s),this.setValue=function(e){var t=this.getLength()-1;this.remove(new o(0,0,t,this.getLine(t).length)),this.insert({row:0,column:0},e)},this.getValue=function(){return this.getAllLines().join(this.getNewLineCharacter())},this.createAnchor=function(e,t){return new u(this,e,t)},"aaa".split(/a/).length===0?this.$split=function(e){return e.replace(/\r\n|\r/g,"\n").split("\n")}:this.$split=function(e){return e.split(/\r\n|\r|\n/)},this.$detectNewLine=function(e){var t=e.match(/^.*?(\r\n|\r|\n)/m);this.$autoNewLine=t?t[1]:"\n",this._signal("changeNewLineMode")},this.getNewLineCharacter=function(){switch(this.$newLineMode){case"windows":return"\r\n";case"unix":return"\n";default:return this.$autoNewLine||"\n"}},this.$autoNewLine="",this.$newLineMode="auto",this.setNewLineMode=function(e){if(this.$newLineMode===e)return;this.$newLineMode=e,this._signal("changeNewLineMode")},this.getNewLineMode=function(){return this.$newLineMode},this.isNewLine=function(e){return e=="\r\n"||e=="\r"||e=="\n"},this.getLine=function(e){return this.$lines[e]||""},this.getLines=function(e,t){return this.$lines.slice(e,t+1)},this.getAllLines=function(){return this.getLines(0,this.getLength())},this.getLength=function(){return this.$lines.length},this.getTextRange=function(e){return this.getLinesForRange(e).join(this.getNewLineCharacter())},this.getLinesForRange=function(e){var t;if(e.start.row===e.end.row)t=[this.getLine(e.start.row).substring(e.start.column,e.end.column)];else{t=this.getLines(e.start.row,e.end.row),t[0]=(t[0]||"").substring(e.start.column);var n=t.length-1;e.end.row-e.start.row==n&&(t[n]=t[n].substring(0,e.end.column))}return t},this.insertLines=function(e,t){return console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."),this.insertFullLines(e,t)},this.removeLines=function(e,t){return console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."),this.removeFullLines(e,t)},this.insertNewLine=function(e){return console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead."),this.insertMergedLines(e,["",""])},this.insert=function(e,t){return this.getLength()<=1&&this.$detectNewLine(t),this.insertMergedLines(e,this.$split(t))},this.insertInLine=function(e,t){var n=this.clippedPos(e.row,e.column),r=this.pos(e.row,e.column+t.length);return this.applyDelta({start:n,end:r,action:"insert",lines:[t]},!0),this.clonePos(r)},this.clippedPos=function(e,t){var n=this.getLength();e===undefined?e=n:e<0?e=0:e>=n&&(e=n-1,t=undefined);var r=this.getLine(e);return t==undefined&&(t=r.length),t=Math.min(Math.max(t,0),r.length),{row:e,column:t}},this.clonePos=function(e){return{row:e.row,column:e.column}},this.pos=function(e,t){return{row:e,column:t}},this.$clipPosition=function(e){var t=this.getLength();return e.row>=t?(e.row=Math.max(0,t-1),e.column=this.getLine(t-1).length):(e.row=Math.max(0,e.row),e.column=Math.min(Math.max(e.column,0),this.getLine(e.row).length)),e},this.insertFullLines=function(e,t){e=Math.min(Math.max(e,0),this.getLength());var n=0;e<this.getLength()?(t=t.concat([""]),n=0):(t=[""].concat(t),e--,n=this.$lines[e].length),this.insertMergedLines({row:e,column:n},t)},this.insertMergedLines=function(e,t){var n=this.clippedPos(e.row,e.column),r={row:n.row+t.length-1,column:(t.length==1?n.column:0)+t[t.length-1].length};return this.applyDelta({start:n,end:r,action:"insert",lines:t}),this.clonePos(r)},this.remove=function(e){var t=this.clippedPos(e.start.row,e.start.column),n=this.clippedPos(e.end.row,e.end.column);return this.applyDelta({start:t,end:n,action:"remove",lines:this.getLinesForRange({start:t,end:n})}),this.clonePos(t)},this.removeInLine=function(e,t,n){var r=this.clippedPos(e,t),i=this.clippedPos(e,n);return this.applyDelta({start:r,end:i,action:"remove",lines:this.getLinesForRange({start:r,end:i})},!0),this.clonePos(r)},this.removeFullLines=function(e,t){e=Math.min(Math.max(0,e),this.getLength()-1),t=Math.min(Math.max(0,t),this.getLength()-1);var n=t==this.getLength()-1&&e>0,r=t<this.getLength()-1,i=n?e-1:e,s=n?this.getLine(i).length:0,u=r?t+1:t,a=r?0:this.getLine(u).length,f=new o(i,s,u,a),l=this.$lines.slice(e,t+1);return this.applyDelta({start:f.start,end:f.end,action:"remove",lines:this.getLinesForRange(f)}),l},this.removeNewLine=function(e){e<this.getLength()-1&&e>=0&&this.applyDelta({start:this.pos(e,this.getLine(e).length),end:this.pos(e+1,0),action:"remove",lines:["",""]})},this.replace=function(e,t){e instanceof o||(e=o.fromPoints(e.start,e.end));if(t.length===0&&e.isEmpty())return e.start;if(t==this.getTextRange(e))return e.end;this.remove(e);var n;return t?n=this.insert(e.start,t):n=e.start,n},this.applyDeltas=function(e){for(var t=0;t<e.length;t++)this.applyDelta(e[t])},this.revertDeltas=function(e){for(var t=e.length-1;t>=0;t--)this.revertDelta(e[t])},this.applyDelta=function(e,t){var n=e.action=="insert";if(n?e.lines.length<=1&&!e.lines[0]:!o.comparePoints(e.start,e.end))return;n&&e.lines.length>2e4&&this.$splitAndapplyLargeDelta(e,2e4),i(this.$lines,e,t),this._signal("change",e)},this.$splitAndapplyLargeDelta=function(e,t){var n=e.lines,r=n.length,i=e.start.row,s=e.start.column,o=0,u=0;do{o=u,u+=t-1;var a=n.slice(o,u);if(u>r){e.lines=a,e.start.row=i+o,e.start.column=s;break}a.push(""),this.applyDelta({start:this.pos(i+o,s),end:this.pos(i+u,s=0),action:e.action,lines:a},!0)}while(!0)},this.revertDelta=function(e){this.applyDelta({start:this.clonePos(e.start),end:this.clonePos(e.end),action:e.action=="insert"?"remove":"insert",lines:e.lines.slice()})},this.indexToPosition=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length;for(var i=t||0,s=n.length;i<s;i++){e-=n[i].length+r;if(e<0)return{row:i,column:e+n[i].length+r}}return{row:s-1,column:n[s-1].length}},this.positionToIndex=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length,i=0,s=Math.min(e.row,n.length);for(var o=t||0;o<s;++o)i+=n[o].length+r;return i+e.column}}).call(a.prototype),t.Document=a}),ace.define("ace/worker/mirror",["require","exports","module","ace/range","ace/document","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../range").Range,i=e("../document").Document,s=e("../lib/lang"),o=t.Mirror=function(e){this.sender=e;var t=this.doc=new i(""),n=this.deferredUpdate=s.delayedCall(this.onUpdate.bind(this)),r=this;e.on("change",function(e){var i=e.data;if(i[0].start)t.applyDeltas(i);else for(var s=0;s<i.length;s+=2){if(Array.isArray(i[s+1]))var o={action:"insert",start:i[s],lines:i[s+1]};else var o={action:"remove",start:i[s],end:i[s+1]};t.applyDelta(o,!0)}if(r.$timeout)return n.schedule(r.$timeout);r.onUpdate()})};(function(){this.$timeout=500,this.setTimeout=function(e){this.$timeout=e},this.setValue=function(e){this.doc.setValue(e),this.deferredUpdate.schedule(this.$timeout)},this.getValue=function(e){this.sender.callback(this.doc.getValue(),e)},this.onUpdate=function(){},this.isPending=function(){return this.deferredUpdate.isPending()}}).call(o.prototype)}),ace.define("ace/mode/xml/sax",["require","exports","module"],function(e,t,n){function d(){}function v(e,t,n,r,i){function s(e){if(e>65535){e-=65536;var t=55296+(e>>10),n=56320+(e&1023);return String.fromCharCode(t,n)}return String.fromCharCode(e)}function o(e){var t=e.slice(1,-1);return t in n?n[t]:t.charAt(0)==="#"?s(parseInt(t.substr(1).replace("x","0x"))):(i.error("entity not found:"+e),e)}function u(t){var n=e.substring(v,t).replace(/&#?\w+;/g,o);h&&a(v),r.characters(n,0,t-v),v=t}function a(t,n){while(t>=l&&(n=c.exec(e)))f=n.index,l=f+n[0].length,h.lineNumber++;h.columnNumber=t-f+1}var f=0,l=0,c=/.+(?:\r\n?|\n)|.*$/g,h=r.locator,p=[{currentNSMap:t}],d={},v=0;for(;;){var E=e.indexOf("<",v);if(E<0){if(!e.substr(v).match(/^\s*$/)){var N=r.document,C=N.createTextNode(e.substr(v));N.appendChild(C),r.currentElement=C}return}E>v&&u(E);switch(e.charAt(E+1)){case"/":var k=e.indexOf(">",E+3),L=e.substring(E+2,k),A;if(!(p.length>1)){i.fatalError("end tag name not found for: "+L);break}A=p.pop();var O=A.localNSMap;A.tagName!=L&&i.fatalError("end tag name: "+L+" does not match the current start tagName: "+A.tagName),r.endElement(A.uri,A.localName,L);if(O)for(var M in O)r.endPrefixMapping(M);k++;break;case"?":h&&a(E),k=x(e,E,r);break;case"!":h&&a(E),k=S(e,E,r,i);break;default:try{h&&a(E);var _=new T,k=g(e,E,_,o,i),D=_.length;if(D&&h){var P=m(h,{});for(var E=0;E<D;E++){var H=_[E];a(H.offset),H.offset=m(h,{})}m(P,h)}!_.closed&&w(e,k,_.tagName,d)&&(_.closed=!0,n.nbsp||i.warning("unclosed xml attribute")),y(_,r,p),_.uri==="http://www.w3.org/1999/xhtml"&&!_.closed?k=b(e,k,_.tagName,o,r):k++}catch(B){i.error("element parse error: "+B),k=-1}}k<0?u(E+1):v=k}}function m(e,t){return t.lineNumber=e.lineNumber,t.columnNumber=e.columnNumber,t}function g(e,t,n,r,i){var s,d,v=++t,m=o;for(;;){var g=e.charAt(v);switch(g){case"=":if(m===u)s=e.slice(t,v),m=f;else{if(m!==a)throw new Error("attribute equal must after attrName");m=f}break;case"'":case'"':if(m===f){t=v+1,v=e.indexOf(g,t);if(!(v>0))throw new Error("attribute value no end '"+g+"' match");d=e.slice(t,v).replace(/&#?\w+;/g,r),n.add(s,d,t-1),m=c}else{if(m!=l)throw new Error('attribute value must after "="');d=e.slice(t,v).replace(/&#?\w+;/g,r),n.add(s,d,t),i.warning('attribute "'+s+'" missed start quot('+g+")!!"),t=v+1,m=c}break;case"/":switch(m){case o:n.setTagName(e.slice(t,v));case c:case h:case p:m=p,n.closed=!0;case l:case u:case a:break;default:throw new Error("attribute invalid close char('/')")}break;case"":i.error("unexpected end of input");case">":switch(m){case o:n.setTagName(e.slice(t,v));case c:case h:case p:break;case l:case u:d=e.slice(t,v),d.slice(-1)==="/"&&(n.closed=!0,d=d.slice(0,-1));case a:m===a&&(d=s),m==l?(i.warning('attribute "'+d+'" missed quot(")!!'),n.add(s,d.replace(/&#?\w+;/g,r),t)):(i.warning('attribute "'+d+'" missed value!! "'+d+'" instead!!'),n.add(d,d,t));break;case f:throw new Error("attribute value missed!!")}return v;case"\u0080":g=" ";default:if(g<=" ")switch(m){case o:n.setTagName(e.slice(t,v)),m=h;break;case u:s=e.slice(t,v),m=a;break;case l:var d=e.slice(t,v).replace(/&#?\w+;/g,r);i.warning('attribute "'+d+'" missed quot(")!!'),n.add(s,d,t);case c:m=h}else switch(m){case a:i.warning('attribute "'+s+'" missed value!! "'+s+'" instead!!'),n.add(s,s,t),t=v,m=u;break;case c:i.warning('attribute space is required"'+s+'"!!');case h:m=u,t=v;break;case f:m=l,t=v;break;case p:throw new Error("elements closed character '/' and '>' must be connected to")}}v++}}function y(e,t,n){var r=e.tagName,i=null,s=n[n.length-1].currentNSMap,o=e.length;while(o--){var u=e[o],a=u.qName,f=u.value,l=a.indexOf(":");if(l>0)var c=u.prefix=a.slice(0,l),h=a.slice(l+1),p=c==="xmlns"&&h;else h=a,c=null,p=a==="xmlns"&&"";u.localName=h,p!==!1&&(i==null&&(i={},E(s,s={})),s[p]=i[p]=f,u.uri="http://www.w3.org/2000/xmlns/",t.startPrefixMapping(p,f))}var o=e.length;while(o--){u=e[o];var c=u.prefix;c&&(c==="xml"&&(u.uri="http://www.w3.org/XML/1998/namespace"),c!=="xmlns"&&(u.uri=s[c]))}var l=r.indexOf(":");l>0?(c=e.prefix=r.slice(0,l),h=e.localName=r.slice(l+1)):(c=null,h=e.localName=r);var d=e.uri=s[c||""];t.startElement(d,h,r,e);if(e.closed){t.endElement(d,h,r);if(i)for(c in i)t.endPrefixMapping(c)}else e.currentNSMap=s,e.localNSMap=i,n.push(e)}function b(e,t,n,r,i){if(/^(?:script|textarea)$/i.test(n)){var s=e.indexOf("</"+n+">",t),o=e.substring(t+1,s);if(/[&<]/.test(o))return/^script$/i.test(n)?(i.characters(o,0,o.length),s):(o=o.replace(/&#?\w+;/g,r),i.characters(o,0,o.length),s)}return t+1}function w(e,t,n,r){var i=r[n];return i==null&&(i=r[n]=e.lastIndexOf("</"+n+">")),i<t}function E(e,t){for(var n in e)t[n]=e[n]}function S(e,t,n,r){var i=e.charAt(t+2);switch(i){case"-":if(e.charAt(t+3)==="-"){var s=e.indexOf("-->",t+4);return s>t?(n.comment(e,t+4,s-t-4),s+3):(r.error("Unclosed comment"),-1)}return-1;default:if(e.substr(t+3,6)=="CDATA["){var s=e.indexOf("]]>",t+9);return n.startCDATA(),n.characters(e,t+9,s-t-9),n.endCDATA(),s+3}var o=C(e,t),u=o.length;if(u>1&&/!doctype/i.test(o[0][0])){var a=o[1][0],f=u>3&&/^public$/i.test(o[2][0])&&o[3][0],l=u>4&&o[4][0],c=o[u-1];return n.startDTD(a,f&&f.replace(/^(['"])(.*?)\1$/,"$2"),l&&l.replace(/^(['"])(.*?)\1$/,"$2")),n.endDTD(),c.index+c[0].length}}return-1}function x(e,t,n){var r=e.indexOf("?>",t);if(r){var i=e.substring(t,r).match(/^<\?(\S*)\s*([\s\S]*?)\s*$/);if(i){var s=i[0].length;return n.processingInstruction(i[1],i[2]),r+2}return-1}return-1}function T(e){}function N(e,t){return e.__proto__=t,e}function C(e,t){var n,r=[],i=/'[^']+'|"[^"]+"|[^\s<>\/=]+=?|(\/?\s*>|<)/g;i.lastIndex=t,i.exec(e);while(n=i.exec(e)){r.push(n);if(n[1])return r}}var r=/[A-Z_a-z\xC0-\xD6\xD8-\xF6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/,i=new RegExp("[\\-\\.0-9"+r.source.slice(1,-1)+"\u00b7\u0300-\u036f\\ux203F-\u2040]"),s=new RegExp("^"+r.source+i.source+"*(?::"+r.source+i.source+"*)?$"),o=0,u=1,a=2,f=3,l=4,c=5,h=6,p=7;return d.prototype={parse:function(e,t,n){var r=this.domBuilder;r.startDocument(),E(t,t={}),v(e,t,n,r,this.errorHandler),r.endDocument()}},T.prototype={setTagName:function(e){if(!s.test(e))throw new Error("invalid tagName:"+e);this.tagName=e},add:function(e,t,n){if(!s.test(e))throw new Error("invalid attribute:"+e);this[this.length++]={qName:e,value:t,offset:n}},length:0,getLocalName:function(e){return this[e].localName},getOffset:function(e){return this[e].offset},getQName:function(e){return this[e].qName},getURI:function(e){return this[e].uri},getValue:function(e){return this[e].value}},N({},N.prototype)instanceof N||(N=function(e,t){function n(){}n.prototype=t,n=new n;for(t in e)n[t]=e[t];return n}),d}),ace.define("ace/mode/xml/dom",["require","exports","module"],function(e,t,n){function r(e,t){for(var n in e)t[n]=e[n]}function i(e,t){var n=e.prototype;if(Object.create){var i=Object.create(t.prototype);n.__proto__=i}if(!(n instanceof t)){function s(){}s.prototype=t.prototype,s=new s,r(n,s),e.prototype=n=s}n.constructor!=e&&(typeof e!="function"&&console.error("unknow Class:"+e),n.constructor=e)}function B(e,t){if(t instanceof Error)var n=t;else n=this,Error.call(this,w[e]),this.message=w[e],Error.captureStackTrace&&Error.captureStackTrace(this,B);return n.code=e,t&&(this.message=this.message+": "+t),n}function j(){}function F(e,t){this._node=e,this._refresh=t,I(this)}function I(e){var t=e._node._inc||e._node.ownerDocument._inc;if(e._inc!=t){var n=e._refresh(e._node);gt(e,"length",n.length),r(n,e),e._inc=t}}function q(){}function R(e,t){var n=e.length;while(n--)if(e[n]===t)return n}function U(e,t,n,r){r?t[R(t,r)]=n:t[t.length++]=n;if(e){n.ownerElement=e;var i=e.ownerDocument;i&&(r&&Q(i,e,r),K(i,e,n))}}function z(e,t,n){var r=R(t,n);if(!(r>=0))throw B(L,new Error);var i=t.length-1;while(r<i)t[r]=t[++r];t.length=i;if(e){var s=e.ownerDocument;s&&(Q(s,e,n),n.ownerElement=null)}}function W(e){this._features={};if(e)for(var t in e)this._features=e[t]}function X(){}function V(e){return e=="<"&&"&lt;"||e==">"&&"&gt;"||e=="&"&&"&amp;"||e=='"'&&"&quot;"||"&#"+e.charCodeAt()+";"}function $(e,t){if(t(e))return!0;if(e=e.firstChild)do if($(e,t))return!0;while(e=e.nextSibling)}function J(){}function K(e,t,n){e&&e._inc++;var r=n.namespaceURI;r=="http://www.w3.org/2000/xmlns/"&&(t._nsMap[n.prefix?n.localName:""]=n.value)}function Q(e,t,n,r){e&&e._inc++;var i=n.namespaceURI;i=="http://www.w3.org/2000/xmlns/"&&delete t._nsMap[n.prefix?n.localName:""]}function G(e,t,n){if(e&&e._inc){e._inc++;var r=t.childNodes;if(n)r[r.length++]=n;else{var i=t.firstChild,s=0;while(i)r[s++]=i,i=i.nextSibling;r.length=s}}}function Y(e,t){var n=t.previousSibling,r=t.nextSibling;return n?n.nextSibling=r:e.firstChild=r,r?r.previousSibling=n:e.lastChild=n,G(e.ownerDocument,e),t}function Z(e,t,n){var r=t.parentNode;r&&r.removeChild(t);if(t.nodeType===g){var i=t.firstChild;if(i==null)return t;var s=t.lastChild}else i=s=t;var o=n?n.previousSibling:e.lastChild;i.previousSibling=o,s.nextSibling=n,o?o.nextSibling=i:e.firstChild=i,n==null?e.lastChild=s:n.previousSibling=s;do i.parentNode=e;while(i!==s&&(i=i.nextSibling));return G(e.ownerDocument||e,e),t.nodeType==g&&(t.firstChild=t.lastChild=null),t}function et(e,t){var n=t.parentNode;if(n){var r=e.lastChild;n.removeChild(t);var r=e.lastChild}var r=e.lastChild;return t.parentNode=e,t.previousSibling=r,t.nextSibling=null,r?r.nextSibling=t:e.firstChild=t,e.lastChild=t,G(e.ownerDocument,e,t),t}function tt(){this._nsMap={}}function nt(){}function rt(){}function it(){}function st(){}function ot(){}function ut(){}function at(){}function ft(){}function lt(){}function ct(){}function ht(){}function pt(){}function dt(e,t){switch(e.nodeType){case u:var n=e.attributes,r=n.length,i=e.firstChild,o=e.tagName,h=s===e.namespaceURI;t.push("<",o);for(var y=0;y<r;y++)dt(n.item(y),t,h);if(i||h&&!/^(?:meta|link|img|br|hr|input|button)$/i.test(o)){t.push(">");if(h&&/^script$/i.test(o))i&&t.push(i.data);else while(i)dt(i,t),i=i.nextSibling;t.push("</",o,">")}else t.push("/>");return;case v:case g:var i=e.firstChild;while(i)dt(i,t),i=i.nextSibling;return;case a:return t.push(" ",e.name,'="',e.value.replace(/[<&"]/g,V),'"');case f:return t.push(e.data.replace(/[<&]/g,V));case l:return t.push("<![CDATA[",e.data,"]]>");case d:return t.push("<!--",e.data,"-->");case m:var b=e.publicId,w=e.systemId;t.push("<!DOCTYPE ",e.name);if(b)t.push(' PUBLIC "',b),w&&w!="."&&t.push('" "',w),t.push('">');else if(w&&w!=".")t.push(' SYSTEM "',w,'">');else{var E=e.internalSubset;E&&t.push(" [",E,"]"),t.push(">")}return;case p:return t.push("<?",e.target," ",e.data,"?>");case c:return t.push("&",e.nodeName,";");default:t.push("??",e.nodeName)}}function vt(e,t,n){var r;switch(t.nodeType){case u:r=t.cloneNode(!1),r.ownerDocument=e;case g:break;case a:n=!0}r||(r=t.cloneNode(!1)),r.ownerDocument=e,r.parentNode=null;if(n){var i=t.firstChild;while(i)r.appendChild(vt(e,i,n)),i=i.nextSibling}return r}function mt(e,t,n){var r=new t.constructor;for(var i in t){var s=t[i];typeof s!="object"&&s!=r[i]&&(r[i]=s)}t.childNodes&&(r.childNodes=new j),r.ownerDocument=e;switch(r.nodeType){case u:var o=t.attributes,f=r.attributes=new q,l=o.length;f._ownerElement=r;for(var c=0;c<l;c++)r.setAttributeNode(mt(e,o.item(c),!0));break;case a:n=!0}if(n){var h=t.firstChild;while(h)r.appendChild(mt(e,h,n)),h=h.nextSibling}return r}function gt(e,t,n){e[t]=n}var s="http://www.w3.org/1999/xhtml",o={},u=o.ELEMENT_NODE=1,a=o.ATTRIBUTE_NODE=2,f=o.TEXT_NODE=3,l=o.CDATA_SECTION_NODE=4,c=o.ENTITY_REFERENCE_NODE=5,h=o.ENTITY_NODE=6,p=o.PROCESSING_INSTRUCTION_NODE=7,d=o.COMMENT_NODE=8,v=o.DOCUMENT_NODE=9,m=o.DOCUMENT_TYPE_NODE=10,g=o.DOCUMENT_FRAGMENT_NODE=11,y=o.NOTATION_NODE=12,b={},w={},E=b.INDEX_SIZE_ERR=(w[1]="Index size error",1),S=b.DOMSTRING_SIZE_ERR=(w[2]="DOMString size error",2),x=b.HIERARCHY_REQUEST_ERR=(w[3]="Hierarchy request error",3),T=b.WRONG_DOCUMENT_ERR=(w[4]="Wrong document",4),N=b.INVALID_CHARACTER_ERR=(w[5]="Invalid character",5),C=b.NO_DATA_ALLOWED_ERR=(w[6]="No data allowed",6),k=b.NO_MODIFICATION_ALLOWED_ERR=(w[7]="No modification allowed",7),L=b.NOT_FOUND_ERR=(w[8]="Not found",8),A=b.NOT_SUPPORTED_ERR=(w[9]="Not supported",9),O=b.INUSE_ATTRIBUTE_ERR=(w[10]="Attribute in use",10),M=b.INVALID_STATE_ERR=(w[11]="Invalid state",11),_=b.SYNTAX_ERR=(w[12]="Syntax error",12),D=b.INVALID_MODIFICATION_ERR=(w[13]="Invalid modification",13),P=b.NAMESPACE_ERR=(w[14]="Invalid namespace",14),H=b.INVALID_ACCESS_ERR=(w[15]="Invalid access",15);B.prototype=Error.prototype,r(b,B),j.prototype={length:0,item:function(e){return this[e]||null}},F.prototype.item=function(e){return I(this),this[e]},i(F,j),q.prototype={length:0,item:j.prototype.item,getNamedItem:function(e){var t=this.length;while(t--){var n=this[t];if(n.nodeName==e)return n}},setNamedItem:function(e){var t=e.ownerElement;if(t&&t!=this._ownerElement)throw new B(O);var n=this.getNamedItem(e.nodeName);return U(this._ownerElement,this,e,n),n},setNamedItemNS:function(e){var t=e.ownerElement,n;if(t&&t!=this._ownerElement)throw new B(O);return n=this.getNamedItemNS(e.namespaceURI,e.localName),U(this._ownerElement,this,e,n),n},removeNamedItem:function(e){var t=this.getNamedItem(e);return z(this._ownerElement,this,t),t},removeNamedItemNS:function(e,t){var n=this.getNamedItemNS(e,t);return z(this._ownerElement,this,n),n},getNamedItemNS:function(e,t){var n=this.length;while(n--){var r=this[n];if(r.localName==t&&r.namespaceURI==e)return r}return null}},W.prototype={hasFeature:function(e,t){var n=this._features[e.toLowerCase()];return n&&(!t||t in n)?!0:!1},createDocument:function(e,t,n){var r=new J;r.implementation=this,r.childNodes=new j,r.doctype=n,n&&r.appendChild(n);if(t){var i=r.createElementNS(e,t);r.appendChild(i)}return r},createDocumentType:function(e,t,n){var r=new ut;return r.name=e,r.nodeName=e,r.publicId=t,r.systemId=n,r}},X.prototype={firstChild:null,lastChild:null,previousSibling:null,nextSibling:null,attributes:null,parentNode:null,childNodes:null,ownerDocument:null,nodeValue:null,namespaceURI:null,prefix:null,localName:null,insertBefore:function(e,t){return Z(this,e,t)},replaceChild:function(e,t){this.insertBefore(e,t),t&&this.removeChild(t)},removeChild:function(e){return Y(this,e)},appendChild:function(e){return this.insertBefore(e,null)},hasChildNodes:function(){return this.firstChild!=null},cloneNode:function(e){return mt(this.ownerDocument||this,this,e)},normalize:function(){var e=this.firstChild;while(e){var t=e.nextSibling;t&&t.nodeType==f&&e.nodeType==f?(this.removeChild(t),e.appendData(t.data)):(e.normalize(),e=t)}},isSupported:function(e,t){return this.ownerDocument.implementation.hasFeature(e,t)},hasAttributes:function(){return this.attributes.length>0},lookupPrefix:function(e){var t=this;while(t){var n=t._nsMap;if(n)for(var r in n)if(n[r]==e)return r;t=t.nodeType==2?t.ownerDocument:t.parentNode}return null},lookupNamespaceURI:function(e){var t=this;while(t){var n=t._nsMap;if(n&&e in n)return n[e];t=t.nodeType==2?t.ownerDocument:t.parentNode}return null},isDefaultNamespace:function(e){var t=this.lookupPrefix(e);return t==null}},r(o,X),r(o,X.prototype),J.prototype={nodeName:"#document",nodeType:v,doctype:null,documentElement:null,_inc:1,insertBefore:function(e,t){if(e.nodeType==g){var n=e.firstChild;while(n){var r=n.nextSibling;this.insertBefore(n,t),n=r}return e}return this.documentElement==null&&e.nodeType==1&&(this.documentElement=e),Z(this,e,t),e.ownerDocument=this,e},removeChild:function(e){return this.documentElement==e&&(this.documentElement=null),Y(this,e)},importNode:function(e,t){return vt(this,e,t)},getElementById:function(e){var t=null;return $(this.documentElement,function(n){if(n.nodeType==1&&n.getAttribute("id")==e)return t=n,!0}),t},createElement:function(e){var t=new tt;t.ownerDocument=this,t.nodeName=e,t.tagName=e,t.childNodes=new j;var n=t.attributes=new q;return n._ownerElement=t,t},createDocumentFragment:function(){var e=new ct;return e.ownerDocument=this,e.childNodes=new j,e},createTextNode:function(e){var t=new it;return t.ownerDocument=this,t.appendData(e),t},createComment:function(e){var t=new st;return t.ownerDocument=this,t.appendData(e),t},createCDATASection:function(e){var t=new ot;return t.ownerDocument=this,t.appendData(e),t},createProcessingInstruction:function(e,t){var n=new ht;return n.ownerDocument=this,n.tagName=n.target=e,n.nodeValue=n.data=t,n},createAttribute:function(e){var t=new nt;return t.ownerDocument=this,t.name=e,t.nodeName=e,t.localName=e,t.specified=!0,t},createEntityReference:function(e){var t=new lt;return t.ownerDocument=this,t.nodeName=e,t},createElementNS:function(e,t){var n=new tt,r=t.split(":"),i=n.attributes=new q;return n.childNodes=new j,n.ownerDocument=this,n.nodeName=t,n.tagName=t,n.namespaceURI=e,r.length==2?(n.prefix=r[0],n.localName=r[1]):n.localName=t,i._ownerElement=n,n},createAttributeNS:function(e,t){var n=new nt,r=t.split(":");return n.ownerDocument=this,n.nodeName=t,n.name=t,n.namespaceURI=e,n.specified=!0,r.length==2?(n.prefix=r[0],n.localName=r[1]):n.localName=t,n}},i(J,X),tt.prototype={nodeType:u,hasAttribute:function(e){return this.getAttributeNode(e)!=null},getAttribute:function(e){var t=this.getAttributeNode(e);return t&&t.value||""},getAttributeNode:function(e){return this.attributes.getNamedItem(e)},setAttribute:function(e,t){var n=this.ownerDocument.createAttribute(e);n.value=n.nodeValue=""+t,this.setAttributeNode(n)},removeAttribute:function(e){var t=this.getAttributeNode(e);t&&this.removeAttributeNode(t)},appendChild:function(e){return e.nodeType===g?this.insertBefore(e,null):et(this,e)},setAttributeNode:function(e){return this.attributes.setNamedItem(e)},setAttributeNodeNS:function(e){return this.attributes.setNamedItemNS(e)},removeAttributeNode:function(e){return this.attributes.removeNamedItem(e.nodeName)},removeAttributeNS:function(e,t){var n=this.getAttributeNodeNS(e,t);n&&this.removeAttributeNode(n)},hasAttributeNS:function(e,t){return this.getAttributeNodeNS(e,t)!=null},getAttributeNS:function(e,t){var n=this.getAttributeNodeNS(e,t);return n&&n.value||""},setAttributeNS:function(e,t,n){var r=this.ownerDocument.createAttributeNS(e,t);r.value=r.nodeValue=""+n,this.setAttributeNode(r)},getAttributeNodeNS:function(e,t){return this.attributes.getNamedItemNS(e,t)},getElementsByTagName:function(e){return new F(this,function(t){var n=[];return $(t,function(r){r!==t&&r.nodeType==u&&(e==="*"||r.tagName==e)&&n.push(r)}),n})},getElementsByTagNameNS:function(e,t){return new F(this,function(n){var r=[];return $(n,function(i){i!==n&&i.nodeType===u&&(e==="*"||i.namespaceURI===e)&&(t==="*"||i.localName==t)&&r.push(i)}),r})}},J.prototype.getElementsByTagName=tt.prototype.getElementsByTagName,J.prototype.getElementsByTagNameNS=tt.prototype.getElementsByTagNameNS,i(tt,X),nt.prototype.nodeType=a,i(nt,X),rt.prototype={data:"",substringData:function(e,t){return this.data.substring(e,e+t)},appendData:function(e){e=this.data+e,this.nodeValue=this.data=e,this.length=e.length},insertData:function(e,t){this.replaceData(e,0,t)},appendChild:function(e){throw new Error(w[3])},deleteData:function(e,t){this.replaceData(e,t,"")},replaceData:function(e,t,n){var r=this.data.substring(0,e),i=this.data.substring(e+t);n=r+n+i,this.nodeValue=this.data=n,this.length=n.length}},i(rt,X),it.prototype={nodeName:"#text",nodeType:f,splitText:function(e){var t=this.data,n=t.substring(e);t=t.substring(0,e),this.data=this.nodeValue=t,this.length=t.length;var r=this.ownerDocument.createTextNode(n);return this.parentNode&&this.parentNode.insertBefore(r,this.nextSibling),r}},i(it,rt),st.prototype={nodeName:"#comment",nodeType:d},i(st,rt),ot.prototype={nodeName:"#cdata-section",nodeType:l},i(ot,rt),ut.prototype.nodeType=m,i(ut,X),at.prototype.nodeType=y,i(at,X),ft.prototype.nodeType=h,i(ft,X),lt.prototype.nodeType=c,i(lt,X),ct.prototype.nodeName="#document-fragment",ct.prototype.nodeType=g,i(ct,X),ht.prototype.nodeType=p,i(ht,X),pt.prototype.serializeToString=function(e){var t=[];return dt(e,t),t.join("")},X.prototype.toString=function(){return pt.prototype.serializeToString(this)};try{if(Object.defineProperty){Object.defineProperty(F.prototype,"length",{get:function(){return I(this),this.$$length}}),Object.defineProperty(X.prototype,"textContent",{get:function(){return yt(this)},set:function(e){switch(this.nodeType){case 1:case 11:while(this.firstChild)this.removeChild(this.firstChild);(e||String(e))&&this.appendChild(this.ownerDocument.createTextNode(e));break;default:this.data=e,this.value=value,this.nodeValue=e}}});function yt(e){switch(e.nodeType){case 1:case 11:var t=[];e=e.firstChild;while(e)e.nodeType!==7&&e.nodeType!==8&&t.push(yt(e)),e=e.nextSibling;return t.join("");default:return e.nodeValue}}gt=function(e,t,n){e["$$"+t]=n}}}catch(bt){}return W}),ace.define("ace/mode/xml/dom-parser",["require","exports","module","ace/mode/xml/sax","ace/mode/xml/dom"],function(e,t,n){"use strict";function s(e){this.options=e||{locator:{}}}function o(e,t,n){function s(t){var s=e[t];if(!s)if(i)s=e.length==2?function(n){e(t,n)}:e;else{var o=arguments.length;while(--o)if(s=e[arguments[o]])break}r[t]=s&&function(e){s(e+f(n),e,n)}||function(){}}if(!e){if(t instanceof u)return t;e=t}var r={},i=e instanceof Function;return n=n||{},s("warning","warn"),s("error","warn","warning"),s("fatalError","warn","warning","error"),r}function u(){this.cdata=!1}function a(e,t){t.lineNumber=e.lineNumber,t.columnNumber=e.columnNumber}function f(e){if(e)return"\n@"+(e.systemId||"")+"#[line:"+e.lineNumber+",col:"+e.columnNumber+"]"}function l(e,t,n){return typeof e=="string"?e.substr(t,n):e.length>=t+n||t?new java.lang.String(e,t,n)+"":e}function c(e,t){e.currentElement?e.currentElement.appendChild(t):e.document.appendChild(t)}var r=e("./sax"),i=e("./dom");return s.prototype.parseFromString=function(e,t){var n=this.options,i=new r,s=n.domBuilder||new u,a=n.errorHandler,f=n.locator,l=n.xmlns||{},c={lt:"<",gt:">",amp:"&",quot:'"',apos:"'"};return f&&s.setDocumentLocator(f),i.errorHandler=o(a,s,f),i.domBuilder=n.domBuilder||s,/\/x?html?$/.test(t)&&(c.nbsp="\u00a0",c.copy="\u00a9",l[""]="http://www.w3.org/1999/xhtml"),e?i.parse(e,l,c):i.errorHandler.error("invalid document source"),s.document},u.prototype={startDocument:function(){this.document=(new i).createDocument(null,null,null),this.locator&&(this.document.documentURI=this.locator.systemId)},startElement:function(e,t,n,r){var i=this.document,s=i.createElementNS(e,n||t),o=r.length;c(this,s),this.currentElement=s,this.locator&&a(this.locator,s);for(var u=0;u<o;u++){var e=r.getURI(u),f=r.getValue(u),n=r.getQName(u),l=i.createAttributeNS(e,n);l.getOffset&&a(l.getOffset(1),l),l.value=l.nodeValue=f,s.setAttributeNode(l)}},endElement:function(e,t,n){var r=this.currentElement,i=r.tagName;this.currentElement=r.parentNode},startPrefixMapping:function(e,t){},endPrefixMapping:function(e){},processingInstruction:function(e,t){var n=this.document.createProcessingInstruction(e,t);this.locator&&a(this.locator,n),c(this,n)},ignorableWhitespace:function(e,t,n){},characters:function(e,t,n){e=l.apply(this,arguments);if(this.currentElement&&e){if(this.cdata){var r=this.document.createCDATASection(e);this.currentElement.appendChild(r)}else{var r=this.document.createTextNode(e);this.currentElement.appendChild(r)}this.locator&&a(this.locator,r)}},skippedEntity:function(e){},endDocument:function(){this.document.normalize()},setDocumentLocator:function(e){if(this.locator=e)e.lineNumber=0},comment:function(e,t,n){e=l.apply(this,arguments);var r=this.document.createComment(e);this.locator&&a(this.locator,r),c(this,r)},startCDATA:function(){this.cdata=!0},endCDATA:function(){this.cdata=!1},startDTD:function(e,t,n){var r=this.document.implementation;if(r&&r.createDocumentType){var i=r.createDocumentType(e,t,n);this.locator&&a(this.locator,i),c(this,i)}},warning:function(e){console.warn(e,f(this.locator))},error:function(e){console.error(e,f(this.locator))},fatalError:function(e){throw console.error(e,f(this.locator)),e}},"endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl".replace(/\w+/g,function(e){u.prototype[e]=function(){return null}}),{DOMParser:s}}),ace.define("ace/mode/xml_worker",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/worker/mirror","ace/mode/xml/dom-parser"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../lib/lang"),s=e("../worker/mirror").Mirror,o=e("./xml/dom-parser").DOMParser,u=t.Worker=function(e){s.call(this,e),this.setTimeout(400),this.context=null};r.inherits(u,s),function(){this.setOptions=function(e){this.context=e.context},this.onUpdate=function(){var e=this.doc.getValue();if(!e)return;var t=new o,n=[];t.options.errorHandler={fatalError:function(e,t,r){n.push({row:r.lineNumber,column:r.columnNumber,text:t,type:"error"})},error:function(e,t,r){n.push({row:r.lineNumber,column:r.columnNumber,text:t,type:"error"})},warning:function(e,t,r){n.push({row:r.lineNumber,column:r.columnNumber,text:t,type:"warning"})}},t.parseFromString(e),this.sender.emit("error",n)}}.call(u.prototype)}),ace.define("ace/lib/es5-shim",["require","exports","module"],function(e,t,n){function r(){}function w(e){try{return Object.defineProperty(e,"sentinel",{}),"sentinel"in e}catch(t){}}function H(e){return e=+e,e!==e?e=0:e!==0&&e!==1/0&&e!==-1/0&&(e=(e>0||-1)*Math.floor(Math.abs(e))),e}function B(e){var t=typeof e;return e===null||t==="undefined"||t==="boolean"||t==="number"||t==="string"}function j(e){var t,n,r;if(B(e))return e;n=e.valueOf;if(typeof n=="function"){t=n.call(e);if(B(t))return t}r=e.toString;if(typeof r=="function"){t=r.call(e);if(B(t))return t}throw new TypeError}Function.prototype.bind||(Function.prototype.bind=function(t){var n=this;if(typeof n!="function")throw new TypeError("Function.prototype.bind called on incompatible "+n);var i=u.call(arguments,1),s=function(){if(this instanceof s){var e=n.apply(this,i.concat(u.call(arguments)));return Object(e)===e?e:this}return n.apply(t,i.concat(u.call(arguments)))};return n.prototype&&(r.prototype=n.prototype,s.prototype=new r,r.prototype=null),s});var i=Function.prototype.call,s=Array.prototype,o=Object.prototype,u=s.slice,a=i.bind(o.toString),f=i.bind(o.hasOwnProperty),l,c,h,p,d;if(d=f(o,"__defineGetter__"))l=i.bind(o.__defineGetter__),c=i.bind(o.__defineSetter__),h=i.bind(o.__lookupGetter__),p=i.bind(o.__lookupSetter__);if([1,2].splice(0).length!=2)if(!function(){function e(e){var t=new Array(e+2);return t[0]=t[1]=0,t}var t=[],n;t.splice.apply(t,e(20)),t.splice.apply(t,e(26)),n=t.length,t.splice(5,0,"XXX"),n+1==t.length;if(n+1==t.length)return!0}())Array.prototype.splice=function(e,t){var n=this.length;e>0?e>n&&(e=n):e==void 0?e=0:e<0&&(e=Math.max(n+e,0)),e+t<n||(t=n-e);var r=this.slice(e,e+t),i=u.call(arguments,2),s=i.length;if(e===n)s&&this.push.apply(this,i);else{var o=Math.min(t,n-e),a=e+o,f=a+s-o,l=n-a,c=n-o;if(f<a)for(var h=0;h<l;++h)this[f+h]=this[a+h];else if(f>a)for(h=l;h--;)this[f+h]=this[a+h];if(s&&e===c)this.length=c,this.push.apply(this,i);else{this.length=c+s;for(h=0;h<s;++h)this[e+h]=i[h]}}return r};else{var v=Array.prototype.splice;Array.prototype.splice=function(e,t){return arguments.length?v.apply(this,[e===void 0?0:e,t===void 0?this.length-e:t].concat(u.call(arguments,2))):[]}}Array.isArray||(Array.isArray=function(t){return a(t)=="[object Array]"});var m=Object("a"),g=m[0]!="a"||!(0 in m);Array.prototype.forEach||(Array.prototype.forEach=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=arguments[1],s=-1,o=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError;while(++s<o)s in r&&t.call(i,r[s],s,n)}),Array.prototype.map||(Array.prototype.map=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=Array(i),o=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var u=0;u<i;u++)u in r&&(s[u]=t.call(o,r[u],u,n));return s}),Array.prototype.filter||(Array.prototype.filter=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=[],o,u=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var f=0;f<i;f++)f in r&&(o=r[f],t.call(u,o,f,n)&&s.push(o));return s}),Array.prototype.every||(Array.prototype.every=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&!t.call(s,r[o],o,n))return!1;return!0}),Array.prototype.some||(Array.prototype.some=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&t.call(s,r[o],o,n))return!0;return!1}),Array.prototype.reduce||(Array.prototype.reduce=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduce of empty array with no initial value");var s=0,o;if(arguments.length>=2)o=arguments[1];else do{if(s in r){o=r[s++];break}if(++s>=i)throw new TypeError("reduce of empty array with no initial value")}while(!0);for(;s<i;s++)s in r&&(o=t.call(void 0,o,r[s],s,n));return o}),Array.prototype.reduceRight||(Array.prototype.reduceRight=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduceRight of empty array with no initial value");var s,o=i-1;if(arguments.length>=2)s=arguments[1];else do{if(o in r){s=r[o--];break}if(--o<0)throw new TypeError("reduceRight of empty array with no initial value")}while(!0);do o in this&&(s=t.call(void 0,s,r[o],o,n));while(o--);return s});if(!Array.prototype.indexOf||[0,1].indexOf(1,2)!=-1)Array.prototype.indexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=0;arguments.length>1&&(i=H(arguments[1])),i=i>=0?i:Math.max(0,r+i);for(;i<r;i++)if(i in n&&n[i]===t)return i;return-1};if(!Array.prototype.lastIndexOf||[0,1].lastIndexOf(0,-3)!=-1)Array.prototype.lastIndexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=r-1;arguments.length>1&&(i=Math.min(i,H(arguments[1]))),i=i>=0?i:r-Math.abs(i);for(;i>=0;i--)if(i in n&&t===n[i])return i;return-1};Object.getPrototypeOf||(Object.getPrototypeOf=function(t){return t.__proto__||(t.constructor?t.constructor.prototype:o)});if(!Object.getOwnPropertyDescriptor){var y="Object.getOwnPropertyDescriptor called on a non-object: ";Object.getOwnPropertyDescriptor=function(t,n){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(y+t);if(!f(t,n))return;var r,i,s;r={enumerable:!0,configurable:!0};if(d){var u=t.__proto__;t.__proto__=o;var i=h(t,n),s=p(t,n);t.__proto__=u;if(i||s)return i&&(r.get=i),s&&(r.set=s),r}return r.value=t[n],r}}Object.getOwnPropertyNames||(Object.getOwnPropertyNames=function(t){return Object.keys(t)});if(!Object.create){var b;Object.prototype.__proto__===null?b=function(){return{__proto__:null}}:b=function(){var e={};for(var t in e)e[t]=null;return e.constructor=e.hasOwnProperty=e.propertyIsEnumerable=e.isPrototypeOf=e.toLocaleString=e.toString=e.valueOf=e.__proto__=null,e},Object.create=function(t,n){var r;if(t===null)r=b();else{if(typeof t!="object")throw new TypeError("typeof prototype["+typeof t+"] != 'object'");var i=function(){};i.prototype=t,r=new i,r.__proto__=t}return n!==void 0&&Object.defineProperties(r,n),r}}if(Object.defineProperty){var E=w({}),S=typeof document=="undefined"||w(document.createElement("div"));if(!E||!S)var x=Object.defineProperty}if(!Object.defineProperty||x){var T="Property description must be an object: ",N="Object.defineProperty called on non-object: ",C="getters & setters can not be defined on this javascript engine";Object.defineProperty=function(t,n,r){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(N+t);if(typeof r!="object"&&typeof r!="function"||r===null)throw new TypeError(T+r);if(x)try{return x.call(Object,t,n,r)}catch(i){}if(f(r,"value"))if(d&&(h(t,n)||p(t,n))){var s=t.__proto__;t.__proto__=o,delete t[n],t[n]=r.value,t.__proto__=s}else t[n]=r.value;else{if(!d)throw new TypeError(C);f(r,"get")&&l(t,n,r.get),f(r,"set")&&c(t,n,r.set)}return t}}Object.defineProperties||(Object.defineProperties=function(t,n){for(var r in n)f(n,r)&&Object.defineProperty(t,r,n[r]);return t}),Object.seal||(Object.seal=function(t){return t}),Object.freeze||(Object.freeze=function(t){return t});try{Object.freeze(function(){})}catch(k){Object.freeze=function(t){return function(n){return typeof n=="function"?n:t(n)}}(Object.freeze)}Object.preventExtensions||(Object.preventExtensions=function(t){return t}),Object.isSealed||(Object.isSealed=function(t){return!1}),Object.isFrozen||(Object.isFrozen=function(t){return!1}),Object.isExtensible||(Object.isExtensible=function(t){if(Object(t)===t)throw new TypeError;var n="";while(f(t,n))n+="?";t[n]=!0;var r=f(t,n);return delete t[n],r});if(!Object.keys){var L=!0,A=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],O=A.length;for(var M in{toString:null})L=!1;Object.keys=function I(e){if(typeof e!="object"&&typeof e!="function"||e===null)throw new TypeError("Object.keys called on a non-object");var I=[];for(var t in e)f(e,t)&&I.push(t);if(L)for(var n=0,r=O;n<r;n++){var i=A[n];f(e,i)&&I.push(i)}return I}}Date.now||(Date.now=function(){return(new Date).getTime()});var _="	\n\f\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\ufeff";if(!String.prototype.trim||_.trim()){_="["+_+"]";var D=new RegExp("^"+_+_+"*"),P=new RegExp(_+_+"*$");String.prototype.trim=function(){return String(this).replace(D,"").replace(P,"")}}var F=function(e){if(e==null)throw new TypeError("can't convert "+e+" to object");return Object(e)}})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-xquery.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-xquery.js
new file mode 100644
index 0000000..3c19f04
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/src-min-noconflict/worker-xquery.js
@@ -0,0 +1 @@
+"no use strict";(function(e){function t(e,t){var n=e,r="";while(n){var i=t[n];if(typeof i=="string")return i+r;if(i)return i.location.replace(/\/*$/,"/")+(r||i.main||i.name);if(i===!1)return"";var s=n.lastIndexOf("/");if(s===-1)break;r=n.substr(s)+r,n=n.slice(0,s)}return e}if(typeof e.window!="undefined"&&e.document)return;if(e.require&&e.define)return;e.console||(e.console=function(){var e=Array.prototype.slice.call(arguments,0);postMessage({type:"log",data:e})},e.console.error=e.console.warn=e.console.log=e.console.trace=e.console),e.window=e,e.ace=e,e.onerror=function(e,t,n,r,i){postMessage({type:"error",data:{message:e,data:i.data,file:t,line:n,col:r,stack:i.stack}})},e.normalizeModule=function(t,n){if(n.indexOf("!")!==-1){var r=n.split("!");return e.normalizeModule(t,r[0])+"!"+e.normalizeModule(t,r[1])}if(n.charAt(0)=="."){var i=t.split("/").slice(0,-1).join("/");n=(i?i+"/":"")+n;while(n.indexOf(".")!==-1&&s!=n){var s=n;n=n.replace(/^\.\//,"").replace(/\/\.\//,"/").replace(/[^\/]+\/\.\.\//,"")}}return n},e.require=function(r,i){i||(i=r,r=null);if(!i.charAt)throw new Error("worker.js require() accepts only (parentId, id) as arguments");i=e.normalizeModule(r,i);var s=e.require.modules[i];if(s)return s.initialized||(s.initialized=!0,s.exports=s.factory().exports),s.exports;if(!e.require.tlns)return console.log("unable to load "+i);var o=t(i,e.require.tlns);return o.slice(-3)!=".js"&&(o+=".js"),e.require.id=i,e.require.modules[i]={},importScripts(o),e.require(r,i)},e.require.modules={},e.require.tlns={},e.define=function(t,n,r){arguments.length==2?(r=n,typeof t!="string"&&(n=t,t=e.require.id)):arguments.length==1&&(r=t,n=[],t=e.require.id);if(typeof r!="function"){e.require.modules[t]={exports:r,initialized:!0};return}n.length||(n=["require","exports","module"]);var i=function(n){return e.require(t,n)};e.require.modules[t]={exports:{},factory:function(){var e=this,t=r.apply(this,n.map(function(t){switch(t){case"require":return i;case"exports":return e.exports;case"module":return e;default:return i(t)}}));return t&&(e.exports=t),e}}},e.define.amd={},require.tlns={},e.initBaseUrls=function(t){for(var n in t)require.tlns[n]=t[n]},e.initSender=function(){var n=e.require("ace/lib/event_emitter").EventEmitter,r=e.require("ace/lib/oop"),i=function(){};return function(){r.implement(this,n),this.callback=function(e,t){postMessage({type:"call",id:t,data:e})},this.emit=function(e,t){postMessage({type:"event",name:e,data:t})}}.call(i.prototype),new i};var n=e.main=null,r=e.sender=null;e.onmessage=function(t){var i=t.data;if(i.event&&r)r._signal(i.event,i.data);else if(i.command)if(n[i.command])n[i.command].apply(n,i.args);else{if(!e[i.command])throw new Error("Unknown command:"+i.command);e[i.command].apply(e,i.args)}else if(i.init){e.initBaseUrls(i.tlns),require("ace/lib/es5-shim"),r=e.sender=e.initSender();var s=require(i.module)[i.classname];n=e.main=new s(r)}}})(this),ace.define("ace/lib/oop",["require","exports","module"],function(e,t,n){"use strict";t.inherits=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})},t.mixin=function(e,t){for(var n in t)e[n]=t[n];return e},t.implement=function(e,n){t.mixin(e,n)}}),ace.define("ace/range",["require","exports","module"],function(e,t,n){"use strict";var r=function(e,t){return e.row-t.row||e.column-t.column},i=function(e,t,n,r){this.start={row:e,column:t},this.end={row:n,column:r}};(function(){this.isEqual=function(e){return this.start.row===e.start.row&&this.end.row===e.end.row&&this.start.column===e.start.column&&this.end.column===e.end.column},this.toString=function(){return"Range: ["+this.start.row+"/"+this.start.column+"] -> ["+this.end.row+"/"+this.end.column+"]"},this.contains=function(e,t){return this.compare(e,t)==0},this.compareRange=function(e){var t,n=e.end,r=e.start;return t=this.compare(n.row,n.column),t==1?(t=this.compare(r.row,r.column),t==1?2:t==0?1:0):t==-1?-2:(t=this.compare(r.row,r.column),t==-1?-1:t==1?42:0)},this.comparePoint=function(e){return this.compare(e.row,e.column)},this.containsRange=function(e){return this.comparePoint(e.start)==0&&this.comparePoint(e.end)==0},this.intersects=function(e){var t=this.compareRange(e);return t==-1||t==0||t==1},this.isEnd=function(e,t){return this.end.row==e&&this.end.column==t},this.isStart=function(e,t){return this.start.row==e&&this.start.column==t},this.setStart=function(e,t){typeof e=="object"?(this.start.column=e.column,this.start.row=e.row):(this.start.row=e,this.start.column=t)},this.setEnd=function(e,t){typeof e=="object"?(this.end.column=e.column,this.end.row=e.row):(this.end.row=e,this.end.column=t)},this.inside=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)||this.isStart(e,t)?!1:!0:!1},this.insideStart=function(e,t){return this.compare(e,t)==0?this.isEnd(e,t)?!1:!0:!1},this.insideEnd=function(e,t){return this.compare(e,t)==0?this.isStart(e,t)?!1:!0:!1},this.compare=function(e,t){return!this.isMultiLine()&&e===this.start.row?t<this.start.column?-1:t>this.end.column?1:0:e<this.start.row?-1:e>this.end.row?1:this.start.row===e?t>=this.start.column?0:-1:this.end.row===e?t<=this.end.column?0:1:0},this.compareStart=function(e,t){return this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.compareEnd=function(e,t){return this.end.row==e&&this.end.column==t?1:this.compare(e,t)},this.compareInside=function(e,t){return this.end.row==e&&this.end.column==t?1:this.start.row==e&&this.start.column==t?-1:this.compare(e,t)},this.clipRows=function(e,t){if(this.end.row>t)var n={row:t+1,column:0};else if(this.end.row<e)var n={row:e,column:0};if(this.start.row>t)var r={row:t+1,column:0};else if(this.start.row<e)var r={row:e,column:0};return i.fromPoints(r||this.start,n||this.end)},this.extend=function(e,t){var n=this.compare(e,t);if(n==0)return this;if(n==-1)var r={row:e,column:t};else var s={row:e,column:t};return i.fromPoints(r||this.start,s||this.end)},this.isEmpty=function(){return this.start.row===this.end.row&&this.start.column===this.end.column},this.isMultiLine=function(){return this.start.row!==this.end.row},this.clone=function(){return i.fromPoints(this.start,this.end)},this.collapseRows=function(){return this.end.column==0?new i(this.start.row,0,Math.max(this.start.row,this.end.row-1),0):new i(this.start.row,0,this.end.row,0)},this.toScreenRange=function(e){var t=e.documentToScreenPosition(this.start),n=e.documentToScreenPosition(this.end);return new i(t.row,t.column,n.row,n.column)},this.moveBy=function(e,t){this.start.row+=e,this.start.column+=t,this.end.row+=e,this.end.column+=t}}).call(i.prototype),i.fromPoints=function(e,t){return new i(e.row,e.column,t.row,t.column)},i.comparePoints=r,i.comparePoints=function(e,t){return e.row-t.row||e.column-t.column},t.Range=i}),ace.define("ace/apply_delta",["require","exports","module"],function(e,t,n){"use strict";function r(e,t){throw console.log("Invalid Delta:",e),"Invalid Delta: "+t}function i(e,t){return t.row>=0&&t.row<e.length&&t.column>=0&&t.column<=e[t.row].length}function s(e,t){t.action!="insert"&&t.action!="remove"&&r(t,"delta.action must be 'insert' or 'remove'"),t.lines instanceof Array||r(t,"delta.lines must be an Array"),(!t.start||!t.end)&&r(t,"delta.start/end must be an present");var n=t.start;i(e,t.start)||r(t,"delta.start must be contained in document");var s=t.end;t.action=="remove"&&!i(e,s)&&r(t,"delta.end must contained in document for 'remove' actions");var o=s.row-n.row,u=s.column-(o==0?n.column:0);(o!=t.lines.length-1||t.lines[o].length!=u)&&r(t,"delta.range must match delta lines")}t.applyDelta=function(e,t,n){var r=t.start.row,i=t.start.column,s=e[r]||"";switch(t.action){case"insert":var o=t.lines;if(o.length===1)e[r]=s.substring(0,i)+t.lines[0]+s.substring(i);else{var u=[r,1].concat(t.lines);e.splice.apply(e,u),e[r]=s.substring(0,i)+e[r],e[r+t.lines.length-1]+=s.substring(i)}break;case"remove":var a=t.end.column,f=t.end.row;r===f?e[r]=s.substring(0,i)+s.substring(a):e.splice(r,f-r+1,s.substring(0,i)+e[f].substring(a))}}}),ace.define("ace/lib/event_emitter",["require","exports","module"],function(e,t,n){"use strict";var r={},i=function(){this.propagationStopped=!0},s=function(){this.defaultPrevented=!0};r._emit=r._dispatchEvent=function(e,t){this._eventRegistry||(this._eventRegistry={}),this._defaultHandlers||(this._defaultHandlers={});var n=this._eventRegistry[e]||[],r=this._defaultHandlers[e];if(!n.length&&!r)return;if(typeof t!="object"||!t)t={};t.type||(t.type=e),t.stopPropagation||(t.stopPropagation=i),t.preventDefault||(t.preventDefault=s),n=n.slice();for(var o=0;o<n.length;o++){n[o](t,this);if(t.propagationStopped)break}if(r&&!t.defaultPrevented)return r(t,this)},r._signal=function(e,t){var n=(this._eventRegistry||{})[e];if(!n)return;n=n.slice();for(var r=0;r<n.length;r++)n[r](t,this)},r.once=function(e,t){var n=this;t&&this.addEventListener(e,function r(){n.removeEventListener(e,r),t.apply(null,arguments)})},r.setDefaultHandler=function(e,t){var n=this._defaultHandlers;n||(n=this._defaultHandlers={_disabled_:{}});if(n[e]){var r=n[e],i=n._disabled_[e];i||(n._disabled_[e]=i=[]),i.push(r);var s=i.indexOf(t);s!=-1&&i.splice(s,1)}n[e]=t},r.removeDefaultHandler=function(e,t){var n=this._defaultHandlers;if(!n)return;var r=n._disabled_[e];if(n[e]==t){var i=n[e];r&&this.setDefaultHandler(e,r.pop())}else if(r){var s=r.indexOf(t);s!=-1&&r.splice(s,1)}},r.on=r.addEventListener=function(e,t,n){this._eventRegistry=this._eventRegistry||{};var r=this._eventRegistry[e];return r||(r=this._eventRegistry[e]=[]),r.indexOf(t)==-1&&r[n?"unshift":"push"](t),t},r.off=r.removeListener=r.removeEventListener=function(e,t){this._eventRegistry=this._eventRegistry||{};var n=this._eventRegistry[e];if(!n)return;var r=n.indexOf(t);r!==-1&&n.splice(r,1)},r.removeAllListeners=function(e){this._eventRegistry&&(this._eventRegistry[e]=[])},t.EventEmitter=r}),ace.define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./lib/event_emitter").EventEmitter,s=t.Anchor=function(e,t,n){this.$onChange=this.onChange.bind(this),this.attach(e),typeof n=="undefined"?this.setPosition(t.row,t.column):this.setPosition(t,n)};(function(){function e(e,t,n){var r=n?e.column<=t.column:e.column<t.column;return e.row<t.row||e.row==t.row&&r}function t(t,n,r){var i=t.action=="insert",s=(i?1:-1)*(t.end.row-t.start.row),o=(i?1:-1)*(t.end.column-t.start.column),u=t.start,a=i?u:t.end;return e(n,u,r)?{row:n.row,column:n.column}:e(a,n,!r)?{row:n.row+s,column:n.column+(n.row==a.row?o:0)}:{row:u.row,column:u.column}}r.implement(this,i),this.getPosition=function(){return this.$clipPositionToDocument(this.row,this.column)},this.getDocument=function(){return this.document},this.$insertRight=!1,this.onChange=function(e){if(e.start.row==e.end.row&&e.start.row!=this.row)return;if(e.start.row>this.row)return;var n=t(e,{row:this.row,column:this.column},this.$insertRight);this.setPosition(n.row,n.column,!0)},this.setPosition=function(e,t,n){var r;n?r={row:e,column:t}:r=this.$clipPositionToDocument(e,t);if(this.row==r.row&&this.column==r.column)return;var i={row:this.row,column:this.column};this.row=r.row,this.column=r.column,this._signal("change",{old:i,value:r})},this.detach=function(){this.document.removeEventListener("change",this.$onChange)},this.attach=function(e){this.document=e||this.document,this.document.on("change",this.$onChange)},this.$clipPositionToDocument=function(e,t){var n={};return e>=this.document.getLength()?(n.row=Math.max(0,this.document.getLength()-1),n.column=this.document.getLine(n.row).length):e<0?(n.row=0,n.column=0):(n.row=e,n.column=Math.min(this.document.getLine(n.row).length,Math.max(0,t))),t<0&&(n.column=0),n}}).call(s.prototype)}),ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"],function(e,t,n){"use strict";var r=e("./lib/oop"),i=e("./apply_delta").applyDelta,s=e("./lib/event_emitter").EventEmitter,o=e("./range").Range,u=e("./anchor").Anchor,a=function(e){this.$lines=[""],e.length===0?this.$lines=[""]:Array.isArray(e)?this.insertMergedLines({row:0,column:0},e):this.insert({row:0,column:0},e)};(function(){r.implement(this,s),this.setValue=function(e){var t=this.getLength()-1;this.remove(new o(0,0,t,this.getLine(t).length)),this.insert({row:0,column:0},e)},this.getValue=function(){return this.getAllLines().join(this.getNewLineCharacter())},this.createAnchor=function(e,t){return new u(this,e,t)},"aaa".split(/a/).length===0?this.$split=function(e){return e.replace(/\r\n|\r/g,"\n").split("\n")}:this.$split=function(e){return e.split(/\r\n|\r|\n/)},this.$detectNewLine=function(e){var t=e.match(/^.*?(\r\n|\r|\n)/m);this.$autoNewLine=t?t[1]:"\n",this._signal("changeNewLineMode")},this.getNewLineCharacter=function(){switch(this.$newLineMode){case"windows":return"\r\n";case"unix":return"\n";default:return this.$autoNewLine||"\n"}},this.$autoNewLine="",this.$newLineMode="auto",this.setNewLineMode=function(e){if(this.$newLineMode===e)return;this.$newLineMode=e,this._signal("changeNewLineMode")},this.getNewLineMode=function(){return this.$newLineMode},this.isNewLine=function(e){return e=="\r\n"||e=="\r"||e=="\n"},this.getLine=function(e){return this.$lines[e]||""},this.getLines=function(e,t){return this.$lines.slice(e,t+1)},this.getAllLines=function(){return this.getLines(0,this.getLength())},this.getLength=function(){return this.$lines.length},this.getTextRange=function(e){return this.getLinesForRange(e).join(this.getNewLineCharacter())},this.getLinesForRange=function(e){var t;if(e.start.row===e.end.row)t=[this.getLine(e.start.row).substring(e.start.column,e.end.column)];else{t=this.getLines(e.start.row,e.end.row),t[0]=(t[0]||"").substring(e.start.column);var n=t.length-1;e.end.row-e.start.row==n&&(t[n]=t[n].substring(0,e.end.column))}return t},this.insertLines=function(e,t){return console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead."),this.insertFullLines(e,t)},this.removeLines=function(e,t){return console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead."),this.removeFullLines(e,t)},this.insertNewLine=function(e){return console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead."),this.insertMergedLines(e,["",""])},this.insert=function(e,t){return this.getLength()<=1&&this.$detectNewLine(t),this.insertMergedLines(e,this.$split(t))},this.insertInLine=function(e,t){var n=this.clippedPos(e.row,e.column),r=this.pos(e.row,e.column+t.length);return this.applyDelta({start:n,end:r,action:"insert",lines:[t]},!0),this.clonePos(r)},this.clippedPos=function(e,t){var n=this.getLength();e===undefined?e=n:e<0?e=0:e>=n&&(e=n-1,t=undefined);var r=this.getLine(e);return t==undefined&&(t=r.length),t=Math.min(Math.max(t,0),r.length),{row:e,column:t}},this.clonePos=function(e){return{row:e.row,column:e.column}},this.pos=function(e,t){return{row:e,column:t}},this.$clipPosition=function(e){var t=this.getLength();return e.row>=t?(e.row=Math.max(0,t-1),e.column=this.getLine(t-1).length):(e.row=Math.max(0,e.row),e.column=Math.min(Math.max(e.column,0),this.getLine(e.row).length)),e},this.insertFullLines=function(e,t){e=Math.min(Math.max(e,0),this.getLength());var n=0;e<this.getLength()?(t=t.concat([""]),n=0):(t=[""].concat(t),e--,n=this.$lines[e].length),this.insertMergedLines({row:e,column:n},t)},this.insertMergedLines=function(e,t){var n=this.clippedPos(e.row,e.column),r={row:n.row+t.length-1,column:(t.length==1?n.column:0)+t[t.length-1].length};return this.applyDelta({start:n,end:r,action:"insert",lines:t}),this.clonePos(r)},this.remove=function(e){var t=this.clippedPos(e.start.row,e.start.column),n=this.clippedPos(e.end.row,e.end.column);return this.applyDelta({start:t,end:n,action:"remove",lines:this.getLinesForRange({start:t,end:n})}),this.clonePos(t)},this.removeInLine=function(e,t,n){var r=this.clippedPos(e,t),i=this.clippedPos(e,n);return this.applyDelta({start:r,end:i,action:"remove",lines:this.getLinesForRange({start:r,end:i})},!0),this.clonePos(r)},this.removeFullLines=function(e,t){e=Math.min(Math.max(0,e),this.getLength()-1),t=Math.min(Math.max(0,t),this.getLength()-1);var n=t==this.getLength()-1&&e>0,r=t<this.getLength()-1,i=n?e-1:e,s=n?this.getLine(i).length:0,u=r?t+1:t,a=r?0:this.getLine(u).length,f=new o(i,s,u,a),l=this.$lines.slice(e,t+1);return this.applyDelta({start:f.start,end:f.end,action:"remove",lines:this.getLinesForRange(f)}),l},this.removeNewLine=function(e){e<this.getLength()-1&&e>=0&&this.applyDelta({start:this.pos(e,this.getLine(e).length),end:this.pos(e+1,0),action:"remove",lines:["",""]})},this.replace=function(e,t){e instanceof o||(e=o.fromPoints(e.start,e.end));if(t.length===0&&e.isEmpty())return e.start;if(t==this.getTextRange(e))return e.end;this.remove(e);var n;return t?n=this.insert(e.start,t):n=e.start,n},this.applyDeltas=function(e){for(var t=0;t<e.length;t++)this.applyDelta(e[t])},this.revertDeltas=function(e){for(var t=e.length-1;t>=0;t--)this.revertDelta(e[t])},this.applyDelta=function(e,t){var n=e.action=="insert";if(n?e.lines.length<=1&&!e.lines[0]:!o.comparePoints(e.start,e.end))return;n&&e.lines.length>2e4&&this.$splitAndapplyLargeDelta(e,2e4),i(this.$lines,e,t),this._signal("change",e)},this.$splitAndapplyLargeDelta=function(e,t){var n=e.lines,r=n.length,i=e.start.row,s=e.start.column,o=0,u=0;do{o=u,u+=t-1;var a=n.slice(o,u);if(u>r){e.lines=a,e.start.row=i+o,e.start.column=s;break}a.push(""),this.applyDelta({start:this.pos(i+o,s),end:this.pos(i+u,s=0),action:e.action,lines:a},!0)}while(!0)},this.revertDelta=function(e){this.applyDelta({start:this.clonePos(e.start),end:this.clonePos(e.end),action:e.action=="insert"?"remove":"insert",lines:e.lines.slice()})},this.indexToPosition=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length;for(var i=t||0,s=n.length;i<s;i++){e-=n[i].length+r;if(e<0)return{row:i,column:e+n[i].length+r}}return{row:s-1,column:n[s-1].length}},this.positionToIndex=function(e,t){var n=this.$lines||this.getAllLines(),r=this.getNewLineCharacter().length,i=0,s=Math.min(e.row,n.length);for(var o=t||0;o<s;++o)i+=n[o].length+r;return i+e.column}}).call(a.prototype),t.Document=a}),ace.define("ace/lib/lang",["require","exports","module"],function(e,t,n){"use strict";t.last=function(e){return e[e.length-1]},t.stringReverse=function(e){return e.split("").reverse().join("")},t.stringRepeat=function(e,t){var n="";while(t>0){t&1&&(n+=e);if(t>>=1)e+=e}return n};var r=/^\s\s*/,i=/\s\s*$/;t.stringTrimLeft=function(e){return e.replace(r,"")},t.stringTrimRight=function(e){return e.replace(i,"")},t.copyObject=function(e){var t={};for(var n in e)t[n]=e[n];return t},t.copyArray=function(e){var t=[];for(var n=0,r=e.length;n<r;n++)e[n]&&typeof e[n]=="object"?t[n]=this.copyObject(e[n]):t[n]=e[n];return t},t.deepCopy=function s(e){if(typeof e!="object"||!e)return e;var t;if(Array.isArray(e)){t=[];for(var n=0;n<e.length;n++)t[n]=s(e[n]);return t}var r=e.constructor;if(r===RegExp)return e;t=r();for(var n in e)t[n]=s(e[n]);return t},t.arrayToMap=function(e){var t={};for(var n=0;n<e.length;n++)t[e[n]]=1;return t},t.createMap=function(e){var t=Object.create(null);for(var n in e)t[n]=e[n];return t},t.arrayRemove=function(e,t){for(var n=0;n<=e.length;n++)t===e[n]&&e.splice(n,1)},t.escapeRegExp=function(e){return e.replace(/([.*+?^${}()|[\]\/\\])/g,"\\$1")},t.escapeHTML=function(e){return e.replace(/&/g,"&#38;").replace(/"/g,"&#34;").replace(/'/g,"&#39;").replace(/</g,"&#60;")},t.getMatchOffsets=function(e,t){var n=[];return e.replace(t,function(e){n.push({offset:arguments[arguments.length-2],length:e.length})}),n},t.deferredCall=function(e){var t=null,n=function(){t=null,e()},r=function(e){return r.cancel(),t=setTimeout(n,e||0),r};return r.schedule=r,r.call=function(){return this.cancel(),e(),r},r.cancel=function(){return clearTimeout(t),t=null,r},r.isPending=function(){return t},r},t.delayedCall=function(e,t){var n=null,r=function(){n=null,e()},i=function(e){n==null&&(n=setTimeout(r,e||t))};return i.delay=function(e){n&&clearTimeout(n),n=setTimeout(r,e||t)},i.schedule=i,i.call=function(){this.cancel(),e()},i.cancel=function(){n&&clearTimeout(n),n=null},i.isPending=function(){return n},i}}),ace.define("ace/worker/mirror",["require","exports","module","ace/range","ace/document","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../range").Range,i=e("../document").Document,s=e("../lib/lang"),o=t.Mirror=function(e){this.sender=e;var t=this.doc=new i(""),n=this.deferredUpdate=s.delayedCall(this.onUpdate.bind(this)),r=this;e.on("change",function(e){var i=e.data;if(i[0].start)t.applyDeltas(i);else for(var s=0;s<i.length;s+=2){if(Array.isArray(i[s+1]))var o={action:"insert",start:i[s],lines:i[s+1]};else var o={action:"remove",start:i[s],end:i[s+1]};t.applyDelta(o,!0)}if(r.$timeout)return n.schedule(r.$timeout);r.onUpdate()})};(function(){this.$timeout=500,this.setTimeout=function(e){this.$timeout=e},this.setValue=function(e){this.doc.setValue(e),this.deferredUpdate.schedule(this.$timeout)},this.getValue=function(e){this.sender.callback(this.doc.getValue(),e)},this.onUpdate=function(){},this.isPending=function(){return this.deferredUpdate.isPending()}}).call(o.prototype)}),ace.define("ace/mode/xquery/xqlint",["require","exports","module","ace/mode/tree_ops","ace/mode/xquery/errors","ace/mode/tree_ops","ace/mode/xquery/errors","ace/mode/xquery/schema_built-in_types","ace/mode/xquery/errors","ace/mode/tree_ops","ace/mode/xquery/static_context","ace/mode/xquery/handlers","ace/mode/tree_ops","ace/mode/xquery/parsers/JSONiqParser","ace/mode/xquery/parsers/XQueryParser","ace/mode/xquery/parsers/JSONParseTreeHandler","ace/mode/xquery/compiler/translator","ace/mode/xquery/formatter/style_checker","ace/mode/lib/completion/completer","ace/mode/xquery/compiler/static_context"],function(e,t,n){n.exports=function r(t,n,i){function s(u,a){if(!n[u]){if(!t[u]){var f=typeof e=="function"&&e;if(!a&&f)return f(u,!0);if(o)return o(u,!0);var l=new Error("Cannot find module '"+u+"'");throw l.code="MODULE_NOT_FOUND",l}var c=n[u]={exports:{}};t[u][0].call(c.exports,function(e){var n=t[u][1][e];return s(n?n:e)},c,c.exports,r,t,n,i)}return n[u].exports}var o=typeof e=="function"&&e;for(var u=0;u<i.length;u++)s(i[u]);return s}({1:[function(e,t,n){"use strict";var r=function(e,t,n,r,i){if(!t)throw new Error(i+" code is missing.");if(!n)throw new Error(i+" message is missing.");if(!r)throw new Error(i+" position is missing.");e.getCode=function(){return t},e.getMessage=function(){return n},e.getPos=function(){return r}},i={},s={};i.prototype=new Error,s.prototype=new Error,n.StaticError=i.prototype.constructor=function(e,t,n){r(this,e,t,n,"Error")},n.StaticWarning=s.prototype.constructor=function(e,t,n){r(this,e,t,n,"Warning")}},{}],2:[function(e,t,n){"use strict";var r=e("../tree_ops").TreeOps,i=e("./errors"),s=i.StaticWarning;n.ModuleDecl=function(e,t,n){var i="";return{NCName:function(e){i=r.flatten(e)},URILiteral:function(s){s=r.flatten(s),s=s.substring(1,s.length-1),e.apply(function(){t.moduleNamespace=s,t.addNamespace(s,i,n.pos,"moduleDecl")})}}},n.ModuleImport=function(e,t,n){var i="",s;return{NCName:function(e){i=r.flatten(e)},URILiteral:function(o){if(s!==undefined)return;o=r.flatten(o),o=o.substring(1,o.length-1),s=o,e.apply(function(){t.importModule(o,i,n.pos)})}}},n.SchemaImport=function(e,t,n){var i="",s;return{SchemaPrefix:function(t){var n=function(){this.NCName=function(e){i=r.flatten(e)}};e.visitChildren(t,new n)},URILiteral:function(o){if(s!==undefined)return;o=r.flatten(o),o=o.substring(1,o.length-1),s=o,e.apply(function(){t.addNamespace(o,i,n.pos,"schema")})}}},n.DefaultNamespaceDecl=function(e,t,n){var i=!1,o="";return{TOKEN:function(e){i=i?!0:e.value==="function"},URILiteral:function(u){o=r.flatten(u),o=o.substring(1,o.length-1),i?t.defaultFunctionNamespace=o:(e.apply(function(){throw new s("W06","Avoid default element namespace declarations.",n.pos)}),t.defaultElementNamespace=o)}}},n.NamespaceDecl=function(e,t,n){var i="";return{NCName:function(e){i=r.flatten(e)},URILiteral:function(s){s=r.flatten(s),s=s.substring(1,s.length-1),e.apply(function(){t.addNamespace(s,i,n.pos,"declare")})}}},n.VarHandler=function(e,t,n){var i=function(i){var s=r.flatten(i);e.apply(function(){var e=t.resolveQName(s,i.pos);t.addVariable(e,n.name,i.pos)})};return{ExprSingle:function(){return!0},VarValue:function(){return!0},VarDefaultValue:function(){return!0},VarName:i,EQName:i}},n.VarRefHandler=function(e,t,n){return{VarName:function(i){var s=r.flatten(i);e.apply(function(){var e=t.resolveQName(s,n.pos);e.uri!==""&&(t.root.namespaces[e.uri].used=!0),t.addVarRef(e,i.pos)})}}}},{"../tree_ops":11,"./errors":1}],3:[function(e,t,n){"use strict";n.getSchemaBuiltinTypes=function(){var e="http://www.w3.org/2001/XMLSchema",t={};return t[e]={variables:{},functions:{}},t[e].functions[e+"#string#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"string",arity:1,eqname:{uri:e,name:"string"}},t[e].functions[e+"#boolean#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"boolean",arity:1,eqname:{uri:e,name:"boolean"}},t[e].functions[e+"#decimal#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"decimal",arity:1,eqname:{uri:e,name:"decimal"}},t[e].functions[e+"#float#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"float",arity:1,eqname:{uri:e,name:"float"}},t[e].functions[e+"#double#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"double",arity:1,eqname:{uri:e,name:"double"}},t[e].functions[e+"#duration#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"duration",arity:1,eqname:{uri:e,name:"duration"}},t[e].functions[e+"#dateTime#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"dateTime",arity:1,eqname:{uri:e,name:"dateTime"}},t[e].functions[e+"#time#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"time",arity:1,eqname:{uri:e,name:"time"}},t[e].functions[e+"#date#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"date",arity:1,eqname:{uri:e,name:"date"}},t[e].functions[e+"#gYearMonth#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"gYearMonth",arity:1,eqname:{uri:e,name:"gYearMonth"}},t[e].functions[e+"#gYear#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"gYear",arity:1,eqname:{uri:e,name:"gYear"}},t[e].functions[e+"#gMonthDay#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"gMonthDay",arity:1,eqname:{uri:e,name:"gMonthDay"}},t[e].functions[e+"#gDay#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"gDay",arity:1,eqname:{uri:e,name:"gDay"}},t[e].functions[e+"#gMonth#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"gMonth",arity:1,eqname:{uri:e,name:"gMonth"}},t[e].functions[e+"#hexBinary#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"hexBinary",arity:1,eqname:{uri:e,name:"hexBinary"}},t[e].functions[e+"#base64Binary#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"base64Binary",arity:1,eqname:{uri:e,name:"base64Binary"}},t[e].functions[e+"#anyURI#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"anyURI",arity:1,eqname:{uri:e,name:"anyURI"}},t[e].functions[e+"#QName#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"QName",arity:1,eqname:{uri:e,name:"QName"}},t[e].functions[e+"#normalizedString#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"normalizedString",arity:1,eqname:{uri:e,name:"normalizedString"}},t[e].functions[e+"#token#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"token",arity:1,eqname:{uri:e,name:"token"}},t[e].functions[e+"#language#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"language",arity:1,eqname:{uri:e,name:"language"}},t[e].functions[e+"#NMTOKEN#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"NMTOKEN",arity:1,eqname:{uri:e,name:"NMTOKEN"}},t[e].functions[e+"#Name#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"Name",arity:1,eqname:{uri:e,name:"Name"}},t[e].functions[e+"#NCName#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"NCName",arity:1,eqname:{uri:e,name:"NCName"}},t[e].functions[e+"#ID#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"ID",arity:1,eqname:{uri:e,name:"ID"}},t[e].functions[e+"#IDREF#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"IDREF",arity:1,eqname:{uri:e,name:"IDREF"}},t[e].functions[e+"#ENTITY#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"ENTITY",arity:1,eqname:{uri:e,name:"ENTITY"}},t[e].functions[e+"#integer#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"integer",arity:1,eqname:{uri:e,name:"integer"}},t[e].functions[e+"#nonPositiveInteger#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"nonPositiveInteger",arity:1,eqname:{uri:e,name:"nonPositiveInteger"}},t[e].functions[e+"#negativeInteger#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"negativeInteger",arity:1,eqname:{uri:e,name:"negativeInteger"}},t[e].functions[e+"#long#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"long",arity:1,eqname:{uri:e,name:"long"}},t[e].functions[e+"#int#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"int",arity:1,eqname:{uri:e,name:"int"}},t[e].functions[e+"#short#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"short",arity:1,eqname:{uri:e,name:"short"}},t[e].functions[e+"#byte#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"byte",arity:1,eqname:{uri:e,name:"byte"}},t[e].functions[e+"#nonNegativeInteger#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"nonNegativeInteger",arity:1,eqname:{uri:e,name:"nonNegativeInteger"}},t[e].functions[e+"#unsignedLong#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"unsignedLong",arity:1,eqname:{uri:e,name:"unsignedLong"}},t[e].functions[e+"#unsignedInt#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"unsignedInt",arity:1,eqname:{uri:e,name:"unsignedInt"}},t[e].functions[e+"#unsignedShort#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"unsignedShort",arity:1,eqname:{uri:e,name:"unsignedShort"}},t[e].functions[e+"#unsignedByte#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"unsignedByte",arity:1,eqname:{uri:e,name:"unsignedByte"}},t[e].functions[e+"#positiveInteger#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"positiveInteger",arity:1,eqname:{uri:e,name:"positiveInteger"}},t[e].functions[e+"#yearMonthDuration#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"yearMonthDuration",arity:1,eqname:{uri:e,name:"yearMonthDuration"}},t[e].functions[e+"#dayTimeDuration#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"dayTimeDuration",arity:1,eqname:{uri:e,name:"dayTimeDuration"}},t[e].functions[e+"#untypedAtomic#1"]={params:["$arg as xs:anyAtomicType?"],annotations:[],name:"untypedAtomic",arity:1,eqname:{uri:e,name:"untypedAtomic"}},t}},{}],4:[function(e,t,n){n.StaticContext=function(t,n){"use strict";var r=e("../tree_ops").TreeOps,i=e("./errors"),s=i.StaticError,o=i.StaticWarning,u=e("./schema_built-in_types").getSchemaBuiltinTypes,a={sl:0,sc:0,el:0,ec:0},f={},l=function(e){return e.uri+"#"+e.name},c=function(e,t){return l(e)+"#"+t};t||(f["http://jsoniq.org/functions"]={prefix:"jn",pos:a,type:"module",override:!0},f["http://www.28msec.com/modules/collections"]={prefix:"db",pos:a,type:"module",override:!0},f["http://www.28msec.com/modules/store"]={prefix:"store",pos:a,type:"module",override:!0},f["http://jsoniq.org/function-library"]={prefix:"libjn",pos:a,type:"module",override:!0},f["http://www.w3.org/2005/xpath-functions"]={prefix:"fn",pos:a,type:"module",override:!0},f["http://www.w3.org/2005/xquery-local-functions"]={prefix:"local",pos:a,type:"declare",override:!0},f["http://www.w3.org/2001/XMLSchema-instance"]={prefix:"xsi",pos:a,type:"declare"},f["http://www.w3.org/2001/XMLSchema"]={prefix:"xs",pos:a,type:"declare"},f["http://www.w3.org/XML/1998/namespace"]={prefix:"xml",pos:a,type:"declare"},f["http://zorba.io/annotations"]={prefix:"an",pos:a,type:"declare",override:!0},f["http://www.28msec.com/annotations/rest"]={prefix:"rest",pos:a,type:"declare",override:!0},f["http://www.w3.org/2005/xqt-errors"]={prefix:"err",pos:a,type:"declare",override:!0},f["http://zorba.io/errors"]={prefix:"zerr",pos:a,type:"declare",override:!0});var h={parent:t,children:[],pos:n,setModuleResolver:function(e){return this.root.moduleResolver=e,this},setModules:function(e){if(this!==this.root)throw new Error("setModules() not invoked from the root static context.");this.moduleResolver=function(t){return e[t]};var t=this;return Object.keys(this.namespaces).forEach(function(e){var n=t.namespaces[e];if(n.type==="module"){var i=t.moduleResolver(e);i.variables&&r.concat(t.variables,i.variables),i.functions&&r.concat(t.functions,i.functions)}}),this},setModulesFromXQDoc:function(e){if(this!==this.root)throw new Error("setModulesFromXQDoc() not invoked from the root static context.");var t={};Object.keys(e).forEach(function(n){var r=e[n],i={},s={};r.functions.forEach(function(e){s[n+"#"+e.name+"#"+e.arity]={params:[],annotations:[],name:e.name,arity:e.arity,eqname:{uri:n,name:e.name}},e.parameters.forEach(function(t){s[n+"#"+e.name+"#"+e.arity].params.push("$"+t.name)})}),r.variables.forEach(function(e){var t=e.name.substring(e.name.indexOf(":")+1);i[n+"#"+t]={type:"VarDecl",annotations:[],eqname:{uri:n,name:t}}}),t[n]={variables:i,functions:s}}),this.root.moduleResolver=function(e){return t[e]};var n=this;return Object.keys(this.namespaces).forEach(function(e){var t=n.namespaces[e];if(t.type==="module"){var i=n.moduleResolver(e);i.variables&&r.concat(n.variables,i.variables),i.functions&&r.concat(n.functions,i.functions)}}),this},moduleNamespace:"",defaultFunctionNamespace:"http://www.w3.org/2005/xpath-functions",defaultFunctionNamespaces:["http://www.28msec.com/modules/collections","http://www.28msec.com/modules/store","http://jsoniq.org/functions","http://jsoniq.org/function-library","http://www.w3.org/2001/XMLSchema"],defaultElementNamespace:"",namespaces:f,availableModuleNamespaces:[],importModule:function(e,t,n){if(this!==this.root)throw new Error("Function not invoked from the root static context.");this.addNamespace(e,t,n,"module");if(this.moduleResolver)try{var i=this.moduleResolver(e,[]);i.variables&&r.concat(this.variables,i.variables),i.functions&&r.concat(this.functions,i.functions)}catch(o){throw new s("XQST0059",'module "'+e+'" not found',n)}return this},getAvailableModuleNamespaces:function(){return this.root.availableModuleNamespaces},getPrefixByNamespace:function(e){return this.root.namespaces[e].prefix},addNamespace:function(e,t,n,r){if(t===""&&r==="module")throw new o("W01","Avoid this type of import. Use import module namespace instead",n);if(e==="")throw new s("XQST0088","empty target namespace in module import or module declaration",n);var i=this.getNamespace(e);if(i&&i.type===r&&r!=="declare"&&!i.override)throw new s("XQST0047",'"'+e+'": duplicate target namespace',n);i=this.getNamespaceByPrefix(t);if(i&&!i.override)throw new s("XQST0033",'"'+t+'": namespace prefix already bound to "'+i.uri+'"',n);i=this.namespaces[e],this.namespaces[e]={prefix:t,pos:n,type:r};if(i)throw new o("W02",'"'+e+'" already bound to the "'+i.prefix+'" prefix',n)},getNamespaces:function(){return this.root.namespaces},getNamespace:function(e){var t=this;while(t){var n=t.namespaces[e];if(n)return n;t=t.parent}},getNamespaceByPrefix:function(e){var t=function(t){var r=n.namespaces[t];if(r.prefix===e)throw r.uri=t,r},n=this;while(n){try{Object.keys(n.namespaces).forEach(t)}catch(r){return r}n=n.parent}},resolveQName:function(e,t){var n={uri:"",prefix:"",name:""},r;if(e.substring(0,2)==="Q{")r=e.indexOf("}"),n.uri=e.substring(2,r),n.name=e.substring(r+1);else{r=e.indexOf(":"),n.prefix=e.substring(0,r);var i=this.getNamespaceByPrefix(n.prefix);if(!i&&n.prefix!==""&&["fn","jn"].indexOf(n.prefix)===-1)throw new s("XPST0081",'"'+n.prefix+'": can not expand prefix of lexical QName to namespace URI',t);i&&(n.uri=i.uri),n.name=e.substring(r+1)}return n},variables:{},varRefs:{},functionCalls:{},addVariable:function(e,t,n){if(t!=="VarDecl"||this.moduleNamespace===""||this.moduleNamespace===e.uri||e.uri===""&&this.defaultFunctionNamespace===this.moduleNamespace){var r=l(e);if(t==="VarDecl"&&this.variables[r])throw new s("XQST0049",'"'+e.name+'": duplicate variable declaration',n);return this.variables[r]={type:t,pos:n,qname:e,annotations:{}},this}throw new s("XQST0048",'"'+e.prefix+":"+e.name+'": Qname not library namespace',n)},getVariables:function(){var e={},t=this,n=function(n){e[n]||(e[n]=t.variables[n])};while(t)Object.keys(t.variables).forEach(n),t=t.parent;return e},getVariable:function(e){var t=l(e),n=this;while(n){if(n.variables[t])return n.variables[t];n=n.parent}},addVarRef:function(e,t){var n=this.getVariable(e);if(!n&&(e.uri===""||this.root.moduleResolver))throw new s("XPST0008",'"'+e.name+'": undeclared variable',t);var r=l(e);this.varRefs[r]=!0},addFunctionCall:function(e,t,n){var r=this.getFunction(e,t);if(!(!!r||e.uri!=="http://www.w3.org/2005/xquery-local-functions"&&!this.root.moduleResolver||(e.uri==="http://www.w3.org/2005/xpath-functions"||e.uri===""&&this.root.defaultFunctionNamespaces.concat(this.root.defaultFunctionNamespace).indexOf("http://www.w3.org/2005/xpath-functions")!==-1)&&e.name==="concat")&&!r)throw new s("XPST0008",'"'+e.name+"#"+t+'": undeclared function',n);var i=c(e,t);this.functionCalls[i]=!0},functions:u()["http://www.w3.org/2001/XMLSchema"].functions,getFunctions:function(){return this.root.functions},getFunction:function(e,t){var n=c(e,t),r;if(e.uri===""){var i=this;return this.root.defaultFunctionNamespaces.concat([this.root.defaultFunctionNamespace]).forEach(function(n){if(!!r)return!1;r=i.getFunction({uri:n,prefix:e.prefix,name:e.name},t)}),r}return this.root.functions[n]},addFunction:function(e,t,n){if(this!==this.root)throw new Error("addFunction() not invoked from the root static context.");var r=n.length;if(this.moduleNamespace===""||this.moduleNamespace===e.uri||e.uri===""&&this.defaultFunctionNamespace===this.moduleNamespace){var i=c(e,r);if(this.functions[i])throw new s("XQST0034",'"'+e.name+'": duplicate function declaration',t);return this.functions[i]={pos:t,params:n},this}throw new s("XQST0048",'"'+e.prefix+":"+e.name+'": Qname not library namespace',t)}};return h.root=t?t.root:h,h}},{"../tree_ops":11,"./errors":1,"./schema_built-in_types":3}],5:[function(e,t,n){n.Translator=function(t,n){"use strict";var r=e("./errors"),i=r.StaticError,s=r.StaticWarning,o=e("../tree_ops").TreeOps,u=e("./static_context").StaticContext,a=e("./handlers"),f=function(e,t){var n=[];return t.length===0?e:(e.children.forEach(function(e){e.name===t[0]&&t.length>1?n=f(e,t.slice(1)):e.name===t[0]&&n.push(e)}),n)},l=[];this.apply=function(e){try{e()}catch(t){if(t instanceof i)c(t);else{if(!(t instanceof s))throw t;h(t.getCode(),t.getMessage(),t.getPos())}}};var c=function(e){l.push({pos:e.getPos(),type:"error",level:"error",message:"["+e.getCode()+"] "+e.getMessage()})},h=function(e,t,n){l.push({pos:n,type:"warning",level:"warning",message:"["+e+"] "+t})};this.getMarkers=function(){return l};var p=this;t.pos=n.pos;var d=t,v=function(e){d=new u(d,e),d.parent.children.push(d)},m=function(e){e!==undefined&&(d.pos.el=e.el,d.pos.ec=e.ec),Object.keys(d.varRefs).forEach(function(e){d.variables[e]||(d.parent.varRefs[e]=!0)}),Object.keys(d.variables).forEach(function(e){!d.varRefs[e]&&d.variables[e].type!=="GroupingVariable"&&d.variables[e].type!=="CatchVar"&&h("W03",'Unused variable "$'+d.variables[e].qname.name+'"',d.variables[e].pos)}),d=d.parent};this.visitOnly=function(e,t){e.children.forEach(function(e){t.indexOf(e.name)!==-1&&p.visit(e)})},this.getFirstChild=function(e,t){var n;return e.children.forEach(function(e){e.name===t&&n===undefined&&(n=e)}),n},this.ModuleDecl=function(e){return this.visitChildren(e,a.ModuleDecl(p,t,e)),!0},this.Prolog=function(e){return this.visitOnly(e,["DefaultNamespaceDecl","Setter","NamespaceDecl","Import"]),n.index.forEach(function(e){if(e.name==="VarDecl")e.children.forEach(function(n){n.name==="VarName"&&p.apply(function(){var r=o.flatten(n),i=t.resolveQName(r,n.pos);t.addVariable(i,e.name,n.pos)})});else if(e.name==="FunctionDecl"){var n,r,i=[];e.children.forEach(function(e){e.name==="EQName"?(n=e,r=e.pos):e.name==="ParamList"&&e.children.forEach(function(e){e.name==="Param"&&i.push(o.flatten(e))})}),p.apply(function(){n=o.flatten(n),n=t.resolveQName(n,r),t.addFunction(n,r,i)})}}),this.visitOnly(e,["ContextItemDecl","AnnotatedDecl","OptionDecl"]),!0},this.ModuleImport=function(e){return this.visitChildren(e,a.ModuleImport(p,t,e)),!0},this.SchemaImport=function(e){return this.visitChildren(e,a.SchemaImport(p,t,e)),!0},this.DefaultNamespaceDecl=function(e){return this.visitChildren(e,a.DefaultNamespaceDecl(p,t,e)),!0},this.NamespaceDecl=function(e){return this.visitChildren(e,a.NamespaceDecl(p,t,e)),!0};var g={};this.AnnotatedDecl=function(e){return g={},this.visitChildren(e,a.NamespaceDecl(p,t,e)),!0},this.CompatibilityAnnotation=function(){return g["http://www.w3.org/2012/xquery#updating"]=[],!0},this.Annotation=function(e){return this.visitChildren(e,{EQName:function(e){var t=o.flatten(e);p.apply(function(){var n=d.resolveQName(t,e.pos);g[n.uri+"#"+n.name]=[]})}}),!0},this.VarDecl=function(e){try{var n=p.getFirstChild(e,"VarName"),r=o.flatten(n),i=d.resolveQName(r,n.pos),s=t.getVariable(i);s&&(s.annotations=g)}catch(u){}return this.visitOnly(e,["ExprSingle","VarValue","VarDefaultValue"]),!0},this.FunctionDecl=function(e){var t=g["http://www.w3.org/2012/xquery#updating"]!==undefined,n=f(e,["ReturnType"])[0],r=f(e,["EQName"])[0];!n&&!t&&h("W05","Untyped return value",r.pos);var i=!1;return e.children.forEach(function(e){if(e.name==="TOKEN"&&e.value==="external")return i=!0,!1}),i||(v(e.pos),this.visitChildren(e),m()),!0},this.VarRef=function(e){return this.visitChildren(e,a.VarRefHandler(p,d,e)),!0},this.Param=function(e){var t=f(e,["TypeDeclaration"])[0];return t||h("W05","Untyped function parameter",e.pos),this.visitChildren(e,a.VarHandler(p,d,e)),!0},this.InlineFunctionExpr=function(e){return v(e.pos),this.visitChildren(e),m(),!0};var y=[],b=function(e){v(e.pos),y.push(0),p.visitChildren(e);for(var t=1;t<=y[y.length-1];t++)m(e.pos);y.pop(),m()};this.StatementsAndOptionalExpr=function(e){return b(e),!0},this.StatementsAndExpr=function(e){return b(e),!0},this.BlockStatement=function(e){return b(e),!0},this.VarDeclStatement=function(e){v(e.pos),y[y.length-1]++,this.visitChildren(e,a.VarHandler(p,d,e))};var w=[];this.FLWORExpr=this.FLWORStatement=function(e){v(e.pos),w.push(0),this.visitChildren(e);for(var t=1;t<=w[w.length-1];t++)m(e.pos);return w.pop(),m(),!0},this.ForBinding=function(e){return this.visitOnly(e,["ExprSingle","VarValue","VarDefaultValue"]),v(e.pos),w[w.length-1]++,this.visitChildren(e,a.VarHandler(p,d,e)),!0},this.LetBinding=function(e){return this.visitOnly(e,["ExprSingle","VarValue","VarDefaultValue"]),v(e.pos),w[w.length-1]++,this.visitChildren(e,a.VarHandler(p,d,e)),!0},this.GroupingSpec=function(e){var t=!1;e.children.forEach(function(e){if(e.value===":=")return t=!0,!1});if(t){var n=e.children[0];return this.visitOnly(e,["ExprSingle","VarValue","VarDefaultValue"]),v(e.pos),w[w.length-1]++,this.visitChildren(n,a.VarHandler(p,d,n)),!0}},this.TumblingWindowClause=function(e){return this.visitOnly(e,["ExprSingle"]),v(e.pos),w[w.length-1]++,this.visitChildren(e,a.VarHandler(p,d,e)),this.visitOnly(e,["WindowStartCondition","WindowEndCondition"]),!0},this.WindowVars=function(e){return v(e.pos),w[w.length-1]++,this.visitChildren(e,a.VarHandler(p,d,e)),!0},this.SlidingWindowClause=function(e){return this.visitOnly(e,["ExprSingle","VarValue","VarDefaultValue"]),v(e.pos),w[w.length-1]++,this.visitChildren(e,a.VarHandler(p,d,e)),this.visitOnly(e,["WindowStartCondition","WindowEndCondition"]),!0},this.PositionalVar=function(e){return this.visitChildren(e,a.VarHandler(p,d,e)),!0},this.PositionalVar=function(e){return this.visitChildren(e,a.VarHandler(p,d,e)),!0},this.CurrentItem=function(e){return this.visitChildren(e,a.VarHandler(p,d,e)),!0},this.PreviousItem=function(e){return this.visitChildren(e,a.VarHandler(p,d,e)),!0},this.NextItem=function(e){return this.visitChildren(e,a.VarHandler(p,d,e)),!0},this.CountClause=function(e){return v(e.pos),w[w.length-1]++,this.visitChildren(e,a.VarHandler(p,d,e)),!0},this.CaseClause=function(e){return v(e.pos),this.visitChildren(e,a.VarHandler(p,d,e)),this.visitOnly(e,["ExprSingle"]),m(),!0},this.TransformExpr=function(e){return v(e.pos),this.visitChildren(e),m(),!0},this.TransformSpec=function(e){return this.visitOnly(e,["ExprSingle","VarValue","VarDefaultValue"]),this.visitChildren(e,a.VarHandler(p,d,e)),!0};var E=[];this.QuantifiedExpr=function(e){v(e.pos),E.push(0),this.visitChildren(e);for(var t=1;t<=E[E.length-1];t++)m(e.pos);return E.pop(),m(),!0},this.QuantifiedVarDecl=function(e){return this.visitOnly(e,["ExprSingle"]),v(e.pos),E[E.length-1]++,this.visitChildren(e,a.VarHandler(p,d,e)),!0},this.FunctionCall=function(e){this.visitOnly(e,["ArgumentList"]);var t=p.getFirstChild(e,"EQName"),n=o.flatten(t),r=f(e,["ArgumentList","Argument"]).length;return p.apply(function(){var i=d.resolveQName(n,e.pos);try{i.uri!==""&&(d.root.namespaces[i.uri].used=!0)}catch(s){}d.addFunctionCall(i,r,t.pos)}),!0},this.TryClause=function(e){return v(e.pos),this.visitChildren(e),m(),!0},this.CatchClause=function(e){v(e.pos);var t="err",n="http://www.w3.org/2005/xqt-errors",r={sl:0,sc:0,el:0,ec:0};return d.addVariable({prefix:t,uri:n,name:"code"},"CatchVar",r),d.addVariable({prefix:t,uri:n,name:"description"},"CatchVar",r),d.addVariable({prefix:t,uri:n,name:"value"},"CatchVar",r),d.addVariable({prefix:t,uri:n,name:"module"},"CatchVar",r),d.addVariable({prefix:t,uri:n,name:"line-number"},"CatchVar",r),d.addVariable({prefix:t,uri:n,name:"column-number"},"CatchVar",r),d.addVariable({prefix:t,uri:n,name:"additional"},"CatchVar",r),this.visitChildren(e),m(),!0},this.Pragma=function(e){var n=o.flatten(f(e,["EQName"])[0]);n=t.resolveQName(n,e);var r=o.flatten(f(e,["PragmaContents"])[0]);if(n.name==="xqlint"&&n.uri==="http://xqlint.io"){v(e.pos);var i=r.match(/[a-zA-Z]+\(([^)]+)\)/g);return i.forEach(function(t){var n=t.substring(0,t.indexOf("(")),r=t.substring(0,t.length-1).substring(t.indexOf("(")+1).split(",").map(function(e){return e.trim()});n==="varrefs"&&r.forEach(function(t){var n=d.resolveQName(t.substring(1),e.pos);n.uri!==""&&(d.root.namespaces[n.uri].used=!0),d.addVarRef(n,e.pos)})}),this.visitChildren(e),m(),!0}},this.visit=function(e){var t=e.name,n=!1;typeof this[t]=="function"&&(n=this[t](e)===!0),n||this.visitChildren(e)},this.visitChildren=function(e,t){for(var n=0;n<e.children.length;n++){var r=e.children[n];t!==undefined&&typeof t[r.name]=="function"?t[r.name](r):this.visit(r)}},this.visit(n),Object.keys(t.variables).forEach(function(e){!t.varRefs[e]&&(t.variables[e].annotations["http://www.w3.org/2005/xpath-functions#private"]||t.moduleNamespace==="")&&t.variables[e].pos&&h("W03",'Unused variable "'+t.variables[e].qname.name+'"',t.variables[e].pos)}),Object.keys(t.namespaces).forEach(function(e){var n=t.namespaces[e];n.used===undefined&&!n.override&&n.type==="module"&&h("W04",'Unused module "'+e+'"',n.pos)})}},{"../tree_ops":11,"./errors":1,"./handlers":2,"./static_context":4}],6:[function(e,t,n){"use strict";function s(e,t,n){n=n||i;var r=[];for(var s=t-1;s>=0;s--){if(!n.test(e[s]))break;r.push(e[s])}return r.reverse().join("")}function o(e,t){var n=0,r=e.length-1,i=Math.floor((r+n)/2);while(r>n&&i>=0&&e[i].indexOf(t)!==0)t<e[i]?r=i-1:t>e[i]&&(n=i+1),i=Math.floor((r+n)/2);while(i>0&&e[i-1].indexOf(t)===0)i--;return i>=0?i:0}var r=e("../tree_ops").TreeOps,i=/[a-zA-Z_0-9\$]/,u=/[a-zA-Z_0-9\/\.:\-#]/,a="-._A-Za-z0-9:\u00b7\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02ff\u0300-\u037d\u037f-\u1fff\u200c\u200d\u203f\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd",f="["+a+"]",l="["+a+"\\$]",c=new RegExp(f),h=new RegExp(l),p={LetBinding:"Let binding",Param:"Function parameter",QuantifiedExpr:"Quantified expression binding",VarDeclStatement:"Local variable",ForBinding:"For binding",TumblingWindowClause:"Tumbling window binding",WindowVars:"Window variable",SlidingWindowClause:"Sliding window binding",PositionalVar:"Positional variable",CurrentItem:"Current item",PreviousItem:"Previous item",NextItem:"Next item",CountClause:"Count binding",GroupingVariable:"Grouping variable",VarDecl:"Module variable"},d=function(e,t){t.sort();var n=o(t,e),r=[];for(var i=n;i<t.length&&t[i].indexOf(e)===0;i++)r.push(t[i]);return r},v=function(e,t,n){var r=e.indexOf(":");if(r===-1){var i=[],s=n.getNamespaces();Object.keys(s).forEach(function(e){(s[e].type==="module"||e==="http://www.w3.org/2005/xquery-local-functions")&&i.push(s[e].prefix)});var o=d(e,i),u=function(e){return{name:e+":",value:e+":",meta:"prefix"}};return o.map(u)}return[]},m=function(e,t,n){var r=[],i={},s=n.getFunctions(),o="",u="",a=e,f=e.indexOf(":"),l=!1;if(f!==-1){u=e.substring(0,f),a=e.substring(f+1);var h=n.getNamespaceByPrefix(u);h&&(o=n.getNamespaceByPrefix(u).uri)}else l=!0,o=n.root.defaultFunctionNamespace;Object.keys(s).forEach(function(e){var t=s[e],u=e.substring(0,e.indexOf("#")),a=e.substring(e.indexOf("#")+1);a=a.substring(0,a.indexOf("#"));if(u!==o)return;l||(a=n.getNamespaces()[u].prefix+":"+a),a+="(";var f=a;f+=t.params.map(function(e,t){return"${"+(t+1)+":\\"+e.split(" ")[0]+"}"}).join(", "),a+=t.params.join(", "),a+=")",f+=")",r.push(a),i[a]=f});var p=d(e,r),v=function(e){return{name:e,value:e,meta:"function",priority:4,identifierRegex:c,snippet:i[e]}};return p.map(v)},g=function(e,t,n){var r="",i="",s=e.indexOf(":");s!==-1&&(i=e.substring(0,s),r=n.getNamespaceByPrefix(i).uri);var o=n.getVariables(),u=[],a={};Object.keys(o).forEach(function(e){var t=e.indexOf("#"),r=e.substring(0,t),i=e.substring(t+1);r!==""?(u.push(n.getPrefixByNamespace(r)+":"+i),a[n.getPrefixByNamespace(r)+":"+i]=o[e].type):(u.push(i),a[i]=o[e].type)});var f=d(e,u),l=function(e){return{name:"$"+e,value:"$"+e,meta:p[a[e]],priority:4,identifierRegex:h}};return f.map(l)},y=function(e,t,n){var r=s(e,t.col,c),i=e.substring(0,t.col-(r.length===0?0:r.length)),o=i[i.length-1]==="$";return o?g(r,t,n):r!==""?m(r,t,n).concat(v(r,t,n)):g(r,t,n).concat(m(r,t,n)).concat(v(r,t,n))},b=function(e,t,n){var r=s(e,t.col,u),i=d(r,n.getAvailableModuleNamespaces()),o=function(e){return{name:e,value:e,meta:"module",priority:4,identifierRegex:u}};return i.map(o)};n.complete=function(e,t,n,i){var s=e.split("\n")[i.line],o=r.findNode(t,i),u=r.findNode(n,i);return u=u?u:n,o&&o.name==="URILiteral"&&o.getParent&&o.getParent.name==="ModuleImport"?b(s,i,u):y(s,i,u)}},{"../tree_ops":11}],7:[function(e,t,n){n.StyleChecker=function(e,t){"use strict";var n="    ",r=[];this.getMarkers=function(){return r},this.WS=function(e){var t=e.value.split("\n");return t.forEach(function(i,s){var o=s===0,u=s===t.length-1;/\r$/.test(i)&&r.push({pos:{sl:e.pos.sl+s,el:e.pos.sl+s,sc:i.length-1,ec:i.length},type:"warning",level:"warning",message:"[SW01] Detected CRLF"});var a=i.match(/\t+/);a!==null&&r.push({pos:{sl:e.pos.sl+s,el:e.pos.sl+s,sc:a.index,ec:a.index+a[0].length},type:"warning",level:"warning",message:"[SW02] Tabs detected"});if(!o&&u){a=i.match(/^\ +/);if(a!==null){var f=a[0].length%n.length;f!==0&&r.push({pos:{sl:e.pos.sl+s,el:e.pos.sl+s,sc:a.index,ec:a.index+a[0].length},type:"warning",level:"warning",message:"[SW03] Unexcepted indentation of "+a[0].length})}}}),!0},this.visit=function(e,t){var n=e.name,r=!1;typeof this[n]=="function"&&(r=this[n](e,t)===!0),r||this.visitChildren(e)},this.visitChildren=function(e,t){for(var n=0;n<e.children.length;n++){var r=e.children[n];t!==undefined&&typeof t[r.name]=="function"?t[r.name](r):this.visit(r)}},t.split("\n").forEach(function(e,t){var n=e.match(/\ +$/);n&&r.push({pos:{sl:t,el:t,sc:n.index,ec:n.index+n[0].length},type:"warning",level:"warning",message:"[SW04] Trailing whitespace"})}),this.visit(e)}},{}],8:[function(e,t,n){n.JSONParseTreeHandler=function(e){"use strict";function f(e){return{name:e,children:[],getParent:null,pos:{sl:0,sc:0,el:0,ec:0}}}function l(e){var t=f(e);r===null?(r=t,r.index=[],i=t):(t.getParent=i,i.children.push(t),i=i.children[i.children.length-1])}function c(){if(i.children.length>0){var e=i.children[0],s=null;for(var o=i.children.length-1;o>=0;o--){s=i.children[o];if(s.pos.el!==0||s.pos.ec!==0)break}i.pos.sl=e.pos.sl,i.pos.sc=e.pos.sc,i.pos.el=s.pos.el,i.pos.ec=s.pos.ec}i.name==="FunctionName"&&(i.name="EQName"),i.name==="EQName"&&i.value===undefined&&(i.value=i.children[0].value,i.children.pop()),t.indexOf(i.name)!==-1&&r.index.push(i),i.getParent!==null&&(i=i.getParent);if(i.children.length>0){var u=i.children[i.children.length-1];u.children.length===1&&n.indexOf(u.name)!==-1&&(i.children[i.children.length-1]=u.children[0])}}function h(e,t,n){var r=n-o;i.value=s.substring(0,r),s=s.substring(r),o=n;var f=a,l=u,c=f+i.value.split("\n").length-1,h=i.value.lastIndexOf("\n"),p=h===-1?l+i.value.length:i.value.substring(h+1).length;a=c,u=p,i.pos.sl=f,i.pos.sc=l,i.pos.el=c,i.pos.ec=p}var t=["VarDecl","FunctionDecl"],n=["OrExpr","AndExpr","ComparisonExpr","StringConcatExpr","RangeExpr","UnionExpr","IntersectExceptExpr","InstanceofExpr","TreatExpr","CastableExpr","CastExpr","UnaryExpr","ValueExpr","FTContainsExpr","SimpleMapExpr","PathExpr","RelativePathExpr","PostfixExpr","StepExpr"],r=null,i=null,s=e,o=0,u=0,a=0;this.closeParseTree=function(){while(i.getParent!==null)c();c()},this.peek=function(){return i},this.getParseTree=function(){return r},this.reset=function(){},this.startNonterminal=function(e,t){l(e,t)},this.endNonterminal=function(){c()},this.terminal=function(e,t,n){e=e.substring(0,1)==="'"&&e.substring(e.length-1)==="'"?"TOKEN":e,l(e,t),h(i,t,n),c()},this.whitespace=function(e,t){var n="WS";l(n,e),h(i,e,t),c()}}},{}],9:[function(e,t,n){var r=n.JSONiqParser=function i(e,t){function r(e,t){ic=t,ac=e,fc=e.length,s(0,0,0)}function s(e,t,n){Xl=t,Vl=t,$l=e,Jl=t,Kl=n,Ql=0,cc=n,ec=-1,sc={},ic.reset(ac)}function o(){ic.startNonterminal("Module",Vl);switch($l){case 170:ql(168);break;default:Wl=$l}(Wl==64682||Wl==137898)&&u(),Il(278);switch($l){case 185:ql(146);break;default:Wl=$l}switch(Wl){case 95929:jl(),a();break;default:jl(),Za()}ic.endNonterminal("Module",Vl)}function u(){ic.startNonterminal("VersionDecl",Vl),Pl(170),Il(120);switch($l){case 126:Pl(126),Il(17),Pl(11);break;default:Pl(269),Il(17),Pl(11),Il(113),$l==126&&(Pl(126),Il(17),Pl(11))}Il(29),jl(),c(),ic.endNonterminal("VersionDecl",Vl)}function a(){ic.startNonterminal("LibraryModule",Vl),f(),Il(142),jl(),l(),ic.endNonterminal("LibraryModule",Vl)}function f(){ic.startNonterminal("ModuleDecl",Vl),Pl(185),Il(64),Pl(187),Il(240),jl(),Ga(),Il(30),Pl(61),Il(15),Pl(7),Il(29),jl(),c(),ic.endNonterminal("ModuleDecl",Vl)}function l(){ic.startNonterminal("Prolog",Vl);for(;;){Il(278);switch($l){case 109:ql(207);break;case 155:ql(169);break;default:Wl=$l}if(Wl!=43117&&Wl!=44141&&Wl!=50797&&Wl!=53869&&Wl!=54893&&Wl!=56429&&Wl!=73325&&Wl!=94875&&Wl!=95853&&Wl!=106093&&Wl!=115821&&Wl!=117403)break;switch($l){case 109:ql(201);break;default:Wl=$l}if(Wl==56429){Wl=uc(0,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{_(),Wl=-1}catch(a){Wl=-2}Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(0,Vl,Wl)}}switch(Wl){case-1:jl(),M();break;case 95853:jl(),O();break;case 155:jl(),C();break;case 73325:jl(),D();break;default:jl(),h()}Il(29),jl(),c()}for(;;){Il(278);switch($l){case 109:ql(202);break;default:Wl=$l}if(Wl!=17005&&Wl!=49261&&Wl!=52333&&Wl!=75373&&Wl!=80493&&Wl!=83565&&Wl!=104045&&Wl!=134765&&Wl!=137325)break;switch($l){case 109:ql(197);break;default:Wl=$l}switch(Wl){case 52333:jl(),R();break;case 104045:jl(),Q();break;default:jl(),P()}Il(29),jl(),c()}ic.endNonterminal("Prolog",Vl)}function c(){ic.startNonterminal("Separator",Vl),Pl(54),ic.endNonterminal("Separator",Vl)}function h(){ic.startNonterminal("Setter",Vl);switch($l){case 109:ql(194);break;default:Wl=$l}if(Wl==56429){Wl=uc(1,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{v(),Wl=-2}catch(a){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),w(),Wl=-6}catch(f){Wl=-9}}Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(1,Vl,Wl)}}switch(Wl){case 44141:p();break;case-2:d();break;case 43117:m();break;case 50797:g();break;case 106093:y();break;case-6:b();break;case 115821:Io();break;case 53869:E();break;default:T()}ic.endNonterminal("Setter",Vl)}function p(){ic.startNonterminal("BoundarySpaceDecl",Vl),Pl(109),Il(36),Pl(86),Il(137);switch($l){case 218:Pl(218);break;default:Pl(246)}ic.endNonterminal("BoundarySpaceDecl",Vl)}function d(){ic.startNonterminal("DefaultCollationDecl",Vl),Pl(109),Il(49),Pl(110),Il(41),Pl(95),Il(15),Pl(7),ic.endNonterminal("DefaultCollationDecl",Vl)}function v(){Hl(109),Il(49),Hl(110),Il(41),Hl(95),Il(15),Hl(7)}function m(){ic.startNonterminal("BaseURIDecl",Vl),Pl(109),Il(35),Pl(84),Il(15),Pl(7),ic.endNonterminal("BaseURIDecl",Vl)}function g(){ic.startNonterminal("ConstructionDecl",Vl),Pl(109),Il(44),Pl(99),Il(137);switch($l){case 246:Pl(246);break;default:Pl(218)}ic.endNonterminal("ConstructionDecl",Vl)}function y(){ic.startNonterminal("OrderingModeDecl",Vl),Pl(109),Il(71),Pl(207),Il(135);switch($l){case 206:Pl(206);break;default:Pl(262)}ic.endNonterminal("OrderingModeDecl",Vl)}function b(){ic.startNonterminal("EmptyOrderDecl",Vl),Pl(109),Il(49),Pl(110),Il(70),Pl(205),Il(52),Pl(124),Il(125);switch($l){case 149:Pl(149);break;default:Pl(176)}ic.endNonterminal("EmptyOrderDecl",Vl)}function w(){Hl(109),Il(49),Hl(110),Il(70),Hl(205),Il(52),Hl(124),Il(125);switch($l){case 149:Hl(149);break;default:Hl(176)}}function E(){ic.startNonterminal("CopyNamespacesDecl",Vl),Pl(109),Il(47),Pl(105),Il(132),jl(),S(),Il(25),Pl(42),Il(127),jl(),x(),ic.endNonterminal("CopyNamespacesDecl",Vl)}function S(){ic.startNonterminal("PreserveMode",Vl);switch($l){case 218:Pl(218);break;default:Pl(193)}ic.endNonterminal("PreserveMode",Vl)}function x(){ic.startNonterminal("InheritMode",Vl);switch($l){case 159:Pl(159);break;default:Pl(192)}ic.endNonterminal("InheritMode",Vl)}function T(){ic.startNonterminal("DecimalFormatDecl",Vl),Pl(109),Il(118);switch($l){case 107:Pl(107),Il(246),jl(),$a();break;default:Pl(110),Il(48),Pl(107)}for(;;){Il(204);if($l==54)break;jl(),N(),Il(30),Pl(61),Il(17),Pl(11)}ic.endNonterminal("DecimalFormatDecl",Vl)}function N(){ic.startNonterminal("DFPropertyName",Vl);switch($l){case 108:Pl(108);break;case 151:Pl(151);break;case 158:Pl(158);break;case 182:Pl(182);break;case 68:Pl(68);break;case 213:Pl(213);break;case 212:Pl(212);break;case 280:Pl(280);break;case 117:Pl(117);break;default:Pl(211)}ic.endNonterminal("DFPropertyName",Vl)}function C(){ic.startNonterminal("Import",Vl);switch($l){case 155:ql(130);break;default:Wl=$l}switch(Wl){case 117403:k();break;default:A()}ic.endNonterminal("Import",Vl)}function k(){ic.startNonterminal("SchemaImport",Vl),Pl(155),Il(76),Pl(229),Il(141),$l!=7&&(jl(),L()),Il(15),Pl(7),Il(112);if($l==82){Pl(82),Il(15),Pl(7);for(;;){Il(107);if($l!=42)break;Pl(42),Il(15),Pl(7)}}ic.endNonterminal("SchemaImport",Vl)}function L(){ic.startNonterminal("SchemaPrefix",Vl);switch($l){case 187:Pl(187),Il(240),jl(),Ga(),Il(30),Pl(61);break;default:Pl(110),Il(50),Pl(122),Il(64),Pl(187)}ic.endNonterminal("SchemaPrefix",Vl)}function A(){ic.startNonterminal("ModuleImport",Vl),Pl(155),Il(63),Pl(185),Il(93),$l==187&&(Pl(187),Il(240),jl(),Ga(),Il(30),Pl(61)),Il(15),Pl(7),Il(112);if($l==82){Pl(82),Il(15),Pl(7);for(;;){Il(107);if($l!=42)break;Pl(42),Il(15),Pl(7)}}ic.endNonterminal("ModuleImport",Vl)}function O(){ic.startNonterminal("NamespaceDecl",Vl),Pl(109),Il(64),Pl(187),Il(240),jl(),Ga(),Il(30),Pl(61),Il(15),Pl(7),ic.endNonterminal("NamespaceDecl",Vl)}function M(){ic.startNonterminal("DefaultNamespaceDecl",Vl),Pl(109),Il(49),Pl(110),Il(119);switch($l){case 122:Pl(122);break;default:Pl(147)}Il(64),Pl(187),Il(15),Pl(7),ic.endNonterminal("DefaultNamespaceDecl",Vl)}function _(){Hl(109),Il(49),Hl(110),Il(119);switch($l){case 122:Hl(122);break;default:Hl(147)}Il(64),Hl(187),Il(15),Hl(7)}function D(){ic.startNonterminal("FTOptionDecl",Vl),Pl(109),Il(55),Pl(143),Il(84),jl(),Qu(),ic.endNonterminal("FTOptionDecl",Vl)}function P(){ic.startNonterminal("AnnotatedDecl",Vl),Pl(109);for(;;){Il(192);if($l!=33&&$l!=263)break;switch($l){case 263:jl(),H();break;default:jl(),B()}}switch($l){case 268:jl(),F();break;case 147:jl(),_l();break;case 96:jl(),Ca();break;case 157:jl(),Ha();break;default:jl(),Ba()}ic.endNonterminal("AnnotatedDecl",Vl)}function H(){ic.startNonterminal("CompatibilityAnnotation",Vl),Pl(263),ic.endNonterminal("CompatibilityAnnotation",Vl)}function B(){ic.startNonterminal("Annotation",Vl),Pl(33),Il(246),jl(),$a(),Il(193);if($l==35){Pl(35),Il(190),jl(),di();for(;;){Il(105);if($l!=42)break;Pl(42),Il(190),jl(),di()}Pl(38)}ic.endNonterminal("Annotation",Vl)}function j(){Hl(33),Il(246),Ja(),Il(193);if($l==35){Hl(35),Il(190),vi();for(;;){Il(105);if($l!=42)break;Hl(42),Il(190),vi()}Hl(38)}}function F(){ic.startNonterminal("VarDecl",Vl),Pl(268),Il(21),Pl(31),Il(246),jl(),Ti(),Il(157),$l==80&&(jl(),Cs()),Il(110);switch($l){case 53:Pl(53),Il(267),jl(),I();break;default:Pl(134),Il(108),$l==53&&(Pl(53),Il(267),jl(),q())}ic.endNonterminal("VarDecl",Vl)}function I(){ic.startNonterminal("VarValue",Vl),Wf(),ic.endNonterminal("VarValue",Vl)}function q(){ic.startNonterminal("VarDefaultValue",Vl),Wf(),ic.endNonterminal("VarDefaultValue",Vl)}function R(){ic.startNonterminal("ContextItemDecl",Vl),Pl(109),Il(46),Pl(102),Il(58),Pl(167),Il(157),$l==80&&(Pl(80),Il(254),jl(),_s()),Il(110);switch($l){case 53:Pl(53),Il(267),jl(),I();break;default:Pl(134),Il(108),$l==53&&(Pl(53),Il(267),jl(),q())}ic.endNonterminal("ContextItemDecl",Vl)}function U(){ic.startNonterminal("ParamList",Vl),W();for(;;){Il(105);if($l!=42)break;Pl(42),Il(21),jl(),W()}ic.endNonterminal("ParamList",Vl)}function z(){X();for(;;){Il(105);if($l!=42)break;Hl(42),Il(21),X()}}function W(){ic.startNonterminal("Param",Vl),Pl(31),Il(246),jl(),$a(),Il(153),$l==80&&(jl(),Cs()),ic.endNonterminal("Param",Vl)}function X(){Hl(31),Il(246),Ja(),Il(153),$l==80&&ks()}function V(){ic.startNonterminal("FunctionBody",Vl),J(),ic.endNonterminal("FunctionBody",Vl)}function $(){K()}function J(){ic.startNonterminal("EnclosedExpr",Vl),Pl(281),Il(267),jl(),G(),Pl(287),ic.endNonterminal("EnclosedExpr",Vl)}function K(){Hl(281),Il(267),Y(),Hl(287)}function Q(){ic.startNonterminal("OptionDecl",Vl),Pl(109),Il(69),Pl(203),Il(246),jl(),$a(),Il(17),Pl(11),ic.endNonterminal("OptionDecl",Vl)}function G(){ic.startNonterminal("Expr",Vl),Wf();for(;;){if($l!=42)break;Pl(42),Il(267),jl(),Wf()}ic.endNonterminal("Expr",Vl)}function Y(){Xf();for(;;){if($l!=42)break;Hl(42),Il(267),Xf()}}function Z(){ic.startNonterminal("FLWORExpr",Vl),tt();for(;;){Il(195);if($l==224)break;jl(),rt()}jl(),rn(),ic.endNonterminal("FLWORExpr",Vl)}function et(){nt();for(;;){Il(195);if($l==224)break;it()}sn()}function tt(){ic.startNonterminal("InitialClause",Vl);switch($l){case 139:ql(151);break;default:Wl=$l}switch(Wl){case 16011:st();break;case 177:vt();break;default:bt()}ic.endNonterminal("InitialClause",Vl)}function nt(){switch($l){case 139:ql(151);break;default:Wl=$l}switch(Wl){case 16011:ot();break;case 177:mt();break;default:wt()}}function rt(){ic.startNonterminal("IntermediateClause",Vl);switch($l){case 139:case 177:tt();break;case 272:It();break;case 150:Rt();break;case 106:jt();break;default:Kt()}ic.endNonterminal("IntermediateClause",Vl)}function it(){switch($l){case 139:case 177:nt();break;case 272:qt();break;case 150:Ut();break;case 106:Ft();break;default:Qt()}}function st(){ic.startNonterminal("ForClause",Vl),Pl(139),Il(21),jl(),ut();for(;;){if($l!=42)break;Pl(42),Il(21),jl(),ut()}ic.endNonterminal("ForClause",Vl)}function ot(){Hl(139),Il(21),at();for(;;){if($l!=42)break;Hl(42),Il(21),at()}}function ut(){ic.startNonterminal("ForBinding",Vl),Pl(31),Il(246),jl(),Ti(),Il(182),$l==80&&(jl(),Cs()),Il(173),$l==73&&(jl(),ft()),Il(160),$l==82&&(jl(),ct()),Il(126),$l==232&&(jl(),pt()),Il(56),Pl(156),Il(267),jl(),Wf(),ic.endNonterminal("ForBinding",Vl)}function at(){Hl(31),Il(246),Ni(),Il(182),$l==80&&ks(),Il(173),$l==73&&lt(),Il(160),$l==82&&ht(),Il(126),$l==232&&dt(),Il(56),Hl(156),Il(267),Xf()}function ft(){ic.startNonterminal("AllowingEmpty",Vl),Pl(73),Il(52),Pl(124),ic.endNonterminal("AllowingEmpty",Vl)}function lt(){Hl(73),Il(52),Hl(124)}function ct(){ic.startNonterminal("PositionalVar",Vl),Pl(82),Il(21),Pl(31),Il(246),jl(),Ti(),ic.endNonterminal("PositionalVar",Vl)}function ht(){Hl(82),Il(21),Hl(31),Il(246),Ni()}function pt(){ic.startNonterminal("FTScoreVar",Vl),Pl(232),Il(21),Pl(31),Il(246),jl(),Ti(),ic.endNonterminal("FTScoreVar",Vl)}function dt(){Hl(232),Il(21),Hl(31),Il(246),Ni()}function vt(){ic.startNonterminal("LetClause",Vl),Pl(177),Il(100),jl(),gt();for(;;){if($l!=42)break;Pl(42),Il(100),jl(),gt()}ic.endNonterminal("LetClause",Vl)}function mt(){Hl(177),Il(100),yt();for(;;){if($l!=42)break;Hl(42),Il(100),yt()}}function gt(){ic.startNonterminal("LetBinding",Vl);switch($l){case 31:Pl(31),Il(246),jl(),Ti(),Il(109),$l==80&&(jl(),Cs());break;default:pt()}Il(28),Pl(53),Il(267),jl(),Wf(),ic.endNonterminal("LetBinding",Vl)}function yt(){switch($l){case 31:Hl(31),Il(246),Ni(),Il(109),$l==80&&ks();break;default:dt()}Il(28),Hl(53),Il(267),Xf()}function bt(){ic.startNonterminal("WindowClause",Vl),Pl(139),Il(139);switch($l){case 257:jl(),Et();break;default:jl(),xt()}ic.endNonterminal("WindowClause",Vl)}function wt(){Hl(139),Il(139);switch($l){case 257:St();break;default:Tt()}}function Et(){ic.startNonterminal("TumblingWindowClause",Vl),Pl(257),Il(88),Pl(275),Il(21),Pl(31),Il(246),jl(),Ti(),Il(114),$l==80&&(jl(),Cs()),Il(56),Pl(156),Il(267),jl(),Wf(),jl(),Nt();if($l==127||$l==202)jl(),kt();ic.endNonterminal("TumblingWindowClause",Vl)}function St(){Hl(257),Il(88),Hl(275),Il(21),Hl(31),Il(246),Ni(),Il(114),$l==80&&ks(),Il(56),Hl(156),Il(267),Xf(),Ct(),($l==127||$l==202)&&Lt()}function xt(){ic.startNonterminal("SlidingWindowClause",Vl),Pl(239),Il(88),Pl(275),Il(21),Pl(31),Il(246),jl(),Ti(),Il(114),$l==80&&(jl(),Cs()),Il(56),Pl(156),Il(267),jl(),Wf(),jl(),Nt(),jl(),kt(),ic.endNonterminal("SlidingWindowClause",Vl)}function Tt(){Hl(239),Il(88),Hl(275),Il(21),Hl(31),Il(246),Ni(),Il(114),$l==80&&ks(),Il(56),Hl(156),Il(267),Xf(),Ct(),Lt()}function Nt(){ic.startNonterminal("WindowStartCondition",Vl),Pl(242),Il(181),jl(),At(),Il(86),Pl(271),Il(267),jl(),Wf(),ic.endNonterminal("WindowStartCondition",Vl)}function Ct(){Hl(242),Il(181),Ot(),Il(86),Hl(271),Il(267),Xf()}function kt(){ic.startNonterminal("WindowEndCondition",Vl),$l==202&&Pl(202),Il(53),Pl(127),Il(181),jl(),At(),Il(86),Pl(271),Il(267),jl(),Wf(),ic.endNonterminal("WindowEndCondition",Vl)}function Lt(){$l==202&&Hl(202),Il(53),Hl(127),Il(181),Ot(),Il(86),Hl(271),Il(267),Xf()}function At(){ic.startNonterminal("WindowVars",Vl),$l==31&&(Pl(31),Il(246),jl(),Mt()),Il(174),$l==82&&(jl(),ct()),Il(163),$l==219&&(Pl(219),Il(21),Pl(31),Il(246),jl(),Dt()),Il(131),$l==190&&(Pl(190),Il(21),Pl(31),Il(246),jl(),Ht()),ic.endNonterminal("WindowVars",Vl)}function Ot(){$l==31&&(Hl(31),Il(246),_t()),Il(174),$l==82&&ht(),Il(163),$l==219&&(Hl(219),Il(21),Hl(31),Il(246),Pt()),Il(131),$l==190&&(Hl(190),Il(21),Hl(31),Il(246),Bt())}function Mt(){ic.startNonterminal("CurrentItem",Vl),$a(),ic.endNonterminal("CurrentItem",Vl)}function _t(){Ja()}function Dt(){ic.startNonterminal("PreviousItem",Vl),$a(),ic.endNonterminal("PreviousItem",Vl)}function Pt(){Ja()}function Ht(){ic.startNonterminal("NextItem",Vl),$a(),ic.endNonterminal("NextItem",Vl)}function Bt(){Ja()}function jt(){ic.startNonterminal("CountClause",Vl),Pl(106),Il(21),Pl(31),Il(246),jl(),Ti(),ic.endNonterminal("CountClause",Vl)}function Ft(){Hl(106),Il(21),Hl(31),Il(246),Ni()}function It(){ic.startNonterminal("WhereClause",Vl),Pl(272),Il(267),jl(),Wf(),ic.endNonterminal("WhereClause",Vl)}function qt(){Hl(272),Il(267),Xf()}function Rt(){ic.startNonterminal("GroupByClause",Vl),Pl(150),Il(37),Pl(88),Il(267),jl(),zt(),ic.endNonterminal("GroupByClause",Vl)}function Ut(){Hl(150),Il(37),Hl(88),Il(267),Wt()}function zt(){ic.startNonterminal("GroupingSpecList",Vl),Xt();for(;;){Il(198);if($l!=42)break;Pl(42),Il(267),jl(),Xt()}ic.endNonterminal("GroupingSpecList",Vl)}function Wt(){Vt();for(;;){Il(198);if($l!=42)break;Hl(42),Il(267),Vt()}}function Xt(){ic.startNonterminal("GroupingSpec",Vl);switch($l){case 31:ql(246);break;default:Wl=$l}if(Wl==3103||Wl==36383||Wl==37407||Wl==37919||Wl==38431||Wl==38943||Wl==39967||Wl==40479||Wl==40991||Wl==41503||Wl==42015||Wl==42527||Wl==43039||Wl==43551||Wl==44063||Wl==44575||Wl==45599||Wl==46111||Wl==46623||Wl==47135||Wl==48159||Wl==48671||Wl==49695||Wl==50207||Wl==50719||Wl==52255||Wl==52767||Wl==53279||Wl==53791||Wl==54303||Wl==54815||Wl==55839||Wl==56351||Wl==56863||Wl==57375||Wl==57887||Wl==58399||Wl==60959||Wl==61471||Wl==61983||Wl==62495||Wl==63007||Wl==63519||Wl==64031||Wl==64543||Wl==65055||Wl==66079||Wl==66591||Wl==67615||Wl==68127||Wl==68639||Wl==69151||Wl==69663||Wl==70175||Wl==70687||Wl==71199||Wl==72735||Wl==73247||Wl==75295||Wl==75807||Wl==76831||Wl==77855||Wl==78367||Wl==78879||Wl==79391||Wl==79903||Wl==80415||Wl==82463||Wl==82975||Wl==83487||Wl==83999||Wl==84511||Wl==85023||Wl==85535||Wl==86047||Wl==86559||Wl==87071||Wl==88607||Wl==89119||Wl==89631||Wl==90655||Wl==91679||Wl==92703||Wl==93727||Wl==94239||Wl==94751||Wl==95775||Wl==96287||Wl==96799||Wl==99359||Wl==99871||Wl==100895||Wl==101407||Wl==103455||Wl==103967||Wl==104479||Wl==104991||Wl==105503||Wl==106015||Wl==107551||Wl==110623||Wl==111135||Wl==112671||Wl==113695||Wl==114207||Wl==114719||Wl==115231||Wl==115743||Wl==116767||Wl==117279||Wl==117791||Wl==118303||Wl==118815||Wl==119327||Wl==119839||Wl==122399||Wl==122911||Wl==123423||Wl==123935||Wl==125471||Wl==126495||Wl==127007||Wl==127519||Wl==129567||Wl==130079||Wl==130591||Wl==131103||Wl==131615||Wl==132127||Wl==132639||Wl==133151||Wl==134175||Wl==134687||Wl==136223||Wl==136735||Wl==137247||Wl==137759||Wl==139295||Wl==139807||Wl==141343){Wl=uc(2,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Jt(),Il(206);if($l==53||$l==80)$l==80&&ks(),Il(28),Hl(53),Il(267),Xf();$l==95&&(Hl(95),Il(15),Hl(7)),Wl=-1}catch(a){Wl=-2}Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(2,Vl,Wl)}}switch(Wl){case-1:$t(),Il(206);if($l==53||$l==80)$l==80&&(jl(),Cs()),Il(28),Pl(53),Il(267),jl(),Wf();$l==95&&(Pl(95),Il(15),Pl(7));break;default:Wf()}ic.endNonterminal("GroupingSpec",Vl)}function Vt(){switch($l){case 31:ql(246);break;default:Wl=$l}if(Wl==3103||Wl==36383||Wl==37407||Wl==37919||Wl==38431||Wl==38943||Wl==39967||Wl==40479||Wl==40991||Wl==41503||Wl==42015||Wl==42527||Wl==43039||Wl==43551||Wl==44063||Wl==44575||Wl==45599||Wl==46111||Wl==46623||Wl==47135||Wl==48159||Wl==48671||Wl==49695||Wl==50207||Wl==50719||Wl==52255||Wl==52767||Wl==53279||Wl==53791||Wl==54303||Wl==54815||Wl==55839||Wl==56351||Wl==56863||Wl==57375||Wl==57887||Wl==58399||Wl==60959||Wl==61471||Wl==61983||Wl==62495||Wl==63007||Wl==63519||Wl==64031||Wl==64543||Wl==65055||Wl==66079||Wl==66591||Wl==67615||Wl==68127||Wl==68639||Wl==69151||Wl==69663||Wl==70175||Wl==70687||Wl==71199||Wl==72735||Wl==73247||Wl==75295||Wl==75807||Wl==76831||Wl==77855||Wl==78367||Wl==78879||Wl==79391||Wl==79903||Wl==80415||Wl==82463||Wl==82975||Wl==83487||Wl==83999||Wl==84511||Wl==85023||Wl==85535||Wl==86047||Wl==86559||Wl==87071||Wl==88607||Wl==89119||Wl==89631||Wl==90655||Wl==91679||Wl==92703||Wl==93727||Wl==94239||Wl==94751||Wl==95775||Wl==96287||Wl==96799||Wl==99359||Wl==99871||Wl==100895||Wl==101407||Wl==103455||Wl==103967||Wl==104479||Wl==104991||Wl==105503||Wl==106015||Wl==107551||Wl==110623||Wl==111135||Wl==112671||Wl==113695||Wl==114207||Wl==114719||Wl==115231||Wl==115743||Wl==116767||Wl==117279||Wl==117791||Wl==118303||Wl==118815||Wl==119327||Wl==119839||Wl==122399||Wl==122911||Wl==123423||Wl==123935||Wl==125471||Wl==126495||Wl==127007||Wl==127519||Wl==129567||Wl==130079||Wl==130591||Wl==131103||Wl==131615||Wl==132127||Wl==132639||Wl==133151||Wl==134175||Wl==134687||Wl==136223||Wl==136735||Wl==137247||Wl==137759||Wl==139295||Wl==139807||Wl==141343){Wl=uc(2,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Jt(),Il(206);if($l==53||$l==80)$l==80&&ks(),Il(28),Hl(53),Il(267),Xf();$l==95&&(Hl(95),Il(15),Hl(7)),oc(2,t,-1),Wl=-3}catch(a){Wl=-2,Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(2,t,-2)}}}switch(Wl){case-1:Jt(),Il(206);if($l==53||$l==80)$l==80&&ks(),Il(28),Hl(53),Il(267),Xf();$l==95&&(Hl(95),Il(15),Hl(7));break;case-3:break;default:Xf()}}function $t(){ic.startNonterminal("GroupingVariable",Vl),Pl(31),Il(246),jl(),Ti(),ic.endNonterminal("GroupingVariable",Vl)}function Jt(){Hl(31),Il(246),Ni()}function Kt(){ic.startNonterminal("OrderByClause",Vl);switch($l){case 205:Pl(205),Il(37),Pl(88);break;default:Pl(241),Il(70),Pl(205),Il(37),Pl(88)}Il(267),jl(),Gt(),ic.endNonterminal("OrderByClause",Vl)}function Qt(){switch($l){case 205:Hl(205),Il(37),Hl(88);break;default:Hl(241),Il(70),Hl(205),Il(37),Hl(88)}Il(267),Yt()}function Gt(){ic.startNonterminal("OrderSpecList",Vl),Zt();for(;;){Il(198);if($l!=42)break;Pl(42),Il(267),jl(),Zt()}ic.endNonterminal("OrderSpecList",Vl)}function Yt(){en();for(;;){Il(198);if($l!=42)break;Hl(42),Il(267),en()}}function Zt(){ic.startNonterminal("OrderSpec",Vl),Wf(),jl(),tn(),ic.endNonterminal("OrderSpec",Vl)}function en(){Xf(),nn()}function tn(){ic.startNonterminal("OrderModifier",Vl);if($l==81||$l==114)switch($l){case 81:Pl(81);break;default:Pl(114)}Il(203);if($l==124){Pl(124),Il(125);switch($l){case 149:Pl(149);break;default:Pl(176)}}Il(199),$l==95&&(Pl(95),Il(15),Pl(7)),ic.endNonterminal("OrderModifier",Vl)}function nn(){if($l==81||$l==114)switch($l){case 81:Hl(81);break;default:Hl(114)}Il(203);if($l==124){Hl(124),Il(125);switch($l){case 149:Hl(149);break;default:Hl(176)}}Il(199),$l==95&&(Hl(95),Il(15),Hl(7))}function rn(){ic.startNonterminal("ReturnClause",Vl),Pl(224),Il(267),jl(),Wf(),ic.endNonterminal("ReturnClause",Vl)}function sn(){Hl(224),Il(267),Xf()}function on(){ic.startNonterminal("QuantifiedExpr",Vl);switch($l){case 240:Pl(240);break;default:Pl(130)}Il(21),jl(),an();for(;;){if($l!=42)break;Pl(42),Il(21),jl(),an()}Pl(228),Il(267),jl(),Wf(),ic.endNonterminal("QuantifiedExpr",Vl)}function un(){switch($l){case 240:Hl(240);break;default:Hl(130)}Il(21),fn();for(;;){if($l!=42)break;Hl(42),Il(21),fn()}Hl(228),Il(267),Xf()}function an(){ic.startNonterminal("QuantifiedVarDecl",Vl),Pl(31),Il(246),jl(),Ti(),Il(114),$l==80&&(jl(),Cs()),Il(56),Pl(156),Il(267),jl(),Wf(),ic.endNonterminal("QuantifiedVarDecl",Vl)}function fn(){Hl(31),Il(246),Ni(),Il(114),$l==80&&ks(),Il(56),Hl(156),Il(267),Xf()}function ln(){ic.startNonterminal("SwitchExpr",Vl),Pl(248),Il(22),Pl(35),Il(267),jl(),G(),Pl(38);for(;;){Il(38),jl(),hn();if($l!=89)break}Pl(110),Il(73),Pl(224),Il(267),jl(),Wf(),ic.endNonterminal("SwitchExpr",Vl)}function cn(){Hl(248),Il(22),Hl(35),Il(267),Y(),Hl(38);for(;;){Il(38),pn();if($l!=89)break}Hl(110),Il(73),Hl(224),Il(267),Xf()}function hn(){ic.startNonterminal("SwitchCaseClause",Vl);for(;;){Pl(89),Il(267),jl(),dn();if($l!=89)break}Pl(224),Il(267),jl(),Wf(),ic.endNonterminal("SwitchCaseClause",Vl)}function pn(){for(;;){Hl(89),Il(267),vn();if($l!=89)break}Hl(224),Il(267),Xf()}function dn(){ic.startNonterminal("SwitchCaseOperand",Vl),Wf(),ic.endNonterminal("SwitchCaseOperand",Vl)}function vn(){Xf()}function mn(){ic.startNonterminal("TypeswitchExpr",Vl),Pl(259),Il(22),Pl(35),Il(267),jl(),G(),Pl(38);for(;;){Il(38),jl(),yn();if($l!=89)break}Pl(110),Il(99),$l==31&&(Pl(31),Il(246),jl(),Ti()),Il(73),Pl(224),Il(267),jl(),Wf(),ic.endNonterminal("TypeswitchExpr",Vl)}function gn(){Hl(259),Il(22),Hl(35),Il(267),Y(),Hl(38);for(;;){Il(38),bn();if($l!=89)break}Hl(110),Il(99),$l==31&&(Hl(31),Il(246),Ni()),Il(73),Hl(224),Il(267),Xf()}function yn(){ic.startNonterminal("CaseClause",Vl),Pl(89),Il(258),$l==31&&(Pl(31),Il(246),jl(),Ti(),Il(33),Pl(80)),Il(254),jl(),wn(),Pl(224),Il(267),jl(),Wf(),ic.endNonterminal("CaseClause",Vl)}function bn(){Hl(89),Il(258),$l==31&&(Hl(31),Il(246),Ni(),Il(33),Hl(80)),Il(254),En(),Hl(224),Il(267),Xf()}function wn(){ic.startNonterminal("SequenceTypeUnion",Vl),Ls();for(;;){Il(138);if($l!=284)break;Pl(284),Il(254),jl(),Ls()}ic.endNonterminal("SequenceTypeUnion",Vl)}function En(){As();for(;;){Il(138);if($l!=284)break;Hl(284),Il(254),As()}}function Sn(){ic.startNonterminal("IfExpr",Vl),Pl(154),Il(22),Pl(35),Il(267),jl(),G(),Pl(38),Il(80),Pl(250),Il(267),jl(),Wf(),Pl(123),Il(267),jl(),Wf(),ic.endNonterminal("IfExpr",Vl)}function xn(){Hl(154),Il(22),Hl(35),Il(267),Y(),Hl(38),Il(80),Hl(250),Il(267),Xf(),Hl(123),Il(267),Xf()}function Tn(){ic.startNonterminal("TryCatchExpr",Vl),Cn();for(;;){Il(39),jl(),On(),Il(208);if($l!=92)break}ic.endNonterminal("TryCatchExpr",Vl)}function Nn(){kn();for(;;){Il(39),Mn(),Il(208);if($l!=92)break}}function Cn(){ic.startNonterminal("TryClause",Vl),Pl(256),Il(90),Pl(281),Il(267),jl(),Ln(),Pl(287),ic.endNonterminal("TryClause",Vl)}function kn(){Hl(256),Il(90),Hl(281),Il(267),An(),Hl(287)}function Ln(){ic.startNonterminal("TryTargetExpr",Vl),G(),ic.endNonterminal("TryTargetExpr",Vl)}function An(){Y()}function On(){ic.startNonterminal("CatchClause",Vl),Pl(92),Il(249),jl(),_n(),Pl(281),Il(267),jl(),G(),Pl(287),ic.endNonterminal("CatchClause",Vl)}function Mn(){Hl(92),Il(249),Dn(),Hl(281),Il(267),Y(),Hl(287)}function _n(){ic.startNonterminal("CatchErrorList",Vl),Yr();for(;;){Il(140);if($l!=284)break;Pl(284),Il(249),jl(),Yr()}ic.endNonterminal("CatchErrorList",Vl)}function Dn(){Zr();for(;;){Il(140);if($l!=284)break;Hl(284),Il(249),Zr()}}function Pn(){ic.startNonterminal("OrExpr",Vl),Bn();for(;;){if($l!=204)break;Pl(204),Il(267),jl(),Bn()}ic.endNonterminal("OrExpr",Vl)}function Hn(){jn();for(;;){if($l!=204)break;Hl(204),Il(267),jn()}}function Bn(){ic.startNonterminal("AndExpr",Vl),Fn();for(;;){if($l!=76)break;Pl(76),Il(267),jl(),Fn()}ic.endNonterminal("AndExpr",Vl)}function jn(){In();for(;;){if($l!=76)break;Hl(76),Il(267),In()}}function Fn(){ic.startNonterminal("NotExpr",Vl),$l==196&&Pl(196),Il(266),jl(),qn(),ic.endNonterminal("NotExpr",Vl)}function In(){$l==196&&Hl(196),Il(266),Rn()}function qn(){ic.startNonterminal("ComparisonExpr",Vl),Un();if($l==27||$l==55||$l==58||$l==59||$l==61||$l==62||$l==63||$l==64||$l==129||$l==148||$l==152||$l==166||$l==175||$l==181||$l==189){switch($l){case 129:case 148:case 152:case 175:case 181:case 189:jl(),yr();break;case 58:case 64:case 166:jl(),wr();break;default:jl(),mr()}Il(266),jl(),Un()}ic.endNonterminal("ComparisonExpr",Vl)}function Rn(){zn();if($l==27||$l==55||$l==58||$l==59||$l==61||$l==62||$l==63||$l==64||$l==129||$l==148||$l==152||$l==166||$l==175||$l==181||$l==189){switch($l){case 129:case 148:case 152:case 175:case 181:case 189:br();break;case 58:case 64:case 166:Er();break;default:gr()}Il(266),zn()}}function Un(){ic.startNonterminal("FTContainsExpr",Vl),Wn(),$l==100&&(Pl(100),Il(79),Pl(249),Il(177),jl(),ou(),$l==277&&(jl(),Ta())),ic.endNonterminal("FTContainsExpr",Vl)}function zn(){Xn(),$l==100&&(Hl(100),Il(79),Hl(249),Il(177),uu(),$l==277&&Na())}function Wn(){ic.startNonterminal("StringConcatExpr",Vl),Vn();for(;;){if($l!=285)break;Pl(285),Il(266),jl(),Vn()}ic.endNonterminal("StringConcatExpr",Vl)}function Xn(){$n();for(;;){if($l!=285)break;Hl(285),Il(266),$n()}}function Vn(){ic.startNonterminal("RangeExpr",Vl),Jn(),$l==253&&(Pl(253),Il(266),jl(),Jn()),ic.endNonterminal("RangeExpr",Vl)}function $n(){Kn(),$l==253&&(Hl(253),Il(266),Kn())}function Jn(){ic.startNonterminal("AdditiveExpr",Vl),Qn();for(;;){if($l!=41&&$l!=43)break;switch($l){case 41:Pl(41);break;default:Pl(43)}Il(266),jl(),Qn()}ic.endNonterminal("AdditiveExpr",Vl)}function Kn(){Gn();for(;;){if($l!=41&&$l!=43)break;switch($l){case 41:Hl(41);break;default:Hl(43)}Il(266),Gn()}}function Qn(){ic.startNonterminal("MultiplicativeExpr",Vl),Yn();for(;;){if($l!=39&&$l!=119&&$l!=153&&$l!=183)break;switch($l){case 39:Pl(39);break;case 119:Pl(119);break;case 153:Pl(153);break;default:Pl(183)}Il(266),jl(),Yn()}ic.endNonterminal("MultiplicativeExpr",Vl)}function Gn(){Zn();for(;;){if($l!=39&&$l!=119&&$l!=153&&$l!=183)break;switch($l){case 39:Hl(39);break;case 119:Hl(119);break;case 153:Hl(153);break;default:Hl(183)}Il(266),Zn()}}function Yn(){ic.startNonterminal("UnionExpr",Vl),er();for(;;){if($l!=260&&$l!=284)break;switch($l){case 260:Pl(260);break;default:Pl(284)}Il(266),jl(),er()}ic.endNonterminal("UnionExpr",Vl)}function Zn(){tr();for(;;){if($l!=260&&$l!=284)break;switch($l){case 260:Hl(260);break;default:Hl(284)}Il(266),tr()}}function er(){ic.startNonterminal("IntersectExceptExpr",Vl),nr();for(;;){Il(222);if($l!=132&&$l!=164)break;switch($l){case 164:Pl(164);break;default:Pl(132)}Il(266),jl(),nr()}ic.endNonterminal("IntersectExceptExpr",Vl)}function tr(){rr();for(;;){Il(222);if($l!=132&&$l!=164)break;switch($l){case 164:Hl(164);break;default:Hl(132)}Il(266),rr()}}function nr(){ic.startNonterminal("InstanceofExpr",Vl),ir(),Il(223),$l==162&&(Pl(162),Il(67),Pl(200),Il(254),jl(),Ls()),ic.endNonterminal("InstanceofExpr",Vl)}function rr(){sr(),Il(223),$l==162&&(Hl(162),Il(67),Hl(200),Il(254),As())}function ir(){ic.startNonterminal("TreatExpr",Vl),or(),Il(224),$l==254&&(Pl(254),Il(33),Pl(80),Il(254),jl(),Ls()),ic.endNonterminal("TreatExpr",Vl)}function sr(){ur(),Il(224),$l==254&&(Hl(254),Il(33),Hl(80),Il(254),As())}function or(){ic.startNonterminal("CastableExpr",Vl),ar(),Il(225),$l==91&&(Pl(91),Il(33),Pl(80),Il(246),jl(),Ts()),ic.endNonterminal("CastableExpr",Vl)}function ur(){fr(),Il(225),$l==91&&(Hl(91),Il(33),Hl(80),Il(246),Ns())}function ar(){ic.startNonterminal("CastExpr",Vl),lr(),Il(227),$l==90&&(Pl(90),Il(33),Pl(80),Il(246),jl(),Ts()),ic.endNonterminal("CastExpr",Vl)}function fr(){cr(),Il(227),$l==90&&(Hl(90),Il(33),Hl(80),Il(246),Ns())}function lr(){ic.startNonterminal("UnaryExpr",Vl);for(;;){Il(266);if($l!=41&&$l!=43)break;switch($l){case 43:Pl(43);break;default:Pl(41)}}jl(),hr(),ic.endNonterminal("UnaryExpr",Vl)}function cr(){for(;;){Il(266);if($l!=41&&$l!=43)break;switch($l){case 43:Hl(43);break;default:Hl(41)}}pr()}function hr(){ic.startNonterminal("ValueExpr",Vl);switch($l){case 266:ql(188);break;default:Wl=$l}switch(Wl){case 89354:case 125706:case 132362:case 144138:Sr();break;case 36:Cr();break;default:dr()}ic.endNonterminal("ValueExpr",Vl)}function pr(){switch($l){case 266:ql(188);break;default:Wl=$l}switch(Wl){case 89354:case 125706:case 132362:case 144138:xr();break;case 36:kr();break;default:vr()}}function dr(){ic.startNonterminal("SimpleMapExpr",Vl),Or();for(;;){if($l!=26)break;Pl(26),Il(263),jl(),Or()}ic.endNonterminal("SimpleMapExpr",Vl)}function vr(){Mr();for(;;){if($l!=26)break;Hl(26),Il(263),Mr()}}function mr(){ic.startNonterminal("GeneralComp",Vl);switch($l){case 61:Pl(61);break;case 27:Pl(27);break;case 55:Pl(55);break;case 59:Pl(59);break;case 62:Pl(62);break;default:Pl(63)}ic.endNonterminal("GeneralComp",Vl)}function gr(){switch($l){case 61:Hl(61);break;case 27:Hl(27);break;case 55:Hl(55);break;case 59:Hl(59);break;case 62:Hl(62);break;default:Hl(63)}}function yr(){ic.startNonterminal("ValueComp",Vl);switch($l){case 129:Pl(129);break;case 189:Pl(189);break;case 181:Pl(181);break;case 175:Pl(175);break;case 152:Pl(152);break;default:Pl(148)}ic.endNonterminal("ValueComp",Vl)}function br(){switch($l){case 129:Hl(129);break;case 189:Hl(189);break;case 181:Hl(181);break;case 175:Hl(175);break;case 152:Hl(152);break;default:Hl(148)}}function wr(){ic.startNonterminal("NodeComp",Vl);switch($l){case 166:Pl(166);break;case 58:Pl(58);break;default:Pl(64)}ic.endNonterminal("NodeComp",Vl)}function Er(){switch($l){case 166:Hl(166);break;case 58:Hl(58);break;default:Hl(64)}}function Sr(){ic.startNonterminal("ValidateExpr",Vl),Pl(266),Il(175);if($l!=281)switch($l){case 258:Pl(258),Il(246),jl(),Ao();break;default:jl(),Tr()}Il(90),Pl(281),Il(267),jl(),G(),Pl(287),ic.endNonterminal("ValidateExpr",Vl)}function xr(){Hl(266),Il(175);if($l!=281)switch($l){case 258:Hl(258),Il(246),Oo();break;default:Nr()}Il(90),Hl(281),Il(267),Y(),Hl(287)}function Tr(){ic.startNonterminal("ValidationMode",Vl);switch($l){case 174:Pl(174);break;default:Pl(245)}ic.endNonterminal("ValidationMode",Vl)}function Nr(){switch($l){case 174:Hl(174);break;default:Hl(245)}}function Cr(){ic.startNonterminal("ExtensionExpr",Vl);for(;;){jl(),Lr(),Il(104);if($l!=36)break}Pl(281),Il(275),$l!=287&&(jl(),G()),Pl(287),ic.endNonterminal("ExtensionExpr",Vl)}function kr(){for(;;){Ar(),Il(104);if($l!=36)break}Hl(281),Il(275),$l!=287&&Y(),Hl(287)}function Lr(){ic.startNonterminal("Pragma",Vl),Pl(36),Rl(243),$l==21&&Pl(21),$a(),Rl(10),$l==21&&(Pl(21),Rl(0),Pl(1)),Rl(5),Pl(30),ic.endNonterminal("Pragma",Vl)}function Ar(){Hl(36),Rl(243),$l==21&&Hl(21),Ja(),Rl(10),$l==21&&(Hl(21),Rl(0),Hl(1)),Rl(5),Hl(30)}function Or(){ic.startNonterminal("PathExpr",Vl);switch($l){case 47:Pl(47),Il(289);switch($l){case 25:case 26:case 27:case 38:case 39:case 41:case 42:case 43:case 50:case 54:case 58:case 59:case 61:case 62:case 63:case 64:case 70:case 88:case 100:case 209:case 237:case 252:case 279:case 284:case 285:case 286:case 287:break;default:jl(),_r()}break;case 48:Pl(48),Il(260),jl(),_r();break;default:_r()}ic.endNonterminal("PathExpr",Vl)}function Mr(){switch($l){case 47:Hl(47),Il(289);switch($l){case 25:case 26:case 27:case 38:case 39:case 41:case 42:case 43:case 50:case 54:case 58:case 59:case 61:case 62:case 63:case 64:case 70:case 88:case 100:case 209:case 237:case 252:case 279:case 284:case 285:case 286:case 287:break;default:Dr()}break;case 48:Hl(48),Il(260),Dr();break;default:Dr()}}function _r(){ic.startNonterminal("RelativePathExpr",Vl),ei();for(;;){switch($l){case 26:ql(265);break;default:Wl=$l}if(Wl!=25&&Wl!=27&&Wl!=38&&Wl!=39&&Wl!=41&&Wl!=42&&Wl!=43&&Wl!=47&&Wl!=48&&Wl!=50&&Wl!=54&&Wl!=55&&Wl!=58&&Wl!=59&&Wl!=61&&Wl!=62&&Wl!=63&&Wl!=64&&Wl!=70&&Wl!=71&&Wl!=76&&Wl!=80&&Wl!=81&&Wl!=82&&Wl!=85&&Wl!=88&&Wl!=89&&Wl!=90&&Wl!=91&&Wl!=95&&Wl!=100&&Wl!=106&&Wl!=110&&Wl!=114&&Wl!=119&&Wl!=123&&Wl!=124&&Wl!=127&&Wl!=129&&Wl!=132&&Wl!=139&&Wl!=148&&Wl!=150&&Wl!=152&&Wl!=153&&Wl!=162&&Wl!=164&&Wl!=165&&Wl!=166&&Wl!=175&&Wl!=177&&Wl!=181&&Wl!=183&&Wl!=184&&Wl!=189&&Wl!=202&&Wl!=204&&Wl!=205&&Wl!=209&&Wl!=224&&Wl!=228&&Wl!=237&&Wl!=241&&Wl!=242&&Wl!=252&&Wl!=253&&Wl!=254&&Wl!=260&&Wl!=272&&Wl!=276&&Wl!=279&&Wl!=284&&Wl!=285&&Wl!=286&&Wl!=287&&Wl!=2586&&Wl!=23578&&Wl!=24090&&Wl!=24602&&Wl!=34330){Wl=uc(3,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{switch($l){case 47:Hl(47);break;case 48:Hl(48);break;default:Hl(26)}Il(264),Hr(),Wl=-1}catch(a){Wl=-2}Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(3,Vl,Wl)}}if(Wl!=-1&&Wl!=47&&Wl!=48&&Wl!=2586&&Wl!=23578&&Wl!=34330)break;switch($l){case 47:Pl(47);break;case 48:Pl(48);break;default:Pl(26)}Il(264),jl(),Pr()}ic.endNonterminal("RelativePathExpr",Vl)}function Dr(){ti();for(;;){switch($l){case 26:ql(265);break;default:Wl=$l}if(Wl!=25&&Wl!=27&&Wl!=38&&Wl!=39&&Wl!=41&&Wl!=42&&Wl!=43&&Wl!=47&&Wl!=48&&Wl!=50&&Wl!=54&&Wl!=55&&Wl!=58&&Wl!=59&&Wl!=61&&Wl!=62&&Wl!=63&&Wl!=64&&Wl!=70&&Wl!=71&&Wl!=76&&Wl!=80&&Wl!=81&&Wl!=82&&Wl!=85&&Wl!=88&&Wl!=89&&Wl!=90&&Wl!=91&&Wl!=95&&Wl!=100&&Wl!=106&&Wl!=110&&Wl!=114&&Wl!=119&&Wl!=123&&Wl!=124&&Wl!=127&&Wl!=129&&Wl!=132&&Wl!=139&&Wl!=148&&Wl!=150&&Wl!=152&&Wl!=153&&Wl!=162&&Wl!=164&&Wl!=165&&Wl!=166&&Wl!=175&&Wl!=177&&Wl!=181&&Wl!=183&&Wl!=184&&Wl!=189&&Wl!=202&&Wl!=204&&Wl!=205&&Wl!=209&&Wl!=224&&Wl!=228&&Wl!=237&&Wl!=241&&Wl!=242&&Wl!=252&&Wl!=253&&Wl!=254&&Wl!=260&&Wl!=272&&Wl!=276&&Wl!=279&&Wl!=284&&Wl!=285&&Wl!=286&&Wl!=287&&Wl!=2586&&Wl!=23578&&Wl!=24090&&Wl!=24602&&Wl!=34330){Wl=uc(3,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{switch($l){case 47:Hl(47);break;case 48:Hl(48);break;default:Hl(26)}Il(264),Hr(),oc(3,t,-1);continue}catch(a){Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(3,t,-2);break}}}if(Wl!=-1&&Wl!=47&&Wl!=48&&Wl!=2586&&Wl!=23578&&Wl!=34330)break;switch($l){case 47:Hl(47);break;case 48:Hl(48);break;default:Hl(26)}Il(264),Hr()}}function Pr(){ic.startNonterminal("StepExpr",Vl);switch($l){case 83:ql(288);break;case 122:ql(287);break;case 187:case 220:ql(285);break;case 135:case 197:case 255:ql(237);break;case 97:case 120:case 206:case 249:case 262:ql(239);break;case 79:case 125:case 154:case 167:case 169:case 247:case 248:case 259:ql(230);break;case 74:case 75:case 94:case 112:case 113:case 137:case 138:case 210:case 216:case 217:case 234:ql(238);break;case 6:case 71:case 73:case 76:case 78:case 80:case 81:case 82:case 84:case 85:case 86:case 87:case 89:case 90:case 91:case 92:case 95:case 98:case 99:case 102:case 103:case 104:case 105:case 106:case 107:case 109:case 110:case 111:case 114:case 119:case 121:case 123:case 124:case 126:case 127:case 129:case 130:case 132:case 133:case 134:case 136:case 139:case 142:case 143:case 147:case 148:case 150:case 152:case 153:case 155:case 156:case 157:case 161:case 162:case 163:case 164:case 165:case 166:case 168:case 170:case 173:case 174:case 175:case 177:case 179:case 181:case 183:case 184:case 185:case 188:case 189:case 194:case 195:case 198:case 202:case 203:case 204:case 205:case 207:case 222:case 223:case 224:case 225:case 226:case 228:case 229:case 230:case 231:case 232:case 233:case 239:case 240:case 241:case 242:case 245:case 253:case 254:case 256:case 257:case 258:case 260:case 263:case 266:case 267:case 268:case 269:case 272:case 273:case 276:ql(234);break;default:Wl=$l}if(Wl==12935||Wl==12997||Wl==13055||Wl==13447||Wl==13509||Wl==13567||Wl==13959||Wl==14021||Wl==14079||Wl==19591||Wl==19653||Wl==19711||Wl==20103||Wl==20165||Wl==20223||Wl==21127||Wl==21189||Wl==21247||Wl==21639||Wl==21701||Wl==21759||Wl==22151||Wl==22213||Wl==22271||Wl==24199||Wl==24261||Wl==24319||Wl==24711||Wl==24773||Wl==24831||Wl==25735||Wl==25797||Wl==25855||Wl==27783||Wl==27845||Wl==27903||Wl==28295||Wl==28357||Wl==28415||Wl==29831||Wl==29893||Wl==29951||Wl==30343||Wl==30405||Wl==30463||Wl==31367||Wl==31429||Wl==31487||Wl==31879||Wl==31941||Wl==31999||Wl==32391||Wl==32453||Wl==32511||Wl==32903||Wl==32965||Wl==33023||Wl==35463||Wl==35525||Wl==35583||Wl==35975||Wl==36037||Wl==36095||Wl==36435||Wl==36474||Wl==36487||Wl==36539||Wl==36549||Wl==36572||Wl==36607||Wl==38995||Wl==39034||Wl==39047||Wl==39099||Wl==39109||Wl==39132||Wl==39167||Wl==41043||Wl==41082||Wl==41095||Wl==41147||Wl==41157||Wl==41180||Wl==41215||Wl==41555||Wl==41594||Wl==41607||Wl==41659||Wl==41669||Wl==41692||Wl==41727||Wl==42067||Wl==42106||Wl==42119||Wl==42171||Wl==42181||Wl==42204||Wl==42239||Wl==43603||Wl==43642||Wl==43655||Wl==43707||Wl==43717||Wl==43740||Wl==43775||Wl==45191||Wl==45253||Wl==45311||Wl==45651||Wl==45690||Wl==45703||Wl==45755||Wl==45765||Wl==45788||Wl==45823||Wl==46163||Wl==46202||Wl==46215||Wl==46267||Wl==46277||Wl==46300||Wl==46335||Wl==46675||Wl==46714||Wl==46727||Wl==46779||Wl==46789||Wl==46812||Wl==46847||Wl==48723||Wl==48762||Wl==48775||Wl==48827||Wl==48837||Wl==48860||Wl==48895||Wl==51335||Wl==51397||Wl==51455||Wl==54355||Wl==54394||Wl==54407||Wl==54459||Wl==54469||Wl==54492||Wl==54527||Wl==56403||Wl==56442||Wl==56455||Wl==56507||Wl==56517||Wl==56540||Wl==56575||Wl==58451||Wl==58490||Wl==58503||Wl==58555||Wl==58565||Wl==58588||Wl==58623||Wl==61011||Wl==61050||Wl==61063||Wl==61115||Wl==61125||Wl==61148||Wl==61183||Wl==63059||Wl==63098||Wl==63111||Wl==63163||Wl==63173||Wl==63196||Wl==63231||Wl==63571||Wl==63610||Wl==63623||Wl==63675||Wl==63685||Wl==63708||Wl==63743||Wl==65107||Wl==65146||Wl==65159||Wl==65211||Wl==65221||Wl==65244||Wl==65279||Wl==66131||Wl==66170||Wl==66183||Wl==66235||Wl==66245||Wl==66268||Wl==66303||Wl==67667||Wl==67706||Wl==67719||Wl==67771||Wl==67781||Wl==67804||Wl==67839||Wl==71251||Wl==71290||Wl==71303||Wl==71355||Wl==71365||Wl==71388||Wl==71423||Wl==75859||Wl==75898||Wl==75911||Wl==75963||Wl==75973||Wl==75996||Wl==76031||Wl==76883||Wl==76922||Wl==76935||Wl==76987||Wl==76997||Wl==77020||Wl==77055||Wl==77907||Wl==77946||Wl==77959||Wl==78011||Wl==78021||Wl==78044||Wl==78079||Wl==78419||Wl==78458||Wl==78471||Wl==78523||Wl==78533||Wl==78556||Wl==78591||Wl==83027||Wl==83066||Wl==83079||Wl==83131||Wl==83141||Wl==83164||Wl==83199||Wl==84051||Wl==84090||Wl==84103||Wl==84155||Wl==84165||Wl==84188||Wl==84223||Wl==84563||Wl==84602||Wl==84615||Wl==84667||Wl==84677||Wl==84700||Wl==84735||Wl==85075||Wl==85114||Wl==85127||Wl==85179||Wl==85189||Wl==85212||Wl==85247||Wl==89683||Wl==89722||Wl==89735||Wl==89787||Wl==89797||Wl==89820||Wl==89855||Wl==90707||Wl==90746||Wl==90759||Wl==90811||Wl==90821||Wl==90844||Wl==90879||Wl==92755||Wl==92794||Wl==92807||Wl==92859||Wl==92869||Wl==92892||Wl==92927||Wl==93779||Wl==93818||Wl==93831||Wl==93883||Wl==93893||Wl==93916||Wl==93951||Wl==94291||Wl==94330||Wl==94343||Wl==94395||Wl==94405||Wl==94428||Wl==94463||Wl==96851||Wl==96890||Wl==96903||Wl==96955||Wl==96965||Wl==96988||Wl==97023||Wl==103507||Wl==103546||Wl==103559||Wl==103611||Wl==103621||Wl==103644||Wl==103679||Wl==104531||Wl==104570||Wl==104583||Wl==104635||Wl==104645||Wl==104668||Wl==104703||Wl==105043||Wl==105082||Wl==105095||Wl==105147||Wl==105157||Wl==105180||Wl==105215||Wl==107143||Wl==107205||Wl==107263||Wl==114771||Wl==114810||Wl==114823||Wl==114875||Wl==114885||Wl==114908||Wl==114943||Wl==116819||Wl==116858||Wl==116871||Wl==116923||Wl==116933||Wl==116956||Wl==116991||Wl==121479||Wl==121541||Wl==121599||Wl==123475||Wl==123514||Wl==123527||Wl==123579||Wl==123589||Wl==123612||Wl==123647||Wl==123987||Wl==124026||Wl==124039||Wl==124091||Wl==124101||Wl==124124||Wl==124159||Wl==129159||Wl==129221||Wl==129279||Wl==129619||Wl==129658||Wl==129671||Wl==129723||Wl==129733||Wl==129756||Wl==129791||Wl==130131||Wl==130170||Wl==130183||Wl==130235||Wl==130245||Wl==130268||Wl==130303||Wl==133203||Wl==133242||Wl==133255||Wl==133307||Wl==133317||Wl==133340||Wl==133375||Wl==139347||Wl==139386||Wl==139399||Wl==139451||Wl==139461||Wl==139484||Wl==139519||Wl==141395||Wl==141434||Wl==141447||Wl==141499||Wl==141509||Wl==141532||Wl==141567||Wl==142983||Wl==143045||Wl==143103||Wl==145543||Wl==145605||Wl==145663||Wl==146055||Wl==146117||Wl==146175||Wl==146567||Wl==146629||Wl==146687||Wl==147079||Wl==147141||Wl==147199){Wl=uc(4,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{ti(),Wl=-1}catch(a){Wl=-2}Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(4,Vl,Wl)}}switch(Wl){case-1:case 8:case 9:case 10:case 11:case 31:case 32:case 33:case 35:case 55:case 56:case 60:case 69:case 281:case 283:case 3155:case 3194:case 9915:case 9948:case 14854:case 14919:case 14921:case 14922:case 14923:case 14924:case 14926:case 14927:case 14928:case 14929:case 14930:case 14931:case 14932:case 14933:case 14934:case 14935:case 14937:case 14938:case 14939:case 14940:case 14942:case 14943:case 14945:case 14946:case 14947:case 14950:case 14951:case 14952:case 14953:case 14954:case 14955:case 14957:case 14958:case 14959:case 14960:case 14961:case 14962:case 14967:case 14968:case 14969:case 14970:case 14971:case 14972:case 14973:case 14974:case 14975:case 14977:case 14978:case 14980:case 14981:case 14982:case 14983:case 14984:case 14985:case 14986:case 14987:case 14990:case 14991:case 14995:case 14996:case 14998:case 15e3:case 15001:case 15002:case 15003:case 15004:case 15005:case 15009:case 15010:case 15011:case 15012:case 15013:case 15014:case 15015:case 15016:case 15017:case 15018:case 15021:case 15022:case 15023:case 15025:case 15027:case 15029:case 15031:case 15032:case 15033:case 15035:case 15036:case 15037:case 15042:case 15043:case 15045:case 15046:case 15050:case 15051:case 15052:case 15053:case 15054:case 15055:case 15058:case 15064:case 15065:case 15068:case 15070:case 15071:case 15072:case 15073:case 15074:case 15076:case 15077:case 15078:case 15079:case 15080:case 15081:case 15082:case 15087:case 15088:case 15089:case 15090:case 15093:case 15095:case 15096:case 15097:case 15101:case 15102:case 15103:case 15104:case 15105:case 15106:case 15107:case 15108:case 15110:case 15111:case 15114:case 15115:case 15116:case 15117:case 15120:case 15121:case 15124:case 17926:case 17991:case 17993:case 17994:case 17995:case 17996:case 17998:case 18e3:case 18001:case 18002:case 18004:case 18005:case 18006:case 18007:case 18009:case 18010:case 18011:case 18012:case 18014:case 18015:case 18018:case 18019:case 18022:case 18023:case 18024:case 18025:case 18026:case 18027:case 18029:case 18030:case 18031:case 18032:case 18033:case 18034:case 18039:case 18040:case 18043:case 18044:case 18046:case 18047:case 18049:case 18050:case 18052:case 18053:case 18054:case 18055:case 18056:case 18057:case 18058:case 18059:case 18062:case 18063:case 18067:case 18068:case 18070:case 18072:case 18073:case 18075:case 18076:case 18077:case 18081:case 18082:case 18083:case 18084:case 18085:case 18086:case 18088:case 18090:case 18093:case 18094:case 18095:case 18097:case 18099:case 18101:case 18103:case 18104:case 18105:case 18107:case 18109:case 18115:case 18117:case 18118:case 18122:case 18123:case 18124:case 18125:case 18126:case 18127:case 18130:case 18136:case 18137:case 18142:case 18143:case 18144:case 18145:case 18146:case 18148:case 18149:case 18152:case 18153:case 18154:case 18159:case 18160:case 18161:case 18162:case 18165:case 18173:case 18174:case 18175:case 18176:case 18177:case 18178:case 18180:case 18182:case 18183:case 18186:case 18187:case 18188:case 18189:case 18192:case 18193:case 18196:case 23175:case 23237:case 23295:case 37459:case 37498:case 37563:case 37596:case 37971:case 38010:case 38075:case 38108:case 38483:case 38522:case 38587:case 38620:case 40019:case 40058:case 40123:case 40156:case 40531:case 40570:case 42579:case 42618:case 42683:case 42716:case 43091:case 43130:case 43195:case 43228:case 44115:case 44154:case 44219:case 44252:case 44627:case 44666:case 44731:case 44764:case 47187:case 47226:case 47291:case 47324:case 48211:case 48250:case 48315:case 48348:case 49747:case 49786:case 49851:case 49884:case 50259:case 50298:case 50363:case 50396:case 50771:case 50810:case 50875:case 50908:case 52307:case 52346:case 52411:case 52444:case 52819:case 52858:case 52923:case 52956:case 53331:case 53370:case 53435:case 53468:case 53843:case 53882:case 53947:case 53980:case 54867:case 54906:case 54971:case 55004:case 55891:case 55930:case 55995:case 56028:case 56915:case 56954:case 57019:case 57052:case 57427:case 57466:case 57531:case 57564:case 57939:case 57978:case 58043:case 58076:case 61523:case 61562:case 61627:case 61660:case 62035:case 62074:case 62139:case 62172:case 62547:case 62586:case 62651:case 62684:case 64083:case 64122:case 64187:case 64220:case 64595:case 64634:case 64699:case 64732:case 66643:case 66682:case 66747:case 66780:case 68179:case 68218:case 68283:case 68316:case 68691:case 68730:case 68795:case 68828:case 69203:case 69242:case 69307:case 69340:case 69715:case 69754:case 69819:case 69852:case 70227:case 70266:case 70331:case 70364:case 70739:case 70778:case 70843:case 70876:case 72787:case 72826:case 72891:case 72924:case 73299:case 73338:case 73403:case 73436:case 75347:case 75386:case 75451:case 75484:case 78931:case 78970:case 79035:case 79068:case 79443:case 79482:case 79547:case 79580:case 79955:case 79994:case 80059:case 80092:case 80467:case 80506:case 80571:case 80604:case 82515:case 82554:case 82619:case 82652:case 83539:case 83578:case 83643:case 83676:case 85587:case 85626:case 85691:case 85724:case 86099:case 86138:case 86203:case 86236:case 86611:case 86650:case 87123:case 87162:case 87227:case 87260:case 88659:case 88698:case 88763:case 88796:case 89171:case 89210:case 89275:case 89308:case 91731:case 91770:case 91835:case 91868:case 94803:case 94842:case 94907:case 94940:case 95827:case 95866:case 95931:case 95964:case 96339:case 96378:case 96443:case 96476:case 99411:case 99450:case 99515:case 99548:case 99923:case 99962:case 100027:case 100060:case 100947:case 100986:case 101051:case 101084:case 101459:case 101498:case 101563:case 101596:case 104019:case 104058:case 104123:case 104156:case 105555:case 105594:case 105659:case 105692:case 106067:case 106106:case 106171:case 106204:case 107603:case 107642:case 107707:case 107740:case 110675:case 110714:case 110779:case 110812:case 111187:case 111226:case 111291:case 111324:case 112723:case 112762:case 112827:case 112860:case 113747:case 113786:case 113851:case 113884:case 114259:case 114298:case 114363:case 114396:case 115283:case 115322:case 115387:case 115420:case 115795:case 115834:case 115899:case 115932:case 117331:case 117370:case 117435:case 117468:case 117843:case 117882:case 117947:case 117980:case 118355:case 118394:case 118459:case 118492:case 118867:case 118906:case 118971:case 119004:case 119379:case 119418:case 119483:case 119516:case 119891:case 119930:case 119995:case 120028:case 122451:case 122490:case 122555:case 122588:case 122963:case 123002:case 123067:case 123100:case 125523:case 125562:case 125627:case 125660:case 126547:case 126586:case 127059:case 127098:case 127163:case 127196:case 127571:case 127610:case 127675:case 127708:case 130643:case 130682:case 130747:case 130780:case 131155:case 131194:case 131259:case 131292:case 131667:case 131706:case 131771:case 131804:case 132179:case 132218:case 132283:case 132316:case 132691:case 132730:case 132795:case 132828:case 134227:case 134266:case 134331:case 134364:case 134739:case 134778:case 134843:case 134876:case 136275:case 136314:case 136379:case 136412:case 136787:case 136826:case 136891:case 136924:case 137299:case 137338:case 137403:case 137436:case 137811:case 137850:case 137915:case 137948:case 139859:case 139898:case 139963:case 139996:case 143955:case 143969:case 143992:case 143994:case 144059:case 144078:case 144092:case 144121:case 144134:ei();break;default:Br()}ic.endNonterminal("StepExpr",Vl)}function Hr(){switch($l){case 83:ql(288);break;case 122:ql(287);break;case 187:case 220:ql(285);break;case 135:case 197:case 255:ql(237);break;case 97:case 120:case 206:case 249:case 262:ql(239);break;case 79:case 125:case 154:case 167:case 169:case 247:case 248:case 259:ql(230);break;case 74:case 75:case 94:case 112:case 113:case 137:case 138:case 210:case 216:case 217:case 234:ql(238);break;case 6:case 71:case 73:case 76:case 78:case 80:case 81:case 82:case 84:case 85:case 86:case 87:case 89:case 90:case 91:case 92:case 95:case 98:case 99:case 102:case 103:case 104:case 105:case 106:case 107:case 109:case 110:case 111:case 114:case 119:case 121:case 123:case 124:case 126:case 127:case 129:case 130:case 132:case 133:case 134:case 136:case 139:case 142:case 143:case 147:case 148:case 150:case 152:case 153:case 155:case 156:case 157:case 161:case 162:case 163:case 164:case 165:case 166:case 168:case 170:case 173:case 174:case 175:case 177:case 179:case 181:case 183:case 184:case 185:case 188:case 189:case 194:case 195:case 198:case 202:case 203:case 204:case 205:case 207:case 222:case 223:case 224:case 225:case 226:case 228:case 229:case 230:case 231:case 232:case 233:case 239:case 240:case 241:case 242:case 245:case 253:case 254:case 256:case 257:case 258:case 260:case 263:case 266:case 267:case 268:case 269:case 272:case 273:case 276:ql(234);break;default:Wl=$l}if(Wl==12935||Wl==12997||Wl==13055||Wl==13447||Wl==13509||Wl==13567||Wl==13959||Wl==14021||Wl==14079||Wl==19591||Wl==19653||Wl==19711||Wl==20103||Wl==20165||Wl==20223||Wl==21127||Wl==21189||Wl==21247||Wl==21639||Wl==21701||Wl==21759||Wl==22151||Wl==22213||Wl==22271||Wl==24199||Wl==24261||Wl==24319||Wl==24711||Wl==24773||Wl==24831||Wl==25735||Wl==25797||Wl==25855||Wl==27783||Wl==27845||Wl==27903||Wl==28295||Wl==28357||Wl==28415||Wl==29831||Wl==29893||Wl==29951||Wl==30343||Wl==30405||Wl==30463||Wl==31367||Wl==31429||Wl==31487||Wl==31879||Wl==31941||Wl==31999||Wl==32391||Wl==32453||Wl==32511||Wl==32903||Wl==32965||Wl==33023||Wl==35463||Wl==35525||Wl==35583||Wl==35975||Wl==36037||Wl==36095||Wl==36435||Wl==36474||Wl==36487||Wl==36539||Wl==36549||Wl==36572||Wl==36607||Wl==38995||Wl==39034||Wl==39047||Wl==39099||Wl==39109||Wl==39132||Wl==39167||Wl==41043||Wl==41082||Wl==41095||Wl==41147||Wl==41157||Wl==41180||Wl==41215||Wl==41555||Wl==41594||Wl==41607||Wl==41659||Wl==41669||Wl==41692||Wl==41727||Wl==42067||Wl==42106||Wl==42119||Wl==42171||Wl==42181||Wl==42204||Wl==42239||Wl==43603||Wl==43642||Wl==43655||Wl==43707||Wl==43717||Wl==43740||Wl==43775||Wl==45191||Wl==45253||Wl==45311||Wl==45651||Wl==45690||Wl==45703||Wl==45755||Wl==45765||Wl==45788||Wl==45823||Wl==46163||Wl==46202||Wl==46215||Wl==46267||Wl==46277||Wl==46300||Wl==46335||Wl==46675||Wl==46714||Wl==46727||Wl==46779||Wl==46789||Wl==46812||Wl==46847||Wl==48723||Wl==48762||Wl==48775||Wl==48827||Wl==48837||Wl==48860||Wl==48895||Wl==51335||Wl==51397||Wl==51455||Wl==54355||Wl==54394||Wl==54407||Wl==54459||Wl==54469||Wl==54492||Wl==54527||Wl==56403||Wl==56442||Wl==56455||Wl==56507||Wl==56517||Wl==56540||Wl==56575||Wl==58451||Wl==58490||Wl==58503||Wl==58555||Wl==58565||Wl==58588||Wl==58623||Wl==61011||Wl==61050||Wl==61063||Wl==61115||Wl==61125||Wl==61148||Wl==61183||Wl==63059||Wl==63098||Wl==63111||Wl==63163||Wl==63173||Wl==63196||Wl==63231||Wl==63571||Wl==63610||Wl==63623||Wl==63675||Wl==63685||Wl==63708||Wl==63743||Wl==65107||Wl==65146||Wl==65159||Wl==65211||Wl==65221||Wl==65244||Wl==65279||Wl==66131||Wl==66170||Wl==66183||Wl==66235||Wl==66245||Wl==66268||Wl==66303||Wl==67667||Wl==67706||Wl==67719||Wl==67771||Wl==67781||Wl==67804||Wl==67839||Wl==71251||Wl==71290||Wl==71303||Wl==71355||Wl==71365||Wl==71388||Wl==71423||Wl==75859||Wl==75898||Wl==75911||Wl==75963||Wl==75973||Wl==75996||Wl==76031||Wl==76883||Wl==76922||Wl==76935||Wl==76987||Wl==76997||Wl==77020||Wl==77055||Wl==77907||Wl==77946||Wl==77959||Wl==78011||Wl==78021||Wl==78044||Wl==78079||Wl==78419||Wl==78458||Wl==78471||Wl==78523||Wl==78533||Wl==78556||Wl==78591||Wl==83027||Wl==83066||Wl==83079||Wl==83131||Wl==83141||Wl==83164||Wl==83199||Wl==84051||Wl==84090||Wl==84103||Wl==84155||Wl==84165||Wl==84188||Wl==84223||Wl==84563||Wl==84602||Wl==84615||Wl==84667||Wl==84677||Wl==84700||Wl==84735||Wl==85075||Wl==85114||Wl==85127||Wl==85179||Wl==85189||Wl==85212||Wl==85247||Wl==89683||Wl==89722||Wl==89735||Wl==89787||Wl==89797||Wl==89820||Wl==89855||Wl==90707||Wl==90746||Wl==90759||Wl==90811||Wl==90821||Wl==90844||Wl==90879||Wl==92755||Wl==92794||Wl==92807||Wl==92859||Wl==92869||Wl==92892||Wl==92927||Wl==93779||Wl==93818||Wl==93831||Wl==93883||Wl==93893||Wl==93916||Wl==93951||Wl==94291||Wl==94330||Wl==94343||Wl==94395||Wl==94405||Wl==94428||Wl==94463||Wl==96851||Wl==96890||Wl==96903||Wl==96955||Wl==96965||Wl==96988||Wl==97023||Wl==103507||Wl==103546||Wl==103559||Wl==103611||Wl==103621||Wl==103644||Wl==103679||Wl==104531||Wl==104570||Wl==104583||Wl==104635||Wl==104645||Wl==104668||Wl==104703||Wl==105043||Wl==105082||Wl==105095||Wl==105147||Wl==105157||Wl==105180||Wl==105215||Wl==107143||Wl==107205||Wl==107263||Wl==114771||Wl==114810||Wl==114823||Wl==114875||Wl==114885||Wl==114908||Wl==114943||Wl==116819||Wl==116858||Wl==116871||Wl==116923||Wl==116933||Wl==116956||Wl==116991||Wl==121479||Wl==121541||Wl==121599||Wl==123475||Wl==123514||Wl==123527||Wl==123579||Wl==123589||Wl==123612||Wl==123647||Wl==123987||Wl==124026||Wl==124039||Wl==124091||Wl==124101||Wl==124124||Wl==124159||Wl==129159||Wl==129221||Wl==129279||Wl==129619||Wl==129658||Wl==129671||Wl==129723||Wl==129733||Wl==129756||Wl==129791||Wl==130131||Wl==130170||Wl==130183||Wl==130235||Wl==130245||Wl==130268||Wl==130303||Wl==133203||Wl==133242||Wl==133255||Wl==133307||Wl==133317||Wl==133340||Wl==133375||Wl==139347||Wl==139386||Wl==139399||Wl==139451||Wl==139461||Wl==139484||Wl==139519||Wl==141395||Wl==141434||Wl==141447||Wl==141499||Wl==141509||Wl==141532||Wl==141567||Wl==142983||Wl==143045||Wl==143103||Wl==145543||Wl==145605||Wl==145663||Wl==146055||Wl==146117||Wl==146175||Wl==146567||Wl==146629||Wl==146687||Wl==147079||Wl==147141||Wl==147199){Wl=uc(4,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{ti(),oc(4,t,-1),Wl=-3}catch(a){Wl=-2,Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(4,t,-2)}}}switch(Wl){case-1:case 8:case 9:case 10:case 11:case 31:case 32:case 33:case 35:case 55:case 56:case 60:case 69:case 281:case 283:case 3155:case 3194:case 9915:case 9948:case 14854:case 14919:case 14921:case 14922:case 14923:case 14924:case 14926:case 14927:case 14928:case 14929:case 14930:case 14931:case 14932:case 14933:case 14934:case 14935:case 14937:case 14938:case 14939:case 14940:case 14942:case 14943:case 14945:case 14946:case 14947:case 14950:case 14951:case 14952:case 14953:case 14954:case 14955:case 14957:case 14958:case 14959:case 14960:case 14961:case 14962:case 14967:case 14968:case 14969:case 14970:case 14971:case 14972:case 14973:case 14974:case 14975:case 14977:case 14978:case 14980:case 14981:case 14982:case 14983:case 14984:case 14985:case 14986:case 14987:case 14990:case 14991:case 14995:case 14996:case 14998:case 15e3:case 15001:case 15002:case 15003:case 15004:case 15005:case 15009:case 15010:case 15011:case 15012:case 15013:case 15014:case 15015:case 15016:case 15017:case 15018:case 15021:case 15022:case 15023:case 15025:case 15027:case 15029:case 15031:case 15032:case 15033:case 15035:case 15036:case 15037:case 15042:case 15043:case 15045:case 15046:case 15050:case 15051:case 15052:case 15053:case 15054:case 15055:case 15058:case 15064:case 15065:case 15068:case 15070:case 15071:case 15072:case 15073:case 15074:case 15076:case 15077:case 15078:case 15079:case 15080:case 15081:case 15082:case 15087:case 15088:case 15089:case 15090:case 15093:case 15095:case 15096:case 15097:case 15101:case 15102:case 15103:case 15104:case 15105:case 15106:case 15107:case 15108:case 15110:case 15111:case 15114:case 15115:case 15116:case 15117:case 15120:case 15121:case 15124:case 17926:case 17991:case 17993:case 17994:case 17995:case 17996:case 17998:case 18e3:case 18001:case 18002:case 18004:case 18005:case 18006:case 18007:case 18009:case 18010:case 18011:case 18012:case 18014:case 18015:case 18018:case 18019:case 18022:case 18023:case 18024:case 18025:case 18026:case 18027:case 18029:case 18030:case 18031:case 18032:case 18033:case 18034:case 18039:case 18040:case 18043:case 18044:case 18046:case 18047:case 18049:case 18050:case 18052:case 18053:case 18054:case 18055:case 18056:case 18057:case 18058:case 18059:case 18062:case 18063:case 18067:case 18068:case 18070:case 18072:case 18073:case 18075:case 18076:case 18077:case 18081:case 18082:case 18083:case 18084:case 18085:case 18086:case 18088:case 18090:case 18093:case 18094:case 18095:case 18097:case 18099:case 18101:case 18103:case 18104:case 18105:case 18107:case 18109:case 18115:case 18117:case 18118:case 18122:case 18123:case 18124:case 18125:case 18126:case 18127:case 18130:case 18136:case 18137:case 18142:case 18143:case 18144:case 18145:case 18146:case 18148:case 18149:case 18152:case 18153:case 18154:case 18159:case 18160:case 18161:case 18162:case 18165:case 18173:case 18174:case 18175:case 18176:case 18177:case 18178:case 18180:case 18182:case 18183:case 18186:case 18187:case 18188:case 18189:case 18192:case 18193:case 18196:case 23175:case 23237:case 23295:case 37459:case 37498:case 37563:case 37596:case 37971:case 38010:case 38075:case 38108:case 38483:case 38522:case 38587:case 38620:case 40019:case 40058:case 40123:case 40156:case 40531:case 40570:case 42579:case 42618:case 42683:case 42716:case 43091:case 43130:case 43195:case 43228:case 44115:case 44154:case 44219:case 44252:case 44627:case 44666:case 44731:case 44764:case 47187:case 47226:case 47291:case 47324:case 48211:case 48250:case 48315:case 48348:case 49747:case 49786:case 49851:case 49884:case 50259:case 50298:case 50363:case 50396:case 50771:case 50810:case 50875:case 50908:case 52307:case 52346:case 52411:case 52444:case 52819:case 52858:case 52923:case 52956:case 53331:case 53370:case 53435:case 53468:case 53843:case 53882:case 53947:case 53980:case 54867:case 54906:case 54971:case 55004:case 55891:case 55930:case 55995:case 56028:case 56915:case 56954:case 57019:case 57052:case 57427:case 57466:case 57531:case 57564:case 57939:case 57978:case 58043:case 58076:case 61523:case 61562:case 61627:case 61660:case 62035:case 62074:case 62139:case 62172:case 62547:case 62586:case 62651:case 62684:case 64083:case 64122:case 64187:case 64220:case 64595:case 64634:case 64699:case 64732:case 66643:case 66682:case 66747:case 66780:case 68179:case 68218:case 68283:case 68316:case 68691:case 68730:case 68795:case 68828:case 69203:case 69242:case 69307:case 69340:case 69715:case 69754:case 69819:case 69852:case 70227:case 70266:case 70331:case 70364:case 70739:case 70778:case 70843:case 70876:case 72787:case 72826:case 72891:case 72924:case 73299:case 73338:case 73403:case 73436:case 75347:case 75386:case 75451:case 75484:case 78931:case 78970:case 79035:case 79068:case 79443:case 79482:case 79547:case 79580:case 79955:case 79994:case 80059:case 80092:case 80467:case 80506:case 80571:case 80604:case 82515:case 82554:case 82619:case 82652:case 83539:case 83578:case 83643:case 83676:case 85587:case 85626:case 85691:case 85724:case 86099:case 86138:case 86203:case 86236:case 86611:case 86650:case 87123:case 87162:case 87227:case 87260:case 88659:case 88698:case 88763:case 88796:case 89171:case 89210:case 89275:case 89308:case 91731:case 91770:case 91835:case 91868:case 94803:case 94842:case 94907:case 94940:case 95827:case 95866:case 95931:case 95964:case 96339:case 96378:case 96443:case 96476:case 99411:case 99450:case 99515:case 99548:case 99923:case 99962:case 100027:case 100060:case 100947:case 100986:case 101051:case 101084:case 101459:case 101498:case 101563:case 101596:case 104019:case 104058:case 104123:case 104156:case 105555:case 105594:case 105659:case 105692:case 106067:case 106106:case 106171:case 106204:case 107603:case 107642:case 107707:case 107740:case 110675:case 110714:case 110779:case 110812:case 111187:case 111226:case 111291:case 111324:case 112723:case 112762:case 112827:case 112860:case 113747:case 113786:case 113851:case 113884:case 114259:case 114298:case 114363:case 114396:case 115283:case 115322:case 115387:case 115420:case 115795:case 115834:case 115899:case 115932:case 117331:case 117370:case 117435:case 117468:case 117843:case 117882:case 117947:case 117980:case 118355:case 118394:case 118459:case 118492:case 118867:case 118906:case 118971:case 119004:case 119379:case 119418:case 119483:case 119516:case 119891:case 119930:case 119995:case 120028:case 122451:case 122490:case 122555:case 122588:case 122963:case 123002:case 123067:case 123100:case 125523:case 125562:case 125627:case 125660:case 126547:case 126586:case 127059:case 127098:case 127163:case 127196:case 127571:case 127610:case 127675:case 127708:case 130643:case 130682:case 130747:case 130780:case 131155:case 131194:case 131259:case 131292:case 131667:case 131706:case 131771:case 131804:case 132179:case 132218:case 132283:case 132316:case 132691:case 132730:case 132795:case 132828:case 134227:case 134266:case 134331:case 134364:case 134739:case 134778:case 134843:case 134876:case 136275:case 136314:case 136379:case 136412:case 136787:case 136826:case 136891:case 136924:case 137299:case 137338:case 137403:case 137436:case 137811:case 137850:case 137915:case 137948:case 139859:case 139898:case 139963:case 139996:case 143955:case 143969:case 143992:case 143994:case 144059:case 144078:case 144092:case 144121:case 144134:ti();break;case-3:break;default:jr()}}function Br(){ic.startNonterminal("AxisStep",Vl);switch($l){case 74:case 75:case 210:case 216:case 217:ql(232);break;default:Wl=$l}switch(Wl){case 46:case 26698:case 26699:case 26834:case 26840:case 26841:Wr();break;default:Fr()}Il(228),jl(),li(),ic.endNonterminal("AxisStep",Vl)}function jr(){switch($l){case 74:case 75:case 210:case 216:case 217:ql(232);break;default:Wl=$l}switch(Wl){case 46:case 26698:case 26699:case 26834:case 26840:case 26841:Xr();break;default:Ir()}Il(228),ci()}function Fr(){ic.startNonterminal("ForwardStep",Vl);switch($l){case 83:ql(236);break;case 94:case 112:case 113:case 137:case 138:case 234:ql(232);break;default:Wl=$l}switch(Wl){case 26707:case 26718:case 26736:case 26737:case 26761:case 26762:case 26858:qr(),Il(249),jl(),Qr();break;default:Ur()}ic.endNonterminal("ForwardStep",Vl)}function Ir(){switch($l){case 83:ql(236);break;case 94:case 112:case 113:case 137:case 138:case 234:ql(232);break;default:Wl=$l}switch(Wl){case 26707:case 26718:case 26736:case 26737:case 26761:case 26762:case 26858:Rr(),Il(249),Gr();break;default:zr()}}function qr(){ic.startNonterminal("ForwardAxis",Vl);switch($l){case 94:Pl(94),Il(27),Pl(52);break;case 112:Pl(112),Il(27),Pl(52);break;case 83:Pl(83),Il(27),Pl(52);break;case 234:Pl(234),Il(27),Pl(52);break;case 113:Pl(113),Il(27),Pl(52);break;case 138:Pl(138),Il(27),Pl(52);break;default:Pl(137),Il(27),Pl(52)}ic.endNonterminal("ForwardAxis",Vl)}function Rr(){switch($l){case 94:Hl(94),Il(27),Hl(52);break;case 112:Hl(112),Il(27),Hl(52);break;case 83:Hl(83),Il(27),Hl(52);break;case 234:Hl(234),Il(27),Hl(52);break;case 113:Hl(113),Il(27),Hl(52);break;case 138:Hl(138),Il(27),Hl(52);break;default:Hl(137),Il(27),Hl(52)}}function Ur(){ic.startNonterminal("AbbrevForwardStep",Vl),$l==67&&Pl(67),Il(249),jl(),Qr(),ic.endNonterminal("AbbrevForwardStep",Vl)}function zr(){$l==67&&Hl(67),Il(249),Gr()}function Wr(){ic.startNonterminal("ReverseStep",Vl);switch($l){case 46:Jr();break;default:Vr(),Il(249),jl(),Qr()}ic.endNonterminal("ReverseStep",Vl)}function Xr(){switch($l){case 46:Kr();break;default:$r(),Il(249),Gr()}}function Vr(){ic.startNonterminal("ReverseAxis",Vl);switch($l){case 210:Pl(210),Il(27),Pl(52);break;case 74:Pl(74),Il(27),Pl(52);break;case 217:Pl(217),Il(27),Pl(52);break;case 216:Pl(216),Il(27),Pl(52);break;default:Pl(75),Il(27),Pl(52)}ic.endNonterminal("ReverseAxis",Vl)}function $r(){switch($l){case 210:Hl(210),Il(27),Hl(52);break;case 74:Hl(74),Il(27),Hl(52);break;case 217:Hl(217),Il(27),Hl(52);break;case 216:Hl(216),Il(27),Hl(52);break;default:Hl(75),Il(27),Hl(52)}}function Jr(){ic.startNonterminal("AbbrevReverseStep",Vl),Pl(46),ic.endNonterminal("AbbrevReverseStep",Vl)}function Kr(){Hl(46)}function Qr(){ic.startNonterminal("NodeTest",Vl);switch($l){case 83:case 97:case 121:case 122:case 188:case 194:case 220:case 230:case 231:case 249:ql(231);break;default:Wl=$l}switch(Wl){case 18003:case 18017:case 18041:case 18042:case 18108:case 18114:case 18140:case 18150:case 18151:case 18169:Vs();break;default:Yr()}ic.endNonterminal("NodeTest",Vl)}function Gr(){switch($l){case 83:case 97:case 121:case 122:case 188:case 194:case 220:case 230:case 231:case 249:ql(231);break;default:Wl=$l}switch(Wl){case 18003:case 18017:case 18041:case 18042:case 18108:case 18114:case 18140:case 18150:case 18151:case 18169:$s();break;default:Zr()}}function Yr(){ic.startNonterminal("NameTest",Vl);switch($l){case 5:Pl(5);break;default:$a()}ic.endNonterminal("NameTest",Vl)}function Zr(){switch($l){case 5:Hl(5);break;default:Ja()}}function ei(){ic.startNonterminal("PostfixExpr",Vl),yl();for(;;){Il(235);if($l!=35&&$l!=45&&$l!=69)break;switch($l){case 69:ql(273);break;default:Wl=$l}if(Wl==35397){Wl=uc(5,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{pi(),Wl=-1}catch(a){Wl=-4}Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(5,Vl,Wl)}}switch(Wl){case 35:jl(),ai();break;case 45:jl(),ni();break;case-4:jl(),ii();break;case 35909:jl(),oi();break;default:jl(),hi()}}ic.endNonterminal("PostfixExpr",Vl)}function ti(){bl();for(;;){Il(235);if($l!=35&&$l!=45&&$l!=69)break;switch($l){case 69:ql(273);break;default:Wl=$l}if(Wl==35397){Wl=uc(5,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{pi(),oc(5,t,-1),Wl=-6}catch(a){Wl=-4,Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(5,t,-4)}}}switch(Wl){case 35:fi();break;case 45:ri();break;case-4:si();break;case 35909:ui();break;case-6:break;default:pi()}}}function ni(){ic.startNonterminal("ObjectLookup",Vl),Pl(45),Il(251);switch($l){case 11:Pl(11);break;case 35:jl(),Ci();break;case 31:jl(),Si();break;case 32:jl(),Li();break;default:jl(),Ga()}ic.endNonterminal("ObjectLookup",Vl)}function ri(){Hl(45),Il(251);switch($l){case 11:Hl(11);break;case 35:ki();break;case 31:xi();break;case 32:Ai();break;default:Ya()}}function ii(){ic.startNonterminal("ArrayLookup",Vl),Pl(69),Il(31),Pl(69),Il(267),jl(),G(),Pl(70),Il(32),Pl(70),ic.endNonterminal("ArrayLookup",Vl)}function si(){Hl(69),Il(31),Hl(69),Il(267),Y(),Hl(70),Il(32),Hl(70)}function oi(){ic.startNonterminal("ArrayUnboxing",Vl),Pl(69),Il(32),Pl(70),ic.endNonterminal("ArrayUnboxing",Vl)}function ui(){Hl(69),Il(32),Hl(70)}function ai(){ic.startNonterminal("ArgumentList",Vl),Pl(35),Il(280);if($l!=38){jl(),Bi();for(;;){Il(105);if($l!=42)break;Pl(42),Il(272),jl(),Bi()}}Pl(38),ic.endNonterminal("ArgumentList",Vl)}function fi(){Hl(35),Il(280);if($l!=38){ji();for(;;){Il(105);if($l!=42)break;Hl(42),Il(272),ji()}}Hl(38)}function li(){ic.startNonterminal("PredicateList",Vl);for(;;){Il(228);if($l!=69)break;jl(),hi()}ic.endNonterminal("PredicateList",Vl)}function ci(){for(;;){Il(228);if($l!=69)break;pi()}}function hi(){ic.startNonterminal("Predicate",Vl),Pl(69),Il(267),jl(),G(),Pl(70),ic.endNonterminal("Predicate",Vl)}function pi(){Hl(69),Il(267),Y(),Hl(70)}function di(){ic.startNonterminal("Literal",Vl);switch($l){case 11:Pl(11);break;case 135:case 255:mi();break;case 197:yi();break;default:wi()}ic.endNonterminal("Literal",Vl)}function vi(){switch($l){case 11:Hl(11);break;case 135:case 255:gi();break;case 197:bi();break;default:Ei()}}function mi(){ic.startNonterminal("BooleanLiteral",Vl);switch($l){case 255:Pl(255);break;default:Pl(135)}ic.endNonterminal("BooleanLiteral",Vl)}function gi(){switch($l){case 255:Hl(255);break;default:Hl(135)}}function yi(){ic.startNonterminal("NullLiteral",Vl),Pl(197),ic.endNonterminal("NullLiteral",Vl)}function bi(){Hl(197)}function wi(){ic.startNonterminal("NumericLiteral",Vl);switch($l){case 8:Pl(8);break;case 9:Pl(9);break;default:Pl(10)}ic.endNonterminal("NumericLiteral",Vl)}function Ei(){switch($l){case 8:Hl(8);break;case 9:Hl(9);break;default:Hl(10)}}function Si(){ic.startNonterminal("VarRef",Vl),Pl(31),Il(246),jl(),Ti(),ic.endNonterminal("VarRef",Vl)}function xi(){Hl(31),Il(246),Ni()}function Ti(){ic.startNonterminal("VarName",Vl),$a(),ic.endNonterminal("VarName",Vl)}function Ni(){Ja()}function Ci(){ic.startNonterminal("ParenthesizedExpr",Vl),Pl(35),Il(270),$l!=38&&(jl(),G()),Pl(38),ic.endNonterminal("ParenthesizedExpr",Vl)}function ki(){Hl(35),Il(270),$l!=38&&Y(),Hl(38)}function Li(){ic.startNonterminal("ContextItemExpr",Vl),Pl(32),ic.endNonterminal("ContextItemExpr",Vl)}function Ai(){Hl(32)}function Oi(){ic.startNonterminal("OrderedExpr",Vl),Pl(206),Il(90),Pl(281),Il(267),jl(),G(),Pl(287),ic.endNonterminal("OrderedExpr",Vl)}function Mi(){Hl(206),Il(90),Hl(281),Il(267),Y(),Hl(287)}function _i(){ic.startNonterminal("UnorderedExpr",Vl),Pl(262),Il(90),Pl(281),Il(267),jl(),G(),Pl(287),ic.endNonterminal("UnorderedExpr",Vl)}function Di(){Hl(262),Il(90),Hl(281),Il(267),Y(),Hl(287)}function Pi(){ic.startNonterminal("FunctionCall",Vl),Ka(),Il(22),jl(),ai(),ic.endNonterminal("FunctionCall",Vl)}function Hi(){Qa(),Il(22),fi()}function Bi(){ic.startNonterminal("Argument",Vl);switch($l){case 65:Fi();break;default:Wf()}ic.endNonterminal("Argument",Vl)}function ji(){switch($l){case 65:Ii();break;default:Xf()}}function Fi(){ic.startNonterminal("ArgumentPlaceholder",Vl),Pl(65),ic.endNonterminal("ArgumentPlaceholder",Vl)}function Ii(){Hl(65)}function qi(){ic.startNonterminal("Constructor",Vl);switch($l){case 55:case 56:case 60:Ui();break;default:os()}ic.endNonterminal("Constructor",Vl)}function Ri(){switch($l){case 55:case 56:case 60:zi();break;default:us()}}function Ui(){ic.startNonterminal("DirectConstructor",Vl);switch($l){case 55:Wi();break;case 56:ns();break;default:is()}ic.endNonterminal("DirectConstructor",Vl)}function zi(){switch($l){case 55:Xi();break;case 56:rs();break;default:ss()}}function Wi(){ic.startNonterminal("DirElemConstructor",Vl),Pl(55),Rl(4),Pl(20),Vi();switch($l){case 49:Pl(49);break;default:Pl(62);for(;;){Rl(196);if($l==57)break;es()}Pl(57),Rl(4),Pl(20),Rl(12),$l==21&&Pl(21),Rl(8),Pl(62)}ic.endNonterminal("DirElemConstructor",Vl)}function Xi(){Hl(55),Rl(4),Hl(20),$i();switch($l){case 49:Hl(49);break;default:Hl(62);for(;;){Rl(196);if($l==57)break;ts()}Hl(57),Rl(4),Hl(20),Rl(12),$l==21&&Hl(21),Rl(8),Hl(62)}}function Vi(){ic.startNonterminal("DirAttributeList",Vl);for(;;){Rl(19);if($l!=21)break;Pl(21),Rl(94),$l==20&&(Pl(20),Rl(11),$l==21&&Pl(21),Rl(7),Pl(61),Rl(18),$l==21&&Pl(21),Ji())}ic.endNonterminal("DirAttributeList",Vl)}function $i(){for(;;){Rl(19);if($l!=21)break;Hl(21),Rl(94),$l==20&&(Hl(20),Rl(11),$l==21&&Hl(21),Rl(7),Hl(61),Rl(18),$l==21&&Hl(21),Ki())}}function Ji(){ic.startNonterminal("DirAttributeValue",Vl),Rl(14);switch($l){case 28:Pl(28);for(;;){Rl(185);if($l==28)break;switch($l){case 13:Pl(13);break;default:Qi()}}Pl(28);break;default:Pl(34);for(;;){Rl(186);if($l==34)break;switch($l){case 14:Pl(14);break;default:Yi()}}Pl(34)}ic.endNonterminal("DirAttributeValue",Vl)}function Ki(){Rl(14);switch($l){case 28:Hl(28);for(;;){Rl(185);if($l==28)break;switch($l){case 13:Hl(13);break;default:Gi()}}Hl(28);break;default:Hl(34);for(;;){Rl(186);if($l==34)break;switch($l){case 14:Hl(14);break;default:Zi()}}Hl(34)}}function Qi(){ic.startNonterminal("QuotAttrValueContent",Vl);switch($l){case 16:Pl(16);break;default:il()}ic.endNonterminal("QuotAttrValueContent",Vl)}function Gi(){switch($l){case 16:Hl(16);break;default:sl()}}function Yi(){ic.startNonterminal("AposAttrValueContent",Vl);switch($l){case 17:Pl(17);break;default:il()}ic.endNonterminal("AposAttrValueContent",Vl)}function Zi(){switch($l){case 17:Hl(17);break;default:sl()}}function es(){ic.startNonterminal("DirElemContent",Vl);switch($l){case 55:case 56:case 60:Ui();break;case 4:Pl(4);break;case 15:Pl(15);break;default:il()}ic.endNonterminal("DirElemContent",Vl)}function ts(){switch($l){case 55:case 56:case 60:zi();break;case 4:Hl(4);break;case 15:Hl(15);break;default:sl()}}function ns(){ic.startNonterminal("DirCommentConstructor",Vl),Pl(56),Rl(1),Pl(2),Rl(6),Pl(44),ic.endNonterminal("DirCommentConstructor",Vl)}function rs(){Hl(56),Rl(1),Hl(2),Rl(6),Hl(44)}function is(){ic.startNonterminal("DirPIConstructor",Vl),Pl(60),Rl(3),Pl(18),Rl(13),$l==21&&(Pl(21),Rl(2),Pl(3)),Rl(9),Pl(66),ic.endNonterminal("DirPIConstructor",Vl)}function ss(){Hl(60),Rl(3),Hl(18),Rl(13),$l==21&&(Hl(21),Rl(2),Hl(3)),Rl(9),Hl(66)}function os(){ic.startNonterminal("ComputedConstructor",Vl);switch($l){case 120:al();break;case 122:as();break;case 83:ll();break;case 187:ls();break;case 249:ml();break;case 97:dl();break;default:hl()}ic.endNonterminal("ComputedConstructor",Vl)}function us(){switch($l){case 120:fl();break;case 122:fs();break;case 83:cl();break;case 187:cs();break;case 249:gl();break;case 97:vl();break;default:pl()}}function as(){ic.startNonterminal("CompElemConstructor",Vl),Pl(122),Il(250);switch($l){case 281:Pl(281),Il(267),jl(),G(),Pl(287);break;default:jl(),$a()}Il(90),Pl(281),Il(281),$l!=287&&(jl(),ol()),Pl(287),ic.endNonterminal("CompElemConstructor",Vl)}function fs(){Hl(122),Il(250);switch($l){case 281:Hl(281),Il(267),Y(),Hl(287);break;default:Ja()}Il(90),Hl(281),Il(281),$l!=287&&ul(),Hl(287)}function ls(){ic.startNonterminal("CompNamespaceConstructor",Vl),Pl(187),Il(242);switch($l){case 281:Pl(281),Il(267),jl(),ds(),Pl(287);break;default:jl(),hs()}Il(90),Pl(281),Il(267),jl(),ms(),Pl(287),ic.endNonterminal("CompNamespaceConstructor",Vl)}function cs(){Hl(187),Il(242);switch($l){case 281:Hl(281),Il(267),vs(),Hl(287);break;default:ps()}Il(90),Hl(281),Il(267),gs(),Hl(287)}function hs(){ic.startNonterminal("Prefix",Vl),Ga(),ic.endNonterminal("Prefix",Vl)}function ps(){Ya()}function ds(){ic.startNonterminal("PrefixExpr",Vl),G(),ic.endNonterminal("PrefixExpr",Vl)}function vs(){Y()}function ms(){ic.startNonterminal("URIExpr",Vl),G(),ic.endNonterminal("URIExpr",Vl)}function gs(){Y()}function ys(){ic.startNonterminal("FunctionItemExpr",Vl);switch($l){case 147:ql(95);break;default:Wl=$l}switch(Wl){case 33:case 18067:Ss();break;default:ws()}ic.endNonterminal("FunctionItemExpr",Vl)}function bs(){switch($l){case 147:ql(95);break;default:Wl=$l}switch(Wl){case 33:case 18067:xs();break;default:Es()}}function ws(){ic.startNonterminal("NamedFunctionRef",Vl),$a(),Il(20),Pl(29),Il(16),Pl(8),ic.endNonterminal("NamedFunctionRef",Vl)}function Es(){Ja(),Il(20),Hl(29),Il(16),Hl(8)}function Ss(){ic.startNonterminal("InlineFunctionExpr",Vl);for(;;){Il(101);if($l!=33)break;jl(),B()}Pl(147),Il(22),Pl(35),Il(98),$l==31&&(jl(),U()),Pl(38),Il(115),$l==80&&(Pl(80),Il(254),jl(),Ls()),Il(90),jl(),V(),ic.endNonterminal("InlineFunctionExpr",Vl)}function xs(){for(;;){Il(101);if($l!=33)break;j()}Hl(147),Il(22),Hl(35),Il(98),$l==31&&z(),Hl(38),Il(115),$l==80&&(Hl(80),Il(254),As()),Il(90),$()}function Ts(){ic.startNonterminal("SingleType",Vl),ko(),Il(226),$l==65&&Pl(65),ic.endNonterminal("SingleType",Vl)}function Ns(){Lo(),Il(226),$l==65&&Hl(65)}function Cs(){ic.startNonterminal("TypeDeclaration",Vl),Pl(80),Il(254),jl(),Ls(),ic.endNonterminal("TypeDeclaration",Vl)}function ks(){Hl(80),Il(254),As()}function Ls(){ic.startNonterminal("SequenceType",Vl);switch($l){case 35:ql(259);break;case 125:ql(233);break;default:Wl=$l}switch(Wl){case 18045:case 19491:$l==125&&Pl(125),Il(22),Pl(35),Il(23),Pl(38);break;default:_s(),Il(229);switch($l){case 40:case 41:case 65:jl(),Os();break;default:}}ic.endNonterminal("SequenceType",Vl)}function As(){switch($l){case 35:ql(259);break;case 125:ql(233);break;default:Wl=$l}switch(Wl){case 18045:case 19491:$l==125&&Hl(125),Il(22),Hl(35),Il(23),Hl(38);break;default:Ds(),Il(229);switch($l){case 40:case 41:case 65:Ms();break;default:}}}function Os(){ic.startNonterminal("OccurrenceIndicator",Vl);switch($l){case 65:Pl(65);break;case 40:Pl(40);break;default:Pl(41)}ic.endNonterminal("OccurrenceIndicator",Vl)}function Ms(){switch($l){case 65:Hl(65);break;case 40:Hl(40);break;default:Hl(41)}}function _s(){ic.startNonterminal("ItemType",Vl);switch($l){case 79:case 83:case 97:case 121:case 122:case 147:case 167:case 169:case 188:case 194:case 198:case 220:case 230:case 231:case 247:case 249:ql(233);break;default:Wl=$l}if(Wl==12879||Wl==12969||Wl==12998||Wl==13047||Wl==13903||Wl==13993||Wl==14022||Wl==14071||Wl==19535||Wl==19625||Wl==19654||Wl==19703||Wl==20047||Wl==20137||Wl==20166||Wl==20215||Wl==20559||Wl==20649||Wl==20678||Wl==20727||Wl==21071||Wl==21161||Wl==21190||Wl==21239||Wl==21583||Wl==21673||Wl==21702||Wl==21751||Wl==22095||Wl==22185||Wl==22214||Wl==22263||Wl==25679||Wl==25769||Wl==25798||Wl==25847||Wl==27215||Wl==27305||Wl==27334||Wl==27383||Wl==27727||Wl==27817||Wl==27846||Wl==27895||Wl==28239||Wl==28329||Wl==28358||Wl==28407||Wl==29775||Wl==29865||Wl==29894||Wl==29943||Wl==30287||Wl==30377||Wl==30406||Wl==30455||Wl==31311||Wl==31401||Wl==31430||Wl==31479||Wl==31823||Wl==31913||Wl==31942||Wl==31991||Wl==32335||Wl==32425||Wl==32454||Wl==32503||Wl==32847||Wl==32937||Wl==32966||Wl==33015||Wl==33359||Wl==33449||Wl==33478||Wl==33527||Wl==35919||Wl==36009||Wl==36038||Wl==36087||Wl==36431||Wl==36521||Wl==36550||Wl==36599||Wl==37455||Wl==37545||Wl==37574||Wl==37623||Wl==38991||Wl==39081||Wl==39110||Wl==39159||Wl==41039||Wl==41129||Wl==41158||Wl==41207||Wl==41551||Wl==41641||Wl==41670||Wl==41719||Wl==42063||Wl==42153||Wl==42182||Wl==42231||Wl==43599||Wl==43689||Wl==43718||Wl==43767||Wl==45647||Wl==45737||Wl==45766||Wl==45815||Wl==48719||Wl==48809||Wl==48838||Wl==48887||Wl==51279||Wl==51369||Wl==51398||Wl==51447||Wl==54351||Wl==54441||Wl==54470||Wl==54519||Wl==56399||Wl==56489||Wl==56518||Wl==56567||Wl==58447||Wl==58537||Wl==58566||Wl==58615||Wl==61007||Wl==61097||Wl==61126||Wl==61175||Wl==63055||Wl==63145||Wl==63174||Wl==63223||Wl==63567||Wl==63657||Wl==63686||Wl==63735||Wl==65103||Wl==65193||Wl==65222||Wl==65271||Wl==66127||Wl==66217||Wl==66246||Wl==66295||Wl==67663||Wl==67753||Wl==67782||Wl==67831||Wl==68687||Wl==68777||Wl==68806||Wl==68855||Wl==71247||Wl==71337||Wl==71366||Wl==71415||Wl==75855||Wl==75945||Wl==75974||Wl==76023||Wl==76879||Wl==76969||Wl==76998||Wl==77047||Wl==77903||Wl==77993||Wl==78022||Wl==78071||Wl==78415||Wl==78505||Wl==78534||Wl==78583||Wl==79951||Wl==80041||Wl==80070||Wl==80119||Wl==83023||Wl==83113||Wl==83142||Wl==83191||Wl==84047||Wl==84137||Wl==84166||Wl==84215||Wl==84559||Wl==84649||Wl==84678||Wl==84727||Wl==85071||Wl==85161||Wl==85190||Wl==85239||Wl==89679||Wl==89769||Wl==89798||Wl==89847||Wl==90703||Wl==90793||Wl==90822||Wl==90871||Wl==92751||Wl==92841||Wl==92870||Wl==92919||Wl==93775||Wl==93865||Wl==93894||Wl==93943||Wl==94287||Wl==94377||Wl==94406||Wl==94455||Wl==96847||Wl==96937||Wl==96966||Wl==97015||Wl==103503||Wl==103593||Wl==103622||Wl==103671||Wl==104527||Wl==104617||Wl==104646||Wl==104695||Wl==105039||Wl==105129||Wl==105158||Wl==105207||Wl==107087||Wl==107177||Wl==107206||Wl==107255||Wl==114767||Wl==114857||Wl==114886||Wl==114935||Wl==116815||Wl==116905||Wl==116934||Wl==116983||Wl==118863||Wl==118953||Wl==118982||Wl==119031||Wl==121423||Wl==121513||Wl==121542||Wl==121591||Wl==123471||Wl==123561||Wl==123590||Wl==123639||Wl==123983||Wl==124073||Wl==124102||Wl==124151||Wl==129103||Wl==129193||Wl==129222||Wl==129271||Wl==129615||Wl==129705||Wl==129734||Wl==129783||Wl==133199||Wl==133289||Wl==133318||Wl==133367||Wl==139343||Wl==139433||Wl==139462||Wl==139511||Wl==141391||Wl==141481||Wl==141510||Wl==141559||Wl==142927||Wl==143017||Wl==143046||Wl==143095||Wl==143951||Wl==144041||Wl==144070||Wl==144119||Wl==145487||Wl==145577||Wl==145606||Wl==145655||Wl==145999||Wl==146089||Wl==146118||Wl==146167||Wl==146511||Wl==146601||Wl==146630||Wl==146679||Wl==147023||Wl==147113||Wl==147142||Wl==147191){Wl=uc(6,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Xs(),Wl=-4}catch(a){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),Hs(),Wl=-6}catch(f){Wl=-7}}Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(6,Vl,Wl)}}switch(Wl){case 18003:case 18017:case 18041:case 18042:case 18108:case 18114:case 18140:case 18150:case 18151:case 18169:Vs();break;case 18087:Pl(167),Il(22),Pl(35),Il(23),Pl(38);break;case 33:case 18067:Mo();break;case 35:jo();break;case-6:case 17999:case 18089:case 18118:Ps();break;case-7:case 18167:Bs();break;default:Ws()}ic.endNonterminal("ItemType",Vl)}function Ds(){switch($l){case 79:case 83:case 97:case 121:case 122:case 147:case 167:case 169:case 188:case 194:case 198:case 220:case 230:case 231:case 247:case 249:ql(233);break;default:Wl=$l}if(Wl==12879||Wl==12969||Wl==12998||Wl==13047||Wl==13903||Wl==13993||Wl==14022||Wl==14071||Wl==19535||Wl==19625||Wl==19654||Wl==19703||Wl==20047||Wl==20137||Wl==20166||Wl==20215||Wl==20559||Wl==20649||Wl==20678||Wl==20727||Wl==21071||Wl==21161||Wl==21190||Wl==21239||Wl==21583||Wl==21673||Wl==21702||Wl==21751||Wl==22095||Wl==22185||Wl==22214||Wl==22263||Wl==25679||Wl==25769||Wl==25798||Wl==25847||Wl==27215||Wl==27305||Wl==27334||Wl==27383||Wl==27727||Wl==27817||Wl==27846||Wl==27895||Wl==28239||Wl==28329||Wl==28358||Wl==28407||Wl==29775||Wl==29865||Wl==29894||Wl==29943||Wl==30287||Wl==30377||Wl==30406||Wl==30455||Wl==31311||Wl==31401||Wl==31430||Wl==31479||Wl==31823||Wl==31913||Wl==31942||Wl==31991||Wl==32335||Wl==32425||Wl==32454||Wl==32503||Wl==32847||Wl==32937||Wl==32966||Wl==33015||Wl==33359||Wl==33449||Wl==33478||Wl==33527||Wl==35919||Wl==36009||Wl==36038||Wl==36087||Wl==36431||Wl==36521||Wl==36550||Wl==36599||Wl==37455||Wl==37545||Wl==37574||Wl==37623||Wl==38991||Wl==39081||Wl==39110||Wl==39159||Wl==41039||Wl==41129||Wl==41158||Wl==41207||Wl==41551||Wl==41641||Wl==41670||Wl==41719||Wl==42063||Wl==42153||Wl==42182||Wl==42231||Wl==43599||Wl==43689||Wl==43718||Wl==43767||Wl==45647||Wl==45737||Wl==45766||Wl==45815||Wl==48719||Wl==48809||Wl==48838||Wl==48887||Wl==51279||Wl==51369||Wl==51398||Wl==51447||Wl==54351||Wl==54441||Wl==54470||Wl==54519||Wl==56399||Wl==56489||Wl==56518||Wl==56567||Wl==58447||Wl==58537||Wl==58566||Wl==58615||Wl==61007||Wl==61097||Wl==61126||Wl==61175||Wl==63055||Wl==63145||Wl==63174||Wl==63223||Wl==63567||Wl==63657||Wl==63686||Wl==63735||Wl==65103||Wl==65193||Wl==65222||Wl==65271||Wl==66127||Wl==66217||Wl==66246||Wl==66295||Wl==67663||Wl==67753||Wl==67782||Wl==67831||Wl==68687||Wl==68777||Wl==68806||Wl==68855||Wl==71247||Wl==71337||Wl==71366||Wl==71415||Wl==75855||Wl==75945||Wl==75974||Wl==76023||Wl==76879||Wl==76969||Wl==76998||Wl==77047||Wl==77903||Wl==77993||Wl==78022||Wl==78071||Wl==78415||Wl==78505||Wl==78534||Wl==78583||Wl==79951||Wl==80041||Wl==80070||Wl==80119||Wl==83023||Wl==83113||Wl==83142||Wl==83191||Wl==84047||Wl==84137||Wl==84166||Wl==84215||Wl==84559||Wl==84649||Wl==84678||Wl==84727||Wl==85071||Wl==85161||Wl==85190||Wl==85239||Wl==89679||Wl==89769||Wl==89798||Wl==89847||Wl==90703||Wl==90793||Wl==90822||Wl==90871||Wl==92751||Wl==92841||Wl==92870||Wl==92919||Wl==93775||Wl==93865||Wl==93894||Wl==93943||Wl==94287||Wl==94377||Wl==94406||Wl==94455||Wl==96847||Wl==96937||Wl==96966||Wl==97015||Wl==103503||Wl==103593||Wl==103622||Wl==103671||Wl==104527||Wl==104617||Wl==104646||Wl==104695||Wl==105039||Wl==105129||Wl==105158||Wl==105207||Wl==107087||Wl==107177||Wl==107206||Wl==107255||Wl==114767||Wl==114857||Wl==114886||Wl==114935||Wl==116815||Wl==116905||Wl==116934||Wl==116983||Wl==118863||Wl==118953||Wl==118982||Wl==119031||Wl==121423||Wl==121513||Wl==121542||Wl==121591||Wl==123471||Wl==123561||Wl==123590||Wl==123639||Wl==123983||Wl==124073||Wl==124102||Wl==124151||Wl==129103||Wl==129193||Wl==129222||Wl==129271||Wl==129615||Wl==129705||Wl==129734||Wl==129783||Wl==133199||Wl==133289||Wl==133318||Wl==133367||Wl==139343||Wl==139433||Wl==139462||Wl==139511||Wl==141391||Wl==141481||Wl==141510||Wl==141559||Wl==142927||Wl==143017||Wl==143046||Wl==143095||Wl==143951||Wl==144041||Wl==144070||Wl==144119||Wl==145487||Wl==145577||Wl==145606||Wl==145655||Wl==145999||Wl==146089||Wl==146118||Wl==146167||Wl==146511||Wl==146601||Wl==146630||Wl==146679||Wl==147023||Wl==147113||Wl==147142||Wl==147191){Wl=uc(6,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Xs(),oc(6,t,-4),Wl=-8}catch(a){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),Hs(),oc(6,t,-6),Wl=-8}catch(f){Wl=-7,Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(6,t,-7)}}}}switch(Wl){case 18003:case 18017:case 18041:case 18042:case 18108:case 18114:case 18140:case 18150:case 18151:case 18169:$s();break;case 18087:Hl(167),Il(22),Hl(35),Il(23),Hl(38);break;case 33:case 18067:_o();break;case 35:Fo();break;case-6:case 17999:case 18089:case 18118:Hs();break;case-7:case 18167:js();break;case-8:break;default:Xs()}}function Ps(){ic.startNonterminal("JSONTest",Vl);switch($l){case 169:Fs();break;case 198:qs();break;default:Us()}ic.endNonterminal("JSONTest",Vl)}function Hs(){switch($l){case 169:Is();break;case 198:Rs();break;default:zs()}}function Bs(){ic.startNonterminal("StructuredItemTest",Vl),Pl(247),Il(233),$l==35&&(Pl(35),Il(23),Pl(38)),ic.endNonterminal("StructuredItemTest",Vl)}function js(){Hl(247),Il(233),$l==35&&(Hl(35),Il(23),Hl(38))}function Fs(){ic.startNonterminal("JSONItemTest",Vl),Pl(169),Il(233),$l==35&&(Pl(35),Il(23),Pl(38)),ic.endNonterminal("JSONItemTest",Vl)}function Is(){Hl(169),Il(233),$l==35&&(Hl(35),Il(23),Hl(38))}function qs(){ic.startNonterminal("JSONObjectTest",Vl),Pl(198),Il(233),$l==35&&(Pl(35),Il(23),Pl(38)),ic.endNonterminal("JSONObjectTest",Vl)}function Rs(){Hl(198),Il(233),$l==35&&(Hl(35),Il(23),Hl(38))}function Us(){ic.startNonterminal("JSONArrayTest",Vl),Pl(79),Il(233),$l==35&&(Pl(35),Il(23),Pl(38)),ic.endNonterminal("JSONArrayTest",Vl)}function zs(){Hl(79),Il(233),$l==35&&(Hl(35),Il(23),Hl(38))}function Ws(){ic.startNonterminal("AtomicOrUnionType",Vl),$a(),ic.endNonterminal("AtomicOrUnionType",Vl)}function Xs(){Ja()}function Vs(){ic.startNonterminal("KindTest",Vl);switch($l){case 121:Qs();break;case 122:vo();break;case 83:oo();break;case 231:bo();break;case 230:lo();break;case 220:io();break;case 97:eo();break;case 249:Ys();break;case 188:no();break;default:Js()}ic.endNonterminal("KindTest",Vl)}function $s(){switch($l){case 121:Gs();break;case 122:mo();break;case 83:uo();break;case 231:wo();break;case 230:co();break;case 220:so();break;case 97:to();break;case 249:Zs();break;case 188:ro();break;default:Ks()}}function Js(){ic.startNonterminal("AnyKindTest",Vl),Pl(194),Il(22),Pl(35),Il(23),Pl(38),ic.endNonterminal("AnyKindTest",Vl)}function Ks(){Hl(194),Il(22),Hl(35),Il(23),Hl(38)}function Qs(){ic.startNonterminal("DocumentTest",Vl),Pl(121),Il(22),Pl(35),Il(154);if($l!=38)switch($l){case 122:jl(),vo();break;default:jl(),bo()}Il(23),Pl(38),ic.endNonterminal("DocumentTest",Vl)}function Gs(){Hl(121),Il(22),Hl(35),Il(154);if($l!=38)switch($l){case 122:mo();break;default:wo()}Il(23),Hl(38)}function Ys(){ic.startNonterminal("TextTest",Vl),Pl(249),Il(22),Pl(35),Il(23),Pl(38),ic.endNonterminal("TextTest",Vl)}function Zs(){Hl(249),Il(22),Hl(35),Il(23),Hl(38)}function eo(){ic.startNonterminal("CommentTest",Vl),Pl(97),Il(22),Pl(35),Il(23),Pl(38),ic.endNonterminal("CommentTest",Vl)}function to(){Hl(97),Il(22),Hl(35),Il(23),Hl(38)}function no(){ic.startNonterminal("NamespaceNodeTest",Vl),Pl(188),Il(22),Pl(35),Il(23),Pl(38),ic.endNonterminal("NamespaceNodeTest",Vl)}function ro(){Hl(188),Il(22),Hl(35),Il(23),Hl(38)}function io(){ic.startNonterminal("PITest",Vl),Pl(220),Il(22),Pl(35),Il(244);if($l!=38)switch($l){case 11:Pl(11);break;default:jl(),Ga()}Il(23),Pl(38),ic.endNonterminal("PITest",Vl)}function so(){Hl(220),Il(22),Hl(35),Il(244);if($l!=38)switch($l){case 11:Hl(11);break;default:Ya()}Il(23),Hl(38)}function oo(){ic.startNonterminal("AttributeTest",Vl),Pl(83),Il(22),Pl(35),Il(255),$l!=38&&(jl(),ao(),Il(105),$l==42&&(Pl(42),Il(246),jl(),Ao())),Il(23),Pl(38),ic.endNonterminal("AttributeTest",Vl)}function uo(){Hl(83),Il(22),Hl(35),Il(255),$l!=38&&(fo(),Il(105),$l==42&&(Hl(42),Il(246),Oo())),Il(23),Hl(38)}function ao(){ic.startNonterminal("AttribNameOrWildcard",Vl);switch($l){case 39:Pl(39);break;default:xo()}ic.endNonterminal("AttribNameOrWildcard",Vl)}function fo(){switch($l){case 39:Hl(39);break;default:To()}}function lo(){ic.startNonterminal("SchemaAttributeTest",Vl),Pl(230),Il(22),Pl(35),Il(246),jl(),ho(),Il(23),Pl(38),ic.endNonterminal("SchemaAttributeTest",Vl)}function co(){Hl(230),Il(22),Hl(35),Il(246),po(),Il(23),Hl(38)}function ho(){ic.startNonterminal("AttributeDeclaration",Vl),xo(),ic.endNonterminal("AttributeDeclaration",Vl)}function po(){To()}function vo(){ic.startNonterminal("ElementTest",Vl),Pl(122),Il(22),Pl(35),Il(255),$l!=38&&(jl(),go(),Il(105),$l==42&&(Pl(42),Il(246),jl(),Ao(),Il(106),$l==65&&Pl(65))),Il(23),Pl(38),ic.endNonterminal("ElementTest",Vl)}function mo(){Hl(122),Il(22),Hl(35),Il(255),$l!=38&&(yo(),Il(105),$l==42&&(Hl(42),Il(246),Oo(),Il(106),$l==65&&Hl(65))),Il(23),Hl(38)}function go(){ic.startNonterminal("ElementNameOrWildcard",Vl);switch($l){case 39:Pl(39);break;default:No()}ic.endNonterminal("ElementNameOrWildcard",Vl)}function yo(){switch($l){case 39:Hl(39);break;default:Co()}}function bo(){ic.startNonterminal("SchemaElementTest",Vl),Pl(231),Il(22),Pl(35),Il(246),jl(),Eo(),Il(23),Pl(38),ic.endNonterminal("SchemaElementTest",Vl)}function wo(){Hl(231),Il(22),Hl(35),Il(246),So(),Il(23),Hl(38)}function Eo(){ic.startNonterminal("ElementDeclaration",Vl),No(),ic.endNonterminal("ElementDeclaration",Vl)}function So(){Co()}function xo(){ic.startNonterminal("AttributeName",Vl),$a(),ic.endNonterminal("AttributeName",Vl)}function To(){Ja()}function No(){ic.startNonterminal("ElementName",Vl),$a(),ic.endNonterminal("ElementName",Vl)}function Co(){Ja()}function ko(){ic.startNonterminal("SimpleTypeName",Vl),Ao(),ic.endNonterminal("SimpleTypeName",Vl)}function Lo(){Oo()}function Ao(){ic.startNonterminal("TypeName",Vl),$a(),ic.endNonterminal("TypeName",Vl)}function Oo(){Ja()}function Mo(){ic.startNonterminal("FunctionTest",Vl);for(;;){Il(101);if($l!=33)break;jl(),B()}switch($l){case 147:ql(22);break;default:Wl=$l}Wl=uc(7,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Po(),Wl=-1}catch(a){Wl=-2}Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(7,Vl,Wl)}switch(Wl){case-1:jl(),Do();break;default:jl(),Ho()}ic.endNonterminal("FunctionTest",Vl)}function _o(){for(;;){Il(101);if($l!=33)break;j()}switch($l){case 147:ql(22);break;default:Wl=$l}Wl=uc(7,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Po(),oc(7,t,-1),Wl=-3}catch(a){Wl=-2,Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(7,t,-2)}}switch(Wl){case-1:Po();break;case-3:break;default:Bo()}}function Do(){ic.startNonterminal("AnyFunctionTest",Vl),Pl(147),Il(22),Pl(35),Il(24),Pl(39),Il(23),Pl(38),ic.endNonterminal("AnyFunctionTest",Vl)}function Po(){Hl(147),Il(22),Hl(35),Il(24),Hl(39),Il(23),Hl(38)}function Ho(){ic.startNonterminal("TypedFunctionTest",Vl),Pl(147),Il(22),Pl(35),Il(259);if($l!=38){jl(),Ls();for(;;){Il(105);if($l!=42)break;Pl(42),Il(254),jl(),Ls()}}Pl(38),Il(33),Pl(80),Il(254),jl(),Ls(),ic.endNonterminal("TypedFunctionTest",Vl)}function Bo(){Hl(147),Il(22),Hl(35),Il(259);if($l!=38){As();for(;;){Il(105);if($l!=42)break;Hl(42),Il(254),As()}}Hl(38),Il(33),Hl(80),Il(254),As()}function jo(){ic.startNonterminal("ParenthesizedItemType",Vl),Pl(35),Il(254),jl(),_s(),Il(23),Pl(38),ic.endNonterminal("ParenthesizedItemType",Vl)}function Fo(){Hl(35),Il(254),Ds(),Il(23),Hl(38)}function Io(){ic.startNonterminal("RevalidationDecl",Vl),Pl(109),Il(75),Pl(226),Il(162);switch($l){case 245:Pl(245);break;case 174:Pl(174);break;default:Pl(238)}ic.endNonterminal("RevalidationDecl",Vl)}function qo(){ic.startNonterminal("InsertExprTargetChoice",Vl);switch($l){case 71:Pl(71);break;case 85:Pl(85);break;default:if($l==80){Pl(80),Il(123);switch($l){case 136:Pl(136);break;default:Pl(173)}}Il(57),Pl(165)}ic.endNonterminal("InsertExprTargetChoice",Vl)}function Ro(){switch($l){case 71:Hl(71);break;case 85:Hl(85);break;default:if($l==80){Hl(80),Il(123);switch($l){case 136:Hl(136);break;default:Hl(173)}}Il(57),Hl(165)}}function Uo(){ic.startNonterminal("InsertExpr",Vl),Pl(161),Il(133);switch($l){case 194:Pl(194);break;default:Pl(195)}Il(267),jl(),Qo(),jl(),qo(),Il(267),jl(),Yo(),ic.endNonterminal("InsertExpr",Vl)}function zo(){Hl(161),Il(133);switch($l){case 194:Hl(194);break;default:Hl(195)}Il(267),Go(),Ro(),Il(267),Zo()}function Wo(){ic.startNonterminal("DeleteExpr",Vl),Pl(111),Il(133);switch($l){case 194:Pl(194);break;default:Pl(195)}Il(267),jl(),Yo(),ic.endNonterminal("DeleteExpr",Vl)}function Xo(){Hl(111),Il(133);switch($l){case 194:Hl(194);break;default:Hl(195)}Il(267),Zo()}function Vo(){ic.startNonterminal("ReplaceExpr",Vl),Pl(223),Il(134),$l==267&&(Pl(267),Il(67),Pl(200)),Il(65),Pl(194),Il(267),jl(),Yo(),Pl(276),Il(267),jl(),Wf(),ic.endNonterminal("ReplaceExpr",Vl)}function $o(){Hl(223),Il(134),$l==267&&(Hl(267),Il(67),Hl(200)),Il(65),Hl(194),Il(267),Zo(),Hl(276),Il(267),Xf()}function Jo(){ic.startNonterminal("RenameExpr",Vl),Pl(222),Il(65),Pl(194),Il(267),jl(),Yo(),Pl(80),Il(267),jl(),eu(),ic.endNonterminal("RenameExpr",Vl)}function Ko(){Hl(222),Il(65),Hl(194),Il(267),Zo(),Hl(80),Il(267),tu()}function Qo(){ic.startNonterminal("SourceExpr",Vl),Wf(),ic.endNonterminal("SourceExpr",Vl)}function Go(){Xf()}function Yo(){ic.startNonterminal("TargetExpr",Vl),Wf(),ic.endNonterminal("TargetExpr",Vl)}function Zo(){Xf()}function eu(){ic.startNonterminal("NewNameExpr",Vl),Wf(),ic.endNonterminal("NewNameExpr",Vl)}function tu(){Xf()}function nu(){ic.startNonterminal("TransformExpr",Vl),Pl(104),Il(21),jl(),iu();for(;;){if($l!=42)break;Pl(42),Il(21),jl(),iu()}Pl(184),Il(267),jl(),Wf(),Pl(224),Il(267),jl(),Wf(),ic.endNonterminal("TransformExpr",Vl)}function ru(){Hl(104),Il(21),su();for(;;){if($l!=42)break;Hl(42),Il(21),su()}Hl(184),Il(267),Xf(),Hl(224),Il(267),Xf()}function iu(){ic.startNonterminal("TransformSpec",Vl),Pl(31),Il(246),jl(),Ti(),Il(28),Pl(53),Il(267),jl(),Wf(),ic.endNonterminal("TransformSpec",Vl)}function su(){Hl(31),Il(246),Ni(),Il(28),Hl(53),Il(267),Xf()}function ou(){ic.startNonterminal("FTSelection",Vl),lu();for(;;){Il(212);switch($l){case 82:ql(161);break;default:Wl=$l}if(Wl!=116&&Wl!=118&&Wl!=128&&Wl!=206&&Wl!=227&&Wl!=275&&Wl!=65106&&Wl!=123986)break;jl(),Pu()}ic.endNonterminal("FTSelection",Vl)}function uu(){cu();for(;;){Il(212);switch($l){case 82:ql(161);break;default:Wl=$l}if(Wl!=116&&Wl!=118&&Wl!=128&&Wl!=206&&Wl!=227&&Wl!=275&&Wl!=65106&&Wl!=123986)break;Hu()}}function au(){ic.startNonterminal("FTWeight",Vl),Pl(270),Il(90),Pl(281),Il(267),jl(),G(),Pl(287),ic.endNonterminal("FTWeight",Vl)}function fu(){Hl(270),Il(90),Hl(281),Il(267),Y(),Hl(287)}function lu(){ic.startNonterminal("FTOr",Vl),hu();for(;;){if($l!=146)break;Pl(146),Il(177),jl(),hu()}ic.endNonterminal("FTOr",Vl)}function cu(){pu();for(;;){if($l!=146)break;Hl(146),Il(177),pu()}}function hu(){ic.startNonterminal("FTAnd",Vl),du();for(;;){if($l!=144)break;Pl(144),Il(177),jl(),du()}ic.endNonterminal("FTAnd",Vl)}function pu(){vu();for(;;){if($l!=144)break;Hl(144),Il(177),vu()}}function du(){ic.startNonterminal("FTMildNot",Vl),mu();for(;;){Il(213);if($l!=196)break;Pl(196),Il(56),Pl(156),Il(177),jl(),mu()}ic.endNonterminal("FTMildNot",Vl)}function vu(){gu();for(;;){Il(213);if($l!=196)break;Hl(196),Il(56),Hl(156),Il(177),gu()}}function mu(){ic.startNonterminal("FTUnaryNot",Vl),$l==145&&Pl(145),Il(164),jl(),yu(),ic.endNonterminal("FTUnaryNot",Vl)}function gu(){$l==145&&Hl(145),Il(164),bu()}function yu(){ic.startNonterminal("FTPrimaryWithOptions",Vl),wu(),Il(214),$l==265&&(jl(),Qu()),$l==270&&(jl(),au()),ic.endNonterminal("FTPrimaryWithOptions",Vl)}function bu(){Eu(),Il(214),$l==265&&Gu(),$l==270&&fu()}function wu(){ic.startNonterminal("FTPrimary",Vl);switch($l){case 35:Pl(35),Il(177),jl(),ou(),Pl(38);break;case 36:Cu();break;default:Su(),Il(215),$l==199&&(jl(),Ou())}ic.endNonterminal("FTPrimary",Vl)}function Eu(){switch($l){case 35:Hl(35),Il(177),uu(),Hl(38);break;case 36:ku();break;default:xu(),Il(215),$l==199&&Mu()}}function Su(){ic.startNonterminal("FTWords",Vl),Tu(),Il(221);if($l==72||$l==77||$l==214)jl(),Lu();ic.endNonterminal("FTWords",Vl)}function xu(){Nu(),Il(221),($l==72||$l==77||$l==214)&&Au()}function Tu(){ic.startNonterminal("FTWordsValue",Vl);switch($l){case 11:Pl(11);break;default:Pl(281),Il(267),jl(),G(),Pl(287)}ic.endNonterminal("FTWordsValue",Vl)}function Nu(){switch($l){case 11:Hl(11);break;default:Hl(281),Il(267),Y(),Hl(287)}}function Cu(){ic.startNonterminal("FTExtensionSelection",Vl);for(;;){jl(),Lr(),Il(104);if($l!=36)break}Pl(281),Il(184),$l!=287&&(jl(),ou()),Pl(287),ic.endNonterminal("FTExtensionSelection",Vl)}function ku(){for(;;){Ar(),Il(104);if($l!=36)break}Hl(281),Il(184),$l!=287&&uu(),Hl(287)}function Lu(){ic.startNonterminal("FTAnyallOption",Vl);switch($l){case 77:Pl(77),Il(218),$l==278&&Pl(278);break;case 72:Pl(72),Il(219),$l==279&&Pl(279);break;default:Pl(214)}ic.endNonterminal("FTAnyallOption",Vl)}function Au(){switch($l){case 77:Hl(77),Il(218),$l==278&&Hl(278);break;case 72:Hl(72),Il(219),$l==279&&Hl(279);break;default:Hl(214)}}function Ou(){ic.startNonterminal("FTTimes",Vl),Pl(199),Il(159),jl(),_u(),Pl(252),ic.endNonterminal("FTTimes",Vl)}function Mu(){Hl(199),Il(159),Du(),Hl(252)}function _u(){ic.startNonterminal("FTRange",Vl);switch($l){case 131:Pl(131),Il(266),jl(),Jn();break;case 82:Pl(82),Il(129);switch($l){case 176:Pl(176),Il(266),jl(),Jn();break;default:Pl(186),Il(266),jl(),Jn()}break;default:Pl(142),Il(266),jl(),Jn(),Pl(253),Il(266),jl(),Jn()}ic.endNonterminal("FTRange",Vl)}function Du(){switch($l){case 131:Hl(131),Il(266),Kn();break;case 82:Hl(82),Il(129);switch($l){case 176:Hl(176),Il(266),Kn();break;default:Hl(186),Il(266),Kn()}break;default:Hl(142),Il(266),Kn(),Hl(253),Il(266),Kn()}}function Pu(){ic.startNonterminal("FTPosFilter",Vl);switch($l){case 206:Bu();break;case 275:Fu();break;case 118:qu();break;case 116:case 227:Wu();break;default:Ju()}ic.endNonterminal("FTPosFilter",Vl)}function Hu(){switch($l){case 206:ju();break;case 275:Iu();break;case 118:Ru();break;case 116:case 227:Xu();break;default:Ku()}}function Bu(){ic.startNonterminal("FTOrder",Vl),Pl(206),ic.endNonterminal("FTOrder",Vl)}function ju(){Hl(206)}function Fu(){ic.startNonterminal("FTWindow",Vl),Pl(275),Il(266),jl(),Jn(),jl(),Uu(),ic.endNonterminal("FTWindow",Vl)}function Iu(){Hl(275),Il(266),Kn(),zu()}function qu(){ic.startNonterminal("FTDistance",Vl),Pl(118),Il(159),jl(),_u(),jl(),Uu(),ic.endNonterminal("FTDistance",Vl)}function Ru(){Hl(118),Il(159),Du(),zu()}function Uu(){ic.startNonterminal("FTUnit",Vl);switch($l){case 279:Pl(279);break;case 237:Pl(237);break;default:Pl(209)}ic.endNonterminal("FTUnit",Vl)}function zu(){switch($l){case 279:Hl(279);break;case 237:Hl(237);break;default:Hl(209)}}function Wu(){ic.startNonterminal("FTScope",Vl);switch($l){case 227:Pl(227);break;default:Pl(116)}Il(136),jl(),Vu(),ic.endNonterminal("FTScope",Vl)}function Xu(){switch($l){case 227:Hl(227);break;default:Hl(116)}Il(136),$u()}function Vu(){ic.startNonterminal("FTBigUnit",Vl);switch($l){case 236:Pl(236);break;default:Pl(208)}ic.endNonterminal("FTBigUnit",Vl)}function $u(){switch($l){case 236:Hl(236);break;default:Hl(208)}}function Ju(){ic.startNonterminal("FTContent",Vl);switch($l){case 82:Pl(82),Il(121);switch($l){case 242:Pl(242);break;default:Pl(127)}break;default:Pl(128),Il(45),Pl(101)}ic.endNonterminal("FTContent",Vl)}function Ku(){switch($l){case 82:Hl(82),Il(121);switch($l){case 242:Hl(242);break;default:Hl(127)}break;default:Hl(128),Il(45),Hl(101)}}function Qu(){ic.startNonterminal("FTMatchOptions",Vl);for(;;){Pl(265),Il(205),jl(),Yu(),Il(214);if($l!=265)break}ic.endNonterminal("FTMatchOptions",Vl)}function Gu(){for(;;){Hl(265),Il(205),Zu(),Il(214);if($l!=265)break}}function Yu(){ic.startNonterminal("FTMatchOption",Vl);switch($l){case 191:ql(176);break;default:Wl=$l}switch(Wl){case 172:ya();break;case 274:case 140479:wa();break;case 251:case 128703:oa();break;case 243:case 124607:ia();break;case 115:na();break;case 244:case 125119:ha();break;case 203:Sa();break;default:ea()}ic.endNonterminal("FTMatchOption",Vl)}function Zu(){switch($l){case 191:ql(176);break;default:Wl=$l}switch(Wl){case 172:ba();break;case 274:case 140479:Ea();break;case 251:case 128703:ua();break;case 243:case 124607:sa();break;case 115:ra();break;case 244:case 125119:pa();break;case 203:xa();break;default:ta()}}function ea(){ic.startNonterminal("FTCaseOption",Vl);switch($l){case 89:Pl(89),Il(128);switch($l){case 160:Pl(160);break;default:Pl(235)}break;case 180:Pl(180);break;default:Pl(264)}ic.endNonterminal("FTCaseOption",Vl)}function ta(){switch($l){case 89:Hl(89),Il(128);switch($l){case 160:Hl(160);break;default:Hl(235)}break;case 180:Hl(180);break;default:Hl(264)}}function na(){ic.startNonterminal("FTDiacriticsOption",Vl),Pl(115),Il(128);switch($l){case 160:Pl(160);break;default:Pl(235)}ic.endNonterminal("FTDiacriticsOption",Vl)}function ra(){Hl(115),Il(128);switch($l){case 160:Hl(160);break;default:Hl(235)}}function ia(){ic.startNonterminal("FTStemOption",Vl);switch($l){case 243:Pl(243);break;default:Pl(191),Il(77),Pl(243)}ic.endNonterminal("FTStemOption",Vl)}function sa(){switch($l){case 243:Hl(243);break;default:Hl(191),Il(77),Hl(243)}}function oa(){ic.startNonterminal("FTThesaurusOption",Vl);switch($l){case 251:Pl(251),Il(152);switch($l){case 82:jl(),aa();break;case 110:Pl(110);break;default:Pl(35),Il(116);switch($l){case 82:jl(),aa();break;default:Pl(110)}for(;;){Il(105);if($l!=42)break;Pl(42),Il(34),jl(),aa()}Pl(38)}break;default:Pl(191),Il(81),Pl(251)}ic.endNonterminal("FTThesaurusOption",Vl)}function ua(){switch($l){case 251:Hl(251),Il(152);switch($l){case 82:fa();break;case 110:Hl(110);break;default:Hl(35),Il(116);switch($l){case 82:fa();break;default:Hl(110)}for(;;){Il(105);if($l!=42)break;Hl(42),Il(34),fa()}Hl(38)}break;default:Hl(191),Il(81),Hl(251)}}function aa(){ic.startNonterminal("FTThesaurusID",Vl),Pl(82),Il(15),Pl(7),Il(220),$l==221&&(Pl(221),Il(17),Pl(11)),Il(216);switch($l){case 82:ql(183);break;default:Wl=$l}if(Wl==131||Wl==142||Wl==90194||Wl==95314)jl(),la(),Il(61),Pl(178);ic.endNonterminal("FTThesaurusID",Vl)}function fa(){Hl(82),Il(15),Hl(7),Il(220),$l==221&&(Hl(221),Il(17),Hl(11)),Il(216);switch($l){case 82:ql(183);break;default:Wl=$l}if(Wl==131||Wl==142||Wl==90194||Wl==95314)ca(),Il(61),Hl(178)}function la(){ic.startNonterminal("FTLiteralRange",Vl);switch($l){case 131:Pl(131),Il(16),Pl(8);break;case 82:Pl(82),Il(129);switch($l){case 176:Pl(176),Il(16),Pl(8);break;default:Pl(186),Il(16),Pl(8)}break;default:Pl(142),Il(16),Pl(8),Il(82),Pl(253),Il(16),Pl(8)}ic.endNonterminal("FTLiteralRange",Vl)}function ca(){switch($l){case 131:Hl(131),Il(16),Hl(8);break;case 82:Hl(82),Il(129);switch($l){case 176:Hl(176),Il(16),Hl(8);break;default:Hl(186),Il(16),Hl(8)}break;default:Hl(142),Il(16),Hl(8),Il(82),Hl(253),Il(16),Hl(8)}}function ha(){ic.startNonterminal("FTStopWordOption",Vl);switch($l){case 244:Pl(244),Il(89),Pl(279),Il(152);switch($l){case 110:Pl(110);for(;;){Il(217);if($l!=132&&$l!=260)break;jl(),ma()}break;default:jl(),da();for(;;){Il(217);if($l!=132&&$l!=260)break;jl(),ma()}}break;default:Pl(191),Il(78),Pl(244),Il(89),Pl(279)}ic.endNonterminal("FTStopWordOption",Vl)}function pa(){switch($l){case 244:Hl(244),Il(89),Hl(279),Il(152);switch($l){case 110:Hl(110);for(;;){Il(217);if($l!=132&&$l!=260)break;ga()}break;default:va();for(;;){Il(217);if($l!=132&&$l!=260)break;ga()}}break;default:Hl(191),Il(78),Hl(244),Il(89),Hl(279)}}function da(){ic.startNonterminal("FTStopWords",Vl);switch($l){case 82:Pl(82),Il(15),Pl(7);break;default:Pl(35),Il(17),Pl(11);for(;;){Il(105);if($l!=42)break;Pl(42),Il(17),Pl(11)}Pl(38)}ic.endNonterminal("FTStopWords",Vl)}function va(){switch($l){case 82:Hl(82),Il(15),Hl(7);break;default:Hl(35),Il(17),Hl(11);for(;;){Il(105);if($l!=42)break;Hl(42),Il(17),Hl(11)}Hl(38)}}function ma(){ic.startNonterminal("FTStopWordsInclExcl",Vl);switch($l){case 260:Pl(260);break;default:Pl(132)}Il(103),jl(),da(),ic.endNonterminal("FTStopWordsInclExcl",Vl)}function ga(){switch($l){case 260:Hl(260);break;default:Hl(132)}Il(103),va()}function ya(){ic.startNonterminal("FTLanguageOption",Vl),Pl(172),Il(17),Pl(11),ic.endNonterminal("FTLanguageOption",Vl)}function ba(){Hl(172),Il(17),Hl(11)}function wa(){ic.startNonterminal("FTWildCardOption",Vl);switch($l){case 274:Pl(274);break;default:Pl(191),Il(87),Pl(274)}ic.endNonterminal("FTWildCardOption",Vl)}function Ea(){switch($l){case 274:Hl(274);break;default:Hl(191),Il(87),Hl(274)}}function Sa(){ic.startNonterminal("FTExtensionOption",Vl),Pl(203),Il(246),jl(),$a(),Il(17),Pl(11),ic.endNonterminal("FTExtensionOption",Vl)}function xa(){Hl(203),Il(246),Ja(),Il(17),Hl(11)}function Ta(){ic.startNonterminal("FTIgnoreOption",Vl),Pl(277),Il(45),Pl(101),Il(266),jl(),Yn(),ic.endNonterminal("FTIgnoreOption",Vl)}function Na(){Hl(277),Il(45),Hl(101),Il(266),Zn()}function Ca(){ic.startNonterminal("CollectionDecl",Vl),Pl(96),Il(246),jl(),$a(),Il(111),$l==80&&(jl(),ka()),ic.endNonterminal("CollectionDecl",Vl)}function ka(){ic.startNonterminal("CollectionTypeDecl",Vl),Pl(80),Il(200),jl(),Vs(),Il(171),$l!=54&&(jl(),Os()),ic.endNonterminal("CollectionTypeDecl",Vl)}function La(){ic.startNonterminal("IndexName",Vl),$a(),ic.endNonterminal("IndexName",Vl)}function Aa(){ic.startNonterminal("IndexDomainExpr",Vl),Or(),ic.endNonterminal("IndexDomainExpr",Vl)}function Oa(){ic.startNonterminal("IndexKeySpec",Vl),Ma(),$l==80&&(jl(),_a()),Il(156),$l==95&&(jl(),Pa()),ic.endNonterminal("IndexKeySpec",Vl)}function Ma(){ic.startNonterminal("IndexKeyExpr",Vl),Or(),ic.endNonterminal("IndexKeyExpr",Vl)}function _a(){ic.startNonterminal("IndexKeyTypeDecl",Vl),Pl(80),Il(246),jl(),Da(),Il(189);if($l==40||$l==41||$l==65)jl(),Os();ic.endNonterminal("IndexKeyTypeDecl",Vl)}function Da(){ic.startNonterminal("AtomicType",Vl),$a(),ic.endNonterminal("AtomicType",Vl)}function Pa(){ic.startNonterminal("IndexKeyCollation",Vl),Pl(95),Il(15),Pl(7),ic.endNonterminal("IndexKeyCollation",Vl)}function Ha(){ic.startNonterminal("IndexDecl",Vl),Pl(157),Il(246),jl(),La(),Il(68),Pl(201),Il(66),Pl(195),Il(263),jl(),Aa(),Pl(88),Il(263),jl(),Oa();for(;;){Il(107);if($l!=42)break;Pl(42),Il(263),jl(),Oa()}ic.endNonterminal("IndexDecl",Vl)}function Ba(){ic.startNonterminal("ICDecl",Vl),Pl(163),Il(43),Pl(98),Il(246),jl(),$a(),Il(124);switch($l){case 201:jl(),ja();break;default:jl(),Ra()}ic.endNonterminal("ICDecl",Vl)}function ja(){ic.startNonterminal("ICCollection",Vl),Pl(201),Il(42),Pl(96),Il(246),jl(),$a(),Il(150);switch($l){case 31:jl(),Fa();break;case 194:jl(),Ia();break;default:jl(),qa()}ic.endNonterminal("ICCollection",Vl)}function Fa(){ic.startNonterminal("ICCollSequence",Vl),Si(),Il(40),Pl(93),Il(267),jl(),Wf(),ic.endNonterminal("ICCollSequence",Vl)}function Ia(){ic.startNonterminal("ICCollSequenceUnique",Vl),Pl(194),Il(21),jl(),Si(),Il(40),Pl(93),Il(83),Pl(261),Il(60),Pl(171),Il(263),jl(),Or(),ic.endNonterminal("ICCollSequenceUnique",Vl)}function qa(){ic.startNonterminal("ICCollNode",Vl),Pl(140),Il(65),Pl(194),Il(21),jl(),Si(),Il(40),Pl(93),Il(267),jl(),Wf(),ic.endNonterminal("ICCollNode",Vl)}function Ra(){ic.startNonterminal("ICForeignKey",Vl),Pl(141),Il(60),Pl(171),Il(54),jl(),Ua(),jl(),za(),ic.endNonterminal("ICForeignKey",Vl)}function Ua(){ic.startNonterminal("ICForeignKeySource",Vl),Pl(142),Il(42),jl(),Wa(),ic.endNonterminal("ICForeignKeySource",Vl)}function za(){ic.startNonterminal("ICForeignKeyTarget",Vl),Pl(253),Il(42),jl(),Wa(),ic.endNonterminal("ICForeignKeyTarget",Vl)}function Wa(){ic.startNonterminal("ICForeignKeyValues",Vl),Pl(96),Il(246),jl(),$a(),Il(65),Pl(194),Il(21),jl(),Si(),Il(60),Pl(171),Il(263),jl(),Or(),ic.endNonterminal("ICForeignKeyValues",Vl)}function Xa(){Hl(37);for(;;){Rl(92);if($l==51)break;switch($l){case 24:Hl(24);break;default:Xa()}}Hl(51)}function Va(){switch($l){case 22:Hl(22);break;default:Xa()}}function $a(){ic.startNonterminal("EQName",Vl),Rl(241);switch($l){case 83:Pl(83);break;case 97:Pl(97);break;case 121:Pl(121);break;case 122:Pl(122);break;case 125:Pl(125);break;case 147:Pl(147);break;case 154:Pl(154);break;case 167:Pl(167);break;case 188:Pl(188);break;case 194:Pl(194);break;case 220:Pl(220);break;case 230:Pl(230);break;case 231:Pl(231);break;case 248:Pl(248);break;case 249:Pl(249);break;case 259:Pl(259);break;case 79:Pl(79);break;case 169:Pl(169);break;case 247:Pl(247);break;default:Ka()}ic.endNonterminal("EQName",Vl)}function Ja(){Rl(241);switch($l){case 83:Hl(83);break;case 97:Hl(97);break;case 121:Hl(121);break;case 122:Hl(122);break;case 125:Hl(125);break;case 147:Hl(147);break;case 154:Hl(154);break;case 167:Hl(167);break;case 188:Hl(188);break;case 194:Hl(194);break;case 220:Hl(220);break;case 230:Hl(230);break;case 231:Hl(231);break;case 248:Hl(248);break;case 249:Hl(249);break;case 259:Hl(259);break;case 79:Hl(79);break;case 169:Hl(169);break;case 247:Hl(247);break;default:Qa()}}function Ka(){ic.startNonterminal("FunctionName",Vl);switch($l){case 6:Pl(6);break;case 71:Pl(71);break;case 74:Pl(74);break;case 75:Pl(75);break;case 76:Pl(76);break;case 80:Pl(80);break;case 81:Pl(81);break;case 85:Pl(85);break;case 89:Pl(89);break;case 90:Pl(90);break;case 91:Pl(91);break;case 94:Pl(94);break;case 95:Pl(95);break;case 104:Pl(104);break;case 106:Pl(106);break;case 109:Pl(109);break;case 110:Pl(110);break;case 111:Pl(111);break;case 112:Pl(112);break;case 113:Pl(113);break;case 114:Pl(114);break;case 119:Pl(119);break;case 120:Pl(120);break;case 123:Pl(123);break;case 124:Pl(124);break;case 127:Pl(127);break;case 129:Pl(129);break;case 130:Pl(130);break;case 132:Pl(132);break;case 136:Pl(136);break;case 137:Pl(137);break;case 138:Pl(138);break;case 139:Pl(139);break;case 148:Pl(148);break;case 150:Pl(150);break;case 152:Pl(152);break;case 153:Pl(153);break;case 155:Pl(155);break;case 161:Pl(161);break;case 162:Pl(162);break;case 164:Pl(164);break;case 165:Pl(165);break;case 166:Pl(166);break;case 173:Pl(173);break;case 175:Pl(175);break;case 177:Pl(177);break;case 181:Pl(181);break;case 183:Pl(183);break;case 184:Pl(184);break;case 185:Pl(185);break;case 187:Pl(187);break;case 189:Pl(189);break;case 202:Pl(202);break;case 204:Pl(204);break;case 205:Pl(205);break;case 206:Pl(206);break;case 210:Pl(210);break;case 216:Pl(216);break;case 217:Pl(217);break;case 222:Pl(222);break;case 223:Pl(223);break;case 224:Pl(224);break;case 228:Pl(228);break;case 234:Pl(234);break;case 240:Pl(240);break;case 241:Pl(241);break;case 242:Pl(242);break;case 253:Pl(253);break;case 254:Pl(254);break;case 256:Pl(256);break;case 260:Pl(260);break;case 262:Pl(262);break;case 266:Pl(266);break;case 272:Pl(272);break;case 276:Pl(276);break;case 170:Pl(170);break;case 73:Pl(73);break;case 82:Pl(82);break;case 84:Pl(84);break;case 86:Pl(86);break;case 87:Pl(87);break;case 92:Pl(92);break;case 99:Pl(99);break;case 102:Pl(102);break;case 103:Pl(103);break;case 105:Pl(105);break;case 107:Pl(107);break;case 126:Pl(126);break;case 133:Pl(133);break;case 134:Pl(134);break;case 143:Pl(143);break;case 156:Pl(156);break;case 157:Pl(157);break;case 163:Pl(163);break;case 174:Pl(174);break;case 195:Pl(195);break;case 203:Pl(203);break;case 207:Pl(207);break;case 226:Pl(226);break;case 229:Pl(229);break;case 232:Pl(232);break;case 239:Pl(239);break;case 245:Pl(245);break;case 257:Pl(257);break;case 258:Pl(258);break;case 263:Pl(263);break;case 267:Pl(267);break;case 268:Pl(268);break;case 269:Pl(269);break;case 273:Pl(273);break;case 98:Pl(98);break;case 179:Pl(179);break;case 225:Pl(225);break;case 78:Pl(78);break;case 135:Pl(135);break;case 142:Pl(142);break;case 197:Pl(197);break;case 168:Pl(168);break;case 198:Pl(198);break;case 233:Pl(233);break;default:Pl(255)}ic.endNonterminal("FunctionName",Vl)}function Qa(){switch($l){case 6:Hl(6);break;case 71:Hl(71);break;case 74:Hl(74);break;case 75:Hl(75);break;case 76:Hl(76);break;case 80:Hl(80);break;case 81:Hl(81);break;case 85:Hl(85);break;case 89:Hl(89);break;case 90:Hl(90);break;case 91:Hl(91);break;case 94:Hl(94);break;case 95:Hl(95);break;case 104:Hl(104);break;case 106:Hl(106);break;case 109:Hl(109);break;case 110:Hl(110);break;case 111:Hl(111);break;case 112:Hl(112);break;case 113:Hl(113);break;case 114:Hl(114);break;case 119:Hl(119);break;case 120:Hl(120);break;case 123:Hl(123);break;case 124:Hl(124);break;case 127:Hl(127);break;case 129:Hl(129);break;case 130:Hl(130);break;case 132:Hl(132);break;case 136:Hl(136);break;case 137:Hl(137);break;case 138:Hl(138);break;case 139:Hl(139);break;case 148:Hl(148);break;case 150:Hl(150);break;case 152:Hl(152);break;case 153:Hl(153);break;case 155:Hl(155);break;case 161:Hl(161);break;case 162:Hl(162);break;case 164:Hl(164);break;case 165:Hl(165);break;case 166:Hl(166);break;case 173:Hl(173);break;case 175:Hl(175);break;case 177:Hl(177);break;case 181:Hl(181);break;case 183:Hl(183);break;case 184:Hl(184);break;case 185:Hl(185);break;case 187:Hl(187);break;case 189:Hl(189);break;case 202:Hl(202);break;case 204:Hl(204);break;case 205:Hl(205);break;case 206:Hl(206);break;case 210:Hl(210);break;case 216:Hl(216);break;case 217:Hl(217);break;case 222:Hl(222);break;case 223:Hl(223);break;case 224:Hl(224);break;case 228:Hl(228);break;case 234:Hl(234);break;case 240:Hl(240);break;case 241:Hl(241);break;case 242:Hl(242);break;case 253:Hl(253);break;case 254:Hl(254);break;case 256:Hl(256);break;case 260:Hl(260);break;case 262:Hl(262);break;case 266:Hl(266);break;case 272:Hl(272);break;case 276:Hl(276);break;case 170:Hl(170);break;case 73:Hl(73);break;case 82:Hl(82);break;case 84:Hl(84);break;case 86:Hl(86);break;case 87:Hl(87);break;case 92:Hl(92);break;case 99:Hl(99);break;case 102:Hl(102);break;case 103:Hl(103);break;case 105:Hl(105);break;case 107:Hl(107);break;case 126:Hl(126);break;case 133:Hl(133);break;case 134:Hl(134);break;case 143:Hl(143);break;case 156:Hl(156);break;case 157:Hl(157);break;case 163:Hl(163);break;case 174:Hl(174);break;case 195:Hl(195);break;case 203:Hl(203);break;case 207:Hl(207);break;case 226:Hl(226);break;case 229:Hl(229);break;case 232:Hl(232);break;case 239:Hl(239);break;case 245:Hl(245);break;case 257:Hl(257);break;case 258:Hl(258);break;case 263:Hl(263);break;case 267:Hl(267);break;case 268:Hl(268);break;case 269:Hl(269);break;case 273:Hl(273);break;case 98:Hl(98);break;case 179:Hl(179);break;case 225:Hl(225);break;case 78:Hl(78);break;case 135:Hl(135);break;case 142:Hl(142);break;case 197:Hl(197);break;case 168:Hl(168);break;case 198:Hl(198);break;case 233:Hl(233);break;default:Hl(255)}}function Ga(){ic.startNonterminal("NCName",Vl);switch($l){case 19:Pl(19);break;case 71:Pl(71);break;case 76:Pl(76);break;case 80:Pl(80);break;case 81:Pl(81);break;case 85:Pl(85);break;case 89:Pl(89);break;case 90:Pl(90);break;case 91:Pl(91);break;case 95:Pl(95);break;case 106:Pl(106);break;case 110:Pl(110);break;case 114:Pl(114);break;case 119:Pl(119);break;case 123:Pl(123);break;case 124:Pl(124);break;case 127:Pl(127);break;case 129:Pl(129);break;case 132:Pl(132);break;case 139:Pl(139);break;case 148:Pl(148);break;case 150:Pl(150);break;case 152:Pl(152);break;case 153:Pl(153);break;case 162:Pl(162);break;case 164:Pl(164);break;case 165:Pl(165);break;case 166:Pl(166);break;case 175:Pl(175);break;case 177:Pl(177);break;case 181:Pl(181);break;case 183:Pl(183);break;case 184:Pl(184);break;case 189:Pl(189);break;case 202:Pl(202);break;case 204:Pl(204);break;case 205:Pl(205);break;case 224:Pl(224);break;case 228:Pl(228);break;case 241:Pl(241);break;case 242:Pl(242);break;case 253:Pl(253);break;case 254:Pl(254);break;case 260:Pl(260);break;case 272:Pl(272);break;case 276:Pl(276);break;case 74:Pl(74);break;case 75:Pl(75);break;case 83:Pl(83);break;case 94:Pl(94);break;case 97:Pl(97);break;case 104:Pl(104);break;case 109:Pl(109);break;case 111:Pl(111);break;case 112:Pl(112);break;case 113:Pl(113);break;case 120:Pl(120);break;case 121:Pl(121);break;case 122:Pl(122);break;case 125:Pl(125);break;case 130:Pl(130);break;case 136:Pl(136);break;case 137:Pl(137);break;case 138:Pl(138);break;case 147:Pl(147);break;case 154:Pl(154);break;case 155:Pl(155);break;case 161:Pl(161);break;case 167:Pl(167);break;case 173:Pl(173);break;case 185:Pl(185);break;case 187:Pl(187);break;case 188:Pl(188);break;case 194:Pl(194);break;case 206:Pl(206);break;case 210:Pl(210);break;case 216:Pl(216);break;case 217:Pl(217);break;case 220:Pl(220);break;case 222:Pl(222);break;case 223:Pl(223);break;case 230:Pl(230);break;case 231:Pl(231);break;case 234:Pl(234);break;case 240:Pl(240);break;case 248:Pl(248);break;case 249:Pl(249);break;case 256:Pl(256);break;case 259:Pl(259);break;case 262:Pl(262);break;case 266:Pl(266);break;case 268:Pl(268);break;case 170:Pl(170);break;case 73:Pl(73);break;case 82:Pl(82);break;case 84:Pl(84);break;case 86:Pl(86);break;case 87:Pl(87);break;case 92:Pl(92);break;case 99:Pl(99);break;case 102:Pl(102);break;case 103:Pl(103);break;case 105:Pl(105);break;case 107:Pl(107);break;case 126:Pl(126);break;case 133:Pl(133);break;case 134:Pl(134);break;case 143:Pl(143);break;case 156:Pl(156);break;case 157:Pl(157);break;case 163:Pl(163);break;case 174:Pl(174);break;case 195:Pl(195);break;case 203:Pl(203);break;case 207:Pl(207);break;case 226:Pl(226);break;case 229:Pl(229);break;case 232:Pl(232);break;case 239:Pl(239);break;case 245:Pl(245);break;case 257:Pl(257);break;case 258:Pl(258);break;case 263:Pl(263);break;case 267:Pl(267);break;case 269:Pl(269);break;case 273:Pl(273);break;case 98:Pl(98);break;case 179:Pl(179);break;case 225:Pl(225);break;case 78:Pl(78);break;case 135:Pl(135);break;case 142:Pl(142);break;case 197:Pl(197);break;case 168:Pl(168);break;case 198:Pl(198);break;case 233:Pl(233);break;default:Pl(255)}ic.endNonterminal("NCName",Vl)}function Ya(){switch($l){case 19:Hl(19);break;case 71:Hl(71);break;case 76:Hl(76);break;case 80:Hl(80);break;case 81:Hl(81);break;case 85:Hl(85);break;case 89:Hl(89);break;case 90:Hl(90);break;case 91:Hl(91);break;case 95:Hl(95);break;case 106:Hl(106);break;case 110:Hl(110);break;case 114:Hl(114);break;case 119:Hl(119);break;case 123:Hl(123);break;case 124:Hl(124);break;case 127:Hl(127);break;case 129:Hl(129);break;case 132:Hl(132);break;case 139:Hl(139);break;case 148:Hl(148);break;case 150:Hl(150);break;case 152:Hl(152);break;case 153:Hl(153);break;case 162:Hl(162);break;case 164:Hl(164);break;case 165:Hl(165);break;case 166:Hl(166);break;case 175:Hl(175);break;case 177:Hl(177);break;case 181:Hl(181);break;case 183:Hl(183);break;case 184:Hl(184);break;case 189:Hl(189);break;case 202:Hl(202);break;case 204:Hl(204);break;case 205:Hl(205);break;case 224:Hl(224);break;case 228:Hl(228);break;case 241:Hl(241);break;case 242:Hl(242);break;case 253:Hl(253);break;case 254:Hl(254);break;case 260:Hl(260);break;case 272:Hl(272);break;case 276:Hl(276);break;case 74:Hl(74);break;case 75:Hl(75);break;case 83:Hl(83);break;case 94:Hl(94);break;case 97:Hl(97);break;case 104:Hl(104);break;case 109:Hl(109);break;case 111:Hl(111);break;case 112:Hl(112);break;case 113:Hl(113);break;case 120:Hl(120);break;case 121:Hl(121);break;case 122:Hl(122);break;case 125:Hl(125);break;case 130:Hl(130);break;case 136:Hl(136);break;case 137:Hl(137);break;case 138:Hl(138);break;case 147:Hl(147);break;case 154:Hl(154);break;case 155:Hl(155);break;case 161:Hl(161);break;case 167:Hl(167);break;case 173:Hl(173);break;case 185:Hl(185);break;case 187:Hl(187);break;case 188:Hl(188);break;case 194:Hl(194);break;case 206:Hl(206);break;case 210:Hl(210);break;case 216:Hl(216);break;case 217:Hl(217);break;case 220:Hl(220);break;case 222:Hl(222);break;case 223:Hl(223);break;case 230:Hl(230);break;case 231:Hl(231);break;case 234:Hl(234);break;case 240:Hl(240);break;case 248:Hl(248);break;case 249:Hl(249);break;case 256:Hl(256);break;case 259:Hl(259);break;case 262:Hl(262);break;case 266:Hl(266);break;case 268:Hl(268);break;case 170:Hl(170);break;case 73:Hl(73);break;case 82:Hl(82);break;case 84:Hl(84);break;case 86:Hl(86);break;case 87:Hl(87);break;case 92:Hl(92);break;case 99:Hl(99);break;case 102:Hl(102);break;case 103:Hl(103);break;case 105:Hl(105);break;case 107:Hl(107);break;case 126:Hl(126);break;case 133:Hl(133);break;case 134:Hl(134);break;case 143:Hl(143);break;case 156:Hl(156);break;case 157:Hl(157);break;case 163:Hl(163);break;case 174:Hl(174);break;case 195:Hl(195);break;case 203:Hl(203);break;case 207:Hl(207);break;case 226:Hl(226);break;case 229:Hl(229);break;case 232:Hl(232);break;case 239:Hl(239);break;case 245:Hl(245);break;case 257:Hl(257);break;case 258:Hl(258);break;case 263:Hl(263);break;case 267:Hl(267);break;case 269:Hl(269);break;case 273:Hl(273);break;case 98:Hl(98);break;case 179:Hl(179);break;case 225:Hl(225);break;case 78:Hl(78);break;case 135:Hl(135);break;case 142:Hl(142);break;case 197:Hl(197);break;case 168:Hl(168);break;case 198:Hl(198);break;case 233:Hl(233);break;default:Hl(255)}}function Za(){ic.startNonterminal("MainModule",Vl),l(),jl(),ef(),ic.endNonterminal("MainModule",Vl)}function ef(){ic.startNonterminal("Program",Vl),of(),ic.endNonterminal("Program",Vl)}function tf(){ic.startNonterminal("Statements",Vl);for(;;){Il(284);switch($l){case 35:ql(270);break;case 36:Ul(243);break;case 47:ql(286);break;case 48:ql(260);break;case 55:Ul(4);break;case 56:Ul(1);break;case 60:Ul(3);break;case 69:ql(273);break;case 78:ql(269);break;case 133:ql(147);break;case 139:ql(179);break;case 161:ql(276);break;case 177:ql(166);break;case 187:ql(247);break;case 220:ql(245);break;case 223:ql(170);break;case 266:ql(188);break;case 281:ql(283);break;case 283:ql(274);break;case 31:case 33:ql(246);break;case 83:case 122:ql(253);break;case 87:case 103:ql(145);break;case 97:case 249:ql(97);break;case 111:case 222:ql(261);break;case 41:case 43:case 196:ql(266);break;case 135:case 197:case 255:ql(211);break;case 104:case 130:case 240:case 268:ql(143);break;case 120:case 206:case 256:case 262:ql(148);break;case 8:case 9:case 10:case 11:case 32:ql(210);break;case 79:case 121:case 125:case 167:case 169:case 188:case 194:case 230:case 231:case 247:ql(20);break;case 6:case 71:case 73:case 74:case 75:case 76:case 80:case 81:case 82:case 84:case 85:case 86:case 89:case 90:case 91:case 92:case 94:case 95:case 98:case 99:case 102:case 105:case 106:case 107:case 109:case 110:case 112:case 113:case 114:case 119:case 123:case 124:case 126:case 127:case 129:case 132:case 134:case 136:case 137:case 138:case 142:case 143:case 147:case 148:case 150:case 152:case 153:case 154:case 155:case 156:case 157:case 162:case 163:case 164:case 165:case 166:case 168:case 170:case 173:case 174:case 175:case 179:case 181:case 183:case 184:case 185:case 189:case 195:case 198:case 202:case 203:case 204:case 205:case 207:case 210:case 216:case 217:case 224:case 225:case 226:case 228:case 229:case 232:case 233:case 234:case 239:case 241:case 242:case 245:case 248:case 253:case 254:case 257:case 258:case 259:case 260:case 263:case 267:case 269:case 272:case 273:case 276:ql(95);break;default:Wl=$l}if(Wl!=25&&Wl!=54&&Wl!=287&&Wl!=12808&&Wl!=12809&&Wl!=12810&&Wl!=12811&&Wl!=12832&&Wl!=12847&&Wl!=12935&&Wl!=12997&&Wl!=13055&&Wl!=16140&&Wl!=21512&&Wl!=21513&&Wl!=21514&&Wl!=21515&&Wl!=21536&&Wl!=21551&&Wl!=21639&&Wl!=21701&&Wl!=21759&&Wl!=27656&&Wl!=27657&&Wl!=27658&&Wl!=27659&&Wl!=27680&&Wl!=27695&&Wl!=27783&&Wl!=27845&&Wl!=27903&&Wl!=91735&&Wl!=91751&&Wl!=115333&&Wl!=146952&&Wl!=146953&&Wl!=146954&&Wl!=146955&&Wl!=146976&&Wl!=146991&&Wl!=147079&&Wl!=147141&&Wl!=147199){Wl=uc(8,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{ff(),Wl=-1}catch(a){Wl=-2}Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(8,Vl,Wl)}}if(Wl!=-1&&Wl!=54&&Wl!=16140&&Wl!=27656&&Wl!=27657&&Wl!=27658&&Wl!=27659&&Wl!=27680&&Wl!=27695&&Wl!=27783&&Wl!=27845&&Wl!=27903&&Wl!=91735&&Wl!=91751&&Wl!=115333)break;jl(),af()}ic.endNonterminal("Statements",Vl)}function nf(){for(;;){Il(284);switch($l){case 35:ql(270);break;case 36:Ul(243);break;case 47:ql(286);break;case 48:ql(260);break;case 55:Ul(4);break;case 56:Ul(1);break;case 60:Ul(3);break;case 69:ql(273);break;case 78:ql(269);break;case 133:ql(147);break;case 139:ql(179);break;case 161:ql(276);break;case 177:ql(166);break;case 187:ql(247);break;case 220:ql(245);break;case 223:ql(170);break;case 266:ql(188);break;case 281:ql(283);break;case 283:ql(274);break;case 31:case 33:ql(246);break;case 83:case 122:ql(253);break;case 87:case 103:ql(145);break;case 97:case 249:ql(97);break;case 111:case 222:ql(261);break;case 41:case 43:case 196:ql(266);break;case 135:case 197:case 255:ql(211);break;case 104:case 130:case 240:case 268:ql(143);break;case 120:case 206:case 256:case 262:ql(148);break;case 8:case 9:case 10:case 11:case 32:ql(210);break;case 79:case 121:case 125:case 167:case 169:case 188:case 194:case 230:case 231:case 247:ql(20);break;case 6:case 71:case 73:case 74:case 75:case 76:case 80:case 81:case 82:case 84:case 85:case 86:case 89:case 90:case 91:case 92:case 94:case 95:case 98:case 99:case 102:case 105:case 106:case 107:case 109:case 110:case 112:case 113:case 114:case 119:case 123:case 124:case 126:case 127:case 129:case 132:case 134:case 136:case 137:case 138:case 142:case 143:case 147:case 148:case 150:case 152:case 153:case 154:case 155:case 156:case 157:case 162:case 163:case 164:case 165:case 166:case 168:case 170:case 173:case 174:case 175:case 179:case 181:case 183:case 184:case 185:case 189:case 195:case 198:case 202:case 203:case 204:case 205:case 207:case 210:case 216:case 217:case 224:case 225:case 226:case 228:case 229:case 232:case 233:case 234:case 239:case 241:case 242:case 245:case 248:case 253:case 254:case 257:case 258:case 259:case 260:case 263:case 267:case 269:case 272:case 273:case 276:ql(95);break;default:Wl=$l}if(Wl!=25&&Wl!=54&&Wl!=287&&Wl!=12808&&Wl!=12809&&Wl!=12810&&Wl!=12811&&Wl!=12832&&Wl!=12847&&Wl!=12935&&Wl!=12997&&Wl!=13055&&Wl!=16140&&Wl!=21512&&Wl!=21513&&Wl!=21514&&Wl!=21515&&Wl!=21536&&Wl!=21551&&Wl!=21639&&Wl!=21701&&Wl!=21759&&Wl!=27656&&Wl!=27657&&Wl!=27658&&Wl!=27659&&Wl!=27680&&Wl!=27695&&Wl!=27783&&Wl!=27845&&Wl!=27903&&Wl!=91735&&Wl!=91751&&Wl!=115333&&Wl!=146952&&Wl!=146953&&Wl!=146954&&Wl!=146955&&Wl!=146976&&Wl!=146991&&Wl!=147079&&Wl!=147141&&Wl!=147199){Wl=uc(8,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{ff(),oc(8,t,-1);continue}catch(a){Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(8,t,-2);break}}}if(Wl!=-1&&Wl!=54&&Wl!=16140&&Wl!=27656&&Wl!=27657&&Wl!=27658&&Wl!=27659&&Wl!=27680&&Wl!=27695&&Wl!=27783&&Wl!=27845&&Wl!=27903&&Wl!=91735&&Wl!=91751&&Wl!=115333)break;ff()}}function rf(){ic.startNonterminal("StatementsAndExpr",Vl),tf(),jl(),G(),ic.endNonterminal("StatementsAndExpr",Vl)}function sf(){nf(),Y()}function of(){ic.startNonterminal("StatementsAndOptionalExpr",Vl),tf(),$l!=25&&$l!=287&&(jl(),G()),ic.endNonterminal("StatementsAndOptionalExpr",Vl)}function uf(){nf(),$l!=25&&$l!=287&&Y()}function af(){ic.startNonterminal("Statement",Vl);switch($l){case 133:ql(147);break;case 139:ql(179);break;case 177:ql(166);break;case 256:ql(148);break;case 268:ql(143);break;case 281:ql(283);break;case 31:case 33:ql(246);break;case 87:case 103:ql(145);break;case 154:case 248:case 259:case 273:ql(95);break;default:Wl=$l}if(Wl!=6&&Wl!=8&&Wl!=9&&Wl!=10&&Wl!=11&&Wl!=32&&Wl!=35&&Wl!=36&&Wl!=41&&Wl!=43&&Wl!=47&&Wl!=48&&Wl!=54&&Wl!=55&&Wl!=56&&Wl!=60&&Wl!=69&&Wl!=71&&Wl!=73&&Wl!=74&&Wl!=75&&Wl!=76&&Wl!=78&&Wl!=79&&Wl!=80&&Wl!=81&&Wl!=82&&Wl!=83&&Wl!=84&&Wl!=85&&Wl!=86&&Wl!=89&&Wl!=90&&Wl!=91&&Wl!=92&&Wl!=94&&Wl!=95&&Wl!=97&&Wl!=98&&Wl!=99&&Wl!=102&&Wl!=104&&Wl!=105&&Wl!=106&&Wl!=107&&Wl!=109&&Wl!=110&&Wl!=111&&Wl!=112&&Wl!=113&&Wl!=114&&Wl!=119&&Wl!=120&&Wl!=121&&Wl!=122&&Wl!=123&&Wl!=124&&Wl!=125&&Wl!=126&&Wl!=127&&Wl!=129&&Wl!=130&&Wl!=132&&Wl!=134&&Wl!=135&&Wl!=136&&Wl!=137&&Wl!=138&&Wl!=142&&Wl!=143&&Wl!=147&&Wl!=148&&Wl!=150&&Wl!=152&&Wl!=153&&Wl!=155&&Wl!=156&&Wl!=157&&Wl!=161&&Wl!=162&&Wl!=163&&Wl!=164&&Wl!=165&&Wl!=166&&Wl!=167&&Wl!=168&&Wl!=169&&Wl!=170&&Wl!=173&&Wl!=174&&Wl!=175&&Wl!=179&&Wl!=181&&Wl!=183&&Wl!=184&&Wl!=185&&Wl!=187&&Wl!=188&&Wl!=189&&Wl!=194&&Wl!=195&&Wl!=196&&Wl!=197&&Wl!=198&&Wl!=202&&Wl!=203&&Wl!=204&&Wl!=205&&Wl!=206&&Wl!=207&&Wl!=210&&Wl!=216&&Wl!=217&&Wl!=220&&Wl!=222&&Wl!=223&&Wl!=224&&Wl!=225&&Wl!=226&&Wl!=228&&Wl!=229&&Wl!=230&&Wl!=231&&Wl!=232&&Wl!=233&&Wl!=234&&Wl!=239&&Wl!=240&&Wl!=241&&Wl!=242&&Wl!=245&&Wl!=247&&Wl!=249&&Wl!=253&&Wl!=254&&Wl!=255&&Wl!=257&&Wl!=258&&Wl!=260&&Wl!=262&&Wl!=263&&Wl!=266&&Wl!=267&&Wl!=269&&Wl!=272&&Wl!=276&&Wl!=283&&Wl!=10009&&Wl!=14935&&Wl!=14951&&Wl!=14981&&Wl!=14987&&Wl!=15002&&Wl!=15025&&Wl!=15096&&Wl!=15104&&Wl!=15107&&Wl!=15116&&Wl!=15121&&Wl!=16011&&Wl!=16049&&Wl!=16140&&Wl!=18007&&Wl!=18023&&Wl!=18053&&Wl!=18059&&Wl!=18074&&Wl!=18097&&Wl!=18168&&Wl!=18176&&Wl!=18179&&Wl!=18188&&Wl!=91735&&Wl!=91751&&Wl!=115333&&Wl!=118961&&Wl!=122507&&Wl!=131723&&Wl!=144128&&Wl!=147225){Wl=uc(9,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{cf(),Wl=-1}catch(a){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),pf(),Wl=-2}catch(f){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),vf(),Wl=-3}catch(l){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),If(),Wl=-12}catch(c){Wl=-13}}}}Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(9,Vl,Wl)}}switch(Wl){case-2:hf();break;case-3:df();break;case 91735:mf();break;case 91751:yf();break;case 115333:wf();break;case 16011:case 16049:case 118961:case 122507:case 131723:Sf();break;case 18074:Cf();break;case 18168:Lf();break;case 144128:_f();break;case 18179:Pf();break;case-12:case 16140:Ff();break;case-13:qf();break;case 54:Uf();break;default:lf()}ic.endNonterminal("Statement",Vl)}function ff(){switch($l){case 133:ql(147);break;case 139:ql(179);break;case 177:ql(166);break;case 256:ql(148);break;case 268:ql(143);break;case 281:ql(283);break;case 31:case 33:ql(246);break;case 87:case 103:ql(145);break;case 154:case 248:case 259:case 273:ql(95);break;default:Wl=$l}if(Wl!=6&&Wl!=8&&Wl!=9&&Wl!=10&&Wl!=11&&Wl!=32&&Wl!=35&&Wl!=36&&Wl!=41&&Wl!=43&&Wl!=47&&Wl!=48&&Wl!=54&&Wl!=55&&Wl!=56&&Wl!=60&&Wl!=69&&Wl!=71&&Wl!=73&&Wl!=74&&Wl!=75&&Wl!=76&&Wl!=78&&Wl!=79&&Wl!=80&&Wl!=81&&Wl!=82&&Wl!=83&&Wl!=84&&Wl!=85&&Wl!=86&&Wl!=89&&Wl!=90&&Wl!=91&&Wl!=92&&Wl!=94&&Wl!=95&&Wl!=97&&Wl!=98&&Wl!=99&&Wl!=102&&Wl!=104&&Wl!=105&&Wl!=106&&Wl!=107&&Wl!=109&&Wl!=110&&Wl!=111&&Wl!=112&&Wl!=113&&Wl!=114&&Wl!=119&&Wl!=120&&Wl!=121&&Wl!=122&&Wl!=123&&Wl!=124&&Wl!=125&&Wl!=126&&Wl!=127&&Wl!=129&&Wl!=130&&Wl!=132&&Wl!=134&&Wl!=135&&Wl!=136&&Wl!=137&&Wl!=138&&Wl!=142&&Wl!=143&&Wl!=147&&Wl!=148&&Wl!=150&&Wl!=152&&Wl!=153&&Wl!=155&&Wl!=156&&Wl!=157&&Wl!=161&&Wl!=162&&Wl!=163&&Wl!=164&&Wl!=165&&Wl!=166&&Wl!=167&&Wl!=168&&Wl!=169&&Wl!=170&&Wl!=173&&Wl!=174&&Wl!=175&&Wl!=179&&Wl!=181&&Wl!=183&&Wl!=184&&Wl!=185&&Wl!=187&&Wl!=188&&Wl!=189&&Wl!=194&&Wl!=195&&Wl!=196&&Wl!=197&&Wl!=198&&Wl!=202&&Wl!=203&&Wl!=204&&Wl!=205&&Wl!=206&&Wl!=207&&Wl!=210&&Wl!=216&&Wl!=217&&Wl!=220&&Wl!=222&&Wl!=223&&Wl!=224&&Wl!=225&&Wl!=226&&Wl!=228&&Wl!=229&&Wl!=230&&Wl!=231&&Wl!=232&&Wl!=233&&Wl!=234&&Wl!=239&&Wl!=240&&Wl!=241&&Wl!=242&&Wl!=245&&Wl!=247&&Wl!=249&&Wl!=253&&Wl!=254&&Wl!=255&&Wl!=257&&Wl!=258&&Wl!=260&&Wl!=262&&Wl!=263&&Wl!=266&&Wl!=267&&Wl!=269&&Wl!=272&&Wl!=276&&Wl!=283&&Wl!=10009&&Wl!=14935&&Wl!=14951&&Wl!=14981&&Wl!=14987&&Wl!=15002&&Wl!=15025&&Wl!=15096&&Wl!=15104&&Wl!=15107&&Wl!=15116&&Wl!=15121&&Wl!=16011&&Wl!=16049&&Wl!=16140&&Wl!=18007&&Wl!=18023&&Wl!=18053&&Wl!=18059&&Wl!=18074&&Wl!=18097&&Wl!=18168&&Wl!=18176&&Wl!=18179&&Wl!=18188&&Wl!=91735&&Wl!=91751&&Wl!=115333&&Wl!=118961&&Wl!=122507&&Wl!=131723&&Wl!=144128&&Wl!=147225){Wl=uc(9,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{cf(),oc(9,t,-1),Wl=-15}catch(a){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),pf(),oc(9,t,-2),Wl=-15}catch(f){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),vf(),oc(9,t,-3),Wl=-15}catch(l){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),If(),oc(9,t,-12),Wl=-15}catch(c){Wl=-13,Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(9,t,-13)}}}}}}switch(Wl){case-2:pf();break;case-3:vf();break;case 91735:gf();break;case 91751:bf();break;case 115333:Ef();break;case 16011:case 16049:case 118961:case 122507:case 131723:xf();break;case 18074:kf();break;case 18168:Af();break;case 144128:Df();break;case 18179:Hf();break;case-12:case 16140:If();break;case-13:Rf();break;case 54:zf();break;case-15:break;default:cf()}}function lf(){ic.startNonterminal("ApplyStatement",Vl),Vf(),Pl(54),ic.endNonterminal("ApplyStatement",Vl)}function cf(){$f(),Hl(54)}function hf(){ic.startNonterminal("AssignStatement",Vl),Pl(31),Il(246),jl(),Ti(),Il(28),Pl(53),Il(267),jl(),Wf(),Pl(54),ic.endNonterminal("AssignStatement",Vl)}function pf(){Hl(31),Il(246),Ni(),Il(28),Hl(53),Il(267),Xf(),Hl(54)}function df(){ic.startNonterminal("BlockStatement",Vl),Pl(281),Il(271),jl(),af(),Il(281),jl(),tf(),Pl(287),ic.endNonterminal("BlockStatement",Vl)}function vf(){Hl(281),Il(271),ff(),Il(281),nf(),Hl(287)}function mf(){ic.startNonterminal("BreakStatement",Vl),Pl(87),Il(62),Pl(179),Il(29),Pl(54),ic.endNonterminal("BreakStatement",Vl)}function gf(){Hl(87),Il(62),Hl(179),Il(29),Hl(54)}function yf(){ic.startNonterminal("ContinueStatement",Vl),Pl(103),Il(62),Pl(179),Il(29),Pl(54),ic.endNonterminal("ContinueStatement",Vl)}function bf(){Hl(103),Il(62),Hl(179),Il(29),Hl(54)}function wf(){ic.startNonterminal("ExitStatement",Vl),Pl(133),Il(74),Pl(225),Il(267),jl(),Wf(),Pl(54),ic.endNonterminal("ExitStatement",Vl)}function Ef(){Hl(133),Il(74),Hl(225),Il(267),Xf(),Hl(54)}function Sf(){ic.startNonterminal("FLWORStatement",Vl),tt();for(;;){Il(195);if($l==224)break;jl(),rt()}jl(),Tf(),ic.endNonterminal("FLWORStatement",Vl)}function xf(){nt();for(;;){Il(195);if($l==224)break;it()}Nf()}function Tf(){ic.startNonterminal("ReturnStatement",Vl),Pl(224),Il(271),jl(),af(),ic.endNonterminal("ReturnStatement",Vl)}function Nf(){Hl(224),Il(271),ff()}function Cf(){ic.startNonterminal("IfStatement",Vl),Pl(154),Il(22),Pl(35),Il(267),jl(),G(),Pl(38),Il(80),Pl(250),Il(271),jl(),af(),Il(51),Pl(123),Il(271),jl(),af(),ic.endNonterminal("IfStatement",Vl)}function kf(){Hl(154),Il(22),Hl(35),Il(267),Y(),Hl(38),Il(80),Hl(250),Il(271),ff(),Il(51),Hl(123),Il(271),ff()}function Lf(){ic.startNonterminal("SwitchStatement",Vl),Pl(248),Il(22),Pl(35),Il(267),jl(),G(),Pl(38);for(;;){Il(38),jl(),Of(),Il(117);if($l!=89)break}Pl(110),Il(73),Pl(224),Il(271),jl(),af(),ic.endNonterminal("SwitchStatement",Vl)}function Af(){Hl(248),Il(22),Hl(35),Il(267),Y(),Hl(38);for(;;){Il(38),Mf(),Il(117);if($l!=89)break}Hl(110),Il(73),Hl(224),Il(271),ff()}function Of(){ic.startNonterminal("SwitchCaseStatement",Vl);for(;;){Pl(89),Il(267),jl(),dn();if($l!=89)break}Pl(224),Il(271),jl(),af(),ic.endNonterminal("SwitchCaseStatement",Vl)}function Mf(){for(;;){Hl(89),Il(267),vn();if($l!=89)break}Hl(224),Il(271),ff()}function _f(){ic.startNonterminal("TryCatchStatement",Vl),Pl(256),Il(90),jl(),df();for(;;){Il(39),Pl(92),Il(249),jl(),_n(),jl(),df(),Il(284);switch($l){case 92:ql(256);break;default:Wl=$l}if(Wl!=2652&&Wl!=3164&&Wl!=36444&&Wl!=37468&&Wl!=37980&&Wl!=38492&&Wl!=39004&&Wl!=40028&&Wl!=40540&&Wl!=41052&&Wl!=41564&&Wl!=42076&&Wl!=42588&&Wl!=43100&&Wl!=43612&&Wl!=44124&&Wl!=44636&&Wl!=45660&&Wl!=46172&&Wl!=46684&&Wl!=47196&&Wl!=48220&&Wl!=48732&&Wl!=49756&&Wl!=50268&&Wl!=50780&&Wl!=52316&&Wl!=52828&&Wl!=53340&&Wl!=53852&&Wl!=54364&&Wl!=54876&&Wl!=55900&&Wl!=56412&&Wl!=56924&&Wl!=57436&&Wl!=57948&&Wl!=58460&&Wl!=61020&&Wl!=61532&&Wl!=62044&&Wl!=62556&&Wl!=63068&&Wl!=63580&&Wl!=64092&&Wl!=64604&&Wl!=65116&&Wl!=66140&&Wl!=66652&&Wl!=67676&&Wl!=68188&&Wl!=68700&&Wl!=69212&&Wl!=69724&&Wl!=70236&&Wl!=70748&&Wl!=71260&&Wl!=72796&&Wl!=73308&&Wl!=75356&&Wl!=75868&&Wl!=76892&&Wl!=77916&&Wl!=78428&&Wl!=78940&&Wl!=79452&&Wl!=79964&&Wl!=80476&&Wl!=82524&&Wl!=83036&&Wl!=83548&&Wl!=84060&&Wl!=84572&&Wl!=85084&&Wl!=85596&&Wl!=86108&&Wl!=86620&&Wl!=87132&&Wl!=88668&&Wl!=89180&&Wl!=89692&&Wl!=90716&&Wl!=91740&&Wl!=92764&&Wl!=93788&&Wl!=94300&&Wl!=94812&&Wl!=95836&&Wl!=96348&&Wl!=96860&&Wl!=99420&&Wl!=99932&&Wl!=100956&&Wl!=101468&&Wl!=103516&&Wl!=104028&&Wl!=104540&&Wl!=105052&&Wl!=105564&&Wl!=106076&&Wl!=107612&&Wl!=110684&&Wl!=111196&&Wl!=112732&&Wl!=113756&&Wl!=114268&&Wl!=114780&&Wl!=115292&&Wl!=115804&&Wl!=116828&&Wl!=117340&&Wl!=117852&&Wl!=118364&&Wl!=118876&&Wl!=119388&&Wl!=119900&&Wl!=122460&&Wl!=122972&&Wl!=123484&&Wl!=123996&&Wl!=125532&&Wl!=126556&&Wl!=127068&&Wl!=127580&&Wl!=129628&&Wl!=130140&&Wl!=130652&&Wl!=131164&&Wl!=131676&&Wl!=132188&&Wl!=132700&&Wl!=133212&&Wl!=134236&&Wl!=134748&&Wl!=136284&&Wl!=136796&&Wl!=137308&&Wl!=137820&&Wl!=139356&&Wl!=139868&&Wl!=141404)break}ic.endNonterminal("TryCatchStatement",Vl)}function Df(){Hl(256),Il(90),vf();for(;;){Il(39),Hl(92),Il(249),Dn(),vf(),Il(284);switch($l){case 92:ql(256);break;default:Wl=$l}if(Wl!=2652&&Wl!=3164&&Wl!=36444&&Wl!=37468&&Wl!=37980&&Wl!=38492&&Wl!=39004&&Wl!=40028&&Wl!=40540&&Wl!=41052&&Wl!=41564&&Wl!=42076&&Wl!=42588&&Wl!=43100&&Wl!=43612&&Wl!=44124&&Wl!=44636&&Wl!=45660&&Wl!=46172&&Wl!=46684&&Wl!=47196&&Wl!=48220&&Wl!=48732&&Wl!=49756&&Wl!=50268&&Wl!=50780&&Wl!=52316&&Wl!=52828&&Wl!=53340&&Wl!=53852&&Wl!=54364&&Wl!=54876&&Wl!=55900&&Wl!=56412&&Wl!=56924&&Wl!=57436&&Wl!=57948&&Wl!=58460&&Wl!=61020&&Wl!=61532&&Wl!=62044&&Wl!=62556&&Wl!=63068&&Wl!=63580&&Wl!=64092&&Wl!=64604&&Wl!=65116&&Wl!=66140&&Wl!=66652&&Wl!=67676&&Wl!=68188&&Wl!=68700&&Wl!=69212&&Wl!=69724&&Wl!=70236&&Wl!=70748&&Wl!=71260&&Wl!=72796&&Wl!=73308&&Wl!=75356&&Wl!=75868&&Wl!=76892&&Wl!=77916&&Wl!=78428&&Wl!=78940&&Wl!=79452&&Wl!=79964&&Wl!=80476&&Wl!=82524&&Wl!=83036&&Wl!=83548&&Wl!=84060&&Wl!=84572&&Wl!=85084&&Wl!=85596&&Wl!=86108&&Wl!=86620&&Wl!=87132&&Wl!=88668&&Wl!=89180&&Wl!=89692&&Wl!=90716&&Wl!=91740&&Wl!=92764&&Wl!=93788&&Wl!=94300&&Wl!=94812&&Wl!=95836&&Wl!=96348&&Wl!=96860&&Wl!=99420&&Wl!=99932&&Wl!=100956&&Wl!=101468&&Wl!=103516&&Wl!=104028&&Wl!=104540&&Wl!=105052&&Wl!=105564&&Wl!=106076&&Wl!=107612&&Wl!=110684&&Wl!=111196&&Wl!=112732&&Wl!=113756&&Wl!=114268&&Wl!=114780&&Wl!=115292&&Wl!=115804&&Wl!=116828&&Wl!=117340&&Wl!=117852&&Wl!=118364&&Wl!=118876&&Wl!=119388&&Wl!=119900&&Wl!=122460&&Wl!=122972&&Wl!=123484&&Wl!=123996&&Wl!=125532&&Wl!=126556&&Wl!=127068&&Wl!=127580&&Wl!=129628&&Wl!=130140&&Wl!=130652&&Wl!=131164&&Wl!=131676&&Wl!=132188&&Wl!=132700&&Wl!=133212&&Wl!=134236&&Wl!=134748&&Wl!=136284&&Wl!=136796&&Wl!=137308&&Wl!=137820&&Wl!=139356&&Wl!=139868&&Wl!=141404)break}}function Pf(){ic.startNonterminal("TypeswitchStatement",Vl),Pl(259),Il(22),Pl(35),Il(267),jl(),G(),Pl(38);for(;;){Il(38),jl(),Bf(),Il(117);if($l!=89)break}Pl(110),Il(99),$l==31&&(Pl(31),Il(246),jl(),Ti()),Il(73),Pl(224),Il(271),jl(),af(),ic.endNonterminal("TypeswitchStatement",Vl)}function Hf(){Hl(259),Il(22),Hl(35),Il(267),Y(),Hl(38);for(;;){Il(38),jf(),Il(117);if($l!=89)break}Hl(110),Il(99),$l==31&&(Hl(31),Il(246),Ni()),Il(73),Hl(224),Il(271),ff()}function Bf(){ic.startNonterminal("CaseStatement",Vl),Pl(89),Il(258),$l==31&&(Pl(31),Il(246),jl(),Ti(),Il(33),Pl(80)),Il(254),jl(),Ls(),Il(73),Pl(224),Il(271),jl(),af(),ic.endNonterminal("CaseStatement",Vl)}function jf(){Hl(89),Il(258),$l==31&&(Hl(31),Il(246),Ni(),Il(33),Hl(80)),Il(254),As(),Il(73),Hl(224),Il(271),ff()}function Ff(){ic.startNonterminal("VarDeclStatement",Vl);for(;;){Il(102);if($l!=33)break;jl(),B()}Pl(268),Il(21),Pl(31),Il(246),jl(),Ti(),Il(172),$l==80&&(jl(),Cs()),Il(155),$l==53&&(Pl(53),Il(267),jl(),Wf());for(;;){if($l!=42)break;Pl(42),Il(21),Pl(31),Il(246),jl(),Ti(),Il(172),$l==80&&(jl(),Cs()),Il(155),$l==53&&(Pl(53),Il(267),jl(),Wf())}Pl(54),ic.endNonterminal("VarDeclStatement",Vl)}function If(){for(;;){Il(102);if($l!=33)break;j()}Hl(268),Il(21),Hl(31),Il(246),Ni(),Il(172),$l==80&&ks(),Il(155),$l==53&&(Hl(53),Il(267),Xf());for(;;){if($l!=42)break;Hl(42),Il(21),Hl(31),Il(246),Ni(),Il(172),$l==80&&ks(),Il(155),$l==53&&(Hl(53),Il(267),Xf())}Hl(54)}function qf(){ic.startNonterminal("WhileStatement",Vl),Pl(273),Il(22),Pl(35),Il(267),jl(),G(),Pl(38),Il(271),jl(),af(),ic.endNonterminal("WhileStatement",Vl)}function Rf(){Hl(273),Il(22),Hl(35),Il(267),Y(),Hl(38),Il(271),ff()}function Uf(){ic.startNonterminal("VoidStatement",Vl),Pl(54),ic.endNonterminal("VoidStatement",Vl)}function zf(){Hl(54)}function Wf(){ic.startNonterminal("ExprSingle",Vl);switch($l){case 139:ql(179);break;case 177:ql(166);break;case 256:ql(148);break;case 154:case 248:case 259:ql(95);break;default:Wl=$l}switch(Wl){case 16011:case 16049:case 118961:case 122507:case 131723:Z();break;case 18074:Sn();break;case 18168:ln();break;case 144128:Tn();break;case 18179:mn();break;default:Vf()}ic.endNonterminal("ExprSingle",Vl)}function Xf(){switch($l){case 139:ql(179);break;case 177:ql(166);break;case 256:ql(148);break;case 154:case 248:case 259:ql(95);break;default:Wl=$l}switch(Wl){case 16011:case 16049:case 118961:case 122507:case 131723:et();break;case 18074:xn();break;case 18168:cn();break;case 144128:Nn();break;case 18179:gn();break;default:$f()}}function Vf(){ic.startNonterminal("ExprSimple",Vl);switch($l){case 78:ql(269);break;case 161:ql(276);break;case 223:ql(170);break;case 111:case 222:ql(261);break;case 104:case 130:case 240:ql(143);break;default:Wl=$l}if(Wl==17998||Wl==18031||Wl==18081||Wl==18142||Wl==99439||Wl==99489||Wl==99550||Wl==99951||Wl==100001||Wl==136927){Wl=uc(10,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Hn(),Wl=-2}catch(a){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),zo(),Wl=-3}catch(f){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),Xo(),Wl=-4}catch(l){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),Ko(),Wl=-5}catch(c){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),$o(),Wl=-6}catch(h){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),Kf(),Wl=-8}catch(p){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),Gf(),Wl=-9}catch(d){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),Zf(),Wl=-10}catch(v){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),tl(),Wl=-11}catch(m){Wl=-12}}}}}}}}}Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(10,Vl,Wl)}}switch(Wl){case 16002:case 16112:on();break;case-3:Uo();break;case-4:Wo();break;case-5:Jo();break;case-6:case 99551:Vo();break;case 15976:nu();break;case-8:case 3183:case 4207:case 4719:case 5231:case 5743:case 15983:case 16495:case 17007:case 28271:case 28783:case 30831:case 35439:case 36463:case 37487:case 37999:case 38511:case 39023:case 40047:case 40559:case 41071:case 41583:case 42095:case 42607:case 43119:case 43631:case 44143:case 44655:case 45679:case 46191:case 46703:case 47215:case 48239:case 48751:case 49775:case 50287:case 50799:case 52335:case 52847:case 53359:case 53871:case 54383:case 54895:case 55919:case 56431:case 56943:case 57455:case 57967:case 58479:case 61039:case 61551:case 62063:case 62575:case 63087:case 63599:case 64111:case 64623:case 65135:case 66159:case 66671:case 67695:case 68207:case 68719:case 69231:case 69743:case 70255:case 70767:case 71279:case 72815:case 73327:case 75375:case 75887:case 76911:case 77935:case 78447:case 78959:case 79471:case 79983:case 80495:case 82543:case 83055:case 83567:case 84079:case 84591:case 85103:case 85615:case 86127:case 86639:case 87151:case 88687:case 89199:case 89711:case 90735:case 91759:case 92783:case 93807:case 94319:case 94831:case 95855:case 96367:case 96879:case 100975:case 101487:case 103535:case 104047:case 104559:case 105071:case 105583:case 106095:case 107631:case 110703:case 111215:case 112751:case 113775:case 114287:case 114799:case 115311:case 115823:case 116847:case 117359:case 117871:case 118383:case 118895:case 119407:case 119919:case 122479:case 122991:case 123503:case 124015:case 125551:case 126575:case 127087:case 127599:case 129647:case 130159:case 130671:case 131183:case 131695:case 132207:case 132719:case 133231:case 134255:case 134767:case 136303:case 136815:case 137327:case 137839:case 139375:case 139887:case 141423:case 143983:case 145007:Jf();break;case-9:case 3233:case 4257:case 4769:case 5281:case 5793:case 9889:case 16033:case 16545:case 17057:case 18593:case 21153:case 22177:case 24225:case 24737:case 28321:case 28833:case 30881:case 35489:case 36513:case 37537:case 38049:case 38561:case 39073:case 40097:case 40609:case 41121:case 41633:case 42145:case 42657:case 43169:case 43681:case 44193:case 44705:case 45729:case 46241:case 46753:case 47265:case 48289:case 48801:case 49825:case 50337:case 50849:case 52385:case 52897:case 53409:case 53921:case 54433:case 54945:case 55969:case 56481:case 56993:case 57505:case 58017:case 58529:case 61089:case 61601:case 62113:case 62625:case 63137:case 63649:case 64161:case 64673:case 65185:case 66209:case 66721:case 67745:case 68257:case 68769:case 69281:case 69793:case 70305:case 70817:case 71329:case 72865:case 73377:case 75425:case 75937:case 76961:case 77985:case 78497:case 79009:case 79521:case 80033:case 80545:case 82593:case 83105:case 83617:case 84129:case 84641:case 85153:case 85665:case 86177:case 86689:case 87201:case 88737:case 89249:case 89761:case 90785:case 91809:case 92833:case 93857:case 94369:case 94881:case 95905:case 96417:case 96929:case 100513:case 101025:case 101537:case 103585:case 104097:case 104609:case 105121:case 105633:case 106145:case 107681:case 110753:case 111265:case 112801:case 113825:case 114337:case 114849:case 115361:case 115873:case 116897:case 117409:case 117921:case 118433:case 118945:case 119457:case 119969:case 122529:case 123041:case 123553:case 124065:case 125601:case 126625:case 127137:case 127649:case 129697:case 130209:case 130721:case 131233:case 131745:case 132257:case 132769:case 133281:case 134305:case 134817:case 136353:case 136865:case 137377:case 137889:case 139425:case 139937:case 141473:case 144033:case 145057:Qf();break;case-10:case 3294:case 4318:case 4830:case 5342:case 5854:case 16094:case 16606:case 17118:case 28382:case 28894:case 30942:case 35550:case 36574:case 37598:case 38110:case 38622:case 39134:case 40158:case 40670:case 41182:case 41694:case 42206:case 42718:case 43230:case 43742:case 44254:case 44766:case 45790:case 46302:case 46814:case 47326:case 48350:case 48862:case 49886:case 50398:case 50910:case 52446:case 52958:case 53470:case 53982:case 54494:case 55006:case 56030:case 56542:case 57054:case 57566:case 58078:case 58590:case 61150:case 61662:case 62174:case 62686:case 63198:case 63710:case 64222:case 64734:case 65246:case 66270:case 66782:case 67806:case 68318:case 68830:case 69342:case 69854:case 70366:case 70878:case 71390:case 72926:case 73438:case 75486:case 75998:case 77022:case 78046:case 78558:case 79070:case 79582:case 80094:case 80606:case 82654:case 83166:case 83678:case 84190:case 84702:case 85214:case 85726:case 86238:case 86750:case 87262:case 88798:case 89310:case 89822:case 90846:case 91870:case 92894:case 93918:case 94430:case 94942:case 95966:case 96478:case 96990:case 100062:case 101086:case 101598:case 103646:case 104158:case 104670:case 105182:case 105694:case 106206:case 107742:case 110814:case 111326:case 112862:case 113886:case 114398:case 114910:case 115422:case 115934:case 116958:case 117470:case 117982:case 118494:case 119006:case 119518:case 120030:case 122590:case 123102:case 123614:case 124126:case 125662:case 126686:case 127198:case 127710:case 129758:case 130270:case 130782:case 131294:case 131806:case 132318:case 132830:case 133342:case 134366:case 134878:case 136414:case 136926:case 137438:case 137950:case 139486:case 139998:case 141534:case 144094:case 145118:Yf();break;case-11:el();break;case-12:case 3150:case 4174:case 4686:case 5198:case 5710:case 15950:case 16462:case 16974:case 18510:case 21070:case 22094:case 24142:case 24654:case 28238:case 28750:case 30798:case 35406:case 36430:case 37454:case 37966:case 38478:case 38990:case 40014:case 40526:case 41038:case 41550:case 42062:case 42574:case 43086:case 43598:case 44110:case 44622:case 45646:case 46158:case 46670:case 47182:case 48206:case 48718:case 49742:case 50254:case 50766:case 52302:case 52814:case 53326:case 53838:case 54350:case 54862:case 55886:case 56398:case 56910:case 57422:case 57934:case 58446:case 61006:case 61518:case 62030:case 62542:case 63054:case 63566:case 64078:case 64590:case 65102:case 66126:case 66638:case 67662:case 68174:case 68686:case 69198:case 69710:case 70222:case 70734:case 71246:case 72782:case 73294:case 75342:case 75854:case 76878:case 77902:case 78414:case 78926:case 79438:case 79950:case 80462:case 82510:case 83022:case 83534:case 84046:case 84558:case 85070:case 85582:case 86094:case 86606:case 87118:case 88654:case 89166:case 89678:case 90702:case 91726:case 92750:case 93774:case 94286:case 94798:case 95822:case 96334:case 96846:case 99406:case 99918:case 100430:case 100942:case 101454:case 103502:case 104014:case 104526:case 105038:case 105550:case 106062:case 107598:case 110670:case 111182:case 112718:case 113742:case 114254:case 114766:case 115278:case 115790:case 116814:case 117326:case 117838:case 118350:case 118862:case 119374:case 119886:case 122446:case 122958:case 123470:case 123982:case 125518:case 126542:case 127054:case 127566:case 129614:case 130126:case 130638:case 131150:case 131662:case 132174:case 132686:case 133198:case 134222:case 134734:case 136270:case 136782:case 137294:case 137806:case 139342:case 139854:case 141390:case 143950:case 144974:nl();break;default:Pn()}ic.endNonterminal("ExprSimple",Vl)}function $f(){switch($l){case 78:ql(269);break;case 161:ql(276);break;case 223:ql(170);break;case 111:case 222:ql(261);break;case 104:case 130:case 240:ql(143);break;default:Wl=$l}if(Wl==17998||Wl==18031||Wl==18081||Wl==18142||Wl==99439||Wl==99489||Wl==99550||Wl==99951||Wl==100001||Wl==136927){Wl=uc(10,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Hn(),oc(10,t,-2),Wl=-13}catch(a){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),zo(),oc(10,t,-3),Wl=-13}catch(f){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),Xo(),oc(10,t,-4),Wl=-13}catch(l){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),Ko(),oc(10,t,-5),Wl=-13}catch(c){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),$o(),oc(10,t,-6),Wl=-13}catch(h){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),Kf(),oc(10,t,-8),Wl=-13}catch(p){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),Gf(),oc(10,t,-9),Wl=-13}catch(d){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),Zf(),oc(10,t,-10),Wl=-13}catch(v){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),tl(),oc(10,t,-11),Wl=-13}catch(m){Wl=-12,Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(10,t,-12)}}}}}}}}}}}switch(Wl){case 16002:case 16112:un();break;case-3:zo();break;case-4:Xo();break;case-5:Ko();break;case-6:case 99551:$o();break;case 15976:ru();break;case-8:case 3183:case 4207:case 4719:case 5231:case 5743:case 15983:case 16495:case 17007:case 28271:case 28783:case 30831:case 35439:case 36463:case 37487:case 37999:case 38511:case 39023:case 40047:case 40559:case 41071:case 41583:case 42095:case 42607:case 43119:case 43631:case 44143:case 44655:case 45679:case 46191:case 46703:case 47215:case 48239:case 48751:case 49775:case 50287:case 50799:case 52335:case 52847:case 53359:case 53871:case 54383:case 54895:case 55919:case 56431:case 56943:case 57455:case 57967:case 58479:case 61039:case 61551:case 62063:case 62575:case 63087:case 63599:case 64111:case 64623:case 65135:case 66159:case 66671:case 67695:case 68207:case 68719:case 69231:case 69743:case 70255:case 70767:case 71279:case 72815:case 73327:case 75375:case 75887:case 76911:case 77935:case 78447:case 78959:case 79471:case 79983:case 80495:case 82543:case 83055:case 83567:case 84079:case 84591:case 85103:case 85615:case 86127:case 86639:case 87151:case 88687:case 89199:case 89711:case 90735:case 91759:case 92783:case 93807:case 94319:case 94831:case 95855:case 96367:case 96879:case 100975:case 101487:case 103535:case 104047:case 104559:case 105071:case 105583:case 106095:case 107631:case 110703:case 111215:case 112751:case 113775:case 114287:case 114799:case 115311:case 115823:case 116847:case 117359:case 117871:case 118383:case 118895:case 119407:case 119919:case 122479:case 122991:case 123503:case 124015:case 125551:case 126575:case 127087:case 127599:case 129647:case 130159:case 130671:case 131183:case 131695:case 132207:case 132719:case 133231:case 134255:case 134767:case 136303:case 136815:case 137327:case 137839:case 139375:case 139887:case 141423:case 143983:case 145007:Kf();break;case-9:case 3233:case 4257:case 4769:case 5281:case 5793:case 9889:case 16033:case 16545:case 17057:case 18593:case 21153:case 22177:case 24225:case 24737:case 28321:case 28833:case 30881:case 35489:case 36513:case 37537:case 38049:case 38561:case 39073:case 40097:case 40609:case 41121:case 41633:case 42145:case 42657:case 43169:case 43681:case 44193:case 44705:case 45729:case 46241:case 46753:case 47265:case 48289:case 48801:case 49825:case 50337:case 50849:case 52385:case 52897:case 53409:case 53921:case 54433:case 54945:case 55969:case 56481:case 56993:case 57505:case 58017:case 58529:case 61089:case 61601:case 62113:case 62625:case 63137:case 63649:case 64161:case 64673:case 65185:case 66209:case 66721:case 67745:case 68257:case 68769:case 69281:case 69793:case 70305:case 70817:case 71329:case 72865:case 73377:case 75425:case 75937:case 76961:case 77985:case 78497:case 79009:case 79521:case 80033:case 80545:case 82593:case 83105:case 83617:case 84129:case 84641:case 85153:case 85665:case 86177:case 86689:case 87201:case 88737:case 89249:case 89761:case 90785:case 91809:case 92833:case 93857:case 94369:case 94881:case 95905:case 96417:case 96929:case 100513:case 101025:case 101537:case 103585:case 104097:case 104609:case 105121:case 105633:case 106145:case 107681:case 110753:case 111265:case 112801:case 113825:case 114337:case 114849:case 115361:case 115873:case 116897:case 117409:case 117921:case 118433:case 118945:case 119457:case 119969:case 122529:case 123041:case 123553:case 124065:case 125601:case 126625:case 127137:case 127649:case 129697:case 130209:case 130721:case 131233:case 131745:case 132257:case 132769:case 133281:case 134305:case 134817:case 136353:case 136865:case 137377:case 137889:case 139425:case 139937:case 141473:case 144033:case 145057:Gf();break;case-10:case 3294:case 4318:case 4830:case 5342:case 5854:case 16094:case 16606:case 17118:case 28382:case 28894:case 30942:case 35550:case 36574:case 37598:case 38110:case 38622:case 39134:case 40158:case 40670:case 41182:case 41694:case 42206:case 42718:case 43230:case 43742:case 44254:case 44766:case 45790:case 46302:case 46814:case 47326:case 48350:case 48862:case 49886:case 50398:case 50910:case 52446:case 52958:case 53470:case 53982:case 54494:case 55006:case 56030:case 56542:case 57054:case 57566:case 58078:case 58590:case 61150:case 61662:case 62174:case 62686:case 63198:case 63710:case 64222:case 64734:case 65246:case 66270:case 66782:case 67806:case 68318:case 68830:case 69342:case 69854:case 70366:case 70878:case 71390:case 72926:case 73438:case 75486:case 75998:case 77022:case 78046:case 78558:case 79070:case 79582:case 80094:case 80606:case 82654:case 83166:case 83678:case 84190:case 84702:case 85214:case 85726:case 86238:case 86750:case 87262:case 88798:case 89310:case 89822:case 90846:case 91870:case 92894:case 93918:case 94430:case 94942:case 95966:case 96478:case 96990:case 100062:case 101086:case 101598:case 103646:case 104158:case 104670:case 105182:case 105694:case 106206:case 107742:case 110814:case 111326:case 112862:case 113886:case 114398:case 114910:case 115422:case 115934:case 116958:case 117470:case 117982:case 118494:case 119006:case 119518:case 120030:case 122590:case 123102:case 123614:case 124126:case 125662:case 126686:case 127198:case 127710:case 129758:case 130270:case 130782:case 131294:case 131806:case 132318:case 132830:case 133342:case 134366:case 134878:case 136414:case 136926:case 137438:case 137950:case 139486:case 139998:case 141534:case 144094:case 145118:Zf();break;case-11:tl();break;case-12:case 3150:case 4174:case 4686:case 5198:case 5710:case 15950:case 16462:case 16974:case 18510:case 21070:case 22094:case 24142:case 24654:case 28238:case 28750:case 30798:case 35406:case 36430:case 37454:case 37966:case 38478:case 38990:case 40014:case 40526:case 41038:case 41550:case 42062:case 42574:case 43086:case 43598:case 44110:case 44622:case 45646:case 46158:case 46670:case 47182:case 48206:case 48718:case 49742:case 50254:case 50766:case 52302:case 52814:case 53326:case 53838:case 54350:case 54862:case 55886:case 56398:case 56910:case 57422:case 57934:case 58446:case 61006:case 61518:case 62030:case 62542:case 63054:case 63566:case 64078:case 64590:case 65102:case 66126:case 66638:case 67662:case 68174:case 68686:case 69198:case 69710:case 70222:case 70734:case 71246:case 72782:case 73294:case 75342:case 75854:case 76878:case 77902:case 78414:case 78926:case 79438:case 79950:case 80462:case 82510:case 83022:case 83534:case 84046:case 84558:case 85070:case 85582:case 86094:case 86606:case 87118:case 88654:case 89166:case 89678:case 90702:case 91726:case 92750:case 93774:case 94286:case 94798:case 95822:case 96334:case 96846:case 99406:case 99918:case 100430:case 100942:case 101454:case 103502:case 104014:case 104526:case 105038:case 105550:case 106062:case 107598:case 110670:case 111182:case 112718:case 113742:case 114254:case 114766:case 115278:case 115790:case 116814:case 117326:case 117838:case 118350:case 118862:case 119374:case 119886:case 122446:case 122958:case 123470:case 123982:case 125518:case 126542:case 127054:case 127566:case 129614:case 130126:case 130638:case 131150:case 131662:case 132174:case 132686:case 133198:case 134222:case 134734:case 136270:case 136782:case 137294:case 137806:case 139342:case 139854:case 141390:case 143950:case 144974:rl();break;case-13:break;default:Hn()}}function Jf(){ic.startNonterminal("JSONDeleteExpr",Vl),Pl(111),Il(260);switch($l){case 168:ql(261);break;default:Wl=$l}if(Wl==18088){Wl=uc(11,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Hl(168),Wl=-1}catch(a){Wl=-2}Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(11,Vl,Wl)}}(Wl==-1||Wl==3240||Wl==4264||Wl==4776||Wl==5288||Wl==5800||Wl==16040||Wl==16552||Wl==17064||Wl==28328||Wl==28840||Wl==30888||Wl==35496||Wl==36520||Wl==37544||Wl==38056||Wl==38568||Wl==39080||Wl==40104||Wl==40616||Wl==41128||Wl==41640||Wl==42152||Wl==42664||Wl==43176||Wl==43688||Wl==44200||Wl==44712||Wl==45736||Wl==46248||Wl==46760||Wl==47272||Wl==48296||Wl==48808||Wl==49832||Wl==50344||Wl==50856||Wl==52392||Wl==52904||Wl==53416||Wl==53928||Wl==54440||Wl==54952||Wl==55976||Wl==56488||Wl==57e3||Wl==57512||Wl==58024||Wl==58536||Wl==61096||Wl==61608||Wl==62120||Wl==62632||Wl==63144||Wl==63656||Wl==64168||Wl==64680||Wl==65192||Wl==66216||Wl==66728||Wl==67752||Wl==68264||Wl==68776||Wl==69288||Wl==69800||Wl==70312||Wl==70824||Wl==71336||Wl==72872||Wl==73384||Wl==75432||Wl==75944||Wl==76968||Wl==77992||Wl==78504||Wl==79016||Wl==79528||Wl==80040||Wl==80552||Wl==82600||Wl==83112||Wl==83624||Wl==84136||Wl==84648||Wl==85160||Wl==85672||Wl==86184||Wl==86696||Wl==87208||Wl==88744||Wl==89256||Wl==89768||Wl==90792||Wl==91816||Wl==92840||Wl==93864||Wl==94376||Wl==94888||Wl==95912||Wl==96424||Wl==96936||Wl==99496||Wl==100008||Wl==101032||Wl==101544||Wl==103592||Wl==104104||Wl==104616||Wl==105128||Wl==105640||Wl==106152||Wl==107688||Wl==110760||Wl==111272||Wl==112808||Wl==113832||Wl==114344||Wl==114856||Wl==115368||Wl==115880||Wl==116904||Wl==117416||Wl==117928||Wl==118440||Wl==118952||Wl==119464||Wl==119976||Wl==122536||Wl==123048||Wl==123560||Wl==124072||Wl==125608||Wl==126632||Wl==127144||Wl==127656||Wl==129704||Wl==130216||Wl==130728||Wl==131240||Wl==131752||Wl==132264||Wl==132776||Wl==133288||Wl==134312||Wl==134824||Wl==136360||Wl==136872||Wl==137384||Wl==137896||Wl==139432||Wl==139944||Wl==141480||Wl==144040||Wl==145064)&&Pl(168),Il(260),jl(),ei(),ic.endNonterminal("JSONDeleteExpr",Vl)}function Kf(){Hl(111),Il(260);switch($l){case 168:ql(261);break;default:Wl=$l}if(Wl==18088){Wl=uc(11,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Hl(168),oc(11,t,-1)}catch(a){Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(11,t,-2)}Wl=-2}}(Wl==-1||Wl==3240||Wl==4264||Wl==4776||Wl==5288||Wl==5800||Wl==16040||Wl==16552||Wl==17064||Wl==28328||Wl==28840||Wl==30888||Wl==35496||Wl==36520||Wl==37544||Wl==38056||Wl==38568||Wl==39080||Wl==40104||Wl==40616||Wl==41128||Wl==41640||Wl==42152||Wl==42664||Wl==43176||Wl==43688||Wl==44200||Wl==44712||Wl==45736||Wl==46248||Wl==46760||Wl==47272||Wl==48296||Wl==48808||Wl==49832||Wl==50344||Wl==50856||Wl==52392||Wl==52904||Wl==53416||Wl==53928||Wl==54440||Wl==54952||Wl==55976||Wl==56488||Wl==57e3||Wl==57512||Wl==58024||Wl==58536||Wl==61096||Wl==61608||Wl==62120||Wl==62632||Wl==63144||Wl==63656||Wl==64168||Wl==64680||Wl==65192||Wl==66216||Wl==66728||Wl==67752||Wl==68264||Wl==68776||Wl==69288||Wl==69800||Wl==70312||Wl==70824||Wl==71336||Wl==72872||Wl==73384||Wl==75432||Wl==75944||Wl==76968||Wl==77992||Wl==78504||Wl==79016||Wl==79528||Wl==80040||Wl==80552||Wl==82600||Wl==83112||Wl==83624||Wl==84136||Wl==84648||Wl==85160||Wl==85672||Wl==86184||Wl==86696||Wl==87208||Wl==88744||Wl==89256||Wl==89768||Wl==90792||Wl==91816||Wl==92840||Wl==93864||Wl==94376||Wl==94888||Wl==95912||Wl==96424||Wl==96936||Wl==99496||Wl==100008||Wl==101032||Wl==101544||Wl==103592||Wl==104104||Wl==104616||Wl==105128||Wl==105640||Wl==106152||Wl==107688||Wl==110760||Wl==111272||Wl==112808||Wl==113832||Wl==114344||Wl==114856||Wl==115368||Wl==115880||Wl==116904||Wl==117416||Wl==117928||Wl==118440||Wl==118952||Wl==119464||Wl==119976||Wl==122536||Wl==123048||Wl==123560||Wl==124072||Wl==125608||Wl==126632||Wl==127144||Wl==127656||Wl==129704||Wl==130216||Wl==130728||Wl==131240||Wl==131752||Wl==132264||Wl==132776||Wl==133288||Wl==134312||Wl==134824||Wl==136360||Wl==136872||Wl==137384||Wl==137896||Wl==139432||Wl==139944||Wl==141480||Wl==144040||Wl==145064)&&Hl(168),Il(260),ti()}function Qf(){ic.startNonterminal("JSONInsertExpr",Vl);switch($l){case 161:ql(268);break;default:Wl=$l}if(Wl!=9889){Wl=uc(12,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Hl(161),Il(267);switch($l){case 168:ql(269);break;default:Wl=$l}if(Wl==18088){Wl=uc(13,Vl);if(Wl==0){var a=Xl,f=Vl,l=$l,c=Jl,h=Kl,p=Ql,d=Gl,v=Yl;try{Hl(168),oc(13,f,-1)}catch(m){Xl=a,Vl=f,$l=l,$l==0?cc=f:(Jl=c,Kl=h,Ql=p,Ql==0?cc=h:(Gl=d,Yl=v,cc=v)),oc(13,f,-2)}Wl=-2}}(Wl==-1||Wl==3240||Wl==4264||Wl==4776||Wl==5288||Wl==5800||Wl==16040||Wl==16552||Wl==17064||Wl==18600||Wl==21160||Wl==22184||Wl==24232||Wl==24744||Wl==28328||Wl==28840||Wl==30888||Wl==35496||Wl==36520||Wl==37544||Wl==38056||Wl==38568||Wl==39080||Wl==40104||Wl==40616||Wl==41128||Wl==41640||Wl==42152||Wl==42664||Wl==43176||Wl==43688||Wl==44200||Wl==44712||Wl==45736||Wl==46248||Wl==46760||Wl==47272||Wl==48296||Wl==48808||Wl==49832||Wl==50344||Wl==50856||Wl==52392||Wl==52904||Wl==53416||Wl==53928||Wl==54440||Wl==54952||Wl==55976||Wl==56488||Wl==57e3||Wl==57512||Wl==58024||Wl==58536||Wl==61096||Wl==61608||Wl==62120||Wl==62632||Wl==63144||Wl==63656||Wl==64168||Wl==64680||Wl==65192||Wl==66216||Wl==66728||Wl==67752||Wl==68264||Wl==68776||Wl==69288||Wl==69800||Wl==70312||Wl==70824||Wl==71336||Wl==72872||Wl==73384||Wl==75432||Wl==75944||Wl==76968||Wl==77992||Wl==78504||Wl==79016||Wl==79528||Wl==80040||Wl==80552||Wl==82600||Wl==83112||Wl==83624||Wl==84136||Wl==84648||Wl==85160||Wl==85672||Wl==86184||Wl==86696||Wl==87208||Wl==88744||Wl==89256||Wl==89768||Wl==90792||Wl==91816||Wl==92840||Wl==93864||Wl==94376||Wl==94888||Wl==95912||Wl==96424||Wl==96936||Wl==99496||Wl==100008||Wl==100520||Wl==101032||Wl==101544||Wl==103592||Wl==104104||Wl==104616||Wl==105128||Wl==105640||Wl==106152||Wl==107688||Wl==110760||Wl==111272||Wl==112808||Wl==113832||Wl==114344||Wl==114856||Wl==115368||Wl==115880||Wl==116904||Wl==117416||Wl==117928||Wl==118440||Wl==118952||Wl==119464||Wl==119976||Wl==122536||Wl==123048||Wl==123560||Wl==124072||Wl==125608||Wl==126632||Wl==127144||Wl==127656||Wl==129704||Wl==130216||Wl==130728||Wl==131240||Wl==131752||Wl==132264||Wl==132776||Wl==133288||Wl==134312||Wl==134824||Wl==136360||Wl==136872||Wl==137384||Wl==137896||Wl==139432||Wl==139944||Wl==141480||Wl==144040||Wl==145064)&&Hl(168),Il(267),Xf(),Hl(165),Il(267),Xf();switch($l){case 82:ql(72);break;default:Wl=$l}if(Wl==110162){Wl=uc(14,Vl);if(Wl==0){var a=Xl,f=Vl,l=$l,c=Jl,h=Kl,p=Ql,d=Gl,v=Yl;try{Hl(82),Il(72),Hl(215),Il(267),Xf(),oc(14,f,-1)}catch(m){Xl=a,Vl=f,$l=l,$l==0?cc=f:(Jl=c,Kl=h,Ql=p,Ql==0?cc=h:(Gl=d,Yl=v,cc=v)),oc(14,f,-2)}Wl=-2}}Wl==-1&&(Hl(82),Il(72),Hl(215),Il(267),Xf()),Wl=-1}catch(g){Wl=-2}Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(12,Vl,Wl)}}switch(Wl){case-1:Pl(161),Il(267);switch($l){case 168:ql(269);break;default:Wl=$l}if(Wl==18088){Wl=uc(13,Vl);if(Wl==0){var a=Xl,f=Vl,l=$l,c=Jl,h=Kl,p=Ql,d=Gl,v=Yl;try{Hl(168),Wl=-1}catch(m){Wl=-2}Xl=a,Vl=f,$l=l,$l==0?cc=f:(Jl=c,Kl=h,Ql=p,Ql==0?cc=h:(Gl=d,Yl=v,cc=v)),oc(13,Vl,Wl)}}(Wl==-1||Wl==3240||Wl==4264||Wl==4776||Wl==5288||Wl==5800||Wl==16040||Wl==16552||Wl==17064||Wl==18600||Wl==21160||Wl==22184||Wl==24232||Wl==24744||Wl==28328||Wl==28840||Wl==30888||Wl==35496||Wl==36520||Wl==37544||Wl==38056||Wl==38568||Wl==39080||Wl==40104||Wl==40616||Wl==41128||Wl==41640||Wl==42152||Wl==42664||Wl==43176||Wl==43688||Wl==44200||Wl==44712||Wl==45736||Wl==46248||Wl==46760||Wl==47272||Wl==48296||Wl==48808||Wl==49832||Wl==50344||Wl==50856||Wl==52392||Wl==52904||Wl==53416||Wl==53928||Wl==54440||Wl==54952||Wl==55976||Wl==56488||Wl==57e3||Wl==57512||Wl==58024||Wl==58536||Wl==61096||Wl==61608||Wl==62120||Wl==62632||Wl==63144||Wl==63656||Wl==64168||Wl==64680||Wl==65192||Wl==66216||Wl==66728||Wl==67752||Wl==68264||Wl==68776||Wl==69288||Wl==69800||Wl==70312||Wl==70824||Wl==71336||Wl==72872||Wl==73384||Wl==75432||Wl==75944||Wl==76968||Wl==77992||Wl==78504||Wl==79016||Wl==79528||Wl==80040||Wl==80552||Wl==82600||Wl==83112||Wl==83624||Wl==84136||Wl==84648||Wl==85160||Wl==85672||Wl==86184||Wl==86696||Wl==87208||Wl==88744||Wl==89256||Wl==89768||Wl==90792||Wl==91816||Wl==92840||Wl==93864||Wl==94376||Wl==94888||Wl==95912||Wl==96424||Wl==96936||Wl==99496||Wl==100008||Wl==100520||Wl==101032||Wl==101544||Wl==103592||Wl==104104||Wl==104616||Wl==105128||Wl==105640||Wl==106152||Wl==107688||Wl==110760||Wl==111272||Wl==112808||Wl==113832||Wl==114344||Wl==114856||Wl==115368||Wl==115880||Wl==116904||Wl==117416||Wl==117928||Wl==118440||Wl==118952||Wl==119464||Wl==119976||Wl==122536||Wl==123048||Wl==123560||Wl==124072||Wl==125608||Wl==126632||Wl==127144||Wl==127656||Wl==129704||Wl==130216||Wl==130728||Wl==131240||Wl==131752||Wl==132264||Wl==132776||Wl==133288||Wl==134312||Wl==134824||Wl==136360||Wl==136872||Wl==137384||Wl==137896||Wl==139432||Wl==139944||Wl==141480||Wl==144040||Wl==145064)&&Pl(168),Il(267),jl(),Wf(),Pl(165),Il(267),jl(),Wf();switch($l){case 82:ql(72);break;default:Wl=$l}if(Wl==110162){Wl=uc(14,Vl);if(Wl==0){var a=Xl,f=Vl,l=$l,c=Jl,h=Kl,p=Ql,d=Gl,v=Yl;try{Hl(82),Il(72),Hl(215),Il(267),Xf(),Wl=-1}catch(m){Wl=-2}Xl=a,Vl=f,$l=l,$l==0?cc=f:(Jl=c,Kl=h,Ql=p,Ql==0?cc=h:(Gl=d,Yl=v,cc=v)),oc(14,Vl,Wl)}}Wl==-1&&(Pl(82),Il(72),Pl(215),Il(267),jl(),Wf());break;default:Pl(161),Il(268);switch($l){case 168:ql(282);break;default:Wl=$l}if(Wl==18088){Wl=uc(15,Vl);if(Wl==0){var a=Xl,f=Vl,l=$l,c=Jl,h=Kl,p=Ql,d=Gl,v=Yl;try{Hl(168),Wl=-1}catch(m){Wl=-2}Xl=a,Vl=f,$l=l,$l==0?cc=f:(Jl=c,Kl=h,Ql=p,Ql==0?cc=h:(Gl=d,Yl=v,cc=v)),oc(15,Vl,Wl)}}(Wl==-1||Wl==3240||Wl==4264||Wl==4776||Wl==5288||Wl==5800||Wl==9896||Wl==16040||Wl==16552||Wl==17064||Wl==18600||Wl==21160||Wl==22184||Wl==24232||Wl==24744||Wl==28328||Wl==28840||Wl==30888||Wl==35496||Wl==36520||Wl==37544||Wl==38056||Wl==38568||Wl==39080||Wl==40104||Wl==40616||Wl==41128||Wl==41640||Wl==42152||Wl==42664||Wl==43176||Wl==43688||Wl==44200||Wl==44712||Wl==45736||Wl==46248||Wl==46760||Wl==47272||Wl==48296||Wl==48808||Wl==49832||Wl==50344||Wl==50856||Wl==52392||Wl==52904||Wl==53416||Wl==53928||Wl==54440||Wl==54952||Wl==55976||Wl==56488||Wl==57e3||Wl==57512||Wl==58024||Wl==58536||Wl==61096||Wl==61608||Wl==62120||Wl==62632||Wl==63144||Wl==63656||Wl==64168||Wl==64680||Wl==65192||Wl==66216||Wl==66728||Wl==67752||Wl==68264||Wl==68776||Wl==69288||Wl==69800||Wl==70312||Wl==70824||Wl==71336||Wl==72872||Wl==73384||Wl==75432||Wl==75944||Wl==76968||Wl==77992||Wl==78504||Wl==79016||Wl==79528||Wl==80040||Wl==80552||Wl==82600||Wl==83112||Wl==83624||Wl==84136||Wl==84648||Wl==85160||Wl==85672||Wl==86184||Wl==86696||Wl==87208||Wl==88744||Wl==89256||Wl==89768||Wl==90792||Wl==91816||Wl==92840||Wl==93864||Wl==94376||Wl==94888||Wl==95912||Wl==96424||Wl==96936||Wl==99496||Wl==100008||Wl==100520||Wl==101032||Wl==101544||Wl==103592||Wl==104104||Wl==104616||Wl==105128||Wl==105640||Wl==106152||Wl==107688||Wl==110760||Wl==111272||Wl==112808||Wl==113832||Wl==114344||Wl==114856||Wl==115368||Wl==115880||Wl==116904||Wl==117416||Wl==117928||Wl==118440||Wl==118952||Wl==119464||Wl==119976||Wl==122536||Wl==123048||Wl==123560||Wl==124072||Wl==125608||Wl==126632||Wl==127144||Wl==127656||Wl==129704||Wl==130216||Wl==130728||Wl==131240||Wl==131752||Wl==132264||Wl==132776||Wl==133288||Wl==134312||Wl==134824||Wl==136360||Wl==136872||Wl==137384||Wl==137896||Wl==139432||Wl==139944||Wl==141480||Wl==144040||Wl==145064)&&Pl(168),Il(268),jl(),Tl(),Pl(165),Il(267),jl(),Wf()}ic.endNonterminal("JSONInsertExpr",Vl)}function Gf(){switch($l){case 161:ql(268);break;default:Wl=$l}if(Wl!=9889){Wl=uc(12,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Hl(161),Il(267);switch($l){case 168:ql(269);break;default:Wl=$l}if(Wl==18088){Wl=uc(13,Vl);if(Wl==0){var a=Xl,f=Vl,l=$l,c=Jl,h=Kl,p=Ql,d=Gl,v=Yl;try{Hl(168),oc(13,f,-1)}catch(m){Xl=a,Vl=f,$l=l,$l==0?cc=f:(Jl=c,Kl=h,Ql=p,Ql==0?cc=h:(Gl=d,Yl=v,cc=v)),oc(13,f,-2)}Wl=-2}}(Wl==-1||Wl==3240||Wl==4264||Wl==4776||Wl==5288||Wl==5800||Wl==16040||Wl==16552||Wl==17064||Wl==18600||Wl==21160||Wl==22184||Wl==24232||Wl==24744||Wl==28328||Wl==28840||Wl==30888||Wl==35496||Wl==36520||Wl==37544||Wl==38056||Wl==38568||Wl==39080||Wl==40104||Wl==40616||Wl==41128||Wl==41640||Wl==42152||Wl==42664||Wl==43176||Wl==43688||Wl==44200||Wl==44712||Wl==45736||Wl==46248||Wl==46760||Wl==47272||Wl==48296||Wl==48808||Wl==49832||Wl==50344||Wl==50856||Wl==52392||Wl==52904||Wl==53416||Wl==53928||Wl==54440||Wl==54952||Wl==55976||Wl==56488||Wl==57e3||Wl==57512||Wl==58024||Wl==58536||Wl==61096||Wl==61608||Wl==62120||Wl==62632||Wl==63144||Wl==63656||Wl==64168||Wl==64680||Wl==65192||Wl==66216||Wl==66728||Wl==67752||Wl==68264||Wl==68776||Wl==69288||Wl==69800||Wl==70312||Wl==70824||Wl==71336||Wl==72872||Wl==73384||Wl==75432||Wl==75944||Wl==76968||Wl==77992||Wl==78504||Wl==79016||Wl==79528||Wl==80040||Wl==80552||Wl==82600||Wl==83112||Wl==83624||Wl==84136||Wl==84648||Wl==85160||Wl==85672||Wl==86184||Wl==86696||Wl==87208||Wl==88744||Wl==89256||Wl==89768||Wl==90792||Wl==91816||Wl==92840||Wl==93864||Wl==94376||Wl==94888||Wl==95912||Wl==96424||Wl==96936||Wl==99496||Wl==100008||Wl==100520||Wl==101032||Wl==101544||Wl==103592||Wl==104104||Wl==104616||Wl==105128||Wl==105640||Wl==106152||Wl==107688||Wl==110760||Wl==111272||Wl==112808||Wl==113832||Wl==114344||Wl==114856||Wl==115368||Wl==115880||Wl==116904||Wl==117416||Wl==117928||Wl==118440||Wl==118952||Wl==119464||Wl==119976||Wl==122536||Wl==123048||Wl==123560||Wl==124072||Wl==125608||Wl==126632||Wl==127144||Wl==127656||Wl==129704||Wl==130216||Wl==130728||Wl==131240||Wl==131752||Wl==132264||Wl==132776||Wl==133288||Wl==134312||Wl==134824||Wl==136360||Wl==136872||Wl==137384||Wl==137896||Wl==139432||Wl==139944||Wl==141480||Wl==144040||Wl==145064)&&Hl(168),Il(267),Xf(),Hl(165),Il(267),Xf();switch($l){case 82:ql(72);break;default:Wl=$l}if(Wl==110162){Wl=uc(14,Vl);if(Wl==0){var a=Xl,f=Vl,l=$l,c=Jl,h=Kl,p=Ql,d=Gl,v=Yl;try{Hl(82),Il(72),Hl(215),Il(267),Xf(),oc(14,f,-1)}catch(m){Xl=a,Vl=f,$l=l,$l==0?cc=f:(Jl=c,Kl=h,Ql=p,Ql==0?cc=h:(Gl=d,Yl=v,cc=v)),oc(14,f,-2)}Wl=-2}}Wl==-1&&(Hl(82),Il(72),Hl(215),Il(267),Xf()),oc(12,t,-1),Wl=-3}catch(g){Wl=-2,Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(12,t,-2)}}}switch(Wl){case-1:Hl(161),Il(267);switch($l){case 168:ql(269);break;default:Wl=$l}if(Wl==18088){Wl=uc(13,Vl);if(Wl==0){var a=Xl,f=Vl,l=$l,c=Jl,h=Kl,p=Ql,d=Gl,v=Yl;try{Hl(168),oc(13,f,-1)}catch(m){Xl=a,Vl=f,$l=l,$l==0?cc=f:(Jl=c,Kl=h,Ql=p,Ql==0?cc=h:(Gl=d,Yl=v,cc=v)),oc(13,f,-2)}Wl=-2}}(Wl==-1||Wl==3240||Wl==4264||Wl==4776||Wl==5288||Wl==5800||Wl==16040||Wl==16552||Wl==17064||Wl==18600||Wl==21160||Wl==22184||Wl==24232||Wl==24744||Wl==28328||Wl==28840||Wl==30888||Wl==35496||Wl==36520||Wl==37544||Wl==38056||Wl==38568||Wl==39080||Wl==40104||Wl==40616||Wl==41128||Wl==41640||Wl==42152||Wl==42664||Wl==43176||Wl==43688||Wl==44200||Wl==44712||Wl==45736||Wl==46248||Wl==46760||Wl==47272||Wl==48296||Wl==48808||Wl==49832||Wl==50344||Wl==50856||Wl==52392||Wl==52904||Wl==53416||Wl==53928||Wl==54440||Wl==54952||Wl==55976||Wl==56488||Wl==57e3||Wl==57512||Wl==58024||Wl==58536||Wl==61096||Wl==61608||Wl==62120||Wl==62632||Wl==63144||Wl==63656||Wl==64168||Wl==64680||Wl==65192||Wl==66216||Wl==66728||Wl==67752||Wl==68264||Wl==68776||Wl==69288||Wl==69800||Wl==70312||Wl==70824||Wl==71336||Wl==72872||Wl==73384||Wl==75432||Wl==75944||Wl==76968||Wl==77992||Wl==78504||Wl==79016||Wl==79528||Wl==80040||Wl==80552||Wl==82600||Wl==83112||Wl==83624||Wl==84136||Wl==84648||Wl==85160||Wl==85672||Wl==86184||Wl==86696||Wl==87208||Wl==88744||Wl==89256||Wl==89768||Wl==90792||Wl==91816||Wl==92840||Wl==93864||Wl==94376||Wl==94888||Wl==95912||Wl==96424||Wl==96936||Wl==99496||Wl==100008||Wl==100520||Wl==101032||Wl==101544||Wl==103592||Wl==104104||Wl==104616||Wl==105128||Wl==105640||Wl==106152||Wl==107688||Wl==110760||Wl==111272||Wl==112808||Wl==113832||Wl==114344||Wl==114856||Wl==115368||Wl==115880||Wl==116904||Wl==117416||Wl==117928||Wl==118440||Wl==118952||Wl==119464||Wl==119976||Wl==122536||Wl==123048||Wl==123560||Wl==124072||Wl==125608||Wl==126632||Wl==127144||Wl==127656||Wl==129704||Wl==130216||Wl==130728||Wl==131240||Wl==131752||Wl==132264||Wl==132776||Wl==133288||Wl==134312||Wl==134824||Wl==136360||Wl==136872||Wl==137384||Wl==137896||Wl==139432||Wl==139944||Wl==141480||Wl==144040||Wl==145064)&&Hl(168),Il(267),Xf(),Hl(165),Il(267),Xf();switch($l){case 82:ql(72);break;default:Wl=$l}if(Wl==110162){Wl=uc(14,Vl);if(Wl==0){var a=Xl,f=Vl,l=$l,c=Jl,h=Kl,p=Ql,d=Gl,v=Yl;try{Hl(82),Il(72),Hl(215),Il(267),Xf(),oc(14,f,-1)}catch(m){Xl=a,Vl=f,$l=l,$l==0?cc=f:(Jl=c,Kl=h,Ql=p,Ql==0?cc=h:(Gl=d,Yl=v,cc=v)),oc(14,f,-2)}Wl=-2}}Wl==-1&&(Hl(82),Il(72),Hl(215),Il(267),Xf());break;case-3:break;default:Hl(161),Il(268);switch($l){case 168:ql(282);break;default:Wl=$l}if(Wl==18088){Wl=uc(15,Vl);if(Wl==0){var a=Xl,f=Vl,l=$l,c=Jl,h=Kl,p=Ql,d=Gl,v=Yl;try{Hl(168),oc(15,f,-1)}catch(m){Xl=a,Vl=f,$l=l,$l==0?cc=f:(Jl=c,Kl=h,Ql=p,Ql==0?cc=h:(Gl=d,Yl=v,cc=v)),oc(15,f,-2)}Wl=-2}}(Wl==-1||Wl==3240||Wl==4264||Wl==4776||Wl==5288||Wl==5800||Wl==9896||Wl==16040||Wl==16552||Wl==17064||Wl==18600||Wl==21160||Wl==22184||Wl==24232||Wl==24744||Wl==28328||Wl==28840||Wl==30888||Wl==35496||Wl==36520||Wl==37544||Wl==38056||Wl==38568||Wl==39080||Wl==40104||Wl==40616||Wl==41128||Wl==41640||Wl==42152||Wl==42664||Wl==43176||Wl==43688||Wl==44200||Wl==44712||Wl==45736||Wl==46248||Wl==46760||Wl==47272||Wl==48296||Wl==48808||Wl==49832||Wl==50344||Wl==50856||Wl==52392||Wl==52904||Wl==53416||Wl==53928||Wl==54440||Wl==54952||Wl==55976||Wl==56488||Wl==57e3||Wl==57512||Wl==58024||Wl==58536||Wl==61096||Wl==61608||Wl==62120||Wl==62632||Wl==63144||Wl==63656||Wl==64168||Wl==64680||Wl==65192||Wl==66216||Wl==66728||Wl==67752||Wl==68264||Wl==68776||Wl==69288||Wl==69800||Wl==70312||Wl==70824||Wl==71336||Wl==72872||Wl==73384||Wl==75432||Wl==75944||Wl==76968||Wl==77992||Wl==78504||Wl==79016||Wl==79528||Wl==80040||Wl==80552||Wl==82600||Wl==83112||Wl==83624||Wl==84136||Wl==84648||Wl==85160||Wl==85672||Wl==86184||Wl==86696||Wl==87208||Wl==88744||Wl==89256||Wl==89768||Wl==90792||Wl==91816||Wl==92840||Wl==93864||Wl==94376||Wl==94888||Wl==95912||Wl==96424||Wl==96936||Wl==99496||Wl==100008||Wl==100520||Wl==101032||Wl==101544||Wl==103592||Wl==104104||Wl==104616||Wl==105128||Wl==105640||Wl==106152||Wl==107688||Wl==110760||Wl==111272||Wl==112808||Wl==113832||Wl==114344||Wl==114856||Wl==115368||Wl==115880||Wl==116904||Wl==117416||Wl==117928||Wl==118440||Wl==118952||Wl==119464||Wl==119976||Wl==122536||Wl==123048||Wl==123560||Wl==124072||Wl==125608||Wl==126632||Wl==127144||Wl==127656||Wl==129704||Wl==130216||Wl==130728||Wl==131240||Wl==131752||Wl==132264||Wl==132776||Wl==133288||Wl==134312||Wl==134824||Wl==136360||Wl==136872||Wl==137384||Wl==137896||Wl==139432||Wl==139944||Wl==141480||Wl==144040||Wl==145064)&&Hl(168),Il(268),Nl(),Hl(165),Il(267),Xf()}}function Yf(){ic.startNonterminal("JSONRenameExpr",Vl),Pl(222),Il(260);switch($l){case 168:ql(261);break;default:Wl=$l}if(Wl==18088){Wl=uc(16,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Hl(168),Wl=-1}catch(a){Wl=-2}Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(16,Vl,Wl)}}(Wl==-1||Wl==3240||Wl==4264||Wl==4776||Wl==5288||Wl==5800||Wl==16040||Wl==16552||Wl==17064||Wl==28328||Wl==28840||Wl==30888||Wl==35496||Wl==36520||Wl==37544||Wl==38056||Wl==38568||Wl==39080||Wl==40104||Wl==40616||Wl==41128||Wl==41640||Wl==42152||Wl==42664||Wl==43176||Wl==43688||Wl==44200||Wl==44712||Wl==45736||Wl==46248||Wl==46760||Wl==47272||Wl==48296||Wl==48808||Wl==49832||Wl==50344||Wl==50856||Wl==52392||Wl==52904||Wl==53416||Wl==53928||Wl==54440||Wl==54952||Wl==55976||Wl==56488||Wl==57e3||Wl==57512||Wl==58024||Wl==58536||Wl==61096||Wl==61608||Wl==62120||Wl==62632||Wl==63144||Wl==63656||Wl==64168||Wl==64680||Wl==65192||Wl==66216||Wl==66728||Wl==67752||Wl==68264||Wl==68776||Wl==69288||Wl==69800||Wl==70312||Wl==70824||Wl==71336||Wl==72872||Wl==73384||Wl==75432||Wl==75944||Wl==76968||Wl==77992||Wl==78504||Wl==79016||Wl==79528||Wl==80040||Wl==80552||Wl==82600||Wl==83112||Wl==83624||Wl==84136||Wl==84648||Wl==85160||Wl==85672||Wl==86184||Wl==86696||Wl==87208||Wl==88744||Wl==89256||Wl==89768||Wl==90792||Wl==91816||Wl==92840||Wl==93864||Wl==94376||Wl==94888||Wl==95912||Wl==96424||Wl==96936||Wl==99496||Wl==100008||Wl==101032||Wl==101544||Wl==103592||Wl==104104||Wl==104616||Wl==105128||Wl==105640||Wl==106152||Wl==107688||Wl==110760||Wl==111272||Wl==112808||Wl==113832||Wl==114344||Wl==114856||Wl==115368||Wl==115880||Wl==116904||Wl==117416||Wl==117928||Wl==118440||Wl==118952||Wl==119464||Wl==119976||Wl==122536||Wl==123048||Wl==123560||Wl==124072||Wl==125608||Wl==126632||Wl==127144||Wl==127656||Wl==129704||Wl==130216||Wl==130728||Wl==131240||Wl==131752||Wl==132264||Wl==132776||Wl==133288||Wl==134312||Wl==134824||Wl==136360||Wl==136872||Wl==137384||Wl==137896||Wl==139432||Wl==139944||Wl==141480||Wl==144040||Wl==145064)&&Pl(168),Il(260),jl(),ei(),Pl(80),Il(267),jl(),Wf(),ic.endNonterminal("JSONRenameExpr",Vl)}function Zf(){Hl(222),Il(260);switch($l){case 168:ql(261);break;default:Wl=$l}if(Wl==18088){Wl=uc(16,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Hl(168),oc(16,t,-1)}catch(a){Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(16,t,-2)}Wl=-2}}(Wl==-1||Wl==3240||Wl==4264||Wl==4776||Wl==5288||Wl==5800||Wl==16040||Wl==16552||Wl==17064||Wl==28328||Wl==28840||Wl==30888||Wl==35496||Wl==36520||Wl==37544||Wl==38056||Wl==38568||Wl==39080||Wl==40104||Wl==40616||Wl==41128||Wl==41640||Wl==42152||Wl==42664||Wl==43176||Wl==43688||Wl==44200||Wl==44712||Wl==45736||Wl==46248||Wl==46760||Wl==47272||Wl==48296||Wl==48808||Wl==49832||Wl==50344||Wl==50856||Wl==52392||Wl==52904||Wl==53416||Wl==53928||Wl==54440||Wl==54952||Wl==55976||Wl==56488||Wl==57e3||Wl==57512||Wl==58024||Wl==58536||Wl==61096||Wl==61608||Wl==62120||Wl==62632||Wl==63144||Wl==63656||Wl==64168||Wl==64680||Wl==65192||Wl==66216||Wl==66728||Wl==67752||Wl==68264||Wl==68776||Wl==69288||Wl==69800||Wl==70312||Wl==70824||Wl==71336||Wl==72872||Wl==73384||Wl==75432||Wl==75944||Wl==76968||Wl==77992||Wl==78504||Wl==79016||Wl==79528||Wl==80040||Wl==80552||Wl==82600||Wl==83112||Wl==83624||Wl==84136||Wl==84648||Wl==85160||Wl==85672||Wl==86184||Wl==86696||Wl==87208||Wl==88744||Wl==89256||Wl==89768||Wl==90792||Wl==91816||Wl==92840||Wl==93864||Wl==94376||Wl==94888||Wl==95912||Wl==96424||Wl==96936||Wl==99496||Wl==100008||Wl==101032||Wl==101544||Wl==103592||Wl==104104||Wl==104616||Wl==105128||Wl==105640||Wl==106152||Wl==107688||Wl==110760||Wl==111272||Wl==112808||Wl==113832||Wl==114344||Wl==114856||Wl==115368||Wl==115880||Wl==116904||Wl==117416||Wl==117928||Wl==118440||Wl==118952||Wl==119464||Wl==119976||Wl==122536||Wl==123048||Wl==123560||Wl==124072||Wl==125608||Wl==126632||Wl==127144||Wl==127656||Wl==129704||Wl==130216||Wl==130728||Wl==131240||Wl==131752||Wl==132264||Wl==132776||Wl==133288||Wl==134312||Wl==134824||Wl==136360||Wl==136872||Wl==137384||Wl==137896||Wl==139432||Wl==139944||Wl==141480||Wl==144040||Wl==145064)&&Hl(168),Il(260),ti(),Hl(80),Il(267),Xf()}function el(){ic.startNonterminal("JSONReplaceExpr",Vl),Pl(223),Il(85),Pl(267),Il(67),Pl(200),Il(59),Pl(168),Il(260),jl(),ei(),Pl(276),Il(267),jl(),Wf(),ic.endNonterminal("JSONReplaceExpr",Vl)}function tl(){Hl(223),Il(85),Hl(267),Il(67),Hl(200),Il(59),Hl(168),Il(260),ti(),Hl(276),Il(267),Xf()}function nl(){ic.startNonterminal("JSONAppendExpr",Vl),Pl(78),Il(267);switch($l){case 168:ql(269);break;default:Wl=$l}if(Wl==18088){Wl=uc(17,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Hl(168),Wl=-1}catch(a){Wl=-2}Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(17,Vl,Wl)}}(Wl==-1||Wl==3240||Wl==4264||Wl==4776||Wl==5288||Wl==5800||Wl==16040||Wl==16552||Wl==17064||Wl==18600||Wl==21160||Wl==22184||Wl==24232||Wl==24744||Wl==28328||Wl==28840||Wl==30888||Wl==35496||Wl==36520||Wl==37544||Wl==38056||Wl==38568||Wl==39080||Wl==40104||Wl==40616||Wl==41128||Wl==41640||Wl==42152||Wl==42664||Wl==43176||Wl==43688||Wl==44200||Wl==44712||Wl==45736||Wl==46248||Wl==46760||Wl==47272||Wl==48296||Wl==48808||Wl==49832||Wl==50344||Wl==50856||Wl==52392||Wl==52904||Wl==53416||Wl==53928||Wl==54440||Wl==54952||Wl==55976||Wl==56488||Wl==57e3||Wl==57512||Wl==58024||Wl==58536||Wl==61096||Wl==61608||Wl==62120||Wl==62632||Wl==63144||Wl==63656||Wl==64168||Wl==64680||Wl==65192||Wl==66216||Wl==66728||Wl==67752||Wl==68264||Wl==68776||Wl==69288||Wl==69800||Wl==70312||Wl==70824||Wl==71336||Wl==72872||Wl==73384||Wl==75432||Wl==75944||Wl==76968||Wl==77992||Wl==78504||Wl==79016||Wl==79528||Wl==80040||Wl==80552||Wl==82600||Wl==83112||Wl==83624||Wl==84136||Wl==84648||Wl==85160||Wl==85672||Wl==86184||Wl==86696||Wl==87208||Wl==88744||Wl==89256||Wl==89768||Wl==90792||Wl==91816||Wl==92840||Wl==93864||Wl==94376||Wl==94888||Wl==95912||Wl==96424||Wl==96936||Wl==99496||Wl==100008||Wl==100520||Wl==101032||Wl==101544||Wl==103592||Wl==104104||Wl==104616||Wl==105128||Wl==105640||Wl==106152||Wl==107688||Wl==110760||Wl==111272||Wl==112808||Wl==113832||Wl==114344||Wl==114856||Wl==115368||Wl==115880||Wl==116904||Wl==117416||Wl==117928||Wl==118440||Wl==118952||Wl==119464||Wl==119976||Wl==122536||Wl==123048||Wl==123560||Wl==124072||Wl==125608||Wl==126632||Wl==127144||Wl==127656||Wl==129704||Wl==130216||Wl==130728||Wl==131240||Wl==131752||Wl==132264||Wl==132776||Wl==133288||Wl==134312||Wl==134824||Wl==136360||Wl==136872||Wl==137384||Wl==137896||Wl==139432||Wl==139944||Wl==141480||Wl==144040||Wl==145064)&&Pl(168),Il(267),jl(),Wf(),Pl(165),Il(267),jl(),Wf(),ic.endNonterminal("JSONAppendExpr",Vl)}function rl(){Hl(78),Il(267);switch($l){case 168:ql(269);break;default:Wl=$l}if(Wl==18088){Wl=uc(17,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Hl(168),oc(17,t,-1)}catch(a){Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(17,t,-2)}Wl=-2}}(Wl==-1||Wl==3240||Wl==4264||Wl==4776||Wl==5288||Wl==5800||Wl==16040||Wl==16552||Wl==17064||Wl==18600||Wl==21160||Wl==22184||Wl==24232||Wl==24744||Wl==28328||Wl==28840||Wl==30888||Wl==35496||Wl==36520||Wl==37544||Wl==38056||Wl==38568||Wl==39080||Wl==40104||Wl==40616||Wl==41128||Wl==41640||Wl==42152||Wl==42664||Wl==43176||Wl==43688||Wl==44200||Wl==44712||Wl==45736||Wl==46248||Wl==46760||Wl==47272||Wl==48296||Wl==48808||Wl==49832||Wl==50344||Wl==50856||Wl==52392||Wl==52904||Wl==53416||Wl==53928||Wl==54440||Wl==54952||Wl==55976||Wl==56488||Wl==57e3||Wl==57512||Wl==58024||Wl==58536||Wl==61096||Wl==61608||Wl==62120||Wl==62632||Wl==63144||Wl==63656||Wl==64168||Wl==64680||Wl==65192||Wl==66216||Wl==66728||Wl==67752||Wl==68264||Wl==68776||Wl==69288||Wl==69800||Wl==70312||Wl==70824||Wl==71336||Wl==72872||Wl==73384||Wl==75432||Wl==75944||Wl==76968||Wl==77992||Wl==78504||Wl==79016||Wl==79528||Wl==80040||Wl==80552||Wl==82600||Wl==83112||Wl==83624||Wl==84136||Wl==84648||Wl==85160||Wl==85672||Wl==86184||Wl==86696||Wl==87208||Wl==88744||Wl==89256||Wl==89768||Wl==90792||Wl==91816||Wl==92840||Wl==93864||Wl==94376||Wl==94888||Wl==95912||Wl==96424||Wl==96936||Wl==99496||Wl==100008||Wl==100520||Wl==101032||Wl==101544||Wl==103592||Wl==104104||Wl==104616||Wl==105128||Wl==105640||Wl==106152||Wl==107688||Wl==110760||Wl==111272||Wl==112808||Wl==113832||Wl==114344||Wl==114856||Wl==115368||Wl==115880||Wl==116904||Wl==117416||Wl==117928||Wl==118440||Wl==118952||Wl==119464||Wl==119976||Wl==122536||Wl==123048||Wl==123560||Wl==124072||Wl==125608||Wl==126632||Wl==127144||Wl==127656||Wl==129704||Wl==130216||Wl==130728||Wl==131240||Wl==131752||Wl==132264||Wl==132776||Wl==133288||Wl==134312||Wl==134824||Wl==136360||Wl==136872||Wl==137384||Wl==137896||Wl==139432||Wl==139944||Wl==141480||Wl==144040||Wl==145064)&&Hl(168),Il(267),Xf(),Hl(165),Il(267),Xf()}function il(){ic.startNonterminal("CommonContent",Vl);switch($l){case 12:Pl(12);break;case 23:Pl(23);break;case 282:Pl(282);break;case 288:Pl(288);break;default:Ol()}ic.endNonterminal("CommonContent",Vl)}function sl(){switch($l){case 12:Hl(12);break;case 23:Hl(23);break;case 282:Hl(282);break;case 288:Hl(288);break;default:Ml()}}function ol(){ic.startNonterminal("ContentExpr",Vl),rf(),ic.endNonterminal("ContentExpr",Vl)}function ul(){sf()}function al(){ic.startNonterminal("CompDocConstructor",Vl),Pl(120),Il(90),jl(),Ol(),ic.endNonterminal("CompDocConstructor",Vl)}function fl(){Hl(120),Il(90),Ml()}function ll(){ic.startNonterminal("CompAttrConstructor",Vl),Pl(83),Il(250);switch($l){case 281:Pl(281),Il(267),jl(),G(),Pl(287);break;default:jl(),$a()}Il(90);switch($l){case 281:ql(281);break;default:Wl=$l}if(Wl==147225){Wl=uc(18,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Hl(281),Il(91),Hl(287),Wl=-1}catch(a){Wl=-2}Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(18,Vl,Wl)}}switch(Wl){case-1:Pl(281),Il(91),Pl(287);break;default:jl(),Ol()}ic.endNonterminal("CompAttrConstructor",Vl)}function cl(){Hl(83),Il(250);switch($l){case 281:Hl(281),Il(267),Y(),Hl(287);break;default:Ja()}Il(90);switch($l){case 281:ql(281);break;default:Wl=$l}if(Wl==147225){Wl=uc(18,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Hl(281),Il(91),Hl(287),oc(18,t,-1),Wl=-3}catch(a){Wl=-2,Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(18,t,-2)}}}switch(Wl){case-1:Hl(281),Il(91),Hl(287);break;case-3:break;default:Ml()}}function hl(){ic.startNonterminal("CompPIConstructor",Vl),Pl(220),Il(242);switch($l){case 281:Pl(281),Il(267),jl(),G(),Pl(287);break;default:jl(),Ga()}Il(90);switch($l){case 281:ql(281);break;default:Wl=$l}if(Wl==147225){Wl=uc(19,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Hl(281),Il(91),Hl(287),Wl=-1}catch(a){Wl=-2}Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(19,Vl,Wl)}}switch(Wl){case-1:Pl(281),Il(91),Pl(287);break;default:jl(),Ol()}ic.endNonterminal("CompPIConstructor",Vl)}function pl(){Hl(220),Il(242);switch($l){case 281:Hl(281),Il(267),Y(),Hl(287);break;default:Ya()}Il(90);switch($l){case 281:ql(281);break;default:Wl=$l}if(Wl==147225){Wl=uc(19,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Hl(281),Il(91),Hl(287),oc(19,t,-1),Wl=-3}catch(a){Wl=-2,Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(19,t,-2)}}}switch(Wl){case-1:Hl(281),Il(91),Hl(287);break;case-3:break;default:Ml()}}function dl(){ic.startNonterminal("CompCommentConstructor",Vl),Pl(97),Il(90),jl(),Ol(),ic.endNonterminal("CompCommentConstructor",Vl)}function vl(){Hl(97),Il(90),Ml()}function ml(){ic.startNonterminal("CompTextConstructor",Vl),Pl(249),Il(90),jl(),Ol(),ic.endNonterminal("CompTextConstructor",Vl)}function gl(){Hl(249),Il(90),Ml()}function yl(){ic.startNonterminal("PrimaryExpr",Vl);switch($l){case 187:ql(247);break;case 220:ql(245);break;case 281:ql(283);break;case 83:case 122:ql(253);break;case 97:case 249:ql(97);break;case 120:case 206:case 262:ql(148);break;case 135:case 197:case 255:ql(237);break;case 6:case 71:case 73:case 74:case 75:case 76:case 78:case 80:case 81:case 82:case 84:case 85:case 86:case 87:case 89:case 90:case 91:case 92:case 94:case 95:case 98:case 99:case 102:case 103:case 104:case 105:case 106:case 107:case 109:case 110:case 111:case 112:case 113:case 114:case 119:case 123:case 124:case 126:case 127:case 129:case 130:case 132:case 133:case 134:case 136:case 137:case 138:case 139:case 142:case 143:case 148:case 150:case 152:case 153:case 155:case 156:case 157:case 161:case 162:case 163:case 164:case 165:case 166:case 168:case 170:case 173:case 174:case 175:case 177:case 179:case 181:case 183:case 184:case 185:case 189:case 195:case 198:case 202:case 203:case 204:case 205:case 207:case 210:case 216:case 217:case 222:case 223:case 224:case 225:case 226:case 228:case 229:case 232:case 233:case 234:case 239:case 240:case 241:case 242:case 245:case 253:case 254:case 256:case 257:case 258:case 260:case 263:case 266:case 267:case 268:case 269:case 272:case 273:case 276:ql(95);break;default:Wl=$l}if(Wl==3353||Wl==4377||Wl==4889||Wl==5401||Wl==5913||Wl==16153||Wl==16665||Wl==17177||Wl==18055||Wl==18117||Wl==18175||Wl==18201||Wl==18713||Wl==21273||Wl==22297||Wl==24345||Wl==24857||Wl==28441||Wl==28953||Wl==31001||Wl==35609||Wl==36633||Wl==37657||Wl==38169||Wl==38681||Wl==39193||Wl==40217||Wl==40729||Wl==41241||Wl==41753||Wl==42265||Wl==42777||Wl==43289||Wl==43801||Wl==44313||Wl==44825||Wl==45849||Wl==46361||Wl==46873||Wl==47385||Wl==48409||Wl==48921||Wl==49945||Wl==50457||Wl==50969||Wl==52505||Wl==53017||Wl==53529||Wl==54041||Wl==54553||Wl==55065||Wl==56089||Wl==56601||Wl==57113||Wl==57625||Wl==58137||Wl==58649||Wl==61209||Wl==61721||Wl==62233||Wl==62745||Wl==63257||Wl==63769||Wl==64281||Wl==64793||Wl==65305||Wl==66329||Wl==66841||Wl==67865||Wl==68377||Wl==68889||Wl==69401||Wl==69913||Wl==70425||Wl==70937||Wl==71449||Wl==72985||Wl==73497||Wl==75545||Wl==76057||Wl==77081||Wl==78105||Wl==78617||Wl==79129||Wl==79641||Wl==80153||Wl==80665||Wl==82713||Wl==83225||Wl==83737||Wl==84249||Wl==84761||Wl==85273||Wl==85785||Wl==86297||Wl==86809||Wl==87321||Wl==88857||Wl==89369||Wl==89881||Wl==90905||Wl==91929||Wl==92953||Wl==93977||Wl==94489||Wl==95001||Wl==96025||Wl==96537||Wl==97049||Wl==99609||Wl==100121||Wl==100633||Wl==101145||Wl==101657||Wl==103705||Wl==104217||Wl==104729||Wl==105241||Wl==105753||Wl==106265||Wl==107801||Wl==110873||Wl==111385||Wl==112921||Wl==113945||Wl==114457||Wl==114969||Wl==115481||Wl==115993||Wl==117017||Wl==117529||Wl==118041||Wl==118553||Wl==119065||Wl==119577||Wl==120089||Wl==122649||Wl==123161||Wl==123673||Wl==124185||Wl==125721||Wl==126745||Wl==127257||Wl==127769||Wl==129817||Wl==130329||Wl==130841||Wl==131353||Wl==131865||Wl==132377||Wl==132889||Wl==133401||Wl==134425||Wl==134937||Wl==136473||Wl==136985||Wl==137497||Wl==138009||Wl==139545||Wl==140057||Wl==141593||Wl==144153||Wl==145177||Wl==147225){Wl=uc(20,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{vi(),Wl=-1}catch(a){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),Hi(),Wl=-5}catch(f){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),Ml(),Wl=-10}catch(l){Wl=-11}}}Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(20,Vl,Wl)}}switch(Wl){case-1:case 8:case 9:case 10:case 11:case 12935:case 12997:case 13055:case 13447:case 13509:case 13567:case 13959:case 14021:case 14079:case 19591:case 19653:case 19711:case 20103:case 20165:case 20223:case 21127:case 21189:case 21247:case 21639:case 21701:case 21759:case 22151:case 22213:case 22271:case 23175:case 23237:case 23295:case 24199:case 24261:case 24319:case 24711:case 24773:case 24831:case 25735:case 25797:case 25855:case 27783:case 27845:case 27903:case 28295:case 28357:case 28415:case 29831:case 29893:case 29951:case 30343:case 30405:case 30463:case 31367:case 31429:case 31487:case 31879:case 31941:case 31999:case 32391:case 32453:case 32511:case 32903:case 32965:case 33023:case 35463:case 35525:case 35583:case 35975:case 36037:case 36095:case 36487:case 36549:case 36607:case 39047:case 39109:case 39167:case 41095:case 41157:case 41215:case 41607:case 41669:case 41727:case 42119:case 42181:case 42239:case 43655:case 43717:case 43775:case 45191:case 45253:case 45311:case 45703:case 45765:case 45823:case 46215:case 46277:case 46335:case 46727:case 46789:case 46847:case 48775:case 48837:case 48895:case 51335:case 51397:case 51455:case 54407:case 54469:case 54527:case 56455:case 56517:case 56575:case 58503:case 58565:case 58623:case 61063:case 61125:case 61183:case 63111:case 63173:case 63231:case 63623:case 63685:case 63743:case 65159:case 65221:case 65279:case 66183:case 66245:case 66303:case 67719:case 67781:case 67839:case 71303:case 71365:case 71423:case 75911:case 75973:case 76031:case 76935:case 76997:case 77055:case 77959:case 78021:case 78079:case 78471:case 78533:case 78591:case 83079:case 83141:case 83199:case 84103:case 84165:case 84223:case 84615:case 84677:case 84735:case 85127:case 85189:case 85247:case 89735:case 89797:case 89855:case 90759:case 90821:case 90879:case 92807:case 92869:case 92927:case 93831:case 93893:case 93951:case 94343:case 94405:case 94463:case 96903:case 96965:case 97023:case 103559:case 103621:case 103679:case 104583:case 104645:case 104703:case 105095:case 105157:case 105215:case 107143:case 107205:case 107263:case 114823:case 114885:case 114943:case 116871:case 116933:case 116991:case 121479:case 121541:case 121599:case 123527:case 123589:case 123647:case 124039:case 124101:case 124159:case 129159:case 129221:case 129279:case 129671:case 129733:case 129791:case 130183:case 130245:case 130303:case 133255:case 133317:case 133375:case 139399:case 139461:case 139519:case 141447:case 141509:case 141567:case 142983:case 143045:case 143103:case 145543:case 145605:case 145663:case 146055:case 146117:case 146175:case 146567:case 146629:case 146687:case 147079:case 147141:case 147199:di();break;case 31:Si();break;case 35:Ci();break;case 32:Li();break;case-5:case 17926:case 17991:case 17993:case 17994:case 17995:case 17996:case 17998:case 18e3:case 18001:case 18002:case 18004:case 18005:case 18006:case 18007:case 18009:case 18010:case 18011:case 18012:case 18014:case 18015:case 18018:case 18019:case 18022:case 18023:case 18024:case 18025:case 18026:case 18027:case 18029:case 18030:case 18031:case 18032:case 18033:case 18034:case 18039:case 18040:case 18043:case 18044:case 18046:case 18047:case 18049:case 18050:case 18052:case 18053:case 18054:case 18056:case 18057:case 18058:case 18059:case 18062:case 18063:case 18068:case 18070:case 18072:case 18073:case 18075:case 18076:case 18077:case 18081:case 18082:case 18083:case 18084:case 18085:case 18086:case 18088:case 18090:case 18093:case 18094:case 18095:case 18097:case 18099:case 18101:case 18103:case 18104:case 18105:case 18107:case 18109:case 18115:case 18118:case 18122:case 18123:case 18124:case 18125:case 18126:case 18127:case 18130:case 18136:case 18137:case 18142:case 18143:case 18144:case 18145:case 18146:case 18148:case 18149:case 18152:case 18153:case 18154:case 18159:case 18160:case 18161:case 18162:case 18165:case 18173:case 18174:case 18176:case 18177:case 18178:case 18180:case 18182:case 18183:case 18186:case 18187:case 18188:case 18189:case 18192:case 18193:case 18196:Pi();break;case 144078:Oi();break;case 144134:_i();break;case 33:case 79:case 121:case 125:case 147:case 154:case 167:case 169:case 188:case 194:case 230:case 231:case 247:case 248:case 259:case 14854:case 14919:case 14921:case 14922:case 14923:case 14924:case 14926:case 14928:case 14929:case 14930:case 14931:case 14932:case 14933:case 14934:case 14935:case 14937:case 14938:case 14939:case 14940:case 14942:case 14943:case 14945:case 14946:case 14947:case 14950:case 14951:case 14952:case 14953:case 14954:case 14955:case 14957:case 14958:case 14959:case 14960:case 14961:case 14962:case 14967:case 14968:case 14970:case 14971:case 14972:case 14974:case 14975:case 14977:case 14978:case 14980:case 14981:case 14982:case 14983:case 14984:case 14985:case 14986:case 14987:case 14990:case 14991:case 14996:case 14998:case 15e3:case 15001:case 15003:case 15004:case 15005:case 15009:case 15010:case 15011:case 15012:case 15013:case 15014:case 15016:case 15018:case 15021:case 15022:case 15023:case 15025:case 15027:case 15029:case 15031:case 15032:case 15033:case 15035:case 15037:case 15043:case 15045:case 15046:case 15050:case 15051:case 15052:case 15053:case 15054:case 15055:case 15058:case 15064:case 15065:case 15068:case 15070:case 15071:case 15072:case 15073:case 15074:case 15076:case 15077:case 15080:case 15081:case 15082:case 15087:case 15088:case 15089:case 15090:case 15093:case 15097:case 15101:case 15102:case 15103:case 15104:case 15105:case 15106:case 15108:case 15110:case 15111:case 15114:case 15115:case 15116:case 15117:case 15120:case 15121:case 15124:ys();break;case-10:case 27929:Ol();break;case-11:case 10009:Sl();break;case 69:Ll();break;case 283:wl();break;default:qi()}ic.endNonterminal("PrimaryExpr",Vl)}function bl(){switch($l){case 187:ql(247);break;case 220:ql(245);break;case 281:ql(283);break;case 83:case 122:ql(253);break;case 97:case 249:ql(97);break;case 120:case 206:case 262:ql(148);break;case 135:case 197:case 255:ql(237);break;case 6:case 71:case 73:case 74:case 75:case 76:case 78:case 80:case 81:case 82:case 84:case 85:case 86:case 87:case 89:case 90:case 91:case 92:case 94:case 95:case 98:case 99:case 102:case 103:case 104:case 105:case 106:case 107:case 109:case 110:case 111:case 112:case 113:case 114:case 119:case 123:case 124:case 126:case 127:case 129:case 130:case 132:case 133:case 134:case 136:case 137:case 138:case 139:case 142:case 143:case 148:case 150:case 152:case 153:case 155:case 156:case 157:case 161:case 162:case 163:case 164:case 165:case 166:case 168:case 170:case 173:case 174:case 175:case 177:case 179:case 181:case 183:case 184:case 185:case 189:case 195:case 198:case 202:case 203:case 204:case 205:case 207:case 210:case 216:case 217:case 222:case 223:case 224:case 225:case 226:case 228:case 229:case 232:case 233:case 234:case 239:case 240:case 241:case 242:case 245:case 253:case 254:case 256:case 257:case 258:case 260:case 263:case 266:case 267:case 268:case 269:case 272:case 273:case 276:ql(95);break;default:Wl=$l}if(Wl==3353||Wl==4377||Wl==4889||Wl==5401||Wl==5913||Wl==16153||Wl==16665||Wl==17177||Wl==18055||Wl==18117||Wl==18175||Wl==18201||Wl==18713||Wl==21273||Wl==22297||Wl==24345||Wl==24857||Wl==28441||Wl==28953||Wl==31001||Wl==35609||Wl==36633||Wl==37657||Wl==38169||Wl==38681||Wl==39193||Wl==40217||Wl==40729||Wl==41241||Wl==41753||Wl==42265||Wl==42777||Wl==43289||Wl==43801||Wl==44313||Wl==44825||Wl==45849||Wl==46361||Wl==46873||Wl==47385||Wl==48409||Wl==48921||Wl==49945||Wl==50457||Wl==50969||Wl==52505||Wl==53017||Wl==53529||Wl==54041||Wl==54553||Wl==55065||Wl==56089||Wl==56601||Wl==57113||Wl==57625||Wl==58137||Wl==58649||Wl==61209||Wl==61721||Wl==62233||Wl==62745||Wl==63257||Wl==63769||Wl==64281||Wl==64793||Wl==65305||Wl==66329||Wl==66841||Wl==67865||Wl==68377||Wl==68889||Wl==69401||Wl==69913||Wl==70425||Wl==70937||Wl==71449||Wl==72985||Wl==73497||Wl==75545||Wl==76057||Wl==77081||Wl==78105||Wl==78617||Wl==79129||Wl==79641||Wl==80153||Wl==80665||Wl==82713||Wl==83225||Wl==83737||Wl==84249||Wl==84761||Wl==85273||Wl==85785||Wl==86297||Wl==86809||Wl==87321||Wl==88857||Wl==89369||Wl==89881||Wl==90905||Wl==91929||Wl==92953||Wl==93977||Wl==94489||Wl==95001||Wl==96025||Wl==96537||Wl==97049||Wl==99609||Wl==100121||Wl==100633||Wl==101145||Wl==101657||Wl==103705||Wl==104217||Wl==104729||Wl==105241||Wl==105753||Wl==106265||Wl==107801||Wl==110873||Wl==111385||Wl==112921||Wl==113945||Wl==114457||Wl==114969||Wl==115481||Wl==115993||Wl==117017||Wl==117529||Wl==118041||Wl==118553||Wl==119065||Wl==119577||Wl==120089||Wl==122649||Wl==123161||Wl==123673||Wl==124185||Wl==125721||Wl==126745||Wl==127257||Wl==127769||Wl==129817||Wl==130329||Wl==130841||Wl==131353||Wl==131865||Wl==132377||Wl==132889||Wl==133401||Wl==134425||Wl==134937||Wl==136473||Wl==136985||Wl==137497||Wl==138009||Wl==139545||Wl==140057||Wl==141593||Wl==144153||Wl==145177||Wl==147225){Wl=uc(20,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{vi(),oc(20,t,-1),Wl=-14}catch(a){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),Hi(),oc(20,t,-5),Wl=-14}catch(f){try{Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),Ml(),oc(20,t,-10),Wl=-14}catch(l){Wl=-11,Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(20,t,-11)}}}}}switch(Wl){case-1:case 8:case 9:case 10:case 11:case 12935:case 12997:case 13055:case 13447:case 13509:case 13567:case 13959:case 14021:case 14079:case 19591:case 19653:case 19711:case 20103:case 20165:case 20223:case 21127:case 21189:case 21247:case 21639:case 21701:case 21759:case 22151:case 22213:case 22271:case 23175:case 23237:case 23295:case 24199:case 24261:case 24319:case 24711:case 24773:case 24831:case 25735:case 25797:case 25855:case 27783:case 27845:case 27903:case 28295:case 28357:case 28415:case 29831:case 29893:case 29951:case 30343:case 30405:case 30463:case 31367:case 31429:case 31487:case 31879:case 31941:case 31999:case 32391:case 32453:case 32511:case 32903:case 32965:case 33023:case 35463:case 35525:case 35583:case 35975:case 36037:case 36095:case 36487:case 36549:case 36607:case 39047:case 39109:case 39167:case 41095:case 41157:case 41215:case 41607:case 41669:case 41727:case 42119:case 42181:case 42239:case 43655:case 43717:case 43775:case 45191:case 45253:case 45311:case 45703:case 45765:case 45823:case 46215:case 46277:case 46335:case 46727:case 46789:case 46847:case 48775:case 48837:case 48895:case 51335:case 51397:case 51455:case 54407:case 54469:case 54527:case 56455:case 56517:case 56575:case 58503:case 58565:case 58623:case 61063:case 61125:case 61183:case 63111:case 63173:case 63231:case 63623:case 63685:case 63743:case 65159:case 65221:case 65279:case 66183:case 66245:case 66303:case 67719:case 67781:case 67839:case 71303:case 71365:case 71423:case 75911:case 75973:case 76031:case 76935:case 76997:case 77055:case 77959:case 78021:case 78079:case 78471:case 78533:case 78591:case 83079:case 83141:case 83199:case 84103:case 84165:case 84223:case 84615:case 84677:case 84735:case 85127:case 85189:case 85247:case 89735:case 89797:case 89855:case 90759:case 90821:case 90879:case 92807:case 92869:case 92927:case 93831:case 93893:case 93951:case 94343:case 94405:case 94463:case 96903:case 96965:case 97023:case 103559:case 103621:case 103679:case 104583:case 104645:case 104703:case 105095:case 105157:case 105215:case 107143:case 107205:case 107263:case 114823:case 114885:case 114943:case 116871:case 116933:case 116991:case 121479:case 121541:case 121599:case 123527:case 123589:case 123647:case 124039:case 124101:case 124159:case 129159:case 129221:case 129279:case 129671:case 129733:case 129791:case 130183:case 130245:case 130303:case 133255:case 133317:case 133375:case 139399:case 139461:case 139519:case 141447:case 141509:case 141567:case 142983:case 143045:case 143103:case 145543:case 145605:case 145663:case 146055:case 146117:case 146175:case 146567:case 146629:case 146687:case 147079:case 147141:case 147199:vi();break;case 31:xi();break;case 35:ki();break;case 32:Ai();break;case-5:case 17926:case 17991:case 17993:case 17994:case 17995:case 17996:case 17998:case 18e3:case 18001:case 18002:case 18004:case 18005:case 18006:case 18007:case 18009:case 18010:case 18011:case 18012:case 18014:case 18015:case 18018:case 18019:case 18022:case 18023:case 18024:case 18025:case 18026:case 18027:case 18029:case 18030:case 18031:case 18032:case 18033:case 18034:case 18039:case 18040:case 18043:case 18044:case 18046:case 18047:case 18049:case 18050:case 18052:case 18053:case 18054:case 18056:case 18057:case 18058:case 18059:case 18062:case 18063:case 18068:case 18070:case 18072:case 18073:case 18075:case 18076:case 18077:case 18081:case 18082:case 18083:case 18084:case 18085:case 18086:case 18088:case 18090:case 18093:case 18094:case 18095:case 18097:case 18099:case 18101:case 18103:case 18104:case 18105:case 18107:case 18109:case 18115:case 18118:case 18122:case 18123:case 18124:case 18125:case 18126:case 18127:case 18130:case 18136:case 18137:case 18142:case 18143:case 18144:case 18145:case 18146:case 18148:case 18149:case 18152:case 18153:case 18154:case 18159:case 18160:case 18161:case 18162:case 18165:case 18173:case 18174:case 18176:case 18177:case 18178:case 18180:case 18182:case 18183:case 18186:case 18187:case 18188:case 18189:case 18192:case 18193:case 18196:Hi();break;case 144078:Mi();break;case 144134:Di();break;case 33:case 79:case 121:case 125:case 147:case 154:case 167:case 169:case 188:case 194:case 230:case 231:case 247:case 248:case 259:case 14854:case 14919:case 14921:case 14922:case 14923:case 14924:case 14926:case 14928:case 14929:case 14930:case 14931:case 14932:case 14933:case 14934:case 14935:case 14937:case 14938:case 14939:case 14940:case 14942:case 14943:case 14945:case 14946:case 14947:case 14950:case 14951:case 14952:case 14953:case 14954:case 14955:case 14957:case 14958:case 14959:case 14960:case 14961:case 14962:case 14967:case 14968:case 14970:case 14971:case 14972:case 14974:case 14975:case 14977:case 14978:case 14980:case 14981:case 14982:case 14983:case 14984:case 14985:case 14986:case 14987:case 14990:case 14991:case 14996:case 14998:case 15e3:case 15001:case 15003:case 15004:case 15005:case 15009:case 15010:case 15011:case 15012:case 15013:case 15014:case 15016:case 15018:case 15021:case 15022:case 15023:case 15025:case 15027:case 15029:case 15031:case 15032:case 15033:case 15035:case 15037:case 15043:case 15045:case 15046:case 15050:case 15051:case 15052:case 15053:case 15054:case 15055:case 15058:case 15064:case 15065:case 15068:case 15070:case 15071:case 15072:case 15073:case 15074:case 15076:case 15077:case 15080:case 15081:case 15082:case 15087:case 15088:case 15089:case 15090:case 15093:case 15097:case 15101:case 15102:case 15103:case 15104:case 15105:case 15106:case 15108:case 15110:case 15111:case 15114:case 15115:case 15116:case 15117:case 15120:case 15121:case 15124:bs();break;case-10:case 27929:Ml();break;case-11:case 10009:xl();break;case 69:Al();break;case 283:El();break;case-14:break;default:Ri()}}function wl(){ic.startNonterminal("JSONSimpleObjectUnion",Vl),Pl(283),Il(274),$l!=286&&(jl(),G()),Pl(286),ic.endNonterminal("JSONSimpleObjectUnion",Vl)}function El(){Hl(283),Il(274),$l!=286&&Y(),Hl(286)}function Sl(){ic.startNonterminal("ObjectConstructor",Vl),Pl(281),Il(277),$l!=287&&(jl(),Tl()),Pl(287),ic.endNonterminal("ObjectConstructor",Vl)}function xl(){Hl(281),Il(277),$l!=287&&Nl(),Hl(287)}function Tl(){ic.startNonterminal("PairConstructorList",Vl),Cl();for(;;){if($l!=42)break;Pl(42),Il(268),jl(),Cl()}ic.endNonterminal("PairConstructorList",Vl)}function Nl(){kl();for(;;){if($l!=42)break;Hl(42),Il(268),kl()}}function Cl(){ic.startNonterminal("PairConstructor",Vl);switch($l){case 78:ql(279);break;case 139:ql(187);break;case 161:ql(282);break;case 177:ql(178);break;case 187:ql(252);break;case 220:ql(248);break;case 223:ql(180);break;case 266:ql(191);break;case 83:case 122:ql(257);break;case 97:case 249:ql(149);break;case 111:case 222:ql(262);break;case 104:case 130:case 240:ql(165);break;case 135:case 197:case 255:ql(209);break;case 120:case 206:case 256:case 262:ql(167);break;case 121:case 125:case 167:case 188:case 194:case 230:case 231:ql(96);break;case 71:case 73:case 74:case 75:case 76:case 80:case 81:case 82:case 84:case 85:case 86:case 87:case 89:case 90:case 91:case 92:case 94:case 95:case 98:case 99:case 102:case 103:case 105:case 106:case 107:case 109:case 110:case 112:case 113:case 114:case 119:case 123:case 124:case 126:case 127:case 129:case 132:case 133:case 134:case 136:case 137:case 138:case 142:case 143:case 147:case 148:case 150:case 152:case 153:case 154:case 155:case 156:case 157:case 162:case 163:case 164:case 165:case 166:case 168:case 170:case 173:case 174:case 175:case 179:case 181:case 183:case 184:case 185:case 189:case 195:case 198:case 202:case 203:case 204:case 205:case 207:case 210:case 216:case 217:case 224:case 225:case 226:case 228:case 229:case 232:case 233:case 234:case 239:case 241:case 242:case 245:case 248:case 253:case 254:case 257:case 258:case 259:case 260:case 263:case 267:case 268:case 269:case 272:case 273:case 276:ql(144);break;default:Wl=$l}if(Wl==25735||Wl==25797||Wl==25855){Wl=uc(21,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Xf(),Wl=-1}catch(a){Wl=-2}Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(21,Vl,Wl)}}switch(Wl){case-2:case 19:case 25671:case 25673:case 25674:case 25675:case 25676:case 25678:case 25680:case 25681:case 25682:case 25683:case 25684:case 25685:case 25686:case 25687:case 25689:case 25690:case 25691:case 25692:case 25694:case 25695:case 25697:case 25698:case 25699:case 25702:case 25703:case 25704:case 25705:case 25706:case 25707:case 25709:case 25710:case 25711:case 25712:case 25713:case 25714:case 25719:case 25720:case 25721:case 25722:case 25723:case 25724:case 25725:case 25726:case 25727:case 25729:case 25730:case 25732:case 25733:case 25734:case 25736:case 25737:case 25738:case 25739:case 25742:case 25743:case 25747:case 25748:case 25750:case 25752:case 25753:case 25754:case 25755:case 25756:case 25757:case 25761:case 25762:case 25763:case 25764:case 25765:case 25766:case 25767:case 25768:case 25770:case 25773:case 25774:case 25775:case 25777:case 25779:case 25781:case 25783:case 25784:case 25785:case 25787:case 25788:case 25789:case 25794:case 25795:case 25798:case 25802:case 25803:case 25804:case 25805:case 25806:case 25807:case 25810:case 25816:case 25817:case 25820:case 25822:case 25823:case 25824:case 25825:case 25826:case 25828:case 25829:case 25830:case 25831:case 25832:case 25833:case 25834:case 25839:case 25840:case 25841:case 25842:case 25845:case 25848:case 25849:case 25853:case 25854:case 25856:case 25857:case 25858:case 25859:case 25860:case 25862:case 25863:case 25866:case 25867:case 25868:case 25869:case 25872:case 25873:case 25876:Ga();break;default:Wf()}Il(26),Pl(50),Il(267),jl(),Wf(),ic.endNonterminal("PairConstructor",Vl)}function kl(){switch($l){case 78:ql(279);break;case 139:ql(187);break;case 161:ql(282);break;case 177:ql(178);break;case 187:ql(252);break;case 220:ql(248);break;case 223:ql(180);break;case 266:ql(191);break;case 83:case 122:ql(257);break;case 97:case 249:ql(149);break;case 111:case 222:ql(262);break;case 104:case 130:case 240:ql(165);break;case 135:case 197:case 255:ql(209);break;case 120:case 206:case 256:case 262:ql(167);break;case 121:case 125:case 167:case 188:case 194:case 230:case 231:ql(96);break;case 71:case 73:case 74:case 75:case 76:case 80:case 81:case 82:case 84:case 85:case 86:case 87:case 89:case 90:case 91:case 92:case 94:case 95:case 98:case 99:case 102:case 103:case 105:case 106:case 107:case 109:case 110:case 112:case 113:case 114:case 119:case 123:case 124:case 126:case 127:case 129:case 132:case 133:case 134:case 136:case 137:case 138:case 142:case 143:case 147:case 148:case 150:case 152:case 153:case 154:case 155:case 156:case 157:case 162:case 163:case 164:case 165:case 166:case 168:case 170:case 173:case 174:case 175:case 179:case 181:case 183:case 184:case 185:case 189:case 195:case 198:case 202:case 203:case 204:case 205:case 207:case 210:case 216:case 217:case 224:case 225:case 226:case 228:case 229:case 232:case 233:case 234:case 239:case 241:case 242:case 245:case 248:case 253:case 254:case 257:case 258:case 259:case 260:case 263:case 267:case 268:case 269:case 272:case 273:case 276:ql(144);break;default:Wl=$l}if(Wl==25735||Wl==25797||Wl==25855){Wl=uc(21,Vl);if(Wl==0){var e=Xl,t=Vl,n=$l,r=Jl,i=Kl,s=Ql,o=Gl,u=Yl;try{Xf(),oc(21,t,-1),Wl=-3}catch(a){Wl=-2,Xl=e,Vl=t,$l=n,$l==0?cc=t:(Jl=r,Kl=i,Ql=s,Ql==0?cc=i:(Gl=o,Yl=u,cc=u)),oc(21,t,-2)}}}switch(Wl){case-2:case 19:case 25671:case 25673:case 25674:case 25675:case 25676:case 25678:case 25680:case 25681:case 25682:case 25683:case 25684:case 25685:case 25686:case 25687:case 25689:case 25690:case 25691:case 25692:case 25694:case 25695:case 25697:case 25698:case 25699:case 25702:case 25703:case 25704:case 25705:case 25706:case 25707:case 25709:case 25710:case 25711:case 25712:case 25713:case 25714:case 25719:case 25720:case 25721:case 25722:case 25723:case 25724:case 25725:case 25726:case 25727:case 25729:case 25730:case 25732:case 25733:case 25734:case 25736:case 25737:case 25738:case 25739:case 25742:case 25743:case 25747:case 25748:case 25750:case 25752:case 25753:case 25754:case 25755:case 25756:case 25757:case 25761:case 25762:case 25763:case 25764:case 25765:case 25766:case 25767:case 25768:case 25770:case 25773:case 25774:case 25775:case 25777:case 25779:case 25781:case 25783:case 25784:case 25785:case 25787:case 25788:case 25789:case 25794:case 25795:case 25798:case 25802:case 25803:case 25804:case 25805:case 25806:case 25807:case 25810:case 25816:case 25817:case 25820:case 25822:case 25823:case 25824:case 25825:case 25826:case 25828:case 25829:case 25830:case 25831:case 25832:case 25833:case 25834:case 25839:case 25840:case 25841:case 25842:case 25845:case 25848:case 25849:case 25853:case 25854:case 25856:case 25857:case 25858:case 25859:case 25860:case 25862:case 25863:case 25866:case 25867:case 25868:case 25869:case 25872:case 25873:case 25876:Ya();break;case-3:break;default:Xf()}Il(26),Hl(50),Il(267),Xf()}function Ll(){ic.startNonterminal("ArrayConstructor",Vl),Pl(69),Il(273),$l!=70&&(jl(),G()),Pl(70),ic.endNonterminal("ArrayConstructor",Vl)}function Al(){Hl(69),Il(273),$l!=70&&Y(),Hl(70)}function Ol(){ic.startNonterminal("BlockExpr",Vl),Pl(281),Il(281),jl(),of(),Pl(287),ic.endNonterminal("BlockExpr",Vl)}function Ml(){Hl(281),Il(281),uf(),Hl(287)}function _l(){ic.startNonterminal("FunctionDecl",Vl),Pl(147),Il(246),jl(),$a(),Il(22),Pl(35),Il(98),$l==31&&(jl(),U()),Pl(38),Il(158),$l==80&&(jl(),Dl()),Il(122);switch($l){case 281:Pl(281),Il(281),jl(),of(),Pl(287);break;default:Pl(134)}ic.endNonterminal("FunctionDecl",Vl)}function Dl(){ic.startNonterminal("ReturnType",Vl),Pl(80),Il(254),jl(),Ls(),ic.endNonterminal("ReturnType",Vl)}function Pl(e){$l==e?(jl(),ic.terminal(i.TOKEN[$l],Jl,Kl>fc?fc:Kl),Xl=Jl,Vl=Kl,$l=Ql,$l!=0&&(Jl=Gl,Kl=Yl,Ql=0)):zl(Jl,Kl,0,$l,e)}function Hl(e){$l==e?(Xl=Jl,Vl=Kl,$l=Ql,$l!=0&&(Jl=Gl,Kl=Yl,Ql=0)):zl(Jl,Kl,0,$l,e)}function Bl(e){var t=Xl,n=Vl,r=$l,i=Jl,s=Kl;$l=e,Jl=lc,Kl=cc,Ql=0,Va(),Xl=t,Vl=n,$l=r,$l!=0&&(Jl=i,Kl=s)}function jl(){Vl!=Jl&&(Xl=Vl,Vl=Jl,ic.whitespace(Xl,Vl))}function Fl(e){var t;for(;;){t=hc(e);if(t!=22){if(t!=37)break;Bl(t)}}return t}function Il(e){$l==0&&($l=Fl(e),Jl=lc,Kl=cc)}function ql(e){Ql==0&&(Ql=Fl(e),Gl=lc,Yl=cc),Wl=Ql<<9|$l}function Rl(e){$l==0&&($l=hc(e),Jl=lc,Kl=cc)}function Ul(e){Ql==0&&(Ql=hc(e),Gl=lc,Yl=cc),Wl=Ql<<9|$l}function zl(e,t,r,i,s){throw t>ec&&(Zl=e,ec=t,tc=r,nc=i,rc=s),new n.ParseException(Zl,ec,tc,nc,rc)}function oc(e,t,n){sc[(t<<5)+e]=n}function uc(e,t){var n=sc[(t<<5)+e];return typeof n!="undefined"?n:0}function hc(e){var t=!1;lc=cc;var n=cc,r=i.INITIAL[e],s=0;for(var o=r&8191;o!=0;){var u,a=n<fc?ac.charCodeAt(n):0;++n;if(a<128)u=i.MAP0[a];else if(a<55296){var f=a>>4;u=i.MAP1[(a&15)+i.MAP1[(f&31)+i.MAP1[f>>5]]]}else{if(a<56320){var f=n<fc?ac.charCodeAt(n):0;f>=56320&&f<57344&&(++n,a=((a&1023)<<10)+(f&1023)+65536,t=!0)}var l=0,c=5;for(var h=3;;h=c+l>>1){if(i.MAP2[h]>a)c=h-1;else{if(!(i.MAP2[6+h]<a)){u=i.MAP2[12+h];break}l=h+1}if(l>c){u=0;break}}}s=o;var p=(u<<13)+o-1;o=i.TRANSITION[(p&15)+i.TRANSITION[p>>4]],o>8191&&(r=o,o&=8191,cc=n)}r>>=13;if(r==0){cc=n-1;var f=cc<fc?ac.charCodeAt(cc):0;return f>=56320&&f<57344&&--cc,zl(lc,cc,s,-1,-1)}if(t)for(var d=r>>9;d>0;--d){--cc;var f=cc<fc?ac.charCodeAt(cc):0;f>=56320&&f<57344&&--cc}else cc-=r>>9;return(r&511)-1}r(e,t);var n=this;this.ParseException=function(e,t,n,r,i){var s=e,o=t,u=n,a=r,f=i;this.getBegin=function(){return s},this.getEnd=function(){return o},this.getState=function(){return u},this.getExpected=function(){return f},this.getOffending=function(){return a},this.getMessage=function(){return a<0?"lexical analysis failed":"syntax error"}},this.getInput=function(){return ac},this.getOffendingToken=function(e){var t=e.getOffending();return t>=0?i.TOKEN[t]:null},this.getExpectedTokenSet=function(e){var t;return e.getExpected()<0?t=i.getTokenSet(-e.getState()):t=[i.TOKEN[e.getExpected()]],t},this.getErrorMessage=function(e){var t=this.getExpectedTokenSet(e),n=this.getOffendingToken(e),r=ac.substring(0,e.getBegin()),i=r.split("\n"),s=i.length,o=i[s-1].length+1,u=e.getEnd()-e.getBegin();return e.getMessage()+(n==null?"":", found "+n)+"\nwhile expecting "+(t.length==1?t[0]:"["+t.join(", ")+"]")+"\n"+(u==0||n!=null?"":"after successfully scanning "+u+" characters beginning ")+"at line "+s+", column "+o+":\n..."+ac.substring(e.getBegin(),Math.min(ac.length,e.getBegin()+64))+"..."},this.parse_XQuery=function(){ic.startNonterminal("XQuery",Vl),Il(278),jl(),o(),Pl(25),ic.endNonterminal("XQuery",Vl)};var Wl,Xl,Vl,$l,Jl,Kl,Ql,Gl,Yl,Zl,ec,tc,nc,rc,ic,sc,ac,fc,lc,cc};r.getTokenSet=function(e){var t=[],n=e<0?-e:INITIAL[e]&8191;for(var i=0;i<289;i+=32){var s=i,o=(i>>5)*4317+n-1,u=o>>2,a=u>>2,f=r.EXPECTED[(o&3)+r.EXPECTED[(u&3)+r.EXPECTED[(a&15)+r.EXPECTED[a>>4]]]];for(;f!=0;f>>>=1,++s)(f&1)!=0&&t.push(r.TOKEN[s])}return t},r.MAP0=[71,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,17,17,17,17,17,17,17,17,17,18,19,20,21,22,23,24,25,26,27,28,29,26,30,30,30,30,30,31,32,33,30,30,34,30,30,35,30,30,30,36,30,30,37,38,39,40,30,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,40,40],r.MAP1=[108,124,214,214,214,214,214,214,214,214,214,214,214,214,214,214,156,181,181,181,181,181,214,215,213,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,247,261,277,293,309,355,371,387,423,423,423,415,339,331,339,331,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,440,440,440,440,440,440,440,324,339,339,339,339,339,339,339,339,401,423,423,424,422,423,423,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,338,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,423,71,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,17,17,17,17,17,17,17,17,17,18,19,20,21,22,23,24,25,26,27,28,29,26,30,30,30,30,30,31,32,33,30,30,30,30,30,30,30,30,30,30,30,30,30,30,40,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,34,30,30,35,30,30,30,36,30,30,37,38,39,40,30,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,40,40,40,40,40,40,40,40,40,40,40,40,30,30,40,40,40,40,40,40,40,70,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70],r.MAP2=[57344,63744,64976,65008,65536,983040,63743,64975,65007,65533,983039,1114111,40,30,40,30,30,40],r.INITIAL=[1,24578,3,4,5,6,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,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290],r.TRANSITION=[37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,36864,36899,36883,36883,36883,36903,36883,36883,36883,36883,36883,36926,36919,36883,36883,36879,36883,36883,36942,36991,37318,37318,41289,37087,37318,37318,37010,37318,37318,37318,37318,37318,65657,40192,38525,37318,37318,39335,40192,38527,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,37318,37318,37318,37318,48276,37318,37318,37318,37318,37318,67919,57964,39727,39739,37318,37318,72403,39755,36991,37318,37318,41289,37087,37318,37318,37010,39794,37318,37318,37318,37318,65657,40192,38525,37318,37318,39813,40192,39835,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39854,39870,37318,37318,37318,46325,37318,37318,36994,37318,61657,45847,57964,37318,37318,61650,62405,62409,50496,39889,37318,37318,41289,37087,37318,44009,37010,37318,37318,37318,37318,37318,65657,40192,38525,37318,37318,39335,40192,45833,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39908,62747,37318,37318,37318,42026,65655,37318,73568,65651,65646,39935,62736,68791,45102,45088,45095,68779,39950,36991,37318,37318,41289,39994,37318,45426,37010,37318,37318,37318,37318,37318,65657,40192,38525,37318,37318,39335,40192,39370,40016,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,40039,69458,41098,41041,37318,46044,44842,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,47580,37318,37318,37318,48276,40073,37318,37015,71422,71423,40094,57964,37318,37318,67783,40130,40134,40150,36991,37318,37318,41289,37087,37318,37318,37010,37318,37318,37318,37318,37318,65657,40192,38525,37318,37318,40186,40192,38527,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,37318,37318,37318,37318,48276,71599,37318,37318,37318,37318,67919,40209,37318,37318,66772,40222,40225,40241,36991,37318,37318,41289,37087,37318,37318,37010,37318,37318,37318,37318,37318,65657,40192,38525,37318,37318,39335,40192,38527,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,37318,37318,37318,37318,48276,37318,37318,37318,37318,37318,71606,73347,37318,37318,37318,37318,37318,40283,40324,37318,37318,41289,37087,37318,37318,37010,37318,37318,37318,37318,37318,65657,40192,38525,37318,37318,39335,40192,38527,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,40344,37116,37202,37162,40378,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,40416,40432,37318,37318,37318,48315,37318,37318,37526,37318,62612,40451,57964,37318,37318,62605,65082,65086,40487,40535,37318,37318,41289,37087,37318,37318,40554,37318,37318,37318,37318,37318,65657,40192,38525,37318,37318,39335,40192,38131,40575,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,40598,40656,40697,40697,40697,40663,40736,40697,40698,40727,40642,40679,40626,40693,40745,40613,40752,40714,40768,36991,37318,37318,40817,40815,37318,37318,37010,37318,37318,37318,37318,37318,65657,40192,38525,37318,37318,39335,40192,38527,37031,44584,37054,40804,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,43152,37318,37318,37318,48276,40833,37318,37318,73511,37318,67919,57964,40868,40872,43155,43156,43784,40888,36991,37318,37318,41289,40924,37318,37318,37010,37318,37318,37318,37318,37318,65657,40192,38525,37318,37318,39335,40192,38527,37031,44584,37054,40942,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,43775,37318,37318,37318,48276,37318,37318,37318,37318,69945,73273,57964,40977,41007,44794,41023,73756,40991,36991,37318,37318,41289,37087,37318,37318,37010,37318,37318,37318,37318,37318,65657,40192,38525,37318,37318,39335,40192,38527,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,41058,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,37318,37318,37318,37318,48276,37318,37318,37318,37318,45645,38564,57964,41115,41135,37318,41119,41135,41149,36991,37318,37318,41289,37087,37318,37318,37010,37318,37318,37318,37318,37318,65657,40192,38525,37318,37318,39335,40192,38527,37031,44584,37054,37076,37318,37318,37301,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,62620,37318,37318,37318,48276,62315,37318,37318,42112,62617,51150,68655,68669,68671,37318,37318,74e3,41165,36991,37318,37318,41289,37087,37318,37318,37010,37318,37318,37318,37318,37318,65657,40192,38525,37318,37318,39335,40192,38527,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,41215,37318,37318,37318,37318,48276,37318,37318,37318,37318,37318,67919,57964,41238,41258,37318,41242,41258,41272,36991,37318,37318,41289,37087,37318,37318,37010,37318,37318,37318,37318,37318,44404,72644,50028,41369,65498,47282,62003,69205,37318,62433,37318,68839,45752,41288,37301,44633,37318,37318,37318,37318,73164,72644,41305,72644,72644,41324,38775,41542,41542,58552,65498,52179,65498,65498,52319,41461,41342,41461,41461,60376,37318,37318,37318,37318,37318,37318,57380,44576,38329,37318,37318,73164,72644,72644,72644,72644,72644,41363,41542,41542,41542,41542,41542,65493,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,47041,57802,45001,37318,37318,37318,37318,37318,62575,37318,37318,71516,41385,72644,72644,72644,72645,41405,67865,41542,58857,41542,41542,46917,69302,65498,55881,65498,65498,53308,58621,41461,41722,41461,41461,47863,54854,37318,37318,37318,37318,64802,37318,37318,72642,48855,72644,72644,72644,38767,41542,41439,41542,41542,41444,65497,64981,65498,65498,65498,59803,41461,41460,41461,41461,47863,54854,37318,37318,69109,41478,37318,60498,72644,72644,70521,58547,41542,41542,60742,46770,65498,65498,73471,59798,41461,41461,70944,47288,64766,37318,37318,37507,37318,71005,72644,60920,59569,41542,41542,72922,65498,65498,48896,41461,41461,46878,37318,60844,41498,41222,67506,72644,41518,41541,58729,41559,65498,46559,41593,41462,56939,50451,37318,66947,41614,41423,73664,58829,59801,41638,49498,41664,52412,41686,41702,41738,63218,38594,66255,64873,73961,46828,73161,59759,73663,59797,47605,39543,41802,41825,41848,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,37318,37318,37318,37318,48276,37318,37318,37318,37318,37318,45787,57964,41925,72170,37318,38278,38288,41945,36991,37318,37318,41289,37087,37318,37318,41981,37318,37318,37318,37318,37318,65657,40192,38525,37318,37318,69382,40192,38527,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,42002,37318,37318,37318,45026,37318,37318,37318,37318,37318,67919,57964,42022,71555,37318,43019,43028,71570,36991,37318,37318,41289,37087,37318,37318,37010,42042,37318,73045,37318,37318,65657,40192,38525,37318,37318,39335,40192,45833,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,42061,37318,37318,37318,48276,37318,37318,37318,37318,37318,50713,57964,37318,37318,37318,38993,38997,42078,42128,37318,37318,41289,37087,37318,37318,42147,37318,37318,37318,37318,37318,44404,72644,50028,41369,65498,42168,62003,69205,37318,37318,37318,68839,37318,37318,39275,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,41324,41542,41542,41542,58552,65498,65498,65498,65498,57854,41461,41461,41461,41461,64567,42190,37318,37318,37318,37318,37318,42212,37318,37318,37318,37318,73164,72644,72644,72644,72644,72644,41363,41542,41542,41542,41542,41542,65493,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,67436,42249,37318,37318,37318,37318,37318,44403,37318,37318,37318,72643,72644,72644,72644,72644,72187,38772,41542,41542,41542,41542,41542,72266,65498,65498,65498,65498,65498,59800,41461,41461,41461,41461,41461,47863,51497,37318,37318,37318,37318,37318,37318,37318,72642,72644,72644,72644,72644,42270,41542,41542,41542,41542,49331,65497,65498,65498,65498,65498,59803,41461,41461,41461,41461,47863,47501,37318,37318,37318,37318,37318,60498,72644,72644,72644,42291,41542,41542,41542,59595,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,63809,37318,37318,37318,49242,42389,37318,37318,42312,41767,44524,59934,42356,42367,45136,42383,44513,42405,42445,37318,37318,40926,42420,37318,37318,37010,37318,37318,37318,37318,37318,65657,40192,44142,43528,42807,74542,43714,44329,37031,44584,37054,42466,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,42495,44053,42520,44234,42536,42631,42566,42582,42617,43323,74548,42732,42652,43181,43457,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,74695,44148,43301,42504,44146,43812,43314,42636,43906,44107,42807,42594,42699,42706,42722,43750,42901,42677,43141,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,42748,42962,43618,43603,43820,43354,42764,44271,43892,42788,42804,42826,43918,42855,43210,42882,42898,42920,44134,44337,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,42949,44040,42992,42978,43271,43008,43044,42839,43084,44099,43110,43126,43172,43197,43740,43442,43226,43242,38263,37318,38304,37318,38354,38370,45231,38397,38413,43259,44205,43287,43339,74705,42601,43379,43395,43411,42683,43427,43493,43509,57783,51848,38545,38580,73050,38677,38610,43544,43363,43588,43648,42772,43664,43059,43680,43709,43730,43766,38739,38791,38841,38876,38942,38892,43800,43836,43632,43878,43941,43957,42665,43973,43989,39013,39048,39078,44025,44069,44085,43094,44123,43693,44164,39249,55484,44195,43559,43068,43925,39327,39819,44240,42810,42904,39356,44221,43849,44282,42866,45051,43520,43862,42933,39494,44256,44298,44314,39590,43572,44353,42550,44369,44420,44431,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,37091,37318,37318,37318,48276,39140,44447,37318,67184,67184,50155,62190,71955,71957,37318,37089,71946,44465,36991,37318,37318,41289,37087,37318,37318,37010,37318,37318,37318,37318,37318,65657,40192,38525,37318,37318,39335,40192,38527,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,44502,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38381,36956,50180,37398,37414,37436,50351,44540,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,44565,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,44600,38038,38061,37792,39434,44649,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,44665,37459,38432,38451,37229,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,37318,37318,37318,37318,48276,37318,37318,37318,37318,37318,37318,73156,44700,44701,37318,74225,74229,44717,36991,37318,37318,41289,37087,37318,37318,37010,37318,37318,46650,37318,37318,65657,40192,38525,37318,37318,39335,40192,44756,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,44775,67647,37318,37318,37318,48276,37318,37318,37318,37318,37318,67919,57964,44810,44811,37318,37318,74488,44827,44876,37318,37318,41289,37087,37318,37318,37010,37318,37318,44898,37318,37318,65657,40192,38525,37318,37318,39335,40192,44921,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,44940,44949,37318,37318,37318,45580,37318,37318,37318,37318,37318,67919,57964,44969,44970,37318,37318,68795,44986,45022,37318,37318,41289,37087,37318,37318,37010,37318,37318,72142,37318,37318,65657,40192,38525,37318,37318,39335,40192,38201,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,45042,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45074,37318,37318,37318,37318,48276,59955,37318,37318,37318,59954,73317,57964,37318,45118,37318,37318,45127,45152,36991,37318,37318,41289,37087,37318,37318,37010,45201,37318,37318,37318,37318,65657,40192,38525,37318,37318,45220,40192,45247,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,37318,37318,37318,37318,48276,37318,37318,37318,37318,37318,67919,57964,37318,37318,37318,46105,37318,45266,36991,37318,37318,41289,37087,37318,37318,37010,37318,37318,37318,37318,37318,65657,40192,38525,37318,37318,39335,40192,38527,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,37318,44953,37318,37318,37318,37318,37318,67919,57964,37318,37318,45323,45350,63443,47e3,65689,37318,37318,41289,37087,37318,37318,37318,37318,37318,37318,37318,37318,44404,72644,50028,41369,65498,47282,62003,72217,37318,37318,37318,68839,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,45386,41542,41542,41542,52709,65498,65498,65498,65498,57854,41461,41461,41461,41461,64567,41960,37318,37318,37318,37318,37318,44399,37318,37318,37318,37318,73164,72644,72644,72644,72644,72644,41363,41542,41542,41542,41542,41542,65493,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,63696,45404,37318,37318,37318,37318,37318,44403,37318,37318,37318,72643,72644,72644,72644,72644,72645,38772,41542,41542,41542,41542,41542,45363,65498,65498,65498,65498,65498,59800,41461,41461,41461,41461,41461,47863,51497,37318,37318,37318,37318,47785,37318,37318,72642,72644,72644,72644,72644,61913,41542,41542,41542,41542,48876,65497,65498,65498,65498,65498,59803,41461,41461,41461,41461,47863,47501,37318,37318,37318,37318,37318,60498,72644,72644,72644,42291,41542,41542,41542,59595,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,45425,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,37318,44953,37318,37318,37318,37318,37318,67919,57964,37318,37318,45323,45350,63443,47e3,65689,37318,37318,41289,37087,37318,37318,37318,37318,37318,37318,37318,37318,44404,72644,50028,41369,65498,47282,62003,72217,37318,37318,37318,68839,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,45386,41542,41542,41542,52709,65498,65498,65498,65498,57854,41461,41461,41461,41461,64567,41960,37318,37318,37318,37318,37318,44399,37318,37318,37318,37318,73164,72644,72644,72644,72644,72644,41363,41542,41542,41542,41542,41542,65493,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,63696,45404,37318,37318,37318,37318,37318,44403,37318,37318,37318,72643,72644,72644,72644,72644,72645,38772,41542,41542,41542,41542,41542,45363,65498,65498,65498,65498,65498,59800,41461,41461,41461,41461,41461,47863,51497,37318,37318,37318,37318,37318,37318,37318,72642,72644,72644,72644,72644,61913,41542,41542,41542,41542,48876,65497,65498,65498,65498,65498,59803,41461,41461,41461,41461,47863,47501,37318,37318,37318,37318,37318,60498,72644,72644,72644,42291,41542,41542,41542,59595,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,37318,44953,37318,37318,37318,37318,37318,67919,57964,37318,37318,45323,45350,63443,47e3,65689,37318,37318,41289,37087,37318,37318,37318,37318,37318,37318,37318,37318,44404,72644,50028,41369,65498,47282,62003,72217,37318,37318,37318,68839,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,45386,41542,41542,41542,52709,65498,65498,65498,65498,57854,41461,41461,41461,41461,64567,41960,37318,37318,37318,37318,37318,44399,68819,37318,37318,37318,73164,72644,72644,72644,72644,72644,41363,41542,41542,41542,41542,41542,65493,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,63696,45404,37318,37318,37318,37318,37318,44403,37318,37318,37318,72643,72644,72644,72644,72644,72645,38772,41542,41542,41542,41542,41542,45363,65498,65498,65498,65498,65498,59800,41461,41461,41461,41461,41461,47863,51497,37318,37318,37318,37318,37318,37318,37318,72642,72644,72644,72644,72644,61913,41542,41542,41542,41542,48876,65497,65498,65498,65498,65498,59803,41461,41461,41461,41461,47863,47501,37318,37318,37318,37318,37318,60498,72644,72644,72644,42291,41542,41542,41542,59595,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,37318,44953,37318,37318,37318,37318,37318,67919,57964,37318,37318,45323,45350,63443,47e3,65689,37318,37318,41289,37087,37318,37318,37318,37318,37318,37318,37318,37318,44404,72644,50028,41369,65498,47282,62003,72217,37318,37318,37318,68839,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,45386,41542,41542,41542,52709,65498,65498,65498,65498,57854,41461,41461,41461,41461,64567,41960,37318,37318,37318,37318,37318,44399,37318,37318,37318,37318,73164,72644,72644,72644,72644,72644,41363,41542,41542,41542,41542,41542,65493,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,63696,45404,37318,37318,37318,37318,37318,45442,37318,37318,37318,72643,72644,72644,72644,72644,72645,38772,41542,41542,41542,41542,41542,45363,65498,65498,65498,65498,65498,59800,41461,41461,41461,41461,41461,47863,51497,37318,37318,37318,37318,37318,37318,37318,72642,72644,72644,72644,72644,61913,41542,41542,41542,41542,48876,65497,65498,65498,65498,65498,59803,41461,41461,41461,41461,47863,47501,37318,37318,37318,37318,37318,60498,72644,72644,72644,42291,41542,41542,41542,59595,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,37318,44953,37318,37318,37318,37318,37318,67919,57964,37318,37318,45323,45350,63443,47e3,65689,37318,37318,41289,37087,37318,37318,50781,37318,37318,37318,37318,37318,44404,72644,50028,41369,65498,47282,62003,72217,37318,37318,37318,68839,37318,37318,53518,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,45386,41542,41542,41542,52709,65498,65498,65498,65498,57854,41461,41461,41461,41461,64567,41960,37318,37318,37318,37318,37318,44399,37318,37318,37318,37318,73164,72644,72644,72644,72644,72644,41363,41542,41542,41542,41542,41542,65493,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,63696,45404,37318,37318,37318,37318,37318,44403,37318,37318,37318,72643,72644,72644,72644,72644,72645,38772,41542,41542,41542,41542,41542,45363,65498,65498,65498,65498,65498,59800,41461,41461,41461,41461,41461,47863,51497,37318,37318,37318,37318,37318,37318,37318,72642,72644,72644,72644,72644,61913,41542,41542,41542,41542,48876,65497,65498,65498,65498,65498,59803,41461,41461,41461,41461,47863,47501,37318,37318,37318,37318,37318,60498,72644,72644,72644,42291,41542,41542,41542,59595,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,37318,44953,37318,37318,37318,37318,37318,67919,57964,37318,37318,45323,45350,63443,47e3,65689,37318,37318,41289,37087,37318,37318,37318,37318,37318,37318,37318,37318,44404,72644,50028,41369,65498,47282,62003,72217,37318,37318,37318,68839,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,45386,41542,41542,41542,52709,65498,65498,65498,65498,57854,41461,41461,41461,41461,60376,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,72644,41363,41542,41542,41542,41542,41542,65493,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,47041,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,72643,72644,72644,72644,72644,72645,38772,41542,41542,41542,41542,41542,45363,65498,65498,65498,65498,65498,59800,41461,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,37318,37318,72642,72644,72644,72644,72644,38767,41542,41542,41542,41542,41444,65497,65498,65498,65498,65498,59803,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,60498,72644,72644,72644,58547,41542,41542,41542,46770,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,37318,44953,37318,37318,37318,37318,37318,67919,57964,37318,37318,45323,45350,63443,47e3,65689,37318,37318,41289,37087,37318,37318,37318,37318,37318,37318,37318,37318,44404,72644,50028,41369,65498,47282,62003,65804,37318,37318,37318,68839,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,45386,41542,41542,41542,52709,65498,65498,65498,65498,57854,41461,41461,41461,41461,60376,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,72644,41363,41542,41542,41542,41542,41542,65493,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,47041,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,72643,72644,72644,72644,72644,72645,38772,41542,41542,41542,41542,41542,45363,65498,65498,65498,65498,65498,59800,41461,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,37318,37318,72642,72644,72644,72644,72644,38767,41542,41542,41542,41542,41444,65497,65498,65498,65498,65498,59803,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,60498,72644,72644,72644,58547,41542,41542,41542,46770,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,37318,44953,37318,37318,37318,37318,37318,67919,57964,37318,37318,45323,45350,63443,48653,65689,37318,37318,41289,37087,37318,37318,37318,37318,37318,37318,37318,37318,44404,72644,50028,41369,65498,47282,62003,72217,37318,37318,37318,68839,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,45386,41542,41542,41542,52709,65498,65498,65498,65498,57854,41461,41461,41461,41461,60376,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,72644,41363,41542,41542,41542,41542,41542,65493,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,47041,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,72643,72644,72644,72644,72644,72645,38772,41542,41542,41542,41542,41542,45363,65498,65498,65498,65498,65498,59800,41461,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,37318,37318,72642,72644,72644,72644,72644,38767,41542,41542,41542,41542,41444,65497,65498,65498,65498,65498,59803,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,60498,72644,72644,72644,58547,41542,41542,41542,46770,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,37318,44953,37318,37318,37318,37318,37318,67919,60153,37318,37318,45323,45350,63443,47e3,65689,37318,37318,41289,37087,37318,37318,37318,37318,37318,37318,37318,37318,44404,72644,50028,41369,65498,47282,62003,72217,37318,37318,37318,68839,37318,37318,37318,37318,45477,37318,37318,37318,73164,72644,72644,72644,72644,45386,41542,41542,41542,52709,65498,65498,65498,65498,57854,41461,41461,41461,41461,60376,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,72644,41363,41542,41542,41542,41542,41542,65493,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,47041,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,72643,72644,72644,72644,72644,72645,38772,41542,41542,41542,41542,41542,45363,65498,65498,65498,65498,65498,59800,41461,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,37318,37318,72642,72644,72644,72644,72644,38767,41542,41542,41542,41542,41444,65497,65498,65498,65498,65498,59803,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,60498,72644,72644,72644,58547,41542,41542,41542,46770,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,37318,44953,37318,37318,37318,37318,37318,67919,57964,37318,37318,45496,45525,45509,45539,65689,37318,37318,41289,37087,37318,37318,37318,37318,37318,37318,37318,37318,44404,72644,50028,41369,65498,47282,62003,72217,37318,37318,37318,68839,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,45386,41542,41542,41542,52709,65498,65498,65498,65498,57854,41461,41461,41461,41461,60376,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,72644,41363,41542,41542,41542,41542,41542,65493,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,47041,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,72643,72644,72644,72644,72644,72645,38772,41542,41542,41542,41542,41542,45363,65498,65498,65498,65498,65498,59800,41461,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,37318,37318,72642,72644,72644,72644,72644,38767,41542,41542,41542,41542,41444,65497,65498,65498,65498,65498,59803,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,60498,72644,72644,72644,58547,41542,41542,41542,46770,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,37318,44953,37318,37318,37318,37318,37318,67919,57964,37318,37318,45323,45350,63443,47e3,65689,37318,37318,41289,37087,37318,37318,37318,37318,37318,37318,37318,37318,44404,72644,50028,41369,65498,47282,62003,72217,37318,37318,37318,68839,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,45386,41542,41542,41542,52709,65498,65498,65498,65498,57854,41461,41461,41461,41461,60376,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,72644,41363,41542,41542,41542,41542,41542,65493,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,47041,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,72643,72644,72644,72644,72644,72645,38772,41542,41542,41542,41542,41542,45363,65498,65498,65498,65498,65498,59800,41461,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,37318,37318,72642,72644,72644,72644,72644,38767,41542,41542,41542,41542,41444,65497,65498,65498,65498,65498,59803,41461,41461,41461,41461,47863,54854,37318,37318,64785,37318,37318,60498,72644,72644,72644,58547,41542,41542,41542,46770,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45555,37318,37318,37318,37318,44953,37318,37318,37318,37318,37318,67919,57964,37318,37318,45323,45350,63443,47e3,65689,37318,37318,41289,37087,37318,37318,37318,37318,37318,37318,37318,37318,44404,72644,50028,41369,65498,47282,62003,72217,37318,37318,37318,68839,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,45386,41542,41542,41542,52709,65498,65498,65498,65498,57854,41461,41461,41461,41461,60376,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,72644,41363,41542,41542,41542,41542,41542,65493,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,47041,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,72643,72644,72644,72644,72644,72645,38772,41542,41542,41542,41542,41542,45363,65498,65498,65498,65498,65498,59800,41461,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,37318,37318,72642,72644,72644,72644,72644,38767,41542,41542,41542,41542,41444,65497,65498,65498,65498,65498,59803,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,60498,72644,72644,72644,58547,41542,41542,41542,46770,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,38529,37318,37318,37318,48276,37318,37318,37318,37318,37318,67919,57964,45576,74434,37318,74579,74583,74448,36991,37318,37318,41289,37087,37318,37318,37010,37318,37318,37318,37318,37318,65657,40192,38525,37318,37318,39335,40192,38527,37031,44584,37054,37076,37318,37318,74250,68588,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,45596,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,37318,37318,37318,37318,48276,37318,37318,37318,37318,37318,67919,57964,37318,37318,37318,37318,37318,45625,45661,37318,37318,41289,37087,37318,37318,37010,37318,37318,37318,37318,37318,65657,40192,38525,37318,37318,39335,40192,45833,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,37318,45715,37318,37318,48276,37318,37318,37318,37318,37318,67919,57964,45680,45684,37318,37318,45700,45732,36991,37318,37318,41289,37087,37318,37318,37010,37318,37318,37318,37318,37318,65657,40192,38525,37318,37318,39335,40192,38527,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,45768,39048,39078,39105,39169,39156,39172,39188,39089,39218,45803,55484,39265,39291,55476,39311,45819,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,37318,37318,37318,37318,48276,37318,37318,37318,37318,37318,67919,57964,37318,37318,37318,37318,37318,45266,36991,37318,37318,41289,37087,37318,37318,37010,37318,37318,37318,37318,37318,65657,40192,38525,37318,37318,39335,40192,38527,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,45863,37318,37318,44953,53155,45882,37318,52352,45886,39423,67164,45902,45916,45932,45961,45945,45975,45991,37318,45455,41670,46020,50786,46004,46033,45185,46061,46096,44613,41965,46121,46173,46189,46205,46221,46237,46288,65632,46304,37318,37318,68839,40298,50758,37318,41033,53889,69149,37318,46321,73164,72644,72644,72644,46341,45386,41542,41542,59697,52709,65498,65498,65498,64013,57854,41461,41461,41461,53427,64567,41960,63943,65692,37318,55390,46361,44399,46380,37318,58658,46936,46397,46417,72644,72644,59240,58293,46453,46492,41542,41542,52156,55833,61582,46520,65498,65498,64241,46547,52866,68024,41461,41461,68015,46594,47566,46621,37318,37318,46672,37318,46264,44403,37318,40057,46707,46725,63333,41308,72644,46741,63340,42275,46760,41542,46793,66052,61720,45363,46811,65498,49417,68460,65498,46845,46864,41461,51002,52264,41461,46904,52111,46933,46952,37318,46684,52530,67711,37318,59166,64847,72644,54549,51902,61913,46986,41542,41542,73854,71759,72272,41570,65498,54158,68314,46848,58449,41461,41461,47016,47035,51372,47057,47076,37318,47124,37318,47140,47156,71524,72644,42291,47208,67563,41542,59595,47244,47267,65498,59798,47304,47328,41461,53433,37318,47344,37318,61381,37318,72644,47362,47380,41542,47407,47424,65498,47447,64139,63673,47467,64041,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,41347,39062,47486,47520,47551,47602,47622,61702,70577,48688,47605,47638,50030,47449,46829,57656,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,47659,37318,37318,44953,37318,37318,37318,37318,37318,67919,47681,47697,47709,47725,47754,47738,47770,65689,37318,37318,41289,37087,37318,37318,37318,37318,37318,37318,37318,37318,44404,67827,50028,47806,47251,47282,47858,50482,37318,37318,37318,68839,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,45386,41542,41542,41542,52709,65498,65498,65498,65498,57854,41461,41461,41461,41461,64567,41960,37318,37318,37318,37318,73633,44399,56082,37318,56083,37318,73164,72644,72644,72644,72644,47879,41363,41542,41542,41542,41542,47922,65493,65498,65498,65498,65498,47955,46825,41461,41461,41461,67629,66428,63696,45404,37318,37318,37318,37318,37318,44403,37318,37318,37318,72643,72644,72644,72644,72644,72645,38772,41542,41542,41542,41542,41542,45363,65498,65498,65498,65498,65498,59800,41461,41461,41461,41461,41461,47863,51497,37318,58926,37318,37318,64306,57609,37318,65431,72644,72644,72644,56125,63073,47979,41542,41542,41542,70807,58352,65498,65498,65498,65498,47999,41461,41461,41461,41461,48015,47501,37318,37318,37318,37318,37318,60498,72644,72644,72644,42291,41542,41542,41542,59595,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,65375,48037,48062,48088,48113,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,49548,37318,37318,44953,37318,41780,37318,41482,37318,54642,48139,48155,48170,48186,48215,48199,48231,65689,37318,37318,48273,48292,37318,48311,37318,51503,37318,37318,37318,48331,46709,48623,50028,58342,50938,47282,52495,55465,37318,48349,37318,68839,48369,47665,37318,51866,48388,48408,48427,73007,67026,70205,72644,72644,72644,48444,48468,41542,41542,52709,48501,48532,65498,65498,51441,56912,41461,41461,41461,64567,71585,37318,37318,65402,37318,56580,44399,46364,37873,48553,37318,73164,48570,72644,48622,56986,72644,41363,48639,50032,41542,55261,41542,65493,48669,57135,65498,73731,65498,46825,48704,41598,41461,48739,41461,63696,45404,37318,37318,39025,37318,62106,44403,37318,37318,37318,72643,72644,72644,60958,57260,72645,38772,41542,41542,54046,68350,48760,45363,65498,65498,65498,48780,52828,59800,41461,41461,41461,48796,66903,47863,51534,37318,37318,37318,64199,37318,64441,37318,72642,72644,72644,64854,72644,61913,41542,41542,41542,48812,48876,65497,65498,65498,71839,65498,59803,41461,41461,47470,41461,47863,47501,37318,65142,37318,37318,38723,48831,72644,48851,72644,42291,41542,48871,41542,59595,65498,70398,65498,59798,41461,61249,41461,42174,72114,37318,37318,53513,66795,54283,70249,60920,63484,67969,41542,58586,58373,65498,49897,57220,41461,56936,37318,37318,67331,73163,72644,72800,50031,41542,52475,65498,65498,48892,41461,58211,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,47019,45307,48912,48959,48989,49019,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,70340,49053,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,49089,37318,44953,37318,48599,37585,39665,37318,67919,49107,49123,49137,49153,49182,49166,49196,65689,37318,37318,41289,37087,37318,37318,37318,37318,37318,48353,37318,48351,60095,51266,41622,41369,62908,47535,62003,72217,37318,62994,49212,68839,37318,49238,37318,49258,37318,51050,39778,49276,57933,60709,68980,49292,71214,49326,70571,70834,49347,57459,49369,49386,49404,49439,49457,61552,61800,49485,58425,64567,41960,37318,37318,68084,37318,56022,44399,37318,37318,37318,70710,73164,72644,72644,72644,72644,49520,41363,41542,41542,41542,52429,41542,65493,65498,65498,65498,59621,65498,46825,41461,41461,41461,65942,41461,71902,49537,37318,37318,48372,63307,37318,44403,37318,37318,38213,70690,72446,72644,72644,72644,64634,56631,49564,49582,41542,41542,56653,45363,49600,48682,65498,65498,64927,49622,49640,70938,41461,41461,62085,49662,51497,37318,37318,37318,37318,37318,49684,37318,68617,72644,72644,69970,72644,65479,41542,41542,41326,41542,48876,49710,65498,65498,47842,65498,59286,41461,41461,58267,41461,47863,47501,37918,62752,37318,37318,49733,60498,55203,65029,49752,42291,67741,65203,74026,59595,66024,65498,49773,59798,49646,41461,49825,47288,37318,51997,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,49852,37318,73163,72644,60539,50031,41542,72428,65498,65498,49872,41461,70461,56939,61615,37318,72643,60923,41542,57845,65498,49892,41461,49913,72946,72644,50030,54383,59799,54339,40392,49935,49960,49980,50002,57326,50022,50048,50069,50089,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,50115,37318,44953,44449,50137,37318,37060,50171,54108,64429,50196,50210,50226,50255,50239,50269,65689,44626,50285,50301,50316,50332,50367,39233,53108,50384,61398,55344,50419,50467,50512,50528,50544,50594,50610,50651,50667,73014,50694,49260,50729,62653,50756,50774,72085,37318,37318,49073,37318,73164,50802,70730,47643,67373,50837,50866,47931,48477,50890,64147,50934,50954,50974,61240,51024,54206,54678,60300,51066,42093,59527,51082,54503,44179,51132,51166,69514,50121,44486,44480,51182,51198,51247,51290,51306,51322,51357,51407,51457,51482,51519,51581,60231,51607,51635,51659,51675,51432,54188,73942,51691,51713,51750,51800,41753,51824,51840,37318,45167,74354,51864,51882,51918,51962,51982,72643,52018,52052,68101,52072,70228,38772,52096,72897,41542,52136,57279,52172,66566,52195,65498,64541,65498,52222,56902,52245,41461,67612,41461,52280,51497,37891,64079,46636,37318,52344,55168,73701,70986,47906,72644,52368,52401,61913,52428,52445,53191,52464,52511,46777,66351,65498,52546,52580,55946,51008,41461,52615,49469,47863,47501,37318,39657,52645,37318,58484,60498,52664,60195,52685,42291,67536,73887,52704,59595,49809,69760,70602,59798,46578,54457,71795,47288,37318,68581,52725,60872,52759,71031,52775,65989,69245,52802,72675,52206,52852,55908,48097,54237,46605,52882,52918,52936,39919,39478,52952,52973,52992,65449,53038,56792,66087,71786,53088,56765,56939,40362,53104,72643,69978,41542,52310,65498,53124,53817,55637,53146,55211,53171,53289,59799,53207,55668,73239,68122,73294,50578,53242,53264,53284,53305,53324,42326,53340,53356,53372,60496,73658,47451,66435,53400,53449,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,51938,37318,44953,62203,56053,37318,51929,37318,53498,53534,53550,53564,53580,53609,53593,53623,65689,37318,68909,41289,37087,37318,37318,37318,37318,61388,37318,61393,61388,52002,53639,47391,58863,63536,59869,62003,50482,37318,53663,37318,68839,53663,37318,37318,37318,69142,53682,45250,37318,55674,71208,72644,72644,72644,53704,53738,41542,41542,52709,48072,65498,65498,65498,57854,53755,41461,41461,41461,64567,41960,37318,37318,37318,37318,37318,44399,37318,37318,37318,53779,73164,72644,72644,72644,63735,72644,41363,41542,41542,41542,60760,41542,65493,65498,65498,65498,61277,65498,46825,41461,41461,41461,48744,41461,63696,45404,37318,37318,37318,37318,37318,44403,37318,45747,37318,72643,72644,72644,50815,72644,72645,38772,41542,41542,71247,41542,41542,45363,65498,65498,48537,65498,65498,59800,41461,41461,67762,41461,41461,47863,51497,37318,37318,37318,37318,37318,67308,37318,72642,72644,72644,56359,72644,61913,41542,41542,41542,70112,48876,65497,65498,65498,66735,65498,59803,41461,41461,41461,53797,47863,47501,37318,37318,37318,37318,37318,60498,72644,72644,72644,42291,41542,41542,41542,59595,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,54260,37318,37318,37318,73163,67467,72644,48046,41542,73662,48935,65498,59802,53815,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,41851,61054,66378,62339,68189,53833,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,37318,44953,37318,39797,37318,37318,37318,67919,53869,53905,53909,53925,53954,53938,53968,65689,37318,37318,41289,37087,37318,45716,37318,37318,37318,37318,37318,37318,44404,72644,50028,41369,65498,47282,62003,46136,46156,37318,37318,68839,37318,37318,37318,37318,40903,37318,37318,37318,73164,72644,72644,72644,72644,45386,41542,41542,41542,52709,65498,65498,65498,65498,57854,41461,41461,41461,41461,60376,37318,37318,37318,37318,37318,37318,37318,37318,36975,37318,64085,73164,72644,72644,72644,72644,72644,53984,41542,41542,41542,41542,41542,62136,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,47041,37318,37318,37318,54006,37318,54026,36968,37318,37318,53666,72643,72644,65774,72644,72644,72645,38772,41542,41542,54043,41542,41542,45363,65498,65498,53015,65498,65498,59800,41461,41461,66593,41461,41461,71140,54854,37318,37318,54062,37318,37318,37318,37318,72642,72644,72644,72644,72644,38767,41542,41542,41542,41542,41444,65497,65498,65498,65498,65498,59803,41461,41461,41461,41461,47863,54854,37318,37318,54082,64821,37318,60498,72644,72644,62830,58547,41542,41542,58315,46770,65498,65498,71297,59798,41461,41461,54740,47288,59033,54099,69440,44860,37318,54124,64478,44740,41542,54141,70297,54157,61206,54174,54204,58614,54222,56936,53884,37318,41072,40582,71978,54276,54299,54319,56380,73391,73919,41714,55599,54335,56939,50403,59838,42233,54355,53715,54379,54399,59801,54439,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,57408,54473,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,37318,44953,37318,37318,37318,37318,37318,67919,57964,37318,37318,45323,45350,63443,47e3,59399,37318,37318,60166,37087,37318,37318,37318,54501,37318,54501,42045,54519,39472,54546,54565,67872,65498,54590,62375,54624,37318,37318,47504,68839,67717,44759,37318,37318,54658,37318,37318,37318,73164,72644,72644,58045,72644,45386,41542,41542,67542,52709,65498,65498,65498,56180,57854,41461,41461,41461,54676,60376,37318,37318,37318,37318,37318,37318,37318,37318,37318,68532,57795,73164,72644,72644,72644,72644,72644,54694,41542,41542,41542,41542,41542,54716,65498,65498,65498,65498,65498,54737,41461,41461,41461,41461,41461,54756,71731,37318,37318,37318,37318,37318,37318,37318,37318,74625,57661,72644,72644,72644,72644,72645,38772,54791,41542,41542,41542,41542,45363,54808,65498,65498,65498,65498,59800,54829,41461,41461,41461,41461,47863,54854,37318,37318,66657,37318,37318,37318,37318,72642,72644,72644,72644,58513,38767,41542,41542,41542,63753,41444,65497,65498,65498,65498,70365,59803,41461,41461,41461,60263,47863,54854,37318,37318,49068,37318,37318,60498,72644,72644,72644,58547,41542,41542,41542,46770,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,54946,37318,40844,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,54850,61615,65734,72643,61015,41542,72843,65498,54871,41461,54893,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,51946,37318,44953,37318,54915,54931,37318,54967,54974,54990,55006,55021,55037,55066,55050,55080,65689,37318,37318,51966,38825,37318,37318,37318,54010,55096,55115,48257,55149,55184,55227,55249,41525,55284,55303,63265,55333,37318,37318,37318,40256,37318,55133,55360,37318,37318,37318,55377,52524,73164,55412,59232,72644,55450,55508,48452,55571,48764,46504,61212,71358,65498,52836,55590,72384,66401,41461,55624,55653,37318,55162,48123,45480,68146,44384,37318,37318,55690,55710,55730,55750,50821,72644,73775,55770,55805,41363,53990,41542,54303,55821,55849,65493,53022,65498,61780,55897,55924,46825,56459,41461,71394,55962,55996,47041,37318,37318,37318,54660,56044,56069,49736,37318,37318,37318,56099,56122,72644,56141,70528,58519,56160,58143,41542,63117,55574,66717,50850,52564,65498,63146,65498,56203,56221,51808,41461,56467,41461,56251,56269,54854,55099,56307,46073,56323,59679,56339,62046,56355,52688,61008,58074,70003,51212,41542,66283,70084,56375,56396,56430,65125,61593,46531,69280,62369,41461,56449,56483,56517,56546,63230,66178,37927,69494,47228,56575,66873,56144,56596,56612,70031,45388,56647,56669,56693,56729,56747,56781,56815,56873,56892,51765,56928,56955,37318,37318,61883,53848,56976,57010,57028,57047,57072,57089,57107,57133,57151,57170,57197,57216,56936,60597,37318,40353,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,57236,61615,37318,57252,51333,57276,57295,62141,50073,54877,49498,57311,72644,50030,54383,59799,54339,39384,52786,55523,72337,68506,73161,59759,73663,59797,47605,60497,50030,47449,46829,57331,57347,55938,57396,53268,62159,62339,66862,41867,57424,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,42152,37318,44953,37318,37318,37318,37318,37318,67919,57964,37318,37318,57475,57504,57488,57518,65689,37318,37318,41289,37087,37318,37318,37318,37318,37318,37318,37318,37318,44404,72644,50028,41369,65498,47282,62003,72217,37318,37318,37318,68839,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,66211,72644,45386,41542,41542,57534,52709,65498,65498,49388,65498,57854,41461,41461,51784,41461,60376,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,72644,41363,41542,41542,41542,41542,41542,65493,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,47041,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,72643,72644,72644,72644,72644,72645,38772,41542,41542,41542,41542,41542,45363,65498,65498,65498,65498,65498,59800,41461,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,37318,37318,72642,72644,72644,72644,72644,38767,41542,41542,41542,41542,41444,65497,65498,65498,65498,65498,59803,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,60498,72644,72644,72644,58547,41542,41542,41542,46770,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,41502,37318,44953,37318,37318,37318,37318,37318,67919,57964,37318,37318,45323,45350,63443,47e3,65689,37318,37318,41289,37087,37318,52736,37318,37318,37318,37318,37318,37318,44404,72644,50028,41369,65498,47282,62003,72217,37318,37318,37318,68839,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,45386,41542,41542,41542,52709,65498,65498,65498,65498,57854,41461,41461,41461,41461,60376,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,72644,41363,41542,41542,41542,41542,41542,65493,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,47041,47060,37318,37318,37318,37318,37318,37318,37318,37318,37318,57438,72644,72644,72644,72644,72645,61918,41542,41542,41542,41542,41542,45363,57553,65498,65498,65498,65498,59800,57571,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,37318,37318,72642,72644,72644,72644,72644,38767,41542,41542,41542,41542,41444,65497,65498,65498,65498,65498,59803,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,60498,72644,72644,72644,58547,41542,41542,41542,46770,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,39711,37318,44953,37318,42450,57589,57607,57625,51565,57641,57677,57681,57697,57726,57710,57740,65689,51556,37318,41289,37087,47346,60068,37318,37318,39892,37318,40511,57756,45560,57818,57834,63977,57879,60331,41648,58e3,57914,37318,37318,38814,37318,37318,57949,44882,37318,57925,37318,67807,49037,57985,58044,51257,58061,58115,58131,41542,58165,54574,59660,56705,57154,47834,58193,52256,58227,57863,58246,50918,53781,37318,37318,37318,37318,49029,67667,37318,37318,37318,37318,73164,60986,49757,72644,58283,72644,58309,58331,63863,47408,61105,41542,58368,58389,67585,57555,49801,65498,58422,58441,68033,65185,60256,69351,47041,37318,61839,58465,37318,37318,45281,53688,37318,37318,37318,72643,72644,72644,63835,58500,58535,38772,41542,41542,55268,69704,69729,45363,65498,65498,61489,63774,58568,59800,41461,41461,66754,51734,58602,47863,54854,58637,37318,37318,68901,37318,37318,37318,72642,66219,72644,72644,72644,38767,67986,41542,41542,41542,41444,65497,56713,65498,65498,65498,59803,71875,41461,41461,41461,47863,54899,37318,58657,37318,51097,69488,55754,58674,72644,72644,58694,58724,41542,41542,58745,58769,65498,65498,61143,58793,41461,41461,71804,37318,68935,37318,73352,37318,72644,49303,60920,41542,72302,41542,65498,52557,65498,63673,46570,41461,56936,37318,38852,37318,73163,72644,56106,50031,41542,58818,65498,73828,59802,41461,48715,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,53248,58845,64251,68569,67094,58879,59108,47606,53268,62159,58907,58895,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37319,37318,44953,37318,37318,58923,37318,37038,61423,60807,58942,58956,58972,59001,58985,59015,65689,38336,37318,41289,37087,37318,59031,37318,37318,40327,37318,38338,59049,40328,59079,54363,41369,59103,48516,62003,72217,37318,37318,59124,68839,37318,63001,62951,44924,37318,37318,37318,59142,59160,59182,72644,59203,59223,59256,41542,57091,48815,59272,59718,65498,52599,56799,57854,54450,41461,63259,59312,52629,59347,40308,54027,37318,37318,37318,37318,56028,37318,37318,37318,73164,56849,59370,68264,72644,72644,41363,63477,59429,70290,41542,41542,65493,64678,69828,70882,65498,65498,46825,59459,66600,59489,41461,41461,47041,37318,60820,72604,37318,37318,56414,63654,59509,37318,37318,72643,61043,72644,72644,59543,72645,59566,72479,41542,41542,59585,41542,65528,73531,59619,65498,70373,65498,59800,54834,59637,41461,64050,41461,47863,54854,37318,37318,37318,37318,37318,37318,37318,72642,72644,72644,72644,72644,38767,41542,41542,41542,41542,41444,65497,65498,65498,65498,65498,59803,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,60498,72644,72644,72644,58547,41542,41542,41542,46770,65498,65498,65498,59798,41461,41461,41461,47288,44851,37318,37318,37318,37318,59207,72644,60920,61740,41542,41542,73606,65498,65498,49876,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,61445,73662,65498,59655,59802,56876,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,59676,72644,59695,59713,71108,58802,59734,59756,59775,59794,59819,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,59854,73737,67066,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,67305,48392,37318,54855,59885,59896,59919,66152,67290,59971,59985,60001,60031,60044,60015,65689,47586,44905,38860,60060,60084,37318,60579,48333,40435,72237,60111,60138,60122,60182,60217,60279,60316,65566,60366,50482,58641,37318,37318,48606,72949,68216,73429,60392,69215,60419,37318,60465,60494,60514,60535,72871,72644,60555,49584,41542,47939,52709,70645,70888,65498,70640,57854,54601,60344,63674,41461,59473,64205,46157,37318,60571,37318,37318,37318,60595,37318,37318,45177,73164,60613,72644,53647,72644,72644,41363,60640,41542,61097,41542,41542,58708,70406,65498,55874,65498,65498,50904,58204,41461,60666,41461,41461,47041,37318,37318,37318,37318,40106,37318,37318,44677,60687,37318,60703,72644,72644,46744,72644,58087,60725,41542,41542,41542,60758,74033,52815,65498,65498,65498,52593,61759,41832,41461,41461,41461,53066,69906,47863,49504,60776,60792,64608,60842,51384,60860,60895,60918,60939,60974,61031,61070,38767,70056,61088,61121,61167,41444,65497,61193,61228,55536,61274,59803,61293,61309,61258,72531,61332,54854,48246,61348,61369,61414,58477,51897,68272,58678,65107,61439,53722,46795,49566,61461,54813,65498,61486,61505,72623,61531,61548,61568,67348,61609,37318,37318,61636,61678,47889,61697,61718,52147,61736,61756,56291,61775,61796,55608,61816,46251,61838,37318,61855,73163,61899,68974,61934,52295,73662,61950,58777,71058,61966,62e3,62019,63023,62043,40852,60923,72471,73664,62062,59801,62083,49498,62101,55233,62122,54383,62157,62175,62225,62247,62263,62279,62295,62331,57449,55864,54413,66647,60497,50030,47449,46829,60496,73658,47451,47606,62355,62391,62339,66862,41867,41898,57361,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,62425,44953,37318,41929,62645,37318,37318,67919,62449,62465,62479,62495,62524,62508,62538,62554,62570,62591,51116,40267,62636,62669,37763,62688,62721,40114,62768,62784,62800,62846,62862,62878,62894,62929,62967,62983,37318,74513,46381,42254,37318,40466,50397,50445,63017,37318,37318,63039,73164,72644,63059,63089,55789,45386,47983,63105,51466,69257,65498,47963,66977,63139,63162,41461,63187,63203,63246,60376,37318,65243,37318,54083,37318,65923,63281,37318,49694,37318,63306,63323,63356,63373,63389,72644,67473,63412,41542,63428,63500,41542,54700,59443,65498,63522,63557,65498,56187,53414,41461,63578,63594,41461,68051,48021,46148,37318,59832,55125,37318,37318,37318,37318,37318,63803,72643,72644,70758,59187,72644,72645,38772,41542,55434,57073,41542,41542,45363,65498,74070,65498,63613,65498,59800,41461,60671,41461,63633,41461,47863,54854,37318,37318,63653,44684,37318,37318,37318,72642,72644,72644,72644,57012,55426,41542,41542,41542,41542,66835,62140,65498,65498,65498,65498,63670,41461,41461,41461,41461,63690,54854,67948,37318,37318,37318,37318,63712,72644,63734,72644,46430,41542,63751,41542,56170,65498,63769,65498,41577,41461,51728,41461,47288,63790,37318,37318,37318,37318,62822,66520,60920,41416,71239,41542,47825,58753,65498,61151,71116,41461,72584,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,45334,61615,37318,63825,73373,63858,64501,63879,65885,41461,56530,63897,63917,63966,63993,64029,64066,39534,64101,64126,64163,64186,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,50006,53268,62159,64221,66862,41867,64277,64293,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,66665,44953,37318,37318,68891,37318,64328,64337,67698,39838,64353,64369,64398,64382,64414,65689,37318,69115,41289,37087,37318,37318,63950,37318,51547,37318,37318,37318,44404,64465,64494,64517,49717,67057,64557,72217,37318,64583,37318,68839,37318,40908,40502,64605,50368,64607,37318,37318,62231,64624,67101,73183,63396,64650,67404,68345,48485,71344,64666,64694,64712,71834,64730,57181,60350,61532,53072,55317,64759,37318,64782,64801,45664,45866,38224,37318,37318,37318,37318,73164,72644,72644,52669,72644,72644,41363,41542,41542,67409,41542,41542,65493,65498,65498,55555,65498,65498,46825,41461,41461,68042,41461,41461,49668,53220,61353,37318,37318,37318,64818,59354,57374,68538,37318,72643,72644,64837,72644,72644,72645,64870,41542,64889,41542,41542,41542,68453,65498,51231,64925,65498,65498,59800,41461,61515,64943,41461,41461,47863,54854,59903,37318,37318,37318,37909,37318,37318,72642,72644,72644,64960,72644,56626,41542,41542,73894,41542,42296,65497,65498,65498,64978,65498,59803,41461,41461,71869,41461,47863,54854,37318,37318,37318,37318,37318,60498,72644,72644,72644,58547,41542,41542,41542,46770,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,52897,37318,59144,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,62943,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,56828,64997,65024,65045,64231,59603,54339,38753,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,37318,44953,37318,37318,37318,37318,37318,67919,57964,37318,37318,45323,45350,63443,47e3,65689,37318,37318,41289,37087,37318,46305,37318,37318,37318,42426,42429,65068,54066,65102,51341,41369,65123,50559,62003,48585,65141,37318,37318,68839,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,45386,41542,41542,41542,52709,65498,65498,65498,65498,57854,41461,41461,41461,41461,60376,37318,37318,37318,43472,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,72644,65158,41542,41542,41542,41542,41542,66019,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,47041,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,72643,72644,72644,72644,72644,72645,38772,41542,41542,41542,41542,41542,45363,65498,65498,65498,65498,65498,59800,41461,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,37318,37318,72642,72644,52976,72644,72644,38767,41542,41542,73801,41542,41444,65497,65498,49370,65498,65498,59803,41461,41461,65182,41461,47863,54854,37318,37318,37318,37318,37318,60498,72644,72644,72644,58547,41542,41542,41542,46770,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,51274,72644,50031,65201,73662,71079,65498,59802,58261,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,37806,44953,65219,37318,37420,65239,37318,67919,65259,65275,65288,65304,65333,65317,65347,65689,45409,47790,41289,50740,71165,72077,54775,46691,68943,37318,65363,65398,65418,65465,65515,65551,65582,68491,65617,65675,37318,37318,37318,55396,65708,50432,65732,40783,60879,37318,37318,46888,65750,54125,65773,60201,65790,65831,49353,41542,61177,57056,65855,49783,65498,65874,65901,41461,65939,58230,64743,49003,37318,37318,37318,54951,44007,65958,37318,73691,37318,44004,69414,59740,72644,52378,72644,64962,65976,66005,41542,53183,41542,52448,66040,66074,65498,73466,65498,70854,66103,60245,41461,66119,41461,72537,66911,47041,37318,37318,38803,72980,60478,40954,37318,37480,66138,66168,66202,72644,66235,46345,66251,72645,66271,41542,58177,66299,66320,41542,56559,65498,65535,66344,66367,65498,69808,41461,53763,66394,66417,41461,47863,49919,37318,37318,52902,66451,37318,66495,39978,72642,66512,60519,72644,72644,38767,65839,41542,66536,41542,41444,65497,66557,54721,65498,65498,59803,66582,73488,41461,41461,52328,47223,43477,62672,37318,37318,37318,65382,72644,72644,61681,58099,41542,41542,41542,66616,65498,65498,65498,66632,66681,41461,41461,54252,37318,70963,37318,37318,37318,66698,72644,60920,66716,41542,67896,66733,65498,69783,66751,41461,54608,56936,37318,66770,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,56009,66788,66811,66827,66851,66889,49836,61620,60922,73660,47450,46828,42223,66927,59778,49606,47605,66943,50030,47449,46829,60496,73658,47451,52229,66963,67001,67042,47192,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,42006,44953,41194,40023,67082,63290,67117,67133,67149,67200,67214,67230,67259,67243,67275,67324,37318,67347,72149,37087,37318,39873,37318,37318,73640,55694,39647,45609,60403,67364,67389,66058,64007,71278,67425,72217,39770,40165,39032,68839,68408,37318,37318,37318,37318,39965,41180,37318,67452,67489,70764,72644,72644,67522,67558,63467,41542,52709,51619,65498,67579,65498,57854,67601,63637,67628,41461,60376,37318,67645,37318,67663,67683,37318,56960,37318,65223,37318,37318,73164,52080,69630,72644,72644,72644,67733,60734,73861,41542,41542,53739,65493,58399,51643,65498,65498,63881,46825,67757,59323,41461,41461,66122,50625,37318,37318,67778,47108,48295,37318,38228,67799,44787,57969,67823,72644,72644,69591,55783,67843,67888,41542,41542,63123,65166,73809,53005,65498,65498,64714,62913,63541,72852,41461,41461,59639,69865,70909,48723,67912,59519,37318,37900,37318,51391,37318,67935,72642,72644,52056,59087,72644,38767,41542,41542,67964,67985,41444,65497,65498,65858,58406,65498,59803,41461,41461,68002,41461,47863,54854,37318,68397,37318,68076,37318,60498,68624,72644,68100,65444,66541,41542,68117,51222,72818,65498,55549,59798,53799,41461,51777,47288,37318,37318,40078,37318,68138,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,65915,37954,37318,68162,56840,72644,69566,50031,41542,68178,65498,72029,59802,41461,61324,68205,61615,68239,68255,57031,68288,49964,68312,64170,41461,72350,72946,63842,68330,50053,68366,68384,61620,60922,73660,47450,46828,40170,49310,63506,57898,47605,68424,68440,45370,63171,40400,68476,68554,68604,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,38247,68640,37318,37318,44545,44549,42062,66479,66466,68687,68703,68719,68748,68732,68764,68811,49856,37318,68835,73418,40538,54530,37318,68855,37963,68877,39120,68925,68959,68996,69012,46476,69028,71470,69063,59385,62027,45461,65008,68839,69079,37318,38220,69096,65716,69131,41882,69165,69175,69191,63718,59550,63357,69231,50874,46465,70280,70118,64531,65596,69273,69296,57117,69318,73551,69334,69350,69367,69406,69430,37318,69456,69475,69510,37318,37318,68519,50099,69530,44732,69549,69582,60998,72644,69624,41363,69646,69670,69695,41542,69720,65493,69753,69776,69799,65498,69824,48973,69844,69860,69881,41461,69903,51039,37318,69922,62705,62209,69940,52743,51107,45640,57591,40471,72643,69961,69994,72644,48835,70019,70047,70072,69679,41542,41542,70100,64902,48943,63562,65498,65498,70134,59800,68060,61822,41461,41461,70150,47863,72356,45780,37318,73436,47091,37318,37318,70166,72704,72644,70194,70221,70244,47170,73209,73218,70265,66328,41444,70313,65498,70329,70356,70389,60293,70422,70441,54423,70477,47863,50635,37318,50706,66496,53384,69533,46401,70511,72644,72644,70544,70560,70789,41542,70593,70626,69047,65498,52486,70661,69887,41461,70487,37318,41199,59126,70706,37318,70726,70746,56994,70780,70823,72308,70850,70870,65601,70904,70925,51697,70495,37450,37318,70960,70979,71002,71021,63456,46437,71047,71074,71095,49624,59493,71132,71156,71181,41086,71197,69608,71230,71263,71294,71313,57200,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,65052,64909,59331,55194,71329,71374,71410,71439,71455,66985,70676,53268,62159,62339,66862,71486,71502,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,37318,71540,37318,37318,62697,37318,37318,67919,71622,71638,71652,71668,71697,71681,71711,65689,37318,37318,41289,71727,43243,37318,54635,37318,47100,37318,37318,37318,44404,60624,71747,71775,71820,71855,71891,71918,50345,37318,37318,68839,37318,37318,64312,71934,37318,37318,37318,63901,73164,71973,72644,72644,67498,71994,41542,41542,41542,72010,61470,65498,65498,49441,57854,72045,41461,41461,72052,56235,72068,37318,72101,73266,37318,37318,37318,72130,72165,37318,45286,73164,72644,72186,72203,52036,66700,41363,41543,41542,72253,47431,72288,65493,56731,65499,62067,70610,72324,46825,73981,63597,47312,56493,72372,47041,37318,38557,37318,72400,37318,37318,37318,52648,37318,37318,72643,69558,72644,72644,72644,72645,72419,58149,41542,41542,41542,41542,61134,64696,65498,65498,65498,65498,59800,57573,41461,41461,41461,41461,47863,56406,37318,67179,37318,37318,37318,37318,60902,62813,72644,72644,72644,72644,42340,41542,41542,41542,41542,41444,47816,65498,65498,65498,65498,64261,41461,41461,41461,41461,47863,54766,37318,37318,46970,37318,37318,39394,72444,72644,72644,67855,72462,41542,57537,51591,72495,65498,65498,72517,72553,41461,41461,72576,37318,72600,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,65757,60923,69654,73664,69041,59801,72620,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,72639,72661,49423,56501,60496,73658,47451,47606,53268,68368,54485,72691,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,37318,42479,51143,66186,50148,37318,40519,67015,72720,37318,37318,72736,72765,72749,72779,65689,37318,37318,41289,37087,37318,37318,37318,37318,37318,37318,37318,37318,44404,72795,49944,41369,72816,50989,62003,72217,37318,49091,63043,68839,37318,37318,37318,37318,37318,52920,37318,37318,73164,47899,72644,73587,72644,45386,72834,41542,56677,52709,56433,65498,65498,72024,57854,55980,41461,64944,41461,60376,37318,37318,37318,37318,37318,55361,37318,37318,37318,53853,37318,73164,72644,72644,72868,72644,72644,41363,41542,41542,72887,41542,41542,65493,65498,65498,72920,65498,65498,46825,41461,56253,41461,41461,41461,47041,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,72643,72644,72644,72644,72644,72645,38772,41542,41542,41542,41542,41542,45363,65498,65498,65498,65498,65498,59800,41461,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,37318,37318,72642,72644,72644,72644,72644,38767,41542,41542,41542,41542,41444,65497,65498,65498,65498,65498,59803,41461,41461,41461,41461,47863,54854,37318,40788,37318,37318,37318,60498,72644,72644,72644,58547,41542,41542,41542,46770,65498,65498,65498,59798,41461,41461,41461,47288,37318,69080,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,72938,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,37318,50678,37318,37318,72976,37318,72965,72996,73030,73066,73080,73096,73125,73109,73141,65689,37318,37318,41289,37087,37318,37318,37318,37318,37318,37318,37318,37318,44404,49521,50028,47181,50958,47282,59296,63932,37318,37318,37318,68839,37318,37318,37318,37318,45204,37318,37318,37318,73164,72644,72644,72644,72644,45386,41542,41542,41542,52709,65498,65498,65498,65498,57854,41461,41461,41461,41461,60376,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,72644,41363,41542,41542,41542,41542,41542,65493,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,47041,37318,37318,37318,37318,37318,48411,37318,37318,37318,37318,73180,72644,72644,72644,72644,72645,73199,41542,41542,41542,41542,41542,56282,65498,65498,65498,65498,65498,56756,41461,41461,41461,41461,41461,47863,54854,37318,68223,37318,37318,37318,37318,37318,72642,72644,73234,72644,56857,38767,41542,66304,41542,41542,73255,65497,65498,73289,65498,72501,59803,41461,61976,41461,70425,47863,54854,37318,37318,37318,37318,37318,60498,72644,72644,72644,58547,41542,41542,41542,46770,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45555,37318,37318,37318,37318,44953,37318,37318,37318,37318,37318,67919,57964,37318,37318,45323,45350,63443,47e3,65689,37318,37318,41289,73310,37318,39135,37318,37318,37318,46656,37318,73333,55714,73368,64110,41369,73389,53053,62003,72217,37318,37318,37318,73407,48428,48554,40049,37318,37318,37318,37318,37318,73164,72644,61072,72644,52030,45386,41542,41809,41542,73452,65498,65498,58580,63617,57854,41461,41461,73487,55972,60376,73504,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,72644,41363,41542,41542,41542,41542,41542,65493,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,47041,37318,37318,37318,37318,37318,37318,62308,37318,37318,37318,72643,72644,52957,72644,72644,74050,38772,41542,54792,41542,41542,41542,48926,65498,65498,73527,65498,65498,59800,41461,41461,73547,41461,41461,47863,54854,73567,37318,37318,37318,37318,37318,37318,72642,73584,72644,72644,72644,38767,72904,41542,41542,41542,41444,65497,73603,65498,65498,65498,59803,70455,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,60498,72644,72644,72644,58547,41542,41542,41542,46770,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,37318,44953,37318,37318,37318,37318,37318,67919,57964,37318,37318,45323,45350,63443,47e3,73622,37318,37318,41289,37087,37318,42196,37318,37318,37318,37318,37318,37318,4e4,72644,73656,60650,55287,47282,61984,73680,37318,42131,37318,68839,37318,37318,37318,37318,37318,37318,37318,41786,73164,72644,72644,72644,69600,45386,41542,41542,41542,73717,65498,65498,65498,56205,57854,41461,41461,41461,72560,60376,37318,59949,37318,37318,37318,37318,37318,37318,37318,73753,37318,73164,52385,72644,72644,73772,72644,41363,69737,41542,41542,73791,41542,65493,49792,65498,65498,73825,65498,46825,50572,41461,66682,41461,41461,47041,37318,46080,37318,37318,37318,37318,37318,37318,37318,37318,72643,41389,72644,72644,72644,72645,73844,41542,73877,41542,41542,41542,51420,65498,73910,65498,65498,65498,49986,41461,73935,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,61662,37318,72642,72644,47364,72644,72644,38767,41542,41542,70798,41542,41444,65497,65498,65498,73958,65498,59803,41461,41461,73977,41461,47863,54854,37318,37318,42105,37318,37318,60498,72644,72644,72644,58547,41542,41542,41542,46770,65498,65498,65498,59798,41461,41461,41461,47288,73997,37318,37318,40961,37318,60952,72644,60920,74016,41542,41542,57892,65498,65498,71387,41461,41461,56936,37318,60826,37318,73163,72644,74049,50031,68296,73662,65498,74066,59802,53130,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,45302,37318,37318,37318,37318,44953,37318,37318,37318,37318,37318,67919,61870,37318,37318,45323,45350,63443,47e3,65689,37318,37318,41289,37087,37318,37318,37318,37318,37318,37318,37318,37318,44404,72644,50028,41369,65498,47282,62003,72217,37318,37318,37318,68839,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,45386,41542,41542,41542,52709,65498,65498,65498,65498,57854,41461,41461,41461,41461,60376,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,72644,41363,41542,41542,41542,41542,41542,65493,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,47041,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,72643,72644,72644,72644,72644,72645,38772,41542,41542,41542,41542,41542,45363,65498,65498,65498,65498,65498,59800,41461,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,37318,37318,72642,72644,72644,72644,72644,38767,41542,41542,41542,41542,41444,65497,65498,65498,65498,65498,59803,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,60498,72644,72644,72644,58547,41542,41542,41542,46770,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,37318,37318,37318,37318,64589,74088,74086,40559,74115,74104,74140,74169,37318,74124,74153,74190,74194,74210,36991,37318,37318,41289,37087,37318,37318,74245,37318,37318,37318,37318,37318,65657,40192,74266,55734,37318,53472,40192,38527,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,72228,37116,37202,37162,74643,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,37318,37318,37318,37318,48276,37318,37318,53226,37318,37318,67919,57964,74289,74334,37318,37318,74319,74303,36991,37318,37318,41289,37087,37318,37318,37010,37318,37318,37318,74350,37318,53463,40192,38525,37318,37318,74370,40192,38527,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,37182,37116,37202,37162,37222,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,37318,37318,37318,37318,74174,37318,37318,37318,37318,37318,52120,37296,74401,74403,37318,37318,74392,74419,36991,37318,37318,41289,37087,37318,37318,74464,37318,37318,74485,37318,37318,59413,40192,38525,37318,37318,39335,40192,38527,37031,44584,37054,37076,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,74504,37116,37202,37162,74529,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,39013,39048,39078,39105,39169,39156,39172,39188,39089,39218,39249,55484,39265,39291,55476,39311,39327,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,39708,37318,37318,37318,37318,48276,37318,37318,37318,37318,37318,67919,57964,37318,37318,37318,37318,37318,74564,65689,37318,37318,41289,37087,37318,37318,37318,37318,37318,37318,37318,37318,44404,72644,50028,41369,65498,47282,62003,69205,37318,37318,37318,68839,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,41324,41542,41542,41542,58552,65498,65498,65498,65498,57854,41461,41461,41461,41461,60376,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,73164,72644,72644,72644,72644,72644,41363,41542,41542,41542,41542,41542,65493,65498,65498,65498,65498,65498,46825,41461,41461,41461,41461,41461,47041,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,72643,72644,72644,72644,72644,72645,38772,41542,41542,41542,41542,41542,45363,65498,65498,65498,65498,65498,59800,41461,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,37318,37318,72642,72644,72644,72644,72644,38767,41542,41542,41542,41542,41444,65497,65498,65498,65498,65498,59803,41461,41461,41461,41461,47863,54854,37318,37318,37318,37318,37318,60498,72644,72644,72644,58547,41542,41542,41542,46770,65498,65498,65498,59798,41461,41461,41461,47288,37318,37318,37318,37318,37318,72644,72644,60920,41542,41542,41542,65498,65498,65498,63673,41461,41461,56936,37318,37318,37318,73163,72644,72644,50031,41542,73662,65498,65498,59802,41461,41462,56939,61615,37318,72643,60923,41542,73664,65498,59801,41461,49498,72946,72644,50030,54383,59799,54339,61620,60922,73660,47450,46828,73161,59759,73663,59797,47605,60497,50030,47449,46829,60496,73658,47451,47606,53268,62159,62339,66862,41867,41898,41909,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,65960,37318,37318,37318,37318,74599,74601,37318,37318,70178,74617,37014,37318,37318,37318,37318,37318,37318,37010,37318,37318,37318,37318,37318,65657,40192,38525,37318,37318,39335,40192,38527,37031,44584,37054,74641,37318,37318,74250,37318,69924,37107,37136,37152,65815,69390,37247,37265,53482,72228,37116,37202,37162,74643,37186,37120,37206,37166,74726,69388,37245,37263,53480,37281,37318,41092,37317,37318,37318,45006,57380,37335,37318,74671,64449,74683,40193,37351,37378,40192,39199,37741,69458,41098,41041,37318,46044,37882,69459,41099,41042,37318,46045,37371,74376,37355,37382,40192,39202,38523,74469,50180,37398,37414,37436,50351,37475,37318,58014,37496,39340,37628,37651,37674,55492,37717,38230,37546,37566,58028,41986,37605,37523,37542,37562,58024,37582,37601,39304,37621,37644,37667,37690,37709,37733,74273,57770,38317,37757,37779,37822,46961,37943,37979,37995,38150,38170,38011,38093,38038,38061,37792,39434,38084,38100,38045,38068,37799,39441,38116,37992,38147,38166,38186,38022,38246,38263,37318,38304,37318,38354,38370,45231,38397,38413,37861,37459,38432,38451,68861,37456,38429,38448,38467,45226,38483,38407,38516,57783,51848,38545,38580,73050,38677,38610,38626,49222,38643,38660,49221,38642,38659,38676,38693,38624,38714,38739,38791,38841,38876,38942,38892,60443,38908,60433,60449,38914,38930,38946,38962,38978,74659,39048,39078,39105,39169,39156,39172,39188,39089,39218,46272,55484,39265,39291,55476,39311,74721,37693,37318,65659,38698,39356,39410,37835,37848,39457,45051,38498,38500,45058,39494,39520,39559,39504,39575,59063,39606,39616,39632,39681,39692,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,37318,1,24578,3,0,0,0,0,0,0,0,180524,180524,180524,180524,0,188717,0,188717,180524,188717,188717,188717,188717,188717,188717,188717,188717,188717,188717,188717,188717,188717,188717,188717,188717,188717,188717,180524,180524,188717,188717,188717,188717,188717,188717,188717,188717,188717,188717,188717,188717,368,188717,180524,188717,188717,188717,188717,188717,131072,188717,188717,188717,188717,188717,188717,188717,188717,188717,188717,188717,139264,147456,188717,188717,188717,188717,188717,188717,188717,1,24578,3,0,0,4366336,0,0,0,180524,188717,302,303,0,0,307,0,0,0,307,0,0,0,4931584,0,0,0,0,0,0,2367,0,0,0,0,0,0,0,0,0,1854,0,0,0,0,0,0,4268032,306,307,0,0,0,0,0,0,0,0,0,0,0,0,0,302,0,0,0,0,0,0,4268032,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,262144,0,0,4857856,4874240,0,0,4923392,0,0,0,0,0,0,0,0,0,341,0,0,0,0,0,0,0,0,0,0,5840896,5849088,0,0,0,0,0,0,0,0,0,0,328,0,0,375,375,405,0,0,0,6275072,0,0,0,0,0,0,0,368,368,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,450560,0,0,0,0,4857856,0,0,0,0,0,0,0,0,0,0,0,0,5259264,0,0,0,0,0,0,0,0,5414912,0,5447680,0,5464064,0,5414912,5447680,0,0,5562368,5636096,5685248,0,5750784,5873664,0,0,0,0,5636096,5873664,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5873664,0,0,0,0,0,0,0,0,0,0,0,6275072,0,0,0,914,0,0,0,0,0,4857856,4874240,0,0,0,0,0,0,0,0,0,0,0,0,5447680,0,5464064,0,5480448,5562368,0,0,0,5636096,0,5685248,0,0,5750784,0,0,0,0,0,6275072,0,0,0,0,0,0,0,0,0,0,0,990,0,0,0,4841472,0,0,0,4898816,0,4358144,4358144,4358144,4358144,4358144,4358144,5414912,4358144,5447680,4358144,5464064,4358144,5480448,5562368,4358144,4358144,4358144,5636096,4358144,5636096,4358144,5685248,4358144,4358144,5750784,4358144,4358144,4358144,4358144,4358144,5873664,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4923392,4358144,4358144,4358144,4358144,4358144,0,4923392,0,0,0,0,4366336,0,0,0,0,418,0,0,0,0,0,0,0,0,0,0,0,4276224,1258,0,0,0,5603328,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,341,0,0,5341184,0,5652480,0,0,0,0,0,0,0,0,0,0,4759552,4358144,4358144,4358144,4358144,4358144,5242880,4358144,4358144,4358144,4358144,4358144,4358144,4358144,5341184,4358144,4358144,4358144,4358144,4358144,4358144,0,0,5808128,4358144,4358144,4358144,4825088,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,5627904,5652480,4358144,5701632,4358144,4358144,5808128,4358144,4358144,4358144,5668864,0,0,5791744,0,0,0,0,0,0,0,0,0,0,6201344,6242304,6250496,0,0,0,0,6422528,0,0,0,0,0,0,0,0,0,0,351,0,0,0,0,0,0,5619712,0,0,0,0,0,0,0,5726208,5758976,0,0,5791744,0,0,0,0,0,3664,0,0,0,0,0,0,0,0,0,0,5111808,0,0,0,0,0,5283840,0,0,0,0,0,5816320,6291456,0,0,0,0,0,0,0,0,0,0,0,0,2389,0,2391,2392,0,0,0,0,6062080,6463488,0,5398528,0,0,6479872,0,0,0,0,0,0,0,3459,0,0,0,3463,0,0,0,0,0,0,6463488,0,0,0,0,0,0,0,0,0,0,0,0,0,303,0,0,0,0,4931584,4939776,0,0,0,0,0,0,5054464,0,0,0,0,0,0,0,0,5210112,0,0,0,5210112,0,0,0,0,5292032,0,0,0,0,5365760,0,0,0,5455872,0,0,5816320,0,5857280,0,0,0,0,0,0,0,0,0,0,0,0,0,327,401,0,6119424,0,6168576,0,0,0,0,0,6242304,0,6291456,0,6316032,0,0,0,0,0,0,0,4358144,4358144,4931584,4939776,4358144,4358144,4358144,4358144,4358144,4358144,5054464,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,5210112,4358144,4358144,4358144,4358144,4358144,4358144,5210112,4358144,4358144,4358144,4358144,5292032,4358144,4358144,4358144,4358144,5365760,4358144,4358144,4358144,5455872,4358144,4358144,4358144,4358144,4358144,4358144,5455872,4358144,4358144,4358144,4358144,4358144,5554176,5570560,5578752,5619712,5668864,4358144,4358144,4358144,5791744,5816320,4358144,5857280,4358144,4358144,4358144,4358144,5816320,4358144,5857280,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,0,0,0,6119424,4358144,6168576,4358144,4358144,4358144,4358144,4358144,6242304,4358144,6291456,4358144,6316032,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,6463488,0,4358144,4358144,4358144,4358144,4358144,4358144,6463488,4358144,4358144,4358144,4358144,4358144,0,0,0,0,0,4825088,0,0,0,0,0,0,0,6184960,5316608,0,0,5644288,0,0,0,0,0,0,0,0,0,0,646,755,756,757,0,0,6217728,0,0,0,0,0,0,0,0,0,0,5390336,5308416,5488640,0,0,0,0,0,0,0,0,0,5799936,0,0,5881856,0,0,0,0,0,0,0,0,0,351,352,353,0,0,0,0,5070848,5431296,0,6430720,0,0,0,0,0,0,0,0,5160960,0,0,0,0,0,0,6053888,0,0,0,0,0,5013504,0,0,0,0,0,0,6053888,0,0,0,4358144,4358144,5013504,4358144,4358144,4358144,0,0,0,0,4841472,0,0,0,4898816,0,0,0,0,0,0,1851,0,1853,0,0,0,0,0,0,0,0,4825088,0,0,0,0,0,0,0,0,2786,0,0,0,0,0,0,0,0,2809,0,0,0,0,0,0,0,0,2834,0,0,0,0,0,0,0,0,3154,0,0,0,0,0,0,0,0,3167,3168,0,0,0,0,0,0,0,0,0,6283264,6332416,0,0,0,5881856,0,5382144,0,0,0,0,0,0,0,3665,3666,0,0,0,0,0,0,0,665,0,644,0,0,0,0,0,0,0,6266880,4784128,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4915200,4358144,4956160,4972544,4358144,4358144,4358144,4358144,4358144,4358144,5070848,4358144,4358144,4358144,4358144,4358144,4358144,4358144,5218304,4358144,5267456,4358144,4358144,4358144,6184960,4358144,4358144,6283264,4358144,4358144,6332416,4358144,4358144,4358144,6389760,4358144,4358144,6430720,6438912,4358144,4358144,4358144,6266880,6488064,0,0,0,6266880,0,0,4915200,0,4956160,4972544,0,0,0,0,0,0,5070848,0,0,0,0,0,0,0,5218304,0,5267456,0,0,0,0,5218304,0,5267456,0,0,5308416,5316608,0,0,0,5431296,0,5488640,0,0,0,0,0,0,0,0,6332416,0,0,0,6389760,0,0,6430720,6438912,0,0,0,0,0,0,4784128,0,0,0,4849664,0,0,0,0,0,4915200,0,4956160,4972544,0,0,0,6430720,6438912,4784128,4358144,4358144,4358144,4849664,4358144,4358144,4358144,4358144,4358144,4915200,4358144,4358144,0,0,0,0,0,0,0,0,0,0,302,0,303,306,5218304,4358144,5267456,4358144,4358144,5308416,5316608,4358144,4358144,4358144,5431296,4358144,5488640,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,5799936,4358144,4358144,5881856,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,6103040,4358144,4358144,4358144,6103040,4358144,4358144,4358144,6184960,4358144,4358144,4358144,6283264,4358144,4358144,6332416,4358144,4358144,0,0,0,0,0,0,0,0,0,368640,0,0,0,0,0,0,2411,0,0,0,0,0,0,0,0,0,1256,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4931584,4939776,6488064,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,357,5660672,5718016,0,5865472,0,0,6037504,0,0,6078464,0,0,6340608,0,6455296,0,0,0,0,420,420,420,420,597,597,420,420,420,420,420,420,420,420,420,420,420,420,420,0,420,0,0,0,0,5472256,0,0,0,6209536,0,0,0,0,6176768,0,0,0,0,0,0,6373376,6389760,0,0,6488064,6103040,0,0,0,0,0,0,1850,0,0,0,0,0,0,0,0,0,662,0,0,0,0,0,0,0,0,0,4898816,0,5709824,0,0,0,5283840,0,0,0,0,5251072,0,6414336,5832704,0,5955584,0,0,4358144,4358144,4841472,4358144,4358144,4358144,4898816,4358144,4358144,4358144,4358144,4358144,4358144,0,0,0,0,0,0,303,0,0,0,4358144,5472256,5521408,4358144,4358144,4358144,5595136,5709824,5718016,4358144,5824512,5865472,4358144,4358144,5922816,4358144,4358144,6021120,4358144,6037504,4358144,4358144,6078464,6111232,4358144,6176768,6209536,6234112,4358144,4358144,4358144,4358144,5283840,0,0,0,0,5472256,5521408,0,0,0,0,5595136,5709824,5718016,0,5824512,5865472,0,0,5865472,0,0,5922816,0,0,6021120,0,6037504,0,0,6078464,6111232,0,6176768,6209536,0,6234112,0,0,6234112,0,0,0,0,0,0,0,4358144,4358144,4841472,4358144,4358144,4358144,4898816,4358144,5283840,4358144,4358144,4358144,4358144,5472256,5521408,4358144,4358144,4358144,4358144,5595136,5709824,5718016,4358144,4358144,0,0,0,0,0,5193728,0,0,0,0,0,0,0,0,4358144,4358144,6209536,4358144,6234112,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,573440,0,0,5890048,0,0,0,6160384,0,5095424,5349376,0,5275648,0,0,0,0,0,0,2308,0,0,0,0,0,0,0,0,0,139264,147456,0,0,344064,0,0,0,0,4997120,0,0,0,0,0,0,0,0,0,0,5947392,0,0,0,0,0,3675,0,0,0,0,0,0,0,0,4012,528,5103616,4358144,4358144,5201920,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,5890048,4358144,4358144,4358144,6029312,4358144,4358144,4358144,4358144,6160384,4358144,4358144,4358144,4358144,4358144,4358144,6406144,0,5103616,0,0,5201920,0,0,0,0,0,0,0,0,0,0,0,5890048,0,0,0,0,6029312,0,0,0,0,6160384,0,0,0,0,0,0,0,6406144,6406144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4997120,4358144,4358144,5038080,4358144,4358144,4358144,5095424,5095424,5103616,4358144,4358144,5201920,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,0,5013504,0,4358144,6406144,4358144,4358144,4358144,0,0,0,4890624,0,0,0,0,0,0,0,0,3209,0,0,3212,0,0,0,0,0,0,5898240,5963776,0,0,6193152,0,0,5406720,6397952,5300224,5234688,5423104,0,0,0,0,0,3675,0,0,0,0,0,4009,0,4011,528,528,0,0,0,0,0,0,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,58815,57893,57893,0,0,5988352,0,0,6135808,6307840,0,5996544,4800512,0,6356992,0,0,0,0,0,0,2317,2318,0,2320,2321,0,0,0,0,0,0,1207,0,1209,0,0,368,368,0,0,0,0,0,0,0,0,0,710,0,0,0,0,0,0,0,0,5496832,0,0,0,0,0,5611520,0,0,0,0,0,0,0,3673,0,0,0,0,0,0,0,0,693,0,0,0,0,0,0,368,4947968,5021696,5529600,0,0,5169152,0,0,0,4800512,4808704,4358144,4358144,4890624,4358144,4947968,4358144,4358144,4358144,5898240,4358144,4358144,4358144,4358144,4358144,4358144,4358144,6307840,4358144,4358144,6356992,6381568,5185536,0,5234688,5300224,0,0,5406720,5529600,0,0,0,0,5898240,0,0,0,0,0,0,0,0,6307840,0,0,6356992,6381568,6397952,4800512,4808704,4358144,4358144,4890624,4358144,4947968,4358144,4358144,4358144,5046272,4358144,4358144,4358144,4358144,5185536,4358144,5234688,5300224,4358144,4358144,5406720,5529600,4358144,4358144,4358144,4358144,5898240,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,6307840,4358144,4358144,6356992,6381568,6397952,5021696,4358144,4358144,5021696,0,0,0,4980736,0,0,0,0,0,5373952,5734400,6045696,0,0,0,0,421,421,421,421,421,421,421,421,421,421,421,421,421,0,421,0,6258688,6447104,0,0,6127616,0,6348800,5906432,0,5537792,3675,4882432,0,0,0,0,0,0,2329,0,0,0,0,0,0,0,0,0,1195,0,0,0,0,0,0,0,0,0,0,5939200,0,0,5677056,6365184,4866048,0,6070272,5545984,5152768,0,0,0,0,0,3675,0,0,0,0,4008,0,4010,0,528,4013,6144e3,4358144,4866048,4882432,4358144,4980736,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,5324800,5373952,5537792,5545984,5586944,5734400,5971968,4358144,6045696,4358144,6070272,4358144,4358144,5537792,5545984,5734400,5971968,4358144,6045696,4358144,6070272,4358144,4358144,4358144,6348800,0,4866048,4882432,0,0,0,0,644,0,0,0,803,0,808,0,794,0,820,0,0,0,0,735,0,0,0,0,0,0,0,0,0,0,0,450560,450560,0,0,450560,0,6045696,0,6070272,0,0,0,0,6348800,0,4866048,4882432,0,4980736,0,0,0,0,0,0,0,0,5324800,5373952,5537792,5545984,5586944,5734400,5971968,0,6045696,0,6070272,0,0,0,0,6348800,4358144,4866048,4882432,4358144,4980736,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,6299648,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,6348800,4358144,6144e3,0,6144e3,0,4988928,5005312,0,0,0,0,5775360,0,0,0,0,749,0,0,0,0,0,0,0,0,0,0,759,0,0,3675,0,0,0,0,0,0,5693440,0,6496256,5144576,5136384,0,5914624,4358144,6324224,0,0,5005312,0,0,0,512e4,5136384,0,0,0,0,0,0,0,1252,0,0,0,748,1259,0,0,0,0,0,0,0,6324224,0,0,5005312,0,0,0,512e4,5136384,0,0,0,0,0,0,6463488,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,6324224,5914624,5914624,0,0,0,0,0,5513216,5783552,0,3675,0,0,0,0,0,0,0,0,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4931584,4939776,4358144,4358144,4358144,0,6053888,0,0,0,0,0,0,0,0,6012928,4358144,4358144,5013504,4358144,4358144,0,0,0,0,0,0,0,0,0,0,0,1153,0,0,0,0,0,3675,0,0,4006,4007,0,0,0,0,528,528,528,528,3220,528,528,528,528,528,528,3227,4358144,4358144,4358144,4358144,4358144,4358144,4358144,6053888,4358144,4358144,0,0,5013504,0,0,0,0,0,312,414,0,0,139264,147456,0,0,0,0,0,0,0,6103040,0,0,0,6184960,0,0,0,6283264,0,0,6332416,0,0,0,6389760,4358144,4358144,4358144,4358144,4358144,4358144,6053888,4358144,4358144,4358144,0,0,0,0,5193728,0,0,0,0,761,0,0,0,0,0,0,0,0,0,0,528,528,528,3700,528,528,528,5742592,0,0,0,0,0,4358144,4907008,4358144,5079040,4358144,5226496,4358144,5742592,4358144,4358144,4358144,6094848,4358144,5062656,0,0,0,0,0,4358144,4358144,6094848,0,4907008,0,5079040,0,5226496,0,5742592,0,0,0,6094848,0,0,0,0,0,3675,0,4005,0,0,0,0,0,0,528,528,528,528,4155,528,528,528,528,528,528,4907008,0,5079040,0,5226496,0,5742592,0,0,0,6094848,0,4358144,4907008,4358144,5079040,5062656,4358144,4358144,4358144,4358144,4358144,0,5062656,0,0,0,0,0,6225920,0,5062656,4358144,4358144,4358144,4358144,4358144,913,5063569,913,913,913,913,913,6226833,989,5063645,0,0,0,4816896,4358144,4358144,4358144,4358144,6086656,4816896,0,0,0,0,6086656,4816896,4358144,4358144,4358144,4358144,6086656,0,5087232,0,5931008,4358144,5332992,5980160,4358144,0,5332992,5980160,0,0,5332992,5980160,0,4358144,5332992,5980160,4358144,0,0,0,0,787,0,0,0,0,806,0,0,0,0,0,0,0,3166,0,0,0,0,0,0,0,0,327,0,0,0,0,0,0,0,5439488,5128192,4358144,5128192,0,5128192,0,5128192,4358144,0,4358144,0,0,4358144,0,4358144,0,0,4358144,6004736,6004736,6004736,6004736,6004736,0,0,0,1,24578,3,0,0,0,0,0,0,0,0,0,0,0,0,0,339,340,0,0,221652,221652,221652,468,468,468,468,468,468,468,468,468,468,468,468,221652,468,221652,221652,221652,468,221652,221652,221652,221652,221652,221652,221652,221652,1,24578,3,0,0,4366336,0,0,0,0,0,302,303,0,0,0,0,1162,0,0,1164,0,0,0,0,0,0,0,0,1311,0,0,0,0,0,1179,0,0,0,762,0,0,0,0,0,0,0,0,0,0,0,0,0,383,0,0,0,0,1064,0,0,0,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,913,913,913,4358144,4358144,1064,0,0,0,0,0,0,0,0,0,0,0,0,0,507,514,514,1,24578,3,0,0,0,0,0,0,0,0,0,0,0,237568,302,0,306,237568,0,0,0,0,0,0,0,0,0,0,0,0,0,643,0,0,4268032,98304,307,0,0,0,0,0,0,0,0,0,0,0,0,0,661,0,0,4210979,24578,3,0,0,297,0,0,0,0,297,0,0,0,0,0,0,0,3685,0,0,0,3688,3689,0,0,0,0,0,245760,245760,245760,0,0,0,0,139264,147456,245760,245760,0,0,245760,0,4210979,24578,3,0,0,4366336,0,0,0,0,0,302,303,0,0,0,0,1164,1297,0,0,0,0,0,0,1304,0,0,0,0,0,2859,0,0,0,0,0,0,0,0,0,2867,368,368,0,0,0,303104,0,0,0,0,0,0,0,0,0,0,647,0,0,0,0,528,1158,0,4857856,4874240,0,0,4923392,0,0,0,0,0,0,0,0,0,379,0,0,0,0,371,0,4358144,4358144,4358144,4358144,0,1984,0,0,0,4825088,0,0,0,0,0,0,0,1253,0,0,0,0,0,0,0,0,2399,2400,0,0,2402,0,0,0,0,0,262144,262144,262144,0,0,0,0,0,0,0,0,0,0,0,0,3449,0,0,0,0,0,262144,262144,0,262144,0,0,0,139264,147456,262144,0,0,0,0,0,0,2344,2345,0,0,0,0,0,0,0,0,798,0,0,0,0,0,809,0,0,0,262144,0,262738,262738,262738,262738,262738,262738,262738,262738,262738,262738,262738,262738,262738,0,262738,0,0,262738,1,24578,3,0,0,4366336,0,0,0,0,0,302,303,0,0,0,0,1177,0,0,0,0,0,0,0,0,0,0,0,4086,528,528,528,528,0,270336,0,0,0,0,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,5177344,278528,278528,0,0,131072,278528,0,0,0,0,278528,0,0,0,0,278528,278528,278528,278528,278528,278528,278528,278528,278528,278528,278528,278528,278528,278528,0,278528,0,0,278528,1,24578,3,0,0,4366336,0,0,0,0,0,302,303,0,0,0,0,1205,1206,0,0,0,0,0,368,368,0,0,0,0,0,0,0,0,0,0,0,712,0,0,0,0,1,24578,3,0,0,4366336,0,0,0,0,0,302,638,0,0,0,0,1218,0,0,0,0,1223,0,0,0,0,0,0,0,1752,0,0,0,1755,0,0,1758,0,4268032,306,641,0,0,0,0,0,0,0,0,0,0,0,0,0,662,0,0,528,0,1430,0,0,0,0,0,4857856,4874240,0,0,0,0,0,0,0,0,3686,0,0,0,0,0,0,0,0,3826,0,3675,0,0,0,0,0,0,6275072,0,0,0,0,0,0,0,0,0,0,0,1525,0,0,0,0,0,3675,4004,0,0,0,0,0,0,0,528,528,4209,528,4210,528,528,528,528,528,1,24578,3,0,0,0,0,0,0,0,0,0,0,0,286720,303,0,307,286720,0,0,0,0,0,0,0,0,0,0,0,0,0,663,0,792,0,307,0,0,0,0,0,0,307,139264,287139,0,0,0,307,0,0,0,0,1234,0,0,0,0,0,0,0,0,0,0,0,2414,0,0,0,0,0,307,1,24578,3,0,0,4366336,0,0,0,0,0,302,66175,0,0,0,0,1250,0,0,0,1255,0,0,0,0,0,0,0,661,0,0,0,0,0,0,0,0,378,0,363,0,0,0,0,0,4268032,306,98946,0,0,0,0,0,0,0,0,0,0,0,0,0,728,0,0,0,0,122880,0,4268032,0,0,0,0,0,0,0,0,0,0,0,0,2310144,0,0,0,0,307,4857856,4874240,0,0,4923392,0,0,0,0,0,0,0,0,0,528,528,3699,528,528,528,528,1,24578,3,0,0,0,0,0,0,0,0,0,0,0,0,304,0,304,0,304,304,304,295216,304,304,304,295216,295216,304,295216,304,304,131072,304,304,304,304,304,295216,304,304,304,304,295216,304,304,304,304,295286,295216,295216,295216,295216,295216,295216,304,304,304,304,304,0,0,304,304,295216,304,304,304,304,304,304,304,304,304,304,304,304,369,304,0,295216,304,295286,295216,295216,295216,304,304,304,295286,139264,147456,295216,295216,304,304,295216,295216,295216,304,304,304,304,304,304,304,304,304,304,304,304,304,304,304,304,295216,295286,295286,295286,295286,295286,295286,295286,295286,295286,295286,295286,295286,295286,295216,295216,295216,295216,295216,304,304,304,295216,304,304,304,304,304,304,304,295216,374,304,304,304,304,304,304,304,295216,304,295216,295216,295216,295216,295216,295216,295216,295216,295286,295286,295286,295286,295286,295286,295216,295216,1,24578,3,0,0,4366336,0,0,0,0,0,302,303,0,0,0,0,1267,0,0,0,0,0,0,0,0,0,0,0,3170,0,0,0,0,0,0,0,6275072,0,0,0,0,0,0,0,4399804,4399804,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4399804,0,0,319488,0,0,0,0,0,0,319488,319488,0,0,0,0,0,0,0,3696,0,528,528,528,528,528,528,528,528,528,528,528,3849,528,528,528,319488,0,0,0,319488,319488,319488,319488,319488,319488,319488,319488,319488,319488,319488,319488,319488,319488,319488,319488,319488,319488,0,24578,3,0,0,4366336,253952,0,0,0,0,302,303,0,0,0,0,1282,0,0,0,0,0,0,0,0,0,0,0,1241,0,0,0,0,368,425984,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4399805,0,0,0,6275072,0,0,0,0,0,0,0,368,0,0,0,0,0,0,2357,0,0,0,0,0,0,0,0,0,3461,0,0,0,0,0,0,0,327680,327680,327680,0,0,0,0,0,0,0,0,0,0,327680,327680,1,24578,3,0,0,4366336,0,0,0,0,0,302,303,0,327680,327680,327680,327680,327680,335872,327680,327680,327680,335872,327680,327680,327680,327680,327680,327680,49723,0,0,0,0,0,0,0,49723,49723,0,0,0,0,0,0,0,1270,0,0,0,0,0,0,0,0,0,5627904,5652480,0,5701632,0,0,0,0,0,6275072,0,0,0,0,0,0,0,0,0,0,49152,990,0,0,0,0,0,3683,0,0,0,0,0,0,0,3690,0,0,0,0,0,3836,0,0,0,0,0,0,0,0,0,0,5242880,0,0,0,0,0,0,0,5341184,0,0,0,0,0,344064,344064,344064,0,0,0,0,0,0,0,0,0,0,344064,344064,344064,344064,344064,344064,344064,344064,344064,344064,344064,344064,344064,344064,344064,344064,344064,344064,344064,344064,344064,344064,1,24578,3,0,0,4366336,0,0,0,0,0,302,303,0,352256,352256,1,24578,3,0,0,4366336,0,0,0,0,0,302,303,0,0,0,0,1309,0,0,0,0,0,0,0,0,1315,0,0,0,0,371,0,0,0,0,0,0,0,0,0,0,0,3438,0,0,3440,0,1,292,3,0,0,0,298,0,0,0,0,0,0,0,0,0,528,3698,528,528,528,3701,528,0,360448,360448,360448,0,0,0,0,0,0,0,0,0,0,360448,360448,360448,360448,360448,360448,360448,360448,360448,360448,360448,360448,360448,360448,360448,360448,360448,360448,360448,360448,360448,360448,1,0,3,155942,155942,296,0,636,0,0,0,302,303,0,1230,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,368,528,528,1376,528,528,528,528,528,528,528,528,528,528,528,528,528,528,2460,528,0,914,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60322,57943,57943,57943,57943,59004,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,528,57893,3998,0,4e3,528,528,528,528,58773,0,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,0,57916,57916,57916,57916,57916,528,528,528,2437,528,528,528,528,528,528,528,528,528,528,528,528,528,2446,528,2448,0,0,0,57893,57893,57893,57893,57893,57893,57893,59856,57893,57893,57893,57893,57893,57893,60873,57893,57893,57893,57893,57893,57893,57893,57893,57893,61213,57893,57893,57893,57893,61214,61215,57893,57893,57893,57893,60300,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,0,0,0,0,0,60432,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,528,0,0,0,3191,0,0,0,0,0,0,0,0,0,0,0,0,319,0,0,0,0,0,0,3682,0,0,0,0,0,0,0,0,0,0,0,0,338,0,0,0,528,57893,61069,57893,57893,57893,61072,57893,57893,57893,57893,57893,57893,57893,57893,57893,58331,0,57916,57916,57916,57916,57916,61080,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59358,61101,57916,57916,57916,57916,57916,57916,57916,57916,57916,61109,57916,57916,57916,57916,57916,57916,60360,57916,57916,57916,57916,57916,57916,57916,57916,57916,57943,60707,57943,57943,57943,57943,57943,57943,57943,57943,57943,61138,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59568,57943,57943,57943,528,528,3852,3853,528,528,528,528,528,528,528,528,57893,57893,57893,57893,57893,57893,57893,57893,57893,58291,57893,57893,57943,57943,57943,61251,57943,57943,57943,57943,61252,61253,57943,57943,57943,57943,57943,57943,57943,58468,57943,57943,57943,57943,528,528,528,898,0,0,3675,0,0,3929,0,0,0,0,0,0,0,0,0,0,695,0,0,0,0,368,528,528,57893,57893,57893,57893,57893,57893,61299,57893,57893,57893,57893,57893,57893,61305,57893,57893,57893,61309,57893,57916,57916,57916,57916,57916,57916,61315,57916,57916,57916,57916,57916,57943,57943,61128,57943,57943,57943,57943,57943,57943,57943,57943,57943,60066,57943,57943,57943,57943,57943,57943,57916,57916,61321,57916,57916,57916,61325,57916,57943,57943,57943,57943,57943,57943,61331,57943,528,1951,528,2283,528,57893,59394,57893,59632,57893,2290,0,2291,0,0,0,0,0,417792,0,417792,0,0,0,0,310,0,0,0,0,0,316,0,0,0,0,0,0,0,0,0,0,1328,0,0,0,0,0,528,528,57893,57893,57893,57893,61511,57893,57893,57893,57893,57893,57893,57893,57893,57893,58826,57893,57893,57893,57893,57893,57893,57916,57916,57916,57916,61524,57916,57916,57916,57916,57916,57916,57916,57916,57916,57943,57943,57943,60024,57943,60026,57943,57943,57943,57943,57943,61537,57943,57943,57943,57943,57943,57943,57943,57943,57943,0,0,0,0,0,0,4244,528,528,528,57893,57893,57893,57893,57916,57916,57916,57916,57943,57943,57943,57943,0,0,0,0,1310,0,0,0,0,0,0,0,0,0,1316,1269,0,528,528,57893,57893,57916,57916,57943,57943,0,528,57893,57916,57943,0,528,57893,57916,57943,0,528,57893,57916,57943,0,0,0,0,376832,376832,376832,0,0,0,0,0,0,0,0,0,0,0,0,346,0,0,0,0,420,1,24578,3,0,0,4366336,0,0,0,0,0,302,303,0,0,0,0,1731,0,0,0,0,0,0,0,0,0,0,0,648,0,0,0,0,0,0,0,0,4268780,0,0,0,0,0,0,0,0,0,0,0,0,6119424,0,6168576,0,0,0,0,308,0,0,0,0,0,0,0,0,0,0,0,0,354,355,356,0,0,393685,393685,393685,0,0,0,0,0,0,0,0,0,0,0,0,368,0,0,245760,0,0,475136,0,0,0,0,0,0,0,0,0,0,0,0,0,761,0,0,305,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,411,0,421,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,0,0,0,1731,0,0,0,0,1738,0,1740,0,0,0,0,0,0,3180,0,0,0,0,0,0,0,0,0,352256,0,352256,352256,0,0,0,305,306,307,0,0,0,0,0,0,0,0,0,0,0,0,0,1185,0,0,0,0,0,748,421,0,0,0,0,0,0,0,0,0,0,0,337,0,0,0,0,57916,0,0,0,748,57893,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,528,528,3413,57893,57893,60760,1725,0,0,0,1731,1732,0,0,0,0,0,0,0,0,0,0,741,0,0,0,0,0,0,0,0,1252,1825,0,0,0,0,1259,1259,0,0,0,0,0,0,0,4083,0,4085,0,528,528,528,528,528,528,528,528,528,528,3848,528,528,528,528,0,0,2293,1732,2294,0,0,0,0,0,0,0,0,0,0,0,368,368,1212,0,0,528,528,2499,2932,0,0,0,0,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59860,528,528,528,2932,0,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,0,0,2592,0,0,417792,0,0,0,0,417792,0,0,0,0,0,310,0,310,0,0,0,0,0,4151,4152,4153,528,528,528,4156,528,4158,528,528,0,0,0,0,0,0,57893,57893,57893,57893,57893,57893,57893,60283,417792,417792,0,0,417792,417792,417792,417792,417792,417792,417792,417792,417792,417792,417792,417792,418102,417792,417792,418101,418102,417792,417792,418101,417792,418101,417792,0,417792,0,0,0,0,417792,0,0,0,0,0,0,0,0,0,0,0,310,310,310,0,418101,417792,1,24578,3,0,0,4366971,0,0,0,0,0,302,303,311296,4399805,0,0,0,311296,0,0,0,0,0,0,0,0,0,0,800,0,0,0,0,0,0,0,0,4268032,306,307,0,434176,0,0,0,0,0,0,0,0,0,0,0,381,0,384,0,0,0,0,0,6275072,0,0,0,0,0,0,0,0,4399805,0,0,0,0,0,363,0,0,0,0,0,0,368,0,296,0,0,914,913,913,913,913,913,4858769,4875153,913,913,913,913,913,913,913,913,913,5628817,5653393,913,5702545,913,913,913,913,5448593,913,5464977,913,5481361,5563281,913,913,913,5637009,913,5686161,913,913,5751697,913,6275985,913,913,913,913,913,913,913,913,913,0,0,990,989,989,989,989,6087645,4817809,4359057,4359057,4359057,4359057,6087569,0,5087232,0,5931008,4358144,989,989,5260253,989,989,989,989,989,989,989,989,5415901,989,5448669,989,5465053,989,5481437,5563357,989,989,989,5637085,989,5686237,989,989,5751773,989,989,989,989,989,989,6300637,989,989,989,989,989,989,989,989,989,989,5112797,989,989,989,989,989,989,5874653,989,989,989,989,989,989,989,989,989,989,989,6276061,989,989,989,4858845,4875229,989,989,989,989,989,989,989,989,989,989,989,989,989,5178333,989,989,4359057,5637009,4359057,5686161,4359057,4359057,5751697,4359057,4359057,4359057,4359057,4359057,5874577,4359057,4359057,4359057,4359057,5186449,4359057,5235601,5301137,4359057,4359057,5407633,5530513,4359057,4359057,4359057,4359057,4359057,6300561,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,5112721,4359057,4359057,4359057,4359057,989,989,5809041,4359057,4359057,4359057,4826001,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,5178257,4359057,4359057,4359057,4359057,4359057,5243793,4359057,4359057,4359057,4359057,4359057,4359057,4359057,5342097,4359057,4359057,4359057,4359057,4359057,4359057,5415825,4359057,5448593,4359057,5464977,4359057,5481361,5563281,4359057,4359057,0,0,0,913,913,913,913,913,913,913,913,913,913,913,4932497,4940689,913,913,6464401,0,0,0,0,989,989,989,989,989,989,989,989,989,4998109,989,989,5039069,989,989,989,5096413,989,5456861,989,989,989,989,989,5555165,5571549,5579741,5620701,5669853,989,989,989,5792733,5817309,989,5858269,989,989,989,989,989,989,989,989,989,989,989,989,989,989,989,989,4359057,4359057,4359057,6120413,989,6169565,989,989,989,989,989,6243293,989,6292445,989,6317021,989,989,989,989,989,5071837,989,989,989,989,989,989,989,5219293,989,5268445,4359057,4359057,4932497,4940689,4359057,4359057,4359057,4359057,4359057,4359057,5055377,4359057,4359057,4359057,4359057,4359057,4359057,6054801,4359057,4359057,4359057,0,0,0,0,5193728,0,4359057,5456785,4359057,4359057,4359057,4359057,4359057,5555089,5571473,5579665,5620625,5669777,4359057,4359057,4359057,5792657,5817233,4359057,5858193,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,0,5013504,0,6120337,4359057,6169489,4359057,4359057,4359057,4359057,4359057,6243217,4359057,6292369,4359057,6316945,4359057,4359057,4359057,5194641,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4907008,0,5079040,6094848,6430720,6438912,0,0,0,0,0,0,4785041,913,913,913,4850577,913,913,913,913,913,913,5055377,913,913,913,913,913,913,913,913,5211025,5489553,913,913,913,913,913,913,913,913,913,5800849,913,913,5882769,913,913,913,913,5219217,913,5268369,913,913,5309329,5317521,913,913,913,5432209,913,913,913,6333329,913,913,913,6390673,913,913,6431633,6439825,0,0,0,0,0,0,0,393685,0,393685,393685,393685,393685,393685,393685,393685,393685,393685,393685,393685,393685,393685,393685,0,393685,0,4785117,989,989,989,4850653,989,989,989,989,989,4916189,989,4957149,4973533,989,989,989,6030301,989,989,989,989,6161373,989,989,989,989,989,989,989,6325213,4359057,4359057,5006225,4359057,4359057,4359057,5120913,5137297,989,989,5309405,5317597,989,989,989,5432285,989,5489629,989,989,989,989,989,989,5325789,5374941,5538781,5546973,5587933,5735389,5972957,989,6046685,989,6104029,989,989,989,6185949,989,989,989,6284253,989,989,6333405,989,989,989,6390749,989,989,6431709,6439901,4785041,4359057,4359057,4359057,4850577,4359057,4359057,4359057,4359057,4359057,4916113,4359057,4358144,4358144,4358144,4358144,4358144,913,913,913,913,913,0,0,0,0,0,0,0,319488,0,0,0,0,0,0,0,0,0,0,319488,0,4957073,4973457,4359057,4359057,4359057,4359057,4359057,4359057,5071761,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,6275985,4359057,4359057,4359057,4359057,4359057,4359057,4359057,5219217,4359057,5268369,4359057,4359057,5309329,5317521,4359057,4359057,4359057,5432209,4359057,5489553,4359057,4359057,4359057,5211025,4359057,4359057,4359057,4359057,5292945,4359057,4359057,4359057,4359057,5366673,4359057,4359057,4359057,4359057,6390673,4359057,4359057,6431633,6439825,4358144,4358144,4358144,6266880,6488064,913,913,913,6267793,6488977,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,730,4358144,4358144,4358144,0,0,913,913,4842385,913,913,913,4899729,913,913,913,913,913,913,913,6103953,913,913,913,6185873,913,913,913,6284177,913,913,5473169,5522321,913,913,913,913,5596049,5710737,5718929,913,5825425,5866385,913,913,913,913,5243793,913,913,913,913,913,913,913,5342097,913,913,913,0,0,989,989,989,4826077,989,989,989,989,989,989,989,0,913,4359057,4359057,4359057,4359057,4359057,4858769,4875153,5923729,913,913,6022033,913,6038417,913,913,6079377,6112145,913,6177681,6210449,913,6235025,913,913,913,913,6243217,913,6292369,913,6316945,913,913,913,913,913,913,913,4998033,913,913,5038993,913,913,913,5096337,5104529,5284829,989,989,989,989,5473245,5522397,989,989,989,989,5596125,5710813,5719005,989,5825501,5866461,989,989,5923805,989,989,6022109,989,6038493,989,989,6079453,6112221,989,6177757,6210525,989,6235101,989,989,989,989,989,989,989,4359057,4359057,4842385,4359057,4359057,4359057,4899729,4359057,5284753,4359057,4359057,4359057,4359057,5473169,5522321,4359057,4359057,4359057,4359057,5596049,5710737,5718929,4359057,4359057,4359057,6103953,4359057,4359057,4359057,6185873,4359057,4359057,4359057,6284177,4359057,4359057,6333329,4359057,4359057,4923392,4358144,4358144,4358144,4358144,4358144,913,4924305,913,913,913,913,4366336,0,0,0,0,1779,0,0,0,0,0,0,0,0,0,0,0,3156,0,3157,0,0,5825425,5866385,4359057,4359057,5923729,4359057,4359057,6022033,4359057,6038417,4359057,4359057,6079377,6112145,4359057,6177681,6210449,4359057,6235025,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4358144,4358144,4358144,913,913,913,913,913,5194641,913,913,913,913,913,913,913,913,913,913,988,989,989,989,989,989,4358144,4358144,6029312,4358144,4358144,4358144,4358144,6160384,4358144,4358144,4358144,4358144,4358144,4358144,6406144,913,913,913,913,6325137,989,989,5006301,989,989,989,5120989,5137373,989,989,989,989,989,6226909,4359057,5063569,4359057,4359057,4359057,4359057,4359057,6226833,0,6086656,913,913,5202833,913,913,913,913,913,913,913,913,913,913,913,5890961,913,913,913,5555089,5571473,5579665,5620625,5669777,913,913,913,5792657,5817233,913,5858193,913,913,913,913,5292945,913,913,913,913,5366673,913,913,913,5456785,913,913,913,913,913,6308753,913,913,6357905,6382481,6398865,4801501,4809693,989,989,4891613,913,913,6030225,913,913,913,913,6161297,913,913,913,913,913,913,913,6407057,5104605,989,989,5202909,989,989,989,989,989,989,989,989,989,989,989,5891037,6407133,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4998033,4359057,4359057,5038993,4359057,4359057,4359057,5325713,5374865,5538705,5546897,5587857,5735313,5972881,4359057,6046609,4359057,6071185,4359057,4359057,5096337,5104529,4359057,4359057,5202833,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4358144,4358144,4358144,4358144,5890961,4359057,4359057,4359057,6030225,4359057,4359057,4359057,4359057,6161297,4359057,4359057,4359057,4359057,4359057,4359057,5800849,4359057,4359057,5882769,4359057,4359057,4359057,4359057,4359057,4359057,5628817,5653393,4359057,5702545,4359057,4359057,5809041,4359057,4359057,4359057,4359057,6407057,4358144,4358144,4358144,913,913,913,4890624,0,0,0,0,0,0,0,0,327680,0,0,0,0,0,0,0,0,319488,0,0,0,0,319488,0,319488,6397952,4801425,4809617,913,913,4891537,913,4948881,913,913,913,5047185,913,913,913,913,913,913,913,6300561,913,913,913,913,913,913,913,913,913,913,913,913,6120337,913,6169489,913,5186449,913,5235601,5301137,913,913,5407633,5530513,913,913,913,913,5899153,913,913,913,913,913,913,6054801,913,913,913,989,989,5014493,989,989,989,989,989,5194717,989,989,989,989,989,989,989,989,4359057,4359057,989,4948957,989,989,989,5047261,989,989,989,989,5186525,989,5235677,5301213,989,989,989,5211101,989,989,989,989,5293021,989,989,989,989,5366749,989,989,989,5243869,989,989,989,989,989,989,989,5342173,989,989,989,989,989,989,6464477,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,6325137,5914624,5915537,0,0,0,5407709,5530589,989,989,989,989,5899229,989,989,989,989,989,989,989,989,6308829,989,989,6357981,6382557,6398941,4801425,4809617,4359057,4359057,4891537,4359057,4948881,4359057,4359057,4359057,5047185,5899153,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,6308753,4359057,4359057,6357905,6382481,6398865,5021696,4358144,4358144,5022609,913,913,0,4980736,0,0,0,0,0,5373952,5734400,6045696,0,0,0,0,1792,0,0,0,0,0,0,0,0,0,0,0,0,0,0,114688,0,5537792,5545984,5734400,5971968,4358144,6045696,4358144,6070272,4358144,4358144,4358144,6348800,913,4866961,4883345,913,913,4916113,913,4957073,4973457,913,913,913,913,913,913,5071761,913,913,913,913,913,913,5260177,913,913,913,913,913,913,913,913,5415825,4981649,913,913,913,913,913,913,913,913,5325713,5374865,5538705,5546897,5587857,5735313,5972881,913,6046609,913,6071185,913,913,913,913,6349713,989,4867037,4883421,989,4981725,989,989,989,5800925,989,989,5882845,989,989,989,989,989,989,989,989,989,5628893,5653469,989,5702621,989,989,989,989,6071261,989,989,989,989,6349789,4359057,4866961,4883345,4359057,4981649,4359057,4359057,4359057,4359057,4359057,4359057,6464401,4358144,4358144,4358144,4358144,4358144,913,913,913,913,913,913,913,913,913,913,913,913,913,913,913,913,5178257,913,4359057,4359057,6349713,4358144,6144e3,913,6144913,0,4988928,5005312,0,0,0,0,5775360,0,0,0,0,1795,0,0,1798,0,1800,0,0,0,0,0,1806,4358144,6324224,913,913,5006225,913,913,913,5120913,5137297,913,913,913,913,913,913,913,5112721,913,913,913,913,913,5284753,913,913,4358144,4358144,4358144,4358144,4358144,4358144,4358144,6053888,4358144,4358144,913,913,5014417,913,913,913,913,913,5874577,913,913,913,913,913,913,913,913,913,913,913,913,913,989,989,989,4358144,6094848,913,4907921,913,5079953,913,5227409,913,5743505,913,913,913,6095761,913,989,989,4932573,4940765,989,989,989,989,989,989,5055453,989,989,989,989,989,989,6054877,989,989,989,4359057,4359057,5014417,4359057,4359057,4359057,4907997,989,5080029,989,5227485,989,5743581,989,989,989,6095837,989,4359057,4907921,4359057,5079953,4359057,5227409,4359057,5743505,4359057,4359057,4359057,6095761,4359057,5062656,0,0,0,0,0,4358144,4358144,0,913,913,913,913,913,913,0,0,0,0,0,0,0,0,4956160,4964352,0,0,0,0,0,0,0,0,4816896,4358144,4358144,4358144,4358144,6086656,4817809,913,913,913,913,6087569,4817885,5332992,5980160,4358144,913,5333905,5981073,913,989,5333981,5981149,989,4359057,5333905,5981073,4359057,0,0,0,0,1811,0,0,0,0,0,0,0,0,0,1820,0,0,0,0,1825,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,528,5439488,5128192,4358144,5129105,913,5129181,989,5129105,4359057,0,4358144,913,989,4359057,0,4358144,913,989,4359057,6004736,6004736,6005649,6005725,6005649,0,0,0,450560,450560,0,0,0,0,0,0,0,0,0,0,0,0,0,0,375,0,450560,450560,1,24578,3,0,0,4366336,0,0,0,0,0,302,303,0,0,0,0,1876,1877,0,0,0,0,0,0,0,0,0,0,1867,0,0,1870,0,0,0,0,0,196608,0,0,0,106496,0,0,4284416,0,0,0,0,0,0,0,417792,0,0,417792,0,0,417792,0,417792,0,0,0,0,139264,147456,417792,0,0,0,417792,196608,0,0,5816320,6291456,0,0,0,0,0,0,0,0,0,0,0,400,0,0,0,0,0,0,0,0,0,0,303,0,0,307,0,0,0,4956160,4964352,0,0,0,0,0,0,0,466944,0,0,0,0,0,0,0,0,0,5480448,0,0,0,0,0,0,6430720,6438912,914,0,0,0,914,0,4784128,0,0,0,4849664,0,0,0,0,0,648,0,0,0,0,0,0,818,0,0,0,0,0,658,659,0,0,0,0,0,0,0,0,0,1272,0,0,0,0,0,0,0,0,6332416,0,0,0,6389760,0,0,6430720,6438912,990,0,0,0,990,4358144,4358144,4358144,914,0,0,0,4841472,0,0,0,4898816,0,0,0,0,0,0,2383,0,0,0,0,0,0,0,0,0,2825,0,0,0,0,0,0,0,459222,459222,459222,459222,459222,459222,459222,459222,459222,459222,459222,459222,459222,459222,459222,459222,459222,459379,1,24578,3,0,0,4366336,0,0,0,0,0,302,303,0,0,0,0,1887,0,1889,1865,528,528,528,528,528,528,528,528,3516,528,528,3519,528,528,528,60866,4358144,4358144,483328,0,0,0,0,0,0,0,0,0,0,0,0,0,1243,0,0,1,24578,3,0,0,0,0,507904,0,0,0,507904,0,0,0,0,0,0,2398,0,0,0,0,0,0,0,0,0,49723,0,0,0,0,0,327680,0,507904,507904,507904,507904,507904,507904,507904,507904,507904,507904,507904,507904,507904,507904,507904,507904,507904,507904,1,24578,3,0,0,4366336,0,0,0,0,0,302,303,0,0,0,0,2084,0,0,0,4825088,0,0,0,0,0,0,0,0,3423,0,0,0,0,0,0,0,0,3460,0,0,0,0,0,3465,0,4268032,306,307,0,0,442368,0,0,0,0,0,0,0,0,0,0,1168,1167,0,0,0,0,0,0,0,229376,0,491520,524288,0,0,0,0,0,0,0,0,0,678,0,0,0,0,0,0,4358144,4358144,491520,0,0,0,0,0,0,0,0,0,0,0,0,0,1275,0,1277,1,24578,3,0,0,0,0,0,516096,0,0,0,516096,0,0,0,0,0,0,0,0,0,0,0,0,368,0,296,0,0,516567,516567,516567,516567,516567,516567,516567,516567,516567,516567,516567,516567,516567,516567,516567,516567,516567,516567,1,24578,0,0,0,4366336,0,0,548864,0,0,302,303,0,0,0,0,2306,0,0,0,0,0,0,0,0,0,0,0,0,5627904,0,0,0,4268032,306,307,409600,0,0,0,0,0,0,0,0,0,0,0,0,368,0,308,0,0,0,5513216,5783552,0,40960,0,0,0,0,0,0,0,0,4358144,4358144,4358144,4358144,4358144,5193728,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4907008,0,5079040,6094848,1,24578,4227365,0,0,0,0,0,0,299,0,0,0,299,0,0,0,0,0,245760,0,245760,245760,0,0,0,245760,245760,0,0,0,0,0,0,245760,0,0,0,245760,0,0,245760,245760,245760,0,0,540672,0,0,540672,0,0,0,540672,0,0,0,0,0,0,0,540672,0,0,0,0,0,0,0,0,417792,0,0,0,417792,0,0,0,0,0,1,24578,4227365,0,0,4366336,0,0,0,0,0,302,303,0,0,0,0,2328,0,0,0,0,2332,0,0,0,0,0,0,0,1879,0,0,0,0,0,0,0,0,768,0,0,771,0,0,0,0,0,0,499712,0,0,0,0,0,0,0,0,0,0,0,0,0,1291,0,0,0,0,499712,0,0,0,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,5111808,4358144,4358144,4358144,4358144,4358144,5283840,4358144,4358144,4358144,4358144,4358144,499712,0,0,0,0,0,0,0,0,0,0,0,0,0,1314,0,0,0,0,1,24578,3,0,0,4366336,0,0,0,0,0,302,303,0,0,0,0,2355,0,0,0,0,0,0,0,0,0,0,0,1882,0,0,0,0,1,24578,3,155942,296,0,0,0,0,0,0,0,0,0,0,0,528,4087,528,4088,528,528,57893,528,57893,528,528,57893,528,528,57916,57893,528,528,57893,57893,57893,0,0,0,0,0,0,3821,0,0,0,0,57916,57893,57893,57893,57893,57893,57893,57893,57916,57916,57893,57893,57943,57893,57893,57893,0,0,0,0,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,61529,57916,57916,57916,57943,57943,58773,914,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60631,0,0,2293,0,2294,0,0,0,0,0,0,0,0,0,0,0,664,0,0,0,0,3453,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,744,1825,0,0,0,0,0,0,0,0,0,0,0,2373,0,0,0,0,0,674,0,0,0,0,0,0,0,0,0,0,1182,0,0,0,0,0,0,0,1280,0,0,0,0,0,0,0,0,0,0,0,0,0,1788,0,0,528,57894,528,57894,528,528,57894,528,528,57917,57894,528,528,57894,57894,57894,57894,57944,57944,57894,57894,57894,57894,57944,57944,57894,528,57894,57894,57917,57894,57894,57894,57894,57894,57894,57894,57917,57917,57894,57894,57944,57894,57894,57894,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,1,24578,3,155943,296,0,0,0,0,0,0,0,0,0,0,0,740,661,0,0,528,0,573440,573440,573440,0,0,0,0,0,0,0,0,0,0,0,0,368,0,516096,0,0,0,5988352,0,0,6135808,6307840,0,5996544,4800512,0,6356992,3675,0,0,0,0,0,694,0,0,0,787,0,0,0,0,806,0,0,0,1,24578,3,0,0,4366336,0,0,0,0,0,637,303,0,0,0,0,2381,0,0,0,0,0,0,0,0,0,0,0,344064,0,0,0,0,4268032,640,307,0,0,0,0,0,0,0,0,0,0,0,0,0,1804,0,0,581632,0,0,0,581632,581632,581632,581632,581632,581632,581632,581632,581632,581632,581632,581632,581632,581632,581632,581632,0,581632,0,0,0,0,0,0,0,0,0,0,0,581632,0,581632,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,746,581632,581632,1,24578,3,0,0,4366336,0,0,0,0,0,302,303,0,0,0,0,2397,0,0,0,0,0,0,0,0,0,0,0,1225,0,0,0,0,6258688,6447104,0,0,6127616,0,6348800,5906432,0,5537792,3827,4882432,0,0,0,0,0,0,2784,0,0,0,0,0,0,0,0,0,139264,147456,0,0,0,420,0,0,0,3926,0,0,0,0,0,0,5693440,0,6496256,5144576,5136384,0,5914624,0,0,5513216,5783552,0,3926,0,0,0,0,0,0,0,0,4358144,4358144,0,0,0,0,0,0,0,0,0,0,302,0,0,306,0,0,0,0,0,0,306,237983,147456,0,0,0,306,0,0,311,312,0,0,0,0,0,0,0,0,0,0,0,0,0,1819,0,0,312,0,311,311,312,0,0,0,0,0,0,0,0,0,0,0,311,409,312,0,458,472,472,472,485,485,485,485,485,485,485,485,485,506,485,485,485,485,485,524,485,485,485,524,485,485,485,485,485,485,529,57895,529,57895,529,529,57895,529,529,57918,57895,529,529,57895,57895,57895,57895,57945,57945,57895,57895,57895,57895,57945,57945,57895,529,57895,57895,57918,57895,57895,57895,57895,57895,57895,57895,57918,57918,57895,57895,57945,57895,57895,57895,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,0,306,307,0,0,0,0,0,645,0,0,648,649,0,0,0,0,0,736,0,0,0,0,0,0,0,0,0,745,368,368,0,0,704,0,0,0,0,0,0,0,711,0,0,0,0,0,750,0,0,0,0,645,0,0,0,0,0,0,0,6299648,0,0,0,0,0,0,0,0,0,777,0,0,781,0,0,0,0,0,0,0,789,0,0,0,0,0,0,2807,0,0,0,0,0,0,0,0,0,2310,0,0,0,0,0,0,793,0,0,0,0,0,0,0,797,0,0,0,0,0,0,0,0,557056,557056,0,0,0,0,0,0,0,833,793,0,0,0,0,0,837,838,0,0,0,0,793,528,528,0,57893,57893,57893,57893,57893,57893,155942,1151,0,0,1155,0,0,0,0,2295,0,1160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1759,528,847,851,528,528,863,528,528,528,879,528,884,528,892,528,895,528,528,909,528,57893,57893,57893,58266,58270,57893,57893,58282,57893,57893,57893,58298,57893,58303,57893,58311,57893,58314,57893,57893,58328,57893,0,57916,57916,57916,58342,58346,57916,57916,58358,57916,57916,57916,58374,57916,58379,57916,58387,57916,58390,57916,57916,58404,57916,0,0,0,0,58303,57943,57943,57943,58417,58421,57943,57943,58433,57943,57943,528,528,528,57893,57893,57893,0,0,3655,0,3657,0,0,0,0,0,2356,0,2358,0,0,0,0,0,0,0,0,0,5693440,0,6496256,5144576,5136384,0,5914624,57943,58449,57943,58454,57943,58462,57943,58465,57943,57943,58479,57943,847,851,1141,895,1159,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,747,0,0,0,1320,0,0,0,0,0,0,0,0,0,0,0,0,368,302,0,0,528,528,528,1411,528,528,528,528,528,528,528,528,528,528,528,528,528,2470,528,528,0,0,1809,0,0,0,0,0,0,0,0,0,0,0,0,0,1842,0,0,1832,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1201,1885,0,0,1886,0,0,0,0,528,528,528,528,528,528,528,528,528,528,3225,528,528,528,1899,528,528,528,528,528,528,528,528,528,1912,528,528,528,0,0,57893,60609,57893,57893,57893,57893,57893,57893,57893,57893,57893,61085,57893,57893,57893,57893,57893,57893,528,528,528,528,58773,1985,57893,57893,57893,57893,57893,59336,57893,57893,57893,57893,57893,58822,57893,57893,57893,57893,58827,57893,57893,57893,57893,57893,58319,57893,57893,57893,57893,0,57916,57916,58341,57916,57916,57893,59342,57893,57893,57893,57893,57893,57893,57893,57893,57893,59355,57893,57893,57893,57893,57893,58859,57893,57893,57893,58866,57893,50676,58773,990,57916,57916,59442,57916,57916,57916,57916,57916,57916,57916,57916,57916,59455,57916,57916,57916,57916,57916,57916,60387,57916,57916,57916,57916,57916,57916,60394,57916,57916,57916,57916,57916,57916,59514,57916,57916,57916,57916,57916,57916,59520,57916,57916,57916,57916,57916,57943,61127,57943,57943,57943,61130,57943,57943,57943,57943,57943,57943,57943,60968,57943,57943,57943,57943,57943,57943,57943,57943,57943,60721,57943,57943,57943,57943,57943,57943,57943,57943,57943,59610,57943,57943,57943,57943,57943,57943,59616,57943,57943,57943,57943,57943,57943,57943,60982,60984,57943,57943,57943,57943,60988,57943,60990,0,0,2293,0,2294,0,0,0,0,0,0,0,0,0,2300,0,0,0,0,2806,0,0,0,0,0,2811,0,2813,2814,0,0,0,0,0,483328,0,0,0,0,0,0,0,0,0,0,801,0,0,0,0,0,0,2325,0,0,0,0,0,0,0,0,0,2334,0,0,0,0,0,0,2822,0,0,0,0,0,0,0,0,0,769,0,0,0,774,0,0,0,2407,0,0,0,0,0,0,0,0,0,0,0,0,0,0,702,528,2399,528,528,528,528,528,528,528,528,528,528,528,2429,528,528,2432,528,528,2475,528,528,528,528,528,528,528,528,528,528,528,528,528,528,2471,528,57893,57893,59863,57893,57893,57893,57893,57893,57893,59871,57893,57893,57893,57893,57893,57893,0,0,57916,57916,57916,57916,57916,57916,57916,57916,60351,57916,57916,57916,57916,57916,57916,57893,59891,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60640,57916,57916,57916,59949,57916,57916,59952,57916,57916,57916,57916,57916,57916,59960,57916,57916,57893,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,0,0,0,0,57916,57916,60017,57916,57916,57916,57916,57943,57943,57943,57943,57943,57943,57943,57943,57943,60417,57943,57943,57943,57943,57943,60032,57943,57943,60035,57943,57943,57943,57943,57943,57943,60043,57943,57943,528,528,528,57893,57893,57893,0,3654,0,0,0,0,0,0,0,1325,0,0,0,1329,0,0,0,0,57943,57943,60100,57943,57943,57943,57943,2760,528,528,528,528,60109,57893,57893,57893,0,0,0,0,57916,57916,57916,57916,57916,57916,57916,59945,57916,0,0,2781,0,0,0,0,0,0,0,0,0,0,0,0,0,1884,0,0,0,0,2794,0,0,0,0,0,2798,0,0,0,0,0,0,0,0,4784128,0,0,0,0,0,0,0,0,3181,0,0,0,0,0,3186,0,57893,60285,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60293,57893,57893,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,57943,57943,60461,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,4075,0,4076,57943,60472,57943,57943,57943,57943,57943,528,528,528,528,528,57893,57893,57893,57893,57893,0,0,0,0,0,0,0,3150,0,0,0,0,0,0,0,0,0,0,0,0,0,2299,0,0,0,3160,0,0,0,0,0,0,0,0,0,0,0,0,3173,0,0,0,0,2820,0,0,0,2824,0,0,0,0,0,0,0,703,0,0,0,0,0,0,0,0,2331,0,0,0,0,0,0,0,0,3189,0,0,0,0,0,0,0,0,0,0,0,0,3202,3203,0,0,3215,0,528,528,528,528,528,528,528,528,528,528,528,3226,528,528,3230,528,528,528,528,528,528,528,528,528,528,3239,528,528,0,0,0,0,0,0,57893,57893,60279,57893,57893,57893,57893,57893,58320,57893,57893,57893,57893,0,57916,57916,57916,57916,57916,57943,57943,57943,57943,57943,57943,0,0,4289,0,528,60617,57893,57893,60621,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60630,57893,0,0,3137,3138,0,0,0,0,0,0,0,0,0,0,0,3199,0,0,0,0,57916,57916,57916,60666,57916,57916,60670,57916,57916,57916,57916,57916,57916,57916,57916,57916,58383,57916,57916,57916,57916,57916,57916,57916,60679,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60687,57916,0,0,0,0,57893,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,528,528,528,57893,57893,57893,57943,57943,57943,57943,60715,57943,57943,60719,57943,57943,57943,57943,57943,57943,57943,57943,57943,59582,57943,57943,57943,57943,57943,57943,57943,57943,60728,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60736,0,3430,0,0,0,0,0,0,0,0,0,0,0,0,0,0,729,0,528,3495,528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,2904,528,528,528,528,3512,528,3514,528,528,528,528,528,528,528,528,57893,57893,58259,57893,57893,57893,57893,57893,57893,58292,57893,57893,60879,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59389,57893,57893,57893,57893,60897,57893,60899,57893,57893,57893,57893,57893,57893,57893,57893,57893,59399,57893,57893,57893,57893,57893,57893,57916,60921,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57943,57943,57943,57943,57943,57943,60963,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60457,57943,528,4015,528,528,528,528,528,528,528,528,528,528,528,57893,61372,57893,302,306,0,0,0,0,0,0,0,0,0,0,0,0,0,1199,0,0,61374,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57916,61388,57916,0,0,0,0,57893,57943,57943,57943,57943,57943,57943,57943,57943,57943,58442,61390,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57943,61404,57943,528,2281,528,528,528,57893,59630,57893,57893,57893,2290,0,2291,0,0,0,0,0,262144,0,0,0,0,0,0,0,0,0,0,663,0,0,666,667,0,61406,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,0,0,0,0,0,0,528,4077,0,0,0,0,0,0,0,4084,0,0,528,528,528,528,4089,0,0,4148,0,4150,528,528,528,528,528,528,528,528,528,528,528,528,1399,528,528,528,0,0,0,313,314,315,0,0,0,0,0,0,0,0,0,0,1240,0,0,0,0,0,0,0,427,0,131072,0,0,0,0,427,0,0,0,0,0,427,459,0,0,0,459,459,459,459,459,459,459,459,459,459,459,459,523,459,523,523,523,459,523,523,523,523,523,523,530,57896,530,57896,530,530,57896,530,530,57919,57896,530,530,57896,57896,57896,57896,57946,57946,57896,57896,57896,57896,57946,57946,57896,621,57896,57973,57919,57896,57896,57896,57896,57896,57896,57896,57919,57919,57896,57896,57946,57896,57896,57896,57973,57973,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,0,0,0,2830,0,0,0,0,0,0,0,0,0,0,0,680,681,0,0,0,57893,57893,58307,57893,57893,57893,57893,57893,57893,57893,0,57916,57916,57916,57916,57916,57916,57916,60350,57916,57916,57916,57916,57916,57916,57916,60915,57916,57916,57916,57916,57916,57916,57916,57916,58942,57916,57916,57916,57916,57916,57916,57916,57916,60389,57916,57916,57916,57916,57916,57916,57916,57943,57943,57943,57943,58458,57943,57943,57943,57943,57943,57943,57943,528,528,528,528,528,57893,57893,57893,57893,528,528,1965,528,528,528,528,528,528,1972,528,528,528,528,528,528,528,3501,528,3503,528,528,528,528,528,528,1360,528,528,528,528,528,528,528,528,528,2887,528,2889,528,528,528,528,57893,59408,57893,57893,57893,57893,57893,57893,59416,57893,57893,57893,57893,57893,57893,57893,58823,57893,57893,57893,57893,57893,57893,57893,57893,58840,57893,57893,57893,57893,57893,57893,57893,59508,57916,57916,57916,57916,57916,57916,59516,57916,57916,57916,57916,57916,57916,57916,57916,58909,57916,57916,57916,58912,57916,57916,57916,57893,57893,57893,60286,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,58814,57893,57893,57893,60408,57916,57916,57916,57943,57943,57943,57943,57943,57943,60414,57943,57943,57943,57943,60418,57943,57943,57943,60473,57943,57943,57943,528,528,528,528,528,57893,57893,57893,57893,57893,0,0,0,0,2292,528,528,528,4093,528,4095,528,528,4097,528,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,61077,57893,57893,57893,57893,61450,57893,61452,57893,57893,61454,57893,57893,57916,57916,57916,57916,57916,57916,58879,57916,57916,57916,57916,57916,58891,57916,57916,57916,57916,57916,61464,57916,61466,57916,57916,61468,57916,57916,57943,57943,57943,57943,57943,57943,60956,57943,57943,57943,57943,57943,60960,57943,57943,57943,57943,61478,57943,61480,57943,57943,61482,57943,57943,0,0,0,0,0,0,0,1766,0,0,1769,0,0,0,0,0,320,320,428,429,131072,436,429,437,439,428,436,437,0,316,437,455,460,473,473,473,486,486,486,486,486,486,486,486,486,486,508,508,521,521,522,522,508,522,522,522,508,522,522,522,522,522,522,531,57897,531,57897,531,531,57897,531,531,57920,57897,531,531,57897,57897,57897,57897,57947,57947,57897,57897,57897,57897,57947,57947,57897,622,57972,57972,57920,57897,57897,57897,57897,57897,57897,57897,57920,57920,57897,57897,57947,57897,57897,57897,57972,57972,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,0,0,0,3151,0,0,0,0,0,3155,0,0,0,0,0,0,814,0,0,0,0,0,0,819,0,0,0,686,0,0,0,0,0,0,0,0,0,0,0,0,0,368,0,0,0,368,368,702,0,0,0,0,0,0,0,0,0,0,0,0,0,2315,0,0,0,0,0,734,0,0,0,0,0,0,0,0,0,0,0,0,368,303,0,0,0,823,0,0,0,0,0,0,0,0,0,0,0,0,0,0,775,0,0,1174,0,0,0,0,0,0,0,0,0,0,0,0,0,0,804,0,0,0,0,1216,1174,0,0,0,0,0,0,0,0,0,0,0,0,0,2336,0,0,0,0,0,1281,0,0,0,0,0,0,0,0,0,0,0,0,368,342,296,0,0,0,1295,0,0,0,0,0,0,0,0,0,0,0,0,0,2363,0,0,1307,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1229,58773,914,57893,57893,58777,57893,57893,58781,57893,57893,57893,57893,57893,57893,57893,57893,58808,57893,57893,57893,57893,57893,57893,57893,58795,57893,58800,57893,57893,58804,57893,57893,58807,57893,57893,57893,57893,57893,57893,57893,58838,57893,57893,57893,57893,57893,57893,57893,57893,58841,57893,57893,57893,57893,57893,57893,57893,58872,57916,57916,58876,57916,57916,57916,57916,57916,57916,57916,57916,58890,57916,58895,57916,0,0,0,0,57893,57943,57943,57943,57943,57943,57943,58428,57943,57943,58444,57916,58899,57916,57916,58902,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59985,57916,57916,57916,1860,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1245,528,528,528,528,1902,528,528,528,528,528,528,528,528,528,1914,528,528,0,57893,57893,57893,57893,57893,57893,155942,1151,0,0,1156,0,0,0,0,327,327,377,0,0,0,0,0,0,0,0,0,1210,0,368,368,0,1213,0,1929,528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,896,57893,57893,57893,59345,57893,57893,57893,57893,57893,57893,57893,57893,57893,59357,57893,57893,1,24578,3,155942,156282,296,0,0,0,0,0,302,303,0,57916,57916,59445,57916,57916,57916,57916,57916,57916,57916,57916,57916,59457,57916,57916,57916,57916,57916,59967,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57943,57943,57943,57943,61474,57943,59541,57943,57943,57943,57943,57943,57943,57943,57943,57943,59553,57943,57943,57943,57943,57943,57943,57943,61152,57943,57943,57943,57943,57943,57943,57943,528,528,528,2763,2764,57893,57893,57893,60112,57943,57943,57943,59591,59592,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59601,57943,57943,57943,57893,59917,59918,59919,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,58848,57893,57893,58852,57916,59989,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60002,57943,60072,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60085,57893,57893,60325,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,58849,57893,57893,0,0,0,3216,528,528,528,528,528,528,528,528,528,528,528,528,528,2484,528,528,528,528,528,3243,528,528,528,528,528,528,528,528,528,528,528,528,528,2891,528,528,57893,57893,57893,57893,60634,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,0,2999,0,0,0,61125,57916,57916,57916,57916,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60962,528,528,4092,528,528,528,528,528,528,528,57893,61444,57893,61445,57893,57893,57893,2589,0,0,0,57916,57916,57916,57916,57916,57916,57916,57916,57916,61106,57916,57916,57916,57916,57916,57916,57916,57916,59954,57916,57916,59958,57916,57916,57916,59962,57893,61449,57893,57893,57893,57893,57893,57893,57893,57893,57916,61458,57916,61459,57916,57916,57893,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59540,57916,61463,57916,57916,57916,57916,57916,57916,57916,57916,57943,61472,57943,61473,57943,57943,528,528,1715,528,528,1718,57893,57893,59064,57893,57893,59067,1151,0,57943,61477,57943,57943,57943,57943,57943,57943,57943,57943,0,0,0,0,0,0,0,1814,0,0,0,0,0,0,0,0,528,1338,528,528,528,528,528,528,528,528,4291,57893,57893,57893,61637,57916,57916,57916,61639,57943,57943,57943,61641,0,0,0,0,3178,0,0,0,0,0,0,0,0,0,0,0,1312,0,0,0,0,326,327,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1186,0,0,0,377,0,131072,0,0,0,440,377,0,0,445,451,0,377,461,474,474,474,487,487,487,487,487,487,487,487,487,487,509,509,509,509,509,509,509,509,509,509,509,509,509,509,509,509,532,57898,532,57898,532,532,57898,532,532,57921,57898,532,532,57898,57898,57898,57898,57948,57948,57898,57898,57898,57898,57948,57948,57898,532,57898,57898,57921,57898,57898,57898,57898,57898,57898,57898,57921,57921,57898,57898,57948,57898,57898,57898,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,1188,0,1190,1191,0,0,0,1193,1194,0,0,0,0,0,0,0,0,4997120,0,0,5038080,0,0,0,5095424,5103616,0,0,1232,1233,0,0,0,0,0,0,0,0,0,0,0,0,370,0,0,0,1263,1265,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1200,0,1317,0,0,0,0,0,0,0,0,0,1303,0,0,0,1331,1193,528,528,1390,528,528,1392,528,528,528,528,1397,528,528,528,528,528,528,3500,528,528,528,528,528,528,528,528,528,528,61443,57893,57893,57893,57893,57893,58773,914,57893,57893,58778,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,2588,2999,0,0,0,58831,57893,57893,57893,57893,58836,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,58811,58813,57893,57893,57893,57893,58873,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60380,57916,58900,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,58928,57916,57916,58915,57916,57916,57916,57916,57916,57916,57916,58924,57916,57916,58926,57916,57916,57916,57916,57916,59980,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,61530,57916,57916,57943,57943,57916,58931,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,58950,57916,57916,57916,58956,57916,57916,57916,57916,0,58831,57943,57943,58967,57943,57943,57943,57943,57943,57943,60464,57943,57943,57943,57943,57943,57943,57943,57943,60470,57943,57943,57943,57943,59018,57943,57943,59020,57943,57943,57943,57943,59026,57943,57943,57943,528,528,57893,57893,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2778,1963,528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,901,0,0,2293,0,2294,0,0,0,0,0,2297,0,0,0,0,0,0,316,317,318,319,320,321,322,323,324,325,57893,59862,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60650,57893,59878,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,58816,57893,59947,57916,57916,57916,57916,59951,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57943,57943,57943,57943,57943,61475,60015,57916,57916,57916,57916,57916,57916,57943,57943,57943,57943,57943,57943,57943,57943,57943,61133,57943,60030,57943,57943,57943,57943,60034,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60723,57943,57943,57943,60098,57943,57943,57943,57943,57943,57943,528,528,528,528,528,57893,57893,57893,57893,57893,0,0,0,1729,0,0,0,0,2844,0,0,0,0,0,2849,0,0,0,0,0,0,0,1852,0,0,0,0,0,0,0,1859,0,57916,57916,57916,60347,57916,60348,57916,57916,57916,57916,57916,57916,57916,57916,57916,58385,57916,57916,57916,57916,58403,57916,0,0,3205,0,0,0,0,0,0,0,0,0,0,0,0,0,2374,0,0,528,528,528,528,3253,528,528,528,528,528,528,528,528,528,528,528,528,1926,528,528,528,57916,60688,57916,57916,57916,57916,57916,57916,57916,60694,57916,57916,57916,57916,57916,57916,58906,58908,57916,57916,57916,57916,57916,57916,57916,57916,59451,57916,57916,57916,57916,57916,57916,57916,57916,59498,57916,57916,57916,57916,57916,57916,57916,57916,60672,57916,57916,57916,57916,57916,57916,57916,57943,57943,60737,57943,57943,57943,57943,57943,57943,57943,60743,57943,57943,57943,57943,57943,57943,57943,61339,57943,57943,57943,528,57893,0,0,0,0,0,0,3671,0,0,0,0,0,0,0,0,0,0,0,0,665,0,0,668,57916,61126,57916,57916,57916,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60961,57943,57916,57916,57916,61239,57916,57916,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60959,57943,57943,57943,57943,61258,57943,57943,528,528,57893,57893,0,0,0,0,0,0,0,0,0,0,0,0,2776,2777,0,528,528,528,528,4018,528,528,528,528,528,528,528,528,57893,57893,57893,57893,57893,57893,58280,57893,57893,57893,57893,57893,57893,57893,57893,61377,57893,57893,57893,57893,57893,57893,57893,57893,57893,57916,57916,57916,61223,57916,57916,57916,57916,57916,57916,61393,57916,57916,57916,57916,57916,57916,57916,57916,57916,57943,57943,57943,57943,60025,57943,57943,57943,57943,57943,57943,57943,61409,57943,57943,57943,57943,57943,57943,57943,57943,57943,0,0,0,4241,0,4243,528,528,528,528,528,4094,528,528,528,528,528,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59372,57893,57893,57893,61451,57893,57893,57893,57893,57893,57893,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,61318,57916,57916,57916,61465,57916,57916,57916,57916,57916,57916,57943,57943,57943,57943,57943,57943,61244,57943,57943,57943,57943,57943,57943,61479,57943,57943,57943,57943,57943,57943,0,0,0,0,0,0,0,1865,1866,0,0,0,1869,0,0,0,0,0,328,329,330,331,0,0,0,0,0,0,0,0,0,0,1855,1856,0,1857,1858,0,0,376,0,0,0,0,0,328,376,331,375,0,0,0,0,0,0,363,0,0,0,0,0,0,0,0,0,139264,147456,0,0,450560,0,0,0,331,0,0,0,0,0,0,376,0,0,0,0,0,0,0,0,5210112,0,5365760,0,5554176,5570560,5578752,0,462,475,475,475,488,488,488,488,499,501,488,488,499,488,510,510,510,510,510,525,510,510,510,525,510,510,510,510,510,510,533,57899,533,57899,533,533,57899,533,533,57922,57899,533,533,57899,57899,57899,57899,57949,57949,57899,57899,57899,57899,57949,57949,57899,533,57899,57899,57922,57899,57899,57899,57899,57899,57899,57899,57922,57922,57899,57899,57949,57899,57899,57899,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,0,670,671,0,0,0,0,0,0,0,0,0,0,0,683,684,685,0,0,0,689,0,0,0,0,0,0,0,0,0,0,368,368,0,0,0,0,0,0,707,708,0,0,0,0,0,714,0,0,0,718,0,720,0,0,0,0,0,0,727,0,0,0,0,0,1163,0,0,0,0,0,0,0,0,0,0,6152192,0,0,0,6316032,0,731,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1292,778,779,0,0,0,0,0,0,0,0,788,0,790,0,0,0,0,0,1201,0,0,0,0,0,0,0,0,0,0,3675,0,0,0,3830,0,822,0,0,0,0,0,822,822,825,0,0,0,790,0,0,0,0,0,1235,0,1237,0,0,0,0,1242,0,0,0,0,0,1268,0,0,0,0,0,0,0,0,0,0,3675,0,0,3829,0,0,0,0,834,0,0,0,0,0,0,0,788,0,0,0,834,528,528,0,57893,57893,57893,57893,57893,57893,155942,1151,0,302,0,0,306,1,24578,3,0,0,4366336,0,0,0,0,0,65536,303,0,528,848,528,854,528,528,869,528,528,880,528,885,528,528,894,897,902,528,910,528,57893,57893,57893,58267,57893,58273,57893,57893,58288,57893,57893,58299,57893,58304,57893,57893,58313,58316,58321,57893,58329,57893,0,57916,57916,57916,58343,57916,0,0,0,0,57893,57943,57943,57943,57943,57943,57943,58430,57943,57943,57943,57943,57943,59547,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,61417,57943,0,0,0,58349,57916,57916,58364,57916,57916,58375,57916,58380,57916,57916,58389,58392,58397,57916,58405,57916,0,0,0,0,58304,57943,57943,57943,58418,57943,58424,57943,57943,58439,57943,1906,528,528,528,528,59349,57893,57893,57893,57893,0,0,0,0,0,3140,0,0,3143,3144,0,0,3147,3148,0,57943,58450,57943,58455,57943,57943,58464,58467,58472,57943,58480,57943,848,528,528,1142,902,528,0,57893,58267,57893,58492,58321,57893,155942,1151,0,0,0,0,0,0,364,365,366,367,0,0,368,0,296,0,0,0,0,1176,0,0,0,0,0,0,0,1183,0,0,0,0,0,0,3165,0,0,0,0,0,0,0,0,0,139264,147456,0,0,0,421,0,0,1203,1204,0,0,0,0,1208,0,0,0,368,368,0,0,0,0,0,0,0,0,0,0,0,0,713,0,0,1231,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1244,0,0,0,1248,0,0,1200,0,0,0,0,0,749,0,0,0,0,0,0,0,0,0,0,0,726,0,0,0,0,528,1347,528,528,528,528,528,528,1362,528,528,528,1367,528,528,528,528,528,2464,528,528,528,528,528,528,528,528,528,528,528,1910,528,528,528,528,58773,914,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,58786,57893,57893,57893,0,0,0,0,57916,57916,57916,57916,57916,57916,59944,57916,57916,57893,57893,57893,58801,57893,57893,57893,58806,57893,57893,57893,57893,57893,57893,57893,57893,58809,57893,57893,57893,57893,57893,57893,57893,57893,57893,58854,57893,57893,57893,57893,57893,57893,58865,57893,50676,58773,990,57916,57916,57893,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59537,57943,57943,528,1351,528,1408,528,528,58790,57893,57893,58847,57893,57893,1151,0,57916,57916,57916,58901,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,58391,57916,57916,57916,57916,57916,57916,58918,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,58396,57916,57916,57916,57916,57916,57916,58933,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,58949,57916,0,0,0,0,57893,57943,57943,57943,57943,57943,57943,58431,57943,57943,57943,57943,57943,60063,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60428,57943,60430,57943,57943,57943,57943,58975,57943,57943,57943,57943,57943,57943,58990,57943,57943,57943,58995,57943,2280,528,2282,528,528,59629,57893,59631,57893,57893,0,0,0,0,0,0,1298,0,0,0,0,1303,0,0,0,0,59055,57943,528,528,528,528,528,528,57893,57893,57893,57893,57893,57893,1151,1724,0,1760,0,0,1763,1764,1765,0,1767,1768,0,0,0,0,1773,0,0,0,0,3192,0,0,0,0,3197,0,0,0,0,0,0,0,2368,2369,0,0,0,0,0,0,0,692,0,0,0,0,0,0,699,368,1807,0,0,0,0,0,0,0,0,1816,1817,0,0,0,0,0,0,373,0,0,0,0,0,0,0,0,0,139264,147456,0,0,352256,0,0,0,1823,0,0,1825,0,0,0,0,0,0,0,0,1829,1830,1831,0,1870,0,0,0,1888,1740,1740,1890,528,1892,528,1893,1894,528,1896,528,528,528,1900,528,528,528,528,528,528,528,528,528,1913,528,528,0,0,0,0,0,0,57893,60278,57893,57893,57893,57893,57893,57893,0,2592,57916,57916,57916,57916,57916,57916,57916,57916,59969,57916,57916,57916,57916,57916,57916,59974,57916,528,528,1917,528,528,528,528,1921,528,1923,528,528,528,528,528,528,1393,528,1395,528,528,528,528,528,528,528,872,528,528,528,528,528,528,528,528,528,3710,528,528,528,528,528,528,528,528,528,528,1933,1934,1936,528,528,528,528,528,528,528,1944,1945,528,1947,528,528,1950,1951,528,528,528,528,528,528,528,1959,528,1961,528,1964,528,528,528,528,528,1971,528,528,1973,528,528,528,528,528,528,3855,528,528,528,528,528,57893,57893,57893,57893,57893,57893,58279,57893,57893,57893,57893,57893,528,528,528,528,58773,0,59332,57893,59334,57893,59335,57893,59337,57893,59339,57893,302,306,0,0,0,0,3141,0,0,0,3145,0,0,0,0,0,0,2832,0,0,0,0,0,0,0,0,0,2835,0,0,0,0,0,0,57893,57893,59343,57893,57893,57893,57893,57893,57893,57893,57893,57893,59356,57893,57893,57893,0,0,0,0,57916,57916,57916,57916,59942,57916,57916,57916,57916,57916,59515,57916,57916,59517,57916,57916,57916,57916,57916,57916,57916,0,57893,57943,57943,58966,57943,57943,58970,57943,57893,59360,57893,57893,57893,57893,59364,57893,59366,57893,57893,57893,57893,57893,57893,57893,58839,57893,57893,58846,57893,57893,57893,57893,57893,57893,57893,57893,59376,59377,59379,57893,57893,57893,57893,57893,57893,57893,59387,59388,57893,2770,2291,0,2771,2294,0,0,0,0,0,0,0,0,0,0,770,0,0,0,0,0,59390,57893,57893,59393,59394,57893,57893,57893,57893,57893,57893,57893,59402,57893,59404,57893,2770,2291,0,2771,2294,0,0,0,0,0,0,2775,0,0,0,0,0,784,0,0,679,0,0,0,0,0,0,0,660,661,0,0,0,0,0,0,0,384,0,139264,147456,0,406,0,0,406,59407,57893,57893,57893,57893,57893,59415,57893,57893,59417,57893,57893,57893,57893,57893,57893,0,0,57916,57916,57916,57916,60660,57916,57916,57916,57916,59443,57916,57916,57916,57916,57916,57916,57916,57916,57916,59456,57916,57916,57916,57916,57916,58878,57916,57916,57916,58882,57916,57916,58893,57916,57916,58897,59460,57916,57916,57916,57916,59464,57916,59466,57916,57916,57916,57916,57916,57916,57916,57916,59467,59468,57916,57916,57916,57916,57916,57916,57916,57916,59476,59477,59479,57916,57916,57916,57916,57916,57916,57916,59487,59488,57916,59490,57916,57916,59493,59494,57916,57916,57916,57916,57916,57916,57916,59502,57916,59504,57916,59507,57943,57943,57943,59560,57943,59562,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60987,57943,57943,57943,59572,59573,59575,57943,57943,57943,57943,57943,57943,57943,59583,59584,57943,57943,59586,57943,57943,57943,57943,57943,60731,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60081,57943,57943,57943,57943,57943,59589,59590,57943,57943,57943,57943,57943,57943,57943,59598,57943,59600,57943,59603,57943,57943,57943,57943,57943,60739,57943,57943,57943,60742,57943,60744,57943,57943,57943,57943,57943,57943,60740,57943,57943,57943,57943,57943,57943,57943,57943,57943,59023,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59611,57943,57943,59613,57943,57943,57943,57943,57943,57943,57943,57943,57943,60039,57943,57943,57943,57943,57943,57943,0,0,2293,0,2294,0,0,0,0,0,0,0,0,0,0,2301,0,0,2304,2305,0,0,0,2309,0,0,0,0,0,0,0,0,0,6406144,5357568,0,5505024,0,0,0,0,2352,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1276,0,1825,0,2365,0,0,0,0,0,0,0,0,2372,0,0,2375,0,0,0,0,3217,528,528,528,528,528,528,528,528,528,528,528,528,2929,528,528,528,0,2378,0,0,0,0,0,0,2385,0,2387,0,0,0,0,0,0,403,0,0,0,0,0,0,0,0,332,333,0,0,0,0,0,0,0,0,334,335,336,0,0,0,0,0,0,0,0,2396,0,0,0,0,0,0,0,0,0,0,0,0,697,698,0,368,2406,0,0,0,0,0,0,0,0,0,0,0,0,0,2417,0,0,0,0,3433,0,0,0,0,0,0,0,0,0,0,0,786,0,0,0,528,2433,528,2435,528,528,528,528,528,528,2443,528,2445,528,528,528,528,528,1414,528,528,528,528,528,528,528,528,528,528,1956,528,528,528,528,528,528,528,528,2451,528,528,528,528,528,528,528,528,528,528,528,528,528,2902,528,528,2473,528,528,528,528,528,528,2480,528,528,528,528,528,528,528,528,1906,528,528,528,528,528,528,528,57893,57893,57893,59864,57893,59866,57893,57893,57893,57893,57893,57893,59874,57893,59876,57893,2770,2291,0,2771,2294,0,0,2773,0,0,0,0,0,0,0,0,2359296,418,418,0,0,0,0,0,57893,57893,59904,59905,57893,57893,57893,57893,57893,57893,59912,57893,57893,57893,57893,57893,57893,60885,57893,60887,57893,57893,57893,57893,57893,57893,57893,59397,57893,57893,59400,57893,57893,57893,57893,57893,59930,59931,57893,0,0,0,0,57916,57916,57916,57916,57916,57916,57916,57916,57916,58910,57916,57916,57916,57916,57916,57916,59963,57916,59965,57916,57916,57916,57916,57916,57916,57916,59971,57916,57916,57916,57916,57916,57916,60914,57916,57916,57916,57916,57916,60918,57916,57916,57916,57916,60016,57916,57916,60019,60020,57916,57943,57943,57943,57943,57943,57943,57943,57943,57943,0,4239,0,0,0,0,528,60046,57943,60048,57943,57943,57943,57943,57943,57943,57943,60054,57943,57943,57943,57943,57943,57943,58979,58986,57943,57943,57943,57943,57943,57943,57943,57943,57943,60079,57943,57943,57943,57943,57943,57943,57943,60099,57943,57943,60102,60103,57943,2435,528,2762,528,528,59866,57893,60111,57893,57893,57893,57893,57893,61083,57893,57893,57893,57893,57893,57893,57893,57893,61089,57893,57893,57893,57893,57893,61219,57893,57893,57893,57916,57916,57916,57916,57916,57916,57916,1272,57893,57943,57943,57943,57943,57943,57943,57943,528,3132,528,528,528,57893,60479,57893,57893,0,0,2829,0,0,0,0,2833,0,0,0,0,0,0,0,0,312,311,0,0,0,311,311,312,2905,528,528,528,528,2909,528,528,528,2914,528,528,528,528,528,528,1920,528,528,528,528,528,528,528,528,528,1908,528,528,528,528,528,528,528,528,2922,528,528,528,528,528,528,528,2927,528,528,528,528,528,528,3940,528,528,528,528,528,528,3946,528,528,60284,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59406,60296,57893,60298,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59403,57893,57893,57893,60324,57893,57893,57893,57893,57893,57893,57893,57893,60332,57893,57893,57893,57893,57893,57893,61096,57893,57893,57893,57893,57916,57916,57916,57916,57916,57916,60703,57916,57916,57943,57943,57943,57943,57943,57943,57943,58466,57943,57943,57943,57943,528,528,528,896,57893,57893,57893,60338,57893,57893,57893,57893,57893,57893,57893,0,2999,0,0,0,0,0,1323,0,0,0,0,0,0,0,0,0,0,2836,2837,0,0,0,0,57916,60382,57916,57916,57916,57916,60386,57916,57916,57916,60391,57916,57916,57916,57916,57916,57916,60926,57916,57916,57916,57916,57916,57916,57916,57916,57916,59956,57916,57916,57916,57916,57916,57916,57916,57916,57916,60399,57916,57916,57916,57916,57916,57916,57916,57916,60405,57916,57916,57916,57916,57916,59992,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,58925,57916,57916,57916,57916,57916,57943,57943,57943,57943,60447,57943,57943,57943,57943,60451,57943,57943,57943,60456,57943,57943,528,1352,528,528,1717,528,58791,57893,57893,57893,59066,57893,1151,0,0,0,3177,0,0,0,0,0,0,0,0,0,0,0,0,0,2390,0,0,528,528,528,528,3232,528,528,528,528,528,528,528,528,528,528,528,528,1941,528,528,528,528,528,3251,528,528,528,528,528,528,528,528,528,528,528,528,528,528,2892,528,57893,57893,57893,57893,60643,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,50676,58773,990,57916,57916,3442,3443,0,3444,0,3446,0,0,0,0,3448,0,0,0,0,0,0,737,0,0,0,0,0,0,0,0,0,2360,0,0,0,0,0,2364,3467,0,0,0,0,3472,3473,0,3475,0,0,3478,0,0,0,3481,528,528,528,528,3498,528,528,528,528,528,3504,528,528,528,528,528,528,4020,528,4022,4023,528,4025,528,57893,57893,57893,57893,57893,57893,60882,57893,57893,57893,57893,57893,60888,57893,57893,60891,57893,57893,57893,0,0,0,0,57916,57916,57916,59941,57916,59943,57916,57916,57916,57916,57916,60006,60007,60008,57916,57916,57916,57916,57916,57916,57916,57916,58943,57916,57916,58947,57916,57916,57916,57916,57916,57916,57916,57916,60924,57916,57916,57916,57916,57916,60930,57916,57916,60933,57916,57916,57893,57943,57943,57943,57943,57943,59532,57943,57943,57943,57943,57943,59538,57943,60991,57943,528,528,3650,57893,57893,60997,0,0,0,0,0,0,3659,0,0,0,0,3445,0,0,0,0,0,0,0,0,0,0,0,2812,0,0,2815,0,0,3662,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1306,0,3669,0,0,0,0,0,0,0,0,0,0,0,0,3676,0,3678,528,528,528,528,3705,528,528,528,528,528,528,528,528,528,528,528,528,2458,528,528,528,528,528,3715,528,528,528,528,528,528,528,528,528,528,528,528,528,528,2903,528,528,57893,57893,57893,61071,57893,57893,57893,57893,57893,57893,57893,61076,57893,57893,57893,0,0,0,0,57916,57916,59940,57916,57916,57916,57916,57916,57916,59981,57916,57916,57916,57916,57916,57916,57916,57916,57916,59453,57916,57916,57916,57916,57916,57916,57893,57893,57893,57893,61095,57893,57893,57893,57893,57893,57893,57916,57916,57916,61100,57916,0,0,0,0,57893,57943,57943,57943,57943,57943,57943,58432,57943,57943,57943,57943,57943,60075,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59048,57943,57943,57943,57943,61134,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,61145,3832,0,0,3835,0,0,0,0,0,0,0,0,0,0,0,0,772,0,0,0,57916,57916,61238,57916,57916,57916,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,61142,57943,57943,57943,3924,0,3675,0,0,0,0,0,3932,0,0,0,0,0,0,0,312,0,0,0,0,0,311,0,311,528,528,57893,57893,57893,57893,57893,57893,57893,57893,57893,61301,57893,57893,57893,57893,57893,59363,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60315,57893,57893,57893,57893,60319,57893,57893,57943,61333,57943,57943,57943,57943,57943,57943,57943,57943,57943,528,57893,0,0,0,0,0,1736,0,0,0,0,0,0,0,0,0,0,2334720,0,2334720,0,0,0,0,0,0,4079,0,0,0,0,0,0,0,528,528,528,528,528,528,528,4157,528,4159,528,528,4091,528,528,528,528,528,528,528,528,57893,57893,57893,57893,57893,57893,57893,57893,57916,57916,61448,57893,57893,57893,57893,57893,57893,57893,57893,57893,57916,57916,57916,57916,57916,57916,57916,57916,57916,61317,57916,61462,57916,57916,57916,57916,57916,57916,57916,57916,57916,57943,57943,57943,57943,57943,57943,57943,60028,57943,61476,57943,57943,57943,57943,57943,57943,57943,57943,57943,4141,4142,0,0,0,4145,528,528,61507,61508,61509,57893,57893,57893,61512,57893,61514,57893,57893,57893,57893,61519,61520,61521,61522,57916,57916,57916,61525,57916,61527,57916,57916,57916,57916,61532,61533,61534,61535,57943,57943,57943,61538,57943,61540,57943,57943,57943,57943,61545,0,0,0,0,0,0,3194,0,0,0,3198,0,3200,0,0,0,528,4245,528,528,528,4249,57893,57893,61595,57893,57893,57893,61599,57893,57916,57916,57893,57943,59529,57943,57943,57943,57943,57943,57943,57943,59536,57943,57943,57943,57943,57943,59040,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,528,3412,528,57893,60759,57893,61601,57916,57916,57916,61605,57916,57943,57943,61607,57943,57943,57943,61611,57943,0,0,0,0,0,2342912,0,0,0,0,0,0,0,0,0,4358144,4359058,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,6275072,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,0,413,0,0,0,0,0,0,413,139264,147456,0,0,0,422,0,0,0,0,3456,0,0,0,0,0,0,0,0,0,0,0,749,0,0,0,0,372,372,0,430,131072,372,430,430,0,333,372,430,0,0,430,456,430,0,0,0,430,495,495,495,500,495,495,495,500,495,430,430,430,430,430,430,430,430,430,430,430,430,430,430,430,430,534,57900,534,57900,534,534,57900,534,534,57923,57900,534,534,57900,57900,57900,57900,57950,57950,57900,57900,57900,57900,57950,57950,57900,534,57900,57900,57923,57900,57900,57900,57900,57900,57900,57900,57923,57923,57900,57900,57950,57900,57900,57900,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,841,528,528,528,528,528,528,873,528,528,528,528,528,528,528,528,1939,528,528,528,528,528,528,528,0,0,1175,0,0,0,0,0,0,0,0,0,0,0,0,0,2416,0,0,0,0,0,1296,0,1175,0,0,0,0,0,0,0,0,0,0,2371,0,0,0,0,0,58773,914,57893,57893,57893,57893,57893,57893,57893,57893,58784,57893,57893,57893,57893,57893,57893,61210,57893,57893,57893,57893,57893,57893,57893,57893,57893,60626,57893,57893,60629,57893,57893,57893,58796,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59424,57943,58973,57943,57943,57943,57943,57943,58985,57943,57943,57943,57943,57943,57943,57943,57943,57943,60053,57943,57943,57943,57943,57943,57943,0,1873,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1743,1744,57943,60460,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60726,57943,61135,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,61257,528,528,528,61636,57893,57893,57893,61638,57916,57916,57916,61640,57943,57943,57943,0,0,0,0,3471,0,0,0,0,0,0,0,0,0,0,0,1868,0,0,0,0,0,0,0,431,131072,0,431,431,0,0,0,431,446,0,431,0,0,0,0,3663,0,0,0,0,0,0,0,0,0,0,0,1289,0,0,0,0,431,476,476,476,489,489,489,489,489,489,489,489,489,489,489,489,489,489,489,489,535,57901,535,57901,535,535,57901,535,535,57924,57901,535,535,57901,57901,57901,57901,57951,57951,57901,57901,57901,57901,57951,57951,57901,535,57901,57901,57924,57901,57901,57901,57901,57901,57901,57901,57924,57924,57901,57901,57951,57901,57901,57901,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,528,528,528,528,58773,1986,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59353,57893,57893,57893,57893,57893,0,0,0,2327,0,0,0,0,0,0,0,0,0,0,0,0,773,0,0,776,2351,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1774,57893,57893,59892,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59900,57893,57893,0,0,0,2805,0,0,0,0,0,0,0,0,0,0,0,0,800,0,0,528,3175,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1790,0,0,3431,0,0,0,0,0,3437,0,0,0,0,0,0,0,331,0,139264,147456,0,0,0,0,0,3482,528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,1372,57893,57893,57893,57893,60883,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60893,60908,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60396,60935,57916,57916,57916,57916,57916,57916,57916,57916,57916,60944,57916,57916,60947,57916,57916,57893,59528,57943,59530,57943,59531,57943,59533,57943,59535,57943,57943,57943,59539,57916,60950,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59012,57943,57943,60977,57943,57943,57943,57943,57943,57943,57943,57943,57943,60986,57943,57943,60989,57943,57943,57943,57943,57943,60966,57943,57943,57943,57943,57943,60972,57943,57943,60975,57943,57943,57943,57943,57943,60750,57943,57943,57943,57943,528,528,528,57893,57893,57893,0,0,0,0,0,0,0,3660,528,528,528,528,3716,528,3718,528,528,528,528,528,528,528,528,528,528,3491,528,528,528,528,528,528,57893,57893,61070,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59385,57893,57893,57893,57893,57893,57893,57893,61082,57893,57893,57893,57893,57893,57893,57893,57893,61088,57893,61090,57943,61146,57943,61148,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,528,57893,0,0,0,528,528,528,528,3854,528,528,528,528,528,528,528,57893,57893,57893,57893,57893,57893,58277,57893,57893,58293,57893,57893,61216,57893,57893,57893,57893,57893,57893,57893,57893,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,61229,57916,57916,57916,57916,57916,57916,57916,57916,57916,61235,57916,57916,57916,57916,57916,61467,57916,57916,61469,57916,57943,57943,57943,57943,57943,57943,57943,60449,57943,57943,60453,57943,57943,57943,57943,57943,61248,57943,57943,57943,57943,57943,57943,57943,57943,57943,61254,57943,57943,57943,57943,57943,57943,58980,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60734,57943,57943,57943,57943,57943,57916,61625,61626,57916,57916,57943,57943,61629,61630,57943,57943,0,0,0,0,528,528,528,528,4275,528,57893,57893,57893,57893,61623,57893,57916,0,761,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1789,0,761,0,0,0,0,0,761,761,0,0,828,0,0,0,0,0,0,738,0,644,738,0,742,743,644,0,0,528,528,852,528,528,528,528,528,528,528,528,528,528,528,528,528,528,2919,528,528,528,528,911,57893,57893,57893,57893,58271,57893,57893,57893,57893,57893,57893,57893,58862,57893,57893,57893,50676,58773,990,57916,58871,58406,0,0,0,0,57893,57943,57943,57943,57943,58422,57943,57943,57943,57943,57943,57943,58981,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60985,57943,57943,57943,57943,57943,528,911,0,58271,57893,57893,57893,57893,58330,155942,1151,0,0,0,0,0,0,751,0,0,0,0,0,0,0,0,0,139264,147456,0,0,319,0,0,0,1279,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2337,0,57943,59035,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59028,57943,528,528,528,1983,58773,0,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59418,57893,57893,57893,57893,57893,57893,57893,59427,50676,0,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60377,57916,57916,57916,57916,59527,57893,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60746,57943,59623,528,528,528,528,528,57893,57893,57893,57893,57893,0,0,0,0,0,0,0,3142,0,0,0,0,0,0,0,752,0,0,0,0,0,0,758,0,59861,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59889,57916,57916,57916,57916,59950,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60675,57916,57916,60678,57943,57943,57943,57943,60033,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60042,57943,57943,57943,3812,528,57893,61158,57893,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,386,57916,57916,57916,57916,61240,57916,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,61255,57943,57943,57943,57943,61259,57943,528,528,57893,57893,0,0,0,0,0,0,0,0,0,0,0,3146,0,0,0,0,0,334,0,0,0,0,0,0,0,0,0,0,0,334,385,387,0,0,0,0,0,0,0,0,0,0,0,0,0,402,0,0,0,0,3672,0,0,0,0,0,0,0,0,0,0,0,1786,0,0,0,0,334,0,0,0,0,0,0,0,0,0,0,0,0,334,0,0,139264,147456,0,0,0,0,0,425,425,0,0,131072,425,0,0,0,0,425,0,447,0,0,425,335,477,477,477,490,490,490,490,490,490,490,490,490,490,511,519,519,519,519,519,526,519,519,519,526,519,519,519,519,519,519,536,57902,536,57902,536,536,57902,536,536,57925,57902,536,536,57902,57902,57902,57902,57952,57952,57902,57902,57902,57902,57952,57952,57902,536,57902,57902,57925,57902,57902,57902,57902,57902,57902,57902,57925,57925,57902,57902,57952,57902,57902,57902,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,0,0,780,0,0,0,0,0,0,0,0,0,0,0,0,0,2789,2790,0,0,795,0,0,0,0,0,0,0,799,0,0,0,0,0,0,0,2330,0,0,0,0,0,0,0,0,1238,0,0,0,0,0,0,0,819,0,0,0,0,0,819,819,0,0,0,0,799,0,0,0,0,0,1750,0,0,0,0,0,0,0,0,0,0,2850,0,0,0,0,0,0,0,0,835,795,0,0,835,0,0,0,0,0,0,0,528,528,528,4154,528,528,528,528,528,528,528,3234,528,528,528,528,528,528,528,528,528,3942,528,528,528,528,528,528,528,528,528,855,528,864,528,528,528,528,528,528,528,528,528,528,528,3944,528,528,528,528,528,528,528,912,57893,57893,57893,57893,57893,58274,57893,58283,57893,57893,57893,57893,57893,59395,59396,57893,57893,57893,57893,57893,57893,57893,57893,57893,59897,57893,57893,57893,57893,57893,57893,58350,57916,58359,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,58401,57916,57916,58407,0,0,0,0,57893,57943,57943,57943,57943,57943,58425,57943,58434,57943,57943,528,1354,528,528,528,528,58793,57893,57893,57893,57893,57893,1151,0,1143,912,0,57893,57893,57893,57893,58493,58331,155942,1151,0,0,0,0,0,0,790,0,802,0,816,0,0,0,0,810,1246,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1821,0,0,0,1308,0,0,0,0,0,0,0,0,1313,0,0,0,0,0,1796,0,0,0,0,0,0,0,0,0,0,1211,368,368,0,0,1214,528,528,528,1350,528,528,528,528,528,528,528,528,528,1369,528,528,0,0,0,2933,0,1986,57893,57893,57893,57893,57893,57893,57893,57893,59884,57893,57893,57893,57893,57893,57893,57893,528,1409,528,528,1413,528,528,528,528,528,1420,528,528,528,1427,528,528,0,57893,57893,57893,58315,57893,57893,155942,1151,0,0,0,0,0,0,0,6324224,4358144,4358144,5005312,4358144,4358144,4358144,512e4,5136384,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,6119424,4358144,6168576,4358144,4358144,4358144,4358144,58773,914,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,58789,57893,57893,57893,57893,57893,61379,57893,61381,61382,57893,61384,57893,61386,57916,57916,57916,57916,57916,60385,57916,57916,57916,57916,57916,57916,60393,57916,57916,57916,57916,57916,60691,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59484,57916,57916,57916,57916,57916,57893,57893,58818,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59914,57893,57893,57916,58954,57916,57916,57916,58961,57916,0,57893,57943,57943,57943,57943,57943,57943,57943,57943,61140,57943,57943,57943,57943,57943,57943,57943,57943,60969,57943,60971,57943,57943,57943,57943,57943,57943,57943,57943,59038,57943,57943,59042,57943,57943,57943,57943,57943,59049,57943,57943,57943,528,528,57893,57893,0,0,0,0,0,0,0,0,3923,59056,57943,528,528,528,528,528,528,57893,57893,57893,57893,57893,57893,1151,0,0,0,0,4003,3675,0,0,0,0,0,0,0,0,528,528,528,528,528,528,528,1345,1844,1845,0,1847,0,0,0,0,0,0,0,0,0,0,0,0,806,0,0,0,0,1861,0,1863,0,0,0,0,0,0,0,0,0,0,0,0,839,0,0,528,0,0,0,1875,0,0,0,0,0,0,0,0,0,0,0,0,990,0,0,0,0,0,1861,0,0,0,0,0,528,528,528,528,528,528,528,528,3223,528,528,528,528,528,528,1949,528,528,528,528,528,528,528,528,1958,528,528,528,528,528,2478,528,528,528,528,528,528,528,528,528,528,1421,528,528,528,528,528,528,528,528,1967,528,528,528,528,528,528,528,528,528,528,1977,1979,57893,57893,59392,57893,57893,57893,57893,57893,57893,57893,57893,59401,57893,57893,57893,57893,57893,59414,57893,57893,57893,57893,57893,57893,59420,57893,57893,57893,57893,57893,59410,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59421,59423,57893,57893,57893,57893,57893,61453,57893,57893,61455,57893,57916,57916,57916,57916,57916,57916,59482,57916,57916,57916,57916,57916,57916,57916,57916,57916,59983,57916,57916,57916,57916,57916,57916,57916,59492,57916,57916,57916,57916,57916,57916,57916,57916,59501,57916,57916,57916,57916,57916,57916,60940,60942,57916,57916,57916,57916,60946,57916,60948,60949,57916,59510,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59521,59523,57916,57916,57916,57916,57916,61570,57916,61571,57916,57916,57916,57916,57943,57943,57943,57943,57943,57943,57943,57943,60416,57943,57943,57943,59588,57943,57943,57943,57943,57943,57943,57943,57943,59597,57943,57943,57943,57943,57943,57943,57943,59043,57943,57943,57943,57943,57943,57943,57943,57943,58988,57943,57943,57943,57943,57943,57943,57943,59606,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59617,59619,57943,57943,57943,528,528,57893,57893,0,0,0,0,0,3921,0,0,0,0,0,1812,0,0,0,0,0,0,0,0,0,0,1839,0,0,0,0,0,0,0,2340,0,0,0,0,0,2346,0,0,0,0,0,0,0,372,0,0,0,380,382,0,0,0,0,0,0,2354,0,0,0,0,0,0,0,0,2362,0,0,0,0,0,1835,0,0,0,0,0,0,0,0,0,0,0,0,528,528,528,528,528,2424,528,528,528,528,528,528,528,528,528,528,3722,528,528,528,528,528,528,528,2436,528,528,528,528,528,528,528,528,528,528,528,528,528,528,2930,528,528,528,2463,528,528,528,528,528,528,528,528,528,528,528,528,528,528,3240,3241,0,0,0,57893,57893,57893,57893,57893,57893,59855,57893,57893,57893,57893,57893,57893,0,0,57916,60658,57916,57916,57916,57916,57916,57916,58940,57916,57916,57916,57916,57916,57916,57916,57916,57916,59518,57916,57916,57916,57916,57916,57916,57916,60003,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,58951,57916,57916,57916,57916,60018,57916,57916,57916,57943,57943,57943,57943,57943,57943,60027,57943,57943,528,1355,528,528,528,528,58794,57893,57893,57893,57893,57893,1151,0,57943,60086,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59570,57943,57943,57943,57943,60101,57943,57943,57943,2436,528,528,528,528,59867,57893,57893,57893,0,0,0,0,57916,59939,57916,57916,57916,57916,57916,57916,57916,60927,57916,60929,57916,57916,57916,57916,57916,57916,0,2793,0,2795,0,0,0,0,0,0,0,0,2800,0,0,2803,0,0,2818,0,0,0,0,0,0,0,2826,0,0,0,0,2828,0,2842,0,0,2845,0,0,0,0,0,0,0,0,0,0,2855,0,0,528,2869,528,528,528,528,528,528,528,528,528,528,528,528,528,2918,528,528,57893,57893,57893,57893,60327,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57916,57916,61099,57916,57916,60336,57893,57893,57893,60339,57893,57893,57893,57893,57893,57893,0,0,0,0,0,0,2772,0,0,0,0,0,0,0,0,2359,0,0,0,0,0,0,0,0,57916,60345,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,58894,57916,57916,57943,60433,57943,57943,57943,57943,57943,57943,57943,60438,57943,57943,57943,57943,57943,57943,57943,59549,57943,57943,57943,57943,57943,57943,57943,57943,57943,60067,57943,57943,57943,57943,57943,57943,57943,60444,57943,57943,57943,57943,57943,57943,57943,60452,57943,57943,57943,57943,57943,57943,57943,59595,57943,57943,57943,57943,57943,57943,57943,57943,57943,61543,57943,57943,0,0,0,0,60459,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60468,57943,57943,57943,528,528,57893,57893,0,0,0,3919,0,0,3922,0,0,60471,57943,57943,57943,57943,57943,57943,3131,528,528,528,528,60478,57893,57893,57893,0,0,0,0,59938,57916,57916,57916,57916,57916,57916,57916,59946,3204,0,0,0,3206,0,0,0,0,0,0,0,0,0,0,0,1818,0,0,0,0,528,528,528,528,3244,528,528,528,528,528,528,528,528,528,528,3249,528,528,528,3252,528,3254,528,528,528,528,528,528,528,3258,528,528,0,0,2503,0,0,0,57893,57893,57893,57893,57893,57893,57893,57893,57893,59858,57893,57893,57893,60632,57893,57893,57893,57893,60635,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59924,57893,59926,57893,57893,57893,57893,60641,57893,57893,57893,60644,57893,60646,57893,57893,57893,57893,57893,57893,57893,57893,58843,57893,57893,57893,57893,57893,57893,57893,60651,57893,57893,57893,57893,57893,0,0,57916,57916,57916,60659,57916,57916,57916,57916,57916,58905,57916,58907,57916,57916,57916,57916,57916,57916,57916,57916,60362,57916,57916,57916,57916,57916,57916,57916,57916,60664,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59458,57916,57916,57916,60680,60681,57916,57916,57916,57916,60684,57916,57916,57916,57916,57916,57916,57916,57943,60022,57943,57943,57943,57943,57943,57943,57943,57943,61153,57943,57943,57943,57943,57943,57943,528,57916,57916,57916,57916,60690,57916,57916,57916,60693,57916,60695,57916,57916,57916,57916,57916,57916,61105,57916,57916,57916,57916,57916,57916,57916,57916,57916,58944,57916,57916,57916,57916,57916,58952,57916,57916,57916,60700,57916,57916,57916,57916,57916,57943,57943,57943,60708,57943,57943,57943,528,528,57893,57893,3918,0,0,0,3920,0,0,0,0,0,0,3695,0,3697,528,528,528,528,528,528,528,1905,528,528,528,528,528,528,528,528,2926,528,528,528,528,528,528,528,57943,57943,60713,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,61144,57943,57943,57943,57943,60729,60730,57943,57943,57943,57943,60733,57943,57943,57943,57943,57943,57943,57943,60036,57943,60038,57943,57943,57943,57943,57943,57943,57943,58984,57943,58989,57943,57943,58993,57943,57943,58996,57943,57943,57943,57943,60749,57943,57943,57943,57943,57943,528,528,528,57893,57893,57893,0,0,0,0,0,0,0,0,0,0,0,3417,0,0,3420,3421,0,0,0,0,0,0,0,0,0,0,0,1827,0,0,0,0,528,528,528,528,3486,528,528,528,528,3490,528,528,528,528,528,528,1952,1953,528,528,528,528,528,528,528,528,528,3517,528,528,528,528,528,57893,528,3496,528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,2931,528,3510,528,528,528,528,528,528,528,528,528,528,528,528,528,57893,57893,57893,61204,57893,57893,57893,60870,57893,57893,57893,57893,60874,57893,57893,57893,57893,57893,57893,57893,58863,58864,57893,57893,50676,58773,990,57916,57916,60880,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59901,57893,60895,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,58830,57893,57916,57916,57916,57916,60912,57916,57916,57916,57916,60916,57916,57916,57916,57916,57916,57916,58962,0,58963,58964,57943,57943,57943,57943,57943,58971,57916,60922,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59472,57916,57916,57916,60937,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,58927,57916,58929,57916,57943,57943,57943,57943,60954,57943,57943,57943,57943,60958,57943,57943,57943,57943,57943,57943,58982,57943,57943,57943,57943,58992,57943,57943,57943,57943,57943,57943,60964,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,61256,57943,57943,57943,57943,60979,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60974,57943,60976,528,528,57893,57893,57893,0,0,0,0,3819,0,0,0,0,0,3822,0,528,528,528,528,528,528,3844,528,528,528,528,528,528,528,528,2481,528,528,528,528,528,2485,2486,57893,57893,61206,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59927,57893,57893,57893,57893,61217,57893,57893,57893,57893,57893,57893,57916,57916,57916,57916,57916,57916,61225,0,0,3675,0,0,0,0,0,0,0,0,0,0,0,3934,0,0,0,0,4080,0,0,0,0,0,0,528,528,528,528,528,528,4211,528,4212,528,528,528,57893,57893,57893,57893,57893,57893,61562,57893,61563,57893,57893,57893,57893,57916,57943,4313,4314,61659,61660,61661,0,528,57893,57916,57943,0,0,0,0,0,2382,0,0,0,0,0,0,0,0,0,0,4284416,0,0,0,0,0,57943,57943,61578,57943,61579,57943,57943,57943,57943,0,0,0,0,0,0,528,528,4273,4274,528,528,57893,57893,61621,61622,57893,57893,57916,0,528,528,57893,57893,57916,57916,57943,57943,4303,4304,61649,61650,61651,0,528,528,528,528,528,528,528,528,528,2428,528,528,528,528,528,528,4096,528,528,4098,57893,57893,57893,57893,57893,57893,58861,57893,57893,57893,57893,50676,58773,990,57916,57916,537,57903,537,57903,537,537,57903,537,537,57926,57903,537,537,57903,57903,57903,57903,57953,57953,57903,57903,57903,57903,57953,57953,57903,537,57903,57903,57926,57903,57903,57903,57903,57903,57903,57903,57926,57926,57903,57903,57953,57903,57903,57903,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,57893,57893,58833,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60649,57893,57893,57916,59948,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59489,57916,57943,60031,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60044,57943,0,384,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2404,0,0,340,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2854,0,0,0,406,0,0,0,0,0,0,0,0,0,0,0,0,406,0,0,0,432,131072,0,432,432,0,0,0,432,0,452,432,0,0,0,0,4206,0,528,528,528,528,528,528,528,528,528,528,528,528,2430,528,528,432,478,478,478,491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,491,538,57904,538,57904,538,538,57904,538,538,57927,57904,538,538,57904,57904,57904,57904,57954,57954,57904,57904,57904,57904,57954,57954,57904,538,57904,57904,57927,57904,57904,57904,57904,57904,57904,57904,57927,57927,57904,57904,57954,57904,57904,57904,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,0,0,661,0,661,0,0,0,0,826,0,0,0,661,0,0,0,0,0,5218304,0,0,0,0,5799936,0,5881856,0,0,0,0,0,0,5029888,5038080,0,0,5103616,5201920,0,0,0,0,0,0,1878,0,0,0,0,0,0,0,0,0,2296,0,0,0,0,0,0,842,528,528,528,857,528,528,528,528,528,528,528,528,528,528,898,528,528,528,528,57893,57893,58260,57893,57893,57893,58276,57893,57893,57893,57893,57893,57893,61220,57893,57893,57916,57916,57916,57916,57916,57916,57916,0,57893,57943,57943,57943,57943,57943,57943,57943,57943,59022,57943,59024,57943,57943,57943,57943,57943,57916,58352,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,58393,57916,57916,57916,57916,57916,60913,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,61471,57943,57943,57943,57943,57943,1160,0,0,0,0,0,0,0,0,0,1167,1168,0,0,0,0,0,0,1299,0,0,0,0,0,0,0,0,528,528,1340,528,528,528,528,528,0,0,0,1249,0,0,0,0,0,0,0,0,0,1260,1261,0,0,0,0,131072,0,0,0,0,0,0,0,0,0,0,0,0,2415,0,0,2418,528,528,528,528,1351,1358,528,528,528,528,528,528,528,528,1371,528,528,0,57893,57893,57893,58317,57893,57893,294,1151,0,0,1155,0,0,0,0,0,5857280,0,6463488,4939776,0,0,5455872,0,0,0,0,0,5554176,5570560,5578752,5619712,5668864,0,0,0,5791744,5816320,0,5857280,0,1373,528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,1406,1408,528,528,528,528,528,528,528,528,528,528,528,1423,528,528,528,528,528,2910,528,528,528,528,528,528,2917,528,528,528,528,528,2490,528,528,528,528,528,528,528,528,528,0,0,57893,57893,57893,57893,57893,60612,57893,60613,57893,57893,57893,58773,914,57893,58776,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,58790,58797,57893,57893,57893,57893,57893,57893,57893,57893,58810,57893,58812,57893,57893,57893,57893,57893,59867,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59872,57893,57893,57893,57893,57893,57893,58832,57893,58834,57893,57893,57893,57893,57893,57893,57893,58847,57893,57893,57893,57893,57893,59881,57893,57893,57893,57893,57893,57893,57893,57893,59888,57893,57916,57916,57916,58957,57916,57916,57916,0,57893,57943,58965,57943,57943,57943,57943,57943,57943,59548,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,61154,57943,57943,57943,57943,528,58999,57943,59001,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59027,57943,57943,57943,57943,59037,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59052,57943,57943,57943,57943,57943,61139,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60454,57943,57943,57943,57943,1946,528,528,528,528,528,528,528,528,1955,528,528,528,528,528,528,1970,528,528,528,528,528,528,1976,528,528,528,528,1982,528,58773,1986,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60648,57893,57893,57893,57893,57893,57893,57893,57893,57893,59346,59347,57893,57893,57893,57893,59354,57893,57893,57893,57893,57893,58315,57893,57893,57893,57893,0,57916,57916,57916,57916,57916,57916,60349,57916,57916,57916,57916,60353,57916,57916,57916,57893,59426,57893,50676,2086,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60932,57916,60934,57916,57916,57916,57916,59446,59447,57916,57916,57916,57916,59454,57916,57916,57916,57916,57916,57916,59449,57916,57916,57916,57916,57916,57916,57916,57916,57916,60390,57916,57916,57916,57916,57916,57916,59526,57916,57893,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59051,57943,57943,57943,59542,59543,57943,57943,57943,57943,59550,57943,57943,57943,57943,57943,57943,57943,57943,57943,60425,57943,57943,57943,57943,57943,57943,0,2313,0,0,0,0,0,0,0,0,0,2322,0,0,0,0,0,0,3208,0,0,0,0,0,0,0,0,0,3210,3211,0,0,0,0,0,528,528,528,528,2477,528,528,528,528,528,528,528,2483,528,528,528,528,528,2924,528,528,528,528,528,528,528,528,528,528,528,2496,528,528,528,0,528,528,528,2488,528,528,528,528,528,528,528,528,528,528,528,0,0,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,0,0,990,57916,57916,57916,57916,57916,60004,57916,57916,57916,57916,57916,57916,57916,60010,57916,57916,57916,57916,57916,58921,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60917,57916,57916,57916,57916,57916,57943,57943,57943,60087,57943,57943,57943,57943,57943,57943,57943,60093,57943,57943,57943,57943,57943,57943,60967,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60040,57943,57943,57943,57943,57943,0,0,0,2782,0,0,0,0,0,0,0,0,0,0,0,0,1169,1170,1171,1172,3159,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1871,528,528,528,3231,528,528,528,528,528,528,528,528,528,528,528,528,528,3248,528,528,528,3262,528,0,0,57893,57893,57893,57893,57893,57893,57893,57893,60614,57893,57893,57893,50676,0,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59441,57893,57893,57893,57893,60622,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57916,61098,57916,57916,57916,57893,57893,57893,57893,60655,57893,0,0,57916,57916,57916,57916,57916,57916,57916,57916,60928,57916,57916,57916,57916,57916,57916,57916,60663,57916,57916,57916,57916,57916,57916,60671,57916,57916,57916,57916,57916,57916,57916,57916,61118,57916,57916,57916,57916,57916,57916,57916,57943,60712,57943,57943,57943,57943,57943,57943,60720,57943,57943,57943,57943,57943,57943,57943,57943,61340,57943,57943,528,57893,0,0,0,57893,57893,57893,61094,57893,57893,57893,57893,57893,57893,57893,57916,57916,57916,57916,57916,57916,61232,57916,57916,57916,57916,61233,61234,57916,57916,57916,528,528,57893,57893,57893,57893,57893,57893,57893,61513,57893,61515,57893,57893,57893,57893,57893,59894,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,0,57916,57916,58335,57916,57916,528,528,61559,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,61567,61624,57916,57916,57916,57916,57943,61628,57943,57943,57943,57943,0,0,0,0,528,4272,528,528,528,528,57893,61620,57893,57893,57893,57893,57916,0,389,341,0,0,0,0,0,0,0,0,0,0,0,0,0,2801,0,0,463,479,479,479,463,463,463,463,463,463,463,463,463,463,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,539,57905,539,57905,539,539,57905,539,539,57928,57905,539,539,57905,57905,57905,57905,57955,57955,57905,57905,57905,57905,57955,57955,57905,539,57905,57905,57928,57905,57905,57905,57905,57905,57905,57905,57928,57928,57905,57905,57955,57905,57905,57905,1,24578,3,155942,156282,296,0,0,0,0,0,302,303,0,0,732,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3427,0,0,0,662,0,662,0,0,0,0,0,0,0,0,662,0,0,0,0,0,6225920,4358144,5062656,4358144,4358144,4358144,4358144,4358144,6225920,0,6086656,528,528,528,528,858,528,528,874,528,528,528,528,528,528,528,528,2913,528,528,528,528,528,528,528,57916,58353,57916,57916,58369,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,61575,57943,57943,57943,0,1189,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3451,0,0,1318,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3480,0,0,0,1334,0,0,0,0,0,528,528,528,528,528,528,528,528,2876,528,528,528,528,528,528,528,528,528,1352,528,528,528,528,528,528,528,528,528,528,528,528,2469,528,528,528,528,528,528,1391,528,528,528,528,528,528,528,528,528,528,528,528,528,3493,528,528,528,528,1410,528,528,528,528,528,1418,528,528,528,528,528,528,528,1379,528,528,528,528,528,528,528,528,1954,528,528,1957,528,528,528,528,58773,914,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,58791,57893,57893,57893,58857,57893,57893,57893,57893,57893,57893,57893,50676,58773,990,57916,57916,57916,57916,57943,57943,57943,60412,57943,60413,57943,57943,57943,57943,57943,57943,57943,58471,57943,57943,57943,57943,528,528,528,901,57943,57943,57943,57943,59039,57943,57943,57943,57943,57943,59047,57943,57943,57943,57943,57943,57943,59563,59564,57943,57943,57943,57943,57943,57943,57943,57943,57943,61484,0,0,4143,4144,0,0,0,1727,0,0,0,0,1734,0,0,0,0,0,0,0,0,0,2370,0,0,0,0,0,0,528,1916,528,528,528,528,528,528,528,528,528,528,528,528,1927,528,528,0,57893,57893,57893,58319,57893,57893,155942,1151,0,302,0,0,306,307,0,0,0,0,0,0,0,0,0,0,650,0,0,0,0,0,2351104,0,0,0,0,0,0,0,0,0,4358144,59359,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59370,57893,57893,57893,50676,0,57916,59433,57916,57916,57916,57916,57916,57916,57916,59440,57916,57943,57943,57943,59544,57943,57943,57943,57943,57943,57943,57943,57943,57943,59555,57943,57943,528,1714,528,1716,528,528,59063,57893,57893,59065,57893,57893,1151,0,57943,57943,57943,59577,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,61143,57943,57943,0,0,2379,2380,0,0,0,0,0,2386,0,0,0,0,0,0,0,2785,0,0,0,0,0,0,0,0,1753,0,0,0,0,0,0,0,528,2474,528,528,528,528,2479,528,528,528,528,528,528,528,528,528,1396,528,528,528,1403,1405,528,2501,0,0,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60878,57893,57893,57893,57893,57893,57893,59906,57893,57893,57893,57893,59911,57893,57893,57893,57893,57893,57893,2999,0,57916,57916,57916,57916,57916,57916,57916,57916,57943,61327,57943,57943,61329,57943,57943,57943,57916,59964,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59506,57916,57943,60047,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60070,60071,57916,57916,57916,57916,61115,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,58885,58892,57916,57916,57916,0,3925,3675,0,0,0,0,0,0,0,0,0,0,0,0,0,2838,2839,0,3949,528,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,58850,57893,57893,57893,61308,57893,57893,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,58886,57916,57916,57916,57916,4001,0,0,0,0,3675,0,0,0,0,0,0,0,0,528,528,528,528,528,528,1895,528,528,528,4016,528,528,528,528,528,528,528,528,528,528,57893,57893,57893,57893,57893,57893,57893,61375,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57916,57916,57916,57916,57916,61461,57916,61391,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,61407,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,0,0,0,0,0,2316,0,0,0,0,0,0,0,0,0,0,3838,0,0,0,0,0,528,528,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,61566,57916,0,0,0,0,57893,57943,57943,58410,57943,57943,57943,57943,57943,57943,58443,0,0,0,390,391,393,343,0,0,0,0,0,0,342,0,0,0,343,0,0,0,0,0,0,0,0,0,2787,0,0,0,0,0,0,0,0,0,390,0,0,0,0,0,0,343,0,0,0,390,0,0,0,0,131072,0,0,0,0,0,0,0,0,0,310,0,0,0,0,1749,0,0,0,0,0,0,0,0,0,0,0,540672,0,0,0,0,0,0,480,480,480,480,496,496,496,496,496,496,496,496,496,480,480,480,480,480,480,480,480,480,480,480,480,480,480,480,480,540,57906,540,57906,540,540,57906,540,540,57929,57906,540,540,57906,57906,57906,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,57929,57906,57906,57906,57906,57906,57906,57906,57929,57929,57906,57942,57956,57942,57942,57942,57942,57956,57956,57942,57942,57942,57942,57956,57956,57942,540,57906,57906,368,368,0,0,0,0,0,706,0,0,0,0,0,0,0,0,740,0,0,0,0,740,0,746,715,0,717,0,0,0,0,0,0,0,725,0,0,0,0,0,0,804,0,0,0,0,0,0,804,0,528,0,0,813,0,796,0,0,815,0,667,0,792,0,0,0,0,0,836,0,0,0,0,796,663,840,0,528,0,792,815,0,815,813,0,0,0,827,0,0,0,663,830,0,0,0,0,131072,0,0,0,0,0,0,0,444,0,0,0,0,0,690,691,0,0,0,0,696,0,0,0,368,843,528,528,528,859,528,528,875,528,528,528,528,889,528,528,528,528,528,3245,528,528,528,528,528,528,528,528,528,528,528,1398,528,528,528,528,528,907,528,528,57893,57893,58261,57893,57893,57893,58278,57893,57893,58294,57893,57893,57893,50676,0,59432,57916,59434,57916,59435,57916,59437,57916,59439,57916,57916,57893,57943,57943,57943,57943,57943,57943,57943,59534,57943,57943,57943,57943,57943,57943,59594,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60467,57943,57943,57943,57943,57943,57893,57893,58308,57893,57893,57893,57893,58326,57893,57893,0,57916,57916,58337,57916,57916,57916,57916,57943,57943,60411,57943,57943,57943,57943,57943,57943,57943,57943,57943,59044,57943,57943,57943,57943,57943,57943,57916,58354,57916,57916,58370,57916,57916,57916,57916,58384,57916,57916,57916,57916,58402,57916,0,0,0,0,57893,57943,57943,58411,57943,57943,57943,58427,57943,57943,57943,57943,57943,59005,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59008,57943,57943,57943,57943,57943,57943,57943,57943,58459,57943,57943,57943,57943,58477,57943,57943,528,528,528,528,528,528,57893,57893,57893,57893,57893,57893,1151,0,0,0,1170,0,0,0,0,0,0,0,1172,0,0,0,0,0,0,806,0,0,0,0,787,0,806,0,528,1293,0,0,0,0,0,0,0,0,0,0,0,0,1305,0,0,0,0,0,6307840,0,0,6356992,6381568,6397952,4800512,4808704,0,0,4890624,0,4947968,0,0,0,5046272,0,0,0,0,5185536,0,5234688,5300224,0,0,0,0,1210,0,0,0,0,0,0,0,0,0,1305,0,0,0,0,0,2343,0,0,0,0,0,2347,0,0,2349,0,0,1333,0,0,0,0,0,0,528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,1353,528,528,528,528,528,528,528,528,528,528,528,528,2901,528,528,528,528,528,528,1377,528,528,528,528,528,528,528,528,528,528,528,528,528,3724,528,528,58773,914,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,58792,0,0,1777,0,0,1780,0,1782,0,0,0,0,0,0,0,0,753,0,0,0,0,0,0,0,0,1833,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3667,3668,528,1898,528,528,528,528,528,528,528,528,1909,528,528,528,528,528,868,528,528,528,528,528,887,528,528,528,528,59341,57893,57893,57893,57893,57893,57893,57893,57893,59352,57893,57893,57893,57893,57893,57893,58325,57893,57893,57893,0,57916,57916,57916,57916,57916,57943,57943,57943,57943,59578,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60056,57943,57943,57943,0,2394,0,0,0,0,0,0,0,0,0,0,0,0,0,2405,0,528,528,528,2422,2423,528,528,528,528,528,528,528,528,528,528,1366,528,528,528,528,528,0,0,0,57893,57893,57893,59852,57893,59854,57893,57893,57893,57893,57893,57893,57893,59349,57893,57893,57893,57893,57893,57893,57893,57893,60647,57893,57893,57893,57893,57893,57893,57893,57893,59903,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59405,57893,0,2780,0,0,2783,0,0,0,0,0,0,2788,0,0,0,2791,2792,0,0,0,0,0,0,0,0,0,0,0,0,0,2802,0,0,0,0,131072,0,0,0,0,0,0,0,448,0,0,0,0,0,2307,0,0,0,0,0,0,0,0,0,0,3674,0,0,0,0,0,0,2817,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3677,0,0,0,2843,0,0,0,0,0,0,0,0,2851,0,0,0,0,0,0,3448,0,0,0,0,0,0,0,0,0,1287,1288,0,0,0,0,0,0,2857,0,0,0,0,2860,0,0,0,0,0,0,0,0,0,2862,0,0,0,0,0,0,2868,0,528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,57893,57893,57893,57893,2879,528,528,2882,2883,528,528,528,528,528,2888,528,2890,528,528,528,528,528,3487,528,528,528,528,528,528,528,528,528,528,2468,528,528,528,528,528,528,2894,528,528,528,528,528,528,528,528,528,2900,528,528,528,528,528,1903,1904,528,528,528,528,1911,528,528,528,528,528,1935,528,528,528,1940,528,528,528,528,528,528,2897,528,528,528,528,528,528,528,528,528,528,3858,528,57893,57893,57893,57893,528,528,528,528,2908,528,528,528,528,528,528,2916,528,528,528,528,528,2439,528,528,528,528,2444,528,528,528,528,528,528,61594,57893,57893,57893,57893,57893,57893,57893,61600,57916,528,2921,528,528,528,528,528,528,528,528,528,528,528,528,528,528,1387,528,57893,60297,57893,60299,57893,57893,57893,57893,60303,57893,57893,57893,57893,57893,57893,57893,59382,57893,57893,57893,57893,57893,57893,57893,57893,59398,57893,57893,57893,57893,57893,57893,57893,57893,57893,60309,57893,57893,57893,57893,57893,57893,57893,57893,57893,60318,57893,57893,57893,0,0,0,2593,57916,57916,57916,57916,57916,57916,57916,57916,57916,60704,57916,57943,57943,57943,57943,57943,57943,57943,60957,57943,57943,57943,57943,57943,57943,57943,57893,57893,57893,60326,57893,57893,57893,57893,57893,60331,57893,57893,57893,57893,57893,57893,58837,57893,57893,57893,57893,57893,57893,57893,58851,57893,60355,57916,57916,60358,60359,57916,57916,57916,57916,57916,60364,57916,60366,57916,57916,57916,57916,57916,60925,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,58884,57916,57916,57916,57916,57916,57916,60370,57916,57916,57916,57916,57916,57916,57916,57916,57916,60376,57916,57916,57916,57916,57916,58960,57916,0,57893,57943,57943,57943,57943,57943,57943,57943,57943,60732,57943,57943,57943,57943,57943,57943,57943,57943,60450,57943,57943,57943,57943,57943,57943,60458,57916,57916,60398,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59505,57916,57916,57943,57943,57943,60420,57943,57943,60423,60424,57943,57943,57943,57943,57943,60429,57943,60431,57943,57943,57943,57943,60435,57943,57943,57943,57943,57943,57943,57943,57943,57943,60441,57943,57943,57943,57943,57943,61150,57943,57943,57943,57943,57943,57943,57943,57943,57943,528,528,3133,528,528,57893,57893,60480,57893,0,0,3161,3162,3163,0,0,0,0,0,0,0,0,0,0,0,2311,0,0,0,0,0,3176,0,0,0,0,0,0,0,3182,0,3184,0,0,0,0,0,0,3458,0,0,0,0,0,0,0,0,0,786,0,0,0,0,0,0,0,0,0,0,0,802,0,807,0,810,3188,0,0,0,0,3193,0,0,3196,0,0,0,0,0,0,0,389,0,139264,147456,0,0,0,0,0,528,528,3263,0,0,60608,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,61086,57893,57893,57893,57893,57893,57893,57893,60653,57893,57893,60656,0,0,60657,57916,57916,57916,57916,57916,57916,57916,58880,57916,57916,57916,58889,57916,57916,57916,57916,57916,57916,60689,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59986,57916,57916,57916,57916,60699,57916,57916,60702,57916,57916,60705,60706,57943,57943,57943,57943,57943,57943,57943,60052,57943,57943,57943,57943,57943,57943,60057,57943,60727,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59031,57943,57943,57943,60738,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,58994,57943,57943,57943,57943,57943,57943,60748,57943,57943,60751,57943,57943,60754,3411,528,528,60758,57893,57893,57893,50676,2085,57916,57916,57916,57916,57916,59436,57916,57916,57916,57916,57916,57916,60373,57916,57916,57916,57916,57916,57916,57916,60379,57916,3429,0,0,0,0,3434,0,0,0,0,0,0,0,0,0,0,3675,0,0,0,0,0,0,0,0,528,528,0,0,0,3470,0,0,0,0,0,0,3477,0,0,3479,0,0,0,0,306,0,0,0,0,0,0,306,0,0,0,0,0,0,0,0,0,0,0,0,2852,0,0,0,528,528,3484,528,528,528,528,528,528,528,528,528,528,528,528,528,528,3259,528,3509,528,528,3511,528,528,528,528,528,528,528,528,528,528,528,57893,57893,57893,57893,61446,57893,57893,60868,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59928,57893,60894,57893,57893,60896,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60877,57893,57893,57893,57916,57916,60910,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60012,57916,57916,57916,60936,57916,57916,60938,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59485,57916,57916,57916,57916,57916,57943,57943,60952,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59009,57943,57943,57943,57943,57943,60978,57943,57943,60980,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60055,57943,57943,57943,60058,3661,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2312,3679,0,0,0,0,0,0,0,0,0,0,0,0,0,3691,0,0,0,0,131072,0,0,0,0,0,0,0,450,0,0,0,0,0,3457,0,0,0,0,3462,0,0,0,0,3466,3702,3703,528,528,528,528,3707,3708,528,528,528,528,528,3712,528,528,0,2932,0,0,0,0,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59859,57893,57893,528,57893,57893,57893,57893,57893,57893,57893,61073,61074,57893,57893,57893,57893,61078,61079,57916,57916,61102,61103,57916,57916,57916,57916,61107,61108,57916,57916,57916,57916,57916,61112,57943,57943,61136,61137,57943,57943,57943,57943,57943,61141,57943,57943,57943,57943,57943,57943,57943,60436,57943,57943,57943,57943,57943,57943,57943,57943,58476,57943,57943,57943,1139,528,528,528,57943,57943,61147,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,528,528,528,528,528,528,57893,57893,57893,0,0,3817,0,0,0,0,0,0,0,0,1165,0,0,0,0,0,0,0,0,0,3834,0,0,0,0,0,0,0,0,0,0,0,0,0,2865,0,0,57916,57916,57916,57916,61230,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59486,57916,57916,57916,57916,57943,61249,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60096,57943,0,0,3675,0,3928,0,0,0,0,0,0,0,0,0,0,0,2361,0,0,0,0,528,528,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,61303,57893,57893,57893,50676,2086,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,61236,61319,57916,57916,57916,57916,57916,57916,57916,57943,57943,57943,57943,57943,57943,57943,57943,0,0,57943,57943,57943,61335,57943,57943,57943,57943,57943,57943,57943,528,57893,0,3999,0,0,0,0,131072,0,0,0,0,0,0,0,450560,0,0,0,0,0,372,0,0,0,0,0,0,0,0,0,0,2333,0,0,0,0,2338,0,4002,0,0,0,3675,0,0,0,0,0,0,0,0,528,528,528,1341,528,528,528,528,4014,528,528,528,528,4019,528,528,528,528,4024,528,528,57893,57893,61373,57893,57893,57893,57893,61378,57893,57893,57893,57893,61383,57893,57893,57893,57916,57916,61389,57916,57916,57916,57916,61394,57916,57916,57916,57916,61399,57916,57916,57916,57943,57943,61405,57943,57943,57943,57943,61410,57943,57943,57943,57943,61415,57943,57943,57943,0,0,0,0,0,2366,0,0,0,0,0,0,0,0,0,0,352256,0,352256,0,0,0,0,0,0,4078,0,0,4081,0,0,0,0,0,528,528,528,528,528,528,57893,57893,57893,57893,57893,57893,57916,528,528,4246,4247,528,528,57893,57893,57893,61596,61597,57893,57893,57893,57916,57916,57916,57916,57943,60410,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,58481,528,852,528,528,57916,61602,61603,57916,57916,57916,57943,57943,57943,61608,61609,57943,57943,57943,0,0,0,0,306,306,306,306,306,306,306,306,306,306,306,306,306,0,306,0,0,0,0,345,346,347,348,349,0,0,0,0,0,0,0,0,1181,0,0,0,0,0,0,0,0,0,349,348,131072,347,348,348,0,349,347,348,0,347,348,457,464,481,481,481,492,492,492,498,492,492,498,498,492,498,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,513,541,57907,541,57907,541,541,57907,541,541,57930,57907,541,541,57907,57907,57907,57907,57957,57957,57907,57907,57907,57907,57957,57957,57907,541,57907,57907,57930,57907,57907,57907,57907,57907,57907,57907,57930,57930,57907,57907,57957,57907,57907,57907,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,0,306,307,0,0,0,0,0,0,646,0,0,0,0,651,652,653,654,655,656,657,0,0,0,0,0,0,0,0,0,0,0,2388,0,0,0,0,0,0,0,672,673,0,675,676,0,0,0,0,0,682,0,0,0,0,307,0,0,0,0,0,0,307,0,0,0,0,0,0,0,0,0,0,0,0,352256,0,0,0,0,0,0,0,716,0,0,719,0,721,0,723,0,0,0,0,0,0,0,394,0,0,0,0,0,0,0,0,1222,0,0,0,0,0,0,0,0,0,733,0,0,0,0,0,0,0,0,0,0,0,0,0,3172,0,0,0,0,0,763,764,0,766,767,675,0,0,0,0,0,0,0,395,0,0,0,0,0,0,0,0,2319,0,0,0,0,0,0,0,0,0,0,782,783,0,785,0,0,0,0,764,0,0,791,0,0,0,0,131072,0,0,0,0,0,245760,0,0,0,0,245760,0,0,0,0,0,0,0,0,0,0,0,0,3171,0,0,0,0,692,0,0,0,764,0,0,0,0,0,0,0,0,757,821,0,0,0,757,0,0,824,699,0,0,0,829,0,0,0,831,0,0,0,692,699,0,0,692,829,829,0,0,0,0,0,528,528,528,528,528,528,2874,528,528,528,528,528,528,528,3489,528,528,528,528,528,528,528,528,3256,528,528,528,528,528,528,528,528,849,853,856,528,865,528,528,528,881,883,886,528,528,528,899,903,528,528,528,57893,57893,57893,58268,58272,58275,57893,58284,57893,57893,57893,58300,58302,58305,57893,57893,57893,58318,58322,57893,57893,57893,0,57916,57916,57916,58344,58348,58351,57916,58360,57916,57916,57916,58376,58378,58381,57916,57916,57916,58394,58398,57916,57916,57916,57916,58367,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59999,57916,57916,57916,57916,0,0,0,0,58409,57943,57943,57943,58419,58423,58426,57943,58435,57943,57943,528,3649,528,57893,60996,57893,0,0,0,0,0,0,0,0,1254,0,0,0,0,0,0,0,57943,58451,58453,58456,57943,57943,57943,58469,58473,57943,57943,57943,849,1140,528,899,903,1144,0,58489,58268,57893,58318,58322,58494,155942,1151,0,0,0,0,0,0,1179,0,0,0,0,0,0,0,0,0,1239,0,0,0,0,0,0,1278,0,0,0,0,1283,0,0,0,0,0,0,0,0,0,0,3675,0,3828,0,0,0,0,0,0,1321,0,0,0,0,0,0,0,0,0,0,0,0,1198,0,0,0,528,1375,528,528,528,1378,528,528,528,528,528,528,528,1385,528,528,0,2932,0,0,0,0,57893,57893,57893,57893,57893,57893,60282,57893,1389,528,528,528,528,528,528,528,528,528,528,528,1400,528,528,1407,58817,57893,57893,57893,57893,57893,57893,57893,58824,57893,57893,58828,57893,57893,57893,57893,57893,59895,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59898,59899,57893,57893,57893,57893,57916,57916,57916,58934,57916,57916,58941,57916,57916,57916,57916,57916,57916,57916,57916,57916,59984,57916,57916,57916,57916,57916,57916,57916,58955,57916,57916,57916,57916,57916,0,57893,57943,57943,57943,57943,57943,57943,57943,57943,61542,57943,57943,57943,0,4202,0,0,57943,57943,57943,59003,57943,57943,57943,59006,57943,57943,57943,57943,57943,57943,57943,59013,57943,57943,59017,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59029,57943,57943,57943,57943,57943,61337,57943,57943,57943,61341,57943,528,57893,0,0,0,0,3139,0,0,0,0,0,0,0,0,0,3149,57943,59036,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59050,57943,57943,57943,57943,57943,59019,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,58482,528,528,528,528,1822,0,1824,0,0,0,1826,0,746,0,0,0,0,0,0,0,399,0,0,404,0,0,0,0,0,1872,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2350,0,1757,0,0,0,0,0,0,528,1891,528,528,528,528,528,528,2440,528,528,528,528,528,528,528,528,528,528,2495,528,528,528,528,0,1897,528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,1428,528,528,528,528,1919,528,528,528,528,528,528,528,528,528,528,1928,528,528,528,1932,528,528,1937,528,528,528,528,528,528,528,528,528,1419,528,528,528,528,528,528,528,528,528,528,58773,0,57893,59333,57893,57893,57893,57893,57893,57893,57893,59340,57893,57893,57893,59362,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59371,57893,57893,57893,57893,57943,57943,57893,57893,57893,57893,57943,57943,57893,528,57893,57893,57893,57893,57893,57893,57893,57893,57893,61075,57893,57893,57893,57893,57893,58821,57893,57893,57893,58825,57893,57893,57893,57893,57893,57893,59348,57893,57893,57893,57893,57893,57893,57893,57893,57893,60875,57893,57893,57893,57893,57893,57893,57893,57893,59375,57893,57893,59380,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,61457,57916,57916,57916,57916,57916,57916,57916,59462,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59471,57916,57916,57916,57916,58368,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60011,57916,57916,57916,57916,59475,57916,57916,59480,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59972,57916,57916,57916,59975,59558,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59567,57943,57943,57943,59571,57943,57943,59576,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59569,57943,57943,57916,57916,57916,59990,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,58948,57916,57916,57916,57943,57943,57943,60073,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59010,57943,57943,57943,2804,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2376,57916,60409,57916,57916,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59030,57943,57943,57943,57943,60474,57943,57943,528,528,528,528,528,57893,57893,57893,57893,57893,2290,0,2291,0,0,3214,0,0,0,528,3218,528,528,528,528,528,528,528,528,528,528,1383,528,528,528,528,1388,3242,528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,1962,57893,60633,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60335,57893,57916,57916,57916,57916,60682,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59998,57916,57916,57916,57916,0,0,3419,0,0,0,0,0,0,0,0,0,3425,0,0,0,0,0,2410,0,0,0,0,0,0,0,0,0,0,417792,309,310,0,0,0,0,3841,528,528,528,528,528,528,528,3846,528,528,528,528,528,528,2465,528,528,528,528,528,528,528,528,528,528,3943,528,3945,528,528,528,57893,57893,57893,57893,61208,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59369,57893,57893,57893,57893,57916,61227,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59524,57916,0,0,3675,3927,0,0,0,0,0,0,0,0,0,0,0,0,1266,0,0,0,528,528,528,3937,528,528,528,528,3941,528,528,528,528,528,3947,528,528,0,57893,57893,57893,58320,57893,57893,155942,1151,0,0,0,0,0,0,1751,0,0,0,0,0,0,0,0,0,754,0,0,0,0,0,0,528,528,57893,57893,57893,61296,57893,57893,57893,57893,61300,57893,57893,57893,57893,57893,58317,57893,57893,57893,57893,0,57916,57916,58336,57916,57916,61306,57893,57893,57893,57893,57916,57916,57916,61312,57916,57916,57916,57916,61316,57916,57916,57916,57916,58371,58373,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,58945,57916,57916,57916,57916,57916,57916,57916,57916,61322,57916,57916,57916,57916,57943,57943,57943,61328,57943,57943,57943,57943,57943,57943,60981,57943,60983,57943,57943,57943,57943,57943,57943,57943,57943,60078,57943,57943,57943,57943,60083,57943,57943,61332,57943,57943,57943,57943,57943,61338,57943,57943,57943,57943,528,57893,0,0,0,0,0,2797,0,0,0,0,0,0,0,0,0,0,1881,0,0,0,0,0,528,528,528,4017,528,528,528,4021,528,528,528,528,528,57893,57893,57893,57893,57893,57893,58281,57893,57893,57893,57893,57893,57893,57893,61376,57893,57893,57893,61380,57893,57893,57893,57893,57893,57893,57916,57916,57916,57916,57916,60939,57916,60941,57916,57916,57916,57916,57916,57916,57916,57916,58881,57916,57916,57916,57916,57916,57916,58896,57916,57916,61392,57916,57916,57916,61396,57916,57916,57916,57916,57916,57916,57943,57943,57943,61242,57943,57943,57943,61245,57943,57943,57943,57943,61408,57943,57943,57943,61412,57943,57943,57943,57943,57943,57943,0,0,0,0,0,2821,0,0,0,0,0,0,0,0,0,0,1739,0,0,0,0,0,0,4270,0,528,528,528,528,528,528,57893,57893,57893,57893,57893,57893,57916,61311,57916,57916,61313,57916,57916,57916,57916,57916,57916,59497,57916,57916,59500,57916,57916,57916,57916,57916,57916,57916,61526,57916,61528,57916,57916,57916,57916,57943,57943,57943,57943,57943,57943,57943,60415,57943,57943,57943,57943,0,528,528,57893,57893,57916,57916,57943,57943,0,528,57893,57916,57943,4308,4309,61654,61655,61656,0,528,57893,57916,57943,0,528,57893,57916,57943,0,0,0,0,0,2831,0,0,0,0,0,0,0,0,0,0,1257,0,0,0,0,1262,0,350,0,408,0,0,0,0,0,0,0,0,0,0,408,0,350,0,139264,147456,0,0,0,0,0,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,514,542,57908,542,57908,542,542,57908,542,542,57931,57908,542,542,57908,57908,57908,57908,57958,57958,57908,57908,57908,57908,57958,57958,57908,623,57908,57974,57931,57908,57908,57908,57908,57908,57908,57908,57931,57931,57908,57908,57958,57908,57908,57908,57974,57974,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,0,0,0,131072,0,0,0,328,0,0,330,0,0,0,0,0,0,2847,2848,0,0,0,0,0,0,0,0,0,5808128,0,0,0,0,4792320,4833280,844,528,528,528,528,528,528,528,528,528,528,528,890,528,528,528,528,528,3499,528,528,528,528,528,528,528,528,528,3508,528,908,528,528,57893,57893,58262,57893,57893,57893,57893,57893,57893,57893,57893,57893,61222,57916,57916,57916,57916,57916,57916,57893,57893,58309,57893,57893,57893,57893,58327,57893,57893,0,57916,57916,58338,57916,57916,57916,57916,58877,57916,57916,57916,57916,58883,57916,57916,57916,57916,57916,57916,59993,59994,57916,57916,57916,57916,57916,57916,60001,57916,57943,57943,57943,57943,58460,57943,57943,57943,57943,58478,57943,57943,528,528,528,528,528,528,57893,57893,57893,57893,57893,57893,1151,1724,1173,0,0,0,0,1178,0,0,0,0,0,0,0,0,0,0,2310144,0,368,0,0,0,0,0,1173,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2816,528,528,528,528,1354,528,528,528,528,1364,528,528,528,528,528,528,2491,528,2493,528,528,528,528,528,528,0,58773,914,57893,57893,57893,58779,57893,57893,57893,57893,57893,57893,57893,57893,57893,58793,57916,58874,57916,57916,57916,57916,57916,57916,57916,57916,57916,58888,57916,57916,57916,57916,57916,59448,57916,57916,57916,57916,57916,57916,57916,57916,57916,59459,58898,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59961,57916,58914,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59987,59988,58953,57916,57916,57916,57916,57916,57916,0,57893,57943,57943,57943,58968,57943,57943,57943,57943,57943,59041,57943,57943,57943,57943,57943,57943,57943,57943,59053,59054,0,1728,0,0,0,0,1735,0,0,0,0,0,0,0,0,0,3424,0,0,0,0,0,0,0,0,1761,0,0,0,0,0,0,0,0,0,0,0,0,0,3185,0,0,1775,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2840,0,0,2353,0,0,0,0,0,0,0,0,0,0,0,0,0,3201,0,0,2449,528,528,528,528,528,528,2454,528,2456,528,528,528,528,528,528,2884,528,528,528,528,528,528,528,528,528,528,2915,528,528,528,528,528,2502,0,0,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,61387,57916,57916,57893,57893,57893,59880,57893,57893,57893,57893,57893,57893,59885,57893,59887,57893,57893,57893,0,0,2592,0,57916,57916,57916,57916,57916,57916,57916,57916,57916,61470,57943,57943,57943,57943,57943,57943,59976,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60013,57916,60059,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59033,528,2906,528,528,528,528,528,528,528,528,528,528,528,528,528,528,1960,528,57916,57916,60383,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60367,57916,57916,0,0,3675,0,0,0,0,3931,0,0,3933,0,0,0,0,0,0,1192,0,0,0,1196,1197,0,0,0,0,528,3936,528,528,3938,528,528,528,528,528,528,528,528,528,528,528,528,3247,528,528,528,528,528,57893,61295,57893,57893,61297,57893,57893,57893,57893,57893,57893,57893,57893,57893,61456,57916,57916,57916,57916,57916,57916,0,0,800,0,800,0,0,0,0,0,0,0,0,800,0,0,0,0,307,307,307,307,307,307,307,307,307,307,307,307,307,0,307,0,528,528,528,528,860,528,528,528,528,528,528,528,528,528,528,528,528,3257,528,528,3260,57916,58355,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60368,57916,1161,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3174,528,528,528,528,58773,1987,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59910,57893,57893,57893,57893,57893,57893,57893,57943,57943,60445,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59585,57943,57943,57893,61081,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60639,57893,0,0,0,351,0,0,0,0,0,0,0,0,0,0,0,0,1746,0,0,0,0,0,0,352,0,0,0,0,0,0,0,0,0,0,0,0,1756,1757,0,0,0,0,353,351,131072,0,351,351,0,353,0,351,0,0,351,353,351,0,0,0,351,351,351,351,351,351,351,351,505,351,351,351,351,351,351,351,351,351,351,351,351,351,351,351,351,543,57909,543,57909,543,543,57909,543,543,57932,57909,543,543,57909,57909,57909,57909,57959,57959,57909,57909,57909,57909,57959,57959,57909,543,57909,57909,57932,57909,57909,57909,57909,57909,57909,57909,57932,57932,57909,57909,57959,57909,57909,57909,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,811,812,0,0,0,0,0,0,758,0,0,817,0,0,0,0,0,0,4082,0,0,0,0,528,528,528,528,528,3221,528,3222,528,528,528,528,0,817,0,664,0,0,0,0,0,0,0,0,0,0,0,0,1787,0,0,0,832,0,0,0,0,0,0,812,0,0,0,0,0,0,0,528,528,528,528,528,2873,528,528,528,528,2877,528,528,528,0,2503,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,61087,57893,57893,57893,57893,528,850,528,528,528,866,870,528,528,528,528,528,891,893,528,528,0,2932,0,0,0,0,57893,57893,57893,60280,57893,60281,57893,57893,57893,50676,0,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59473,904,528,528,528,57893,57893,58263,58269,57893,57893,57893,58285,58289,57893,57893,57893,0,2590,0,0,57916,57916,57916,57916,57916,57916,57916,57916,57916,59970,57916,57916,57916,57916,57916,57916,57893,57893,58310,58312,57893,57893,58323,57893,57893,57893,0,57916,57916,58339,58345,57916,0,0,0,0,57893,57943,57943,58412,57943,57943,57943,58429,57943,57943,58445,57916,57916,58361,58365,57916,57916,57916,57916,57916,58386,58388,57916,57916,58399,57916,57916,57916,57916,58904,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60945,57916,57916,57916,57916,57943,57943,57943,57943,58461,58463,57943,57943,58474,57943,57943,57943,850,528,893,528,528,0,58270,58266,58491,58314,57893,57893,155942,1151,0,0,1154,0,0,0,0,0,245760,245760,245760,245760,245760,245760,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4358144,4358144,4358144,904,528,0,57893,58269,58312,57893,58323,57893,155942,1151,0,302,0,0,306,307,0,0,0,0,0,0,0,0,0,0,0,0,0,1772,0,0,0,0,0,1217,0,1219,0,1221,0,0,0,0,0,0,0,0,1286,0,0,0,0,0,0,0,0,1247,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3839,0,1332,0,0,0,0,0,0,0,528,528,528,528,528,528,528,528,528,528,528,528,3850,528,528,1374,528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,2461,528,528,528,1412,528,528,528,528,528,528,528,528,1424,1425,528,528,0,57893,57893,57893,57893,57893,57893,294,1151,0,0,0,0,0,0,0,5480448,4358144,4358144,4358144,4358144,4857856,4874240,4358144,4358144,58773,914,57893,57893,57893,57893,58780,57893,57893,57893,57893,57893,57893,57893,57893,57893,60289,57893,57893,57893,57893,57893,60294,57893,57916,57916,58875,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60378,57916,57916,57916,57916,58932,57916,57916,57916,57916,57916,57916,57916,58946,57916,57916,57916,57916,57916,57916,61241,57943,57943,57943,57943,57943,57943,57943,61246,57943,57916,57916,57916,58958,58959,57916,57916,0,57893,57943,57943,57943,57943,58969,57943,57943,3648,528,528,60995,57893,57893,0,0,0,0,0,0,0,0,1815,0,0,0,0,0,0,0,57943,59e3,59002,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59602,57943,57943,0,1808,0,0,0,0,0,0,0,0,0,0,0,0,0,0,212992,0,528,528,1966,528,528,528,528,528,528,528,528,528,1975,528,528,528,528,528,3513,3515,528,528,528,3518,528,3520,3521,528,57893,528,1981,528,528,58773,0,57893,57893,57893,57893,57893,57893,57893,59338,57893,57893,57893,50676,2087,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60674,57916,57916,57916,57916,57893,59409,57893,57893,57893,57893,57893,57893,57893,57893,57893,59419,57893,57893,57893,57893,57893,59907,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,0,57916,57916,58340,57916,57916,59425,57893,57893,50676,0,57916,57916,57916,57916,57916,57916,57916,59438,57916,57916,57916,57916,57916,61116,57916,57916,57916,57916,57916,57916,57916,57916,61124,57916,59509,57916,57916,57916,57916,57916,57916,57916,57916,57916,59519,57916,57916,57916,57916,59525,57943,57943,59559,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59620,57943,57943,2393,0,2395,0,0,0,0,0,0,0,0,0,0,2403,0,0,0,0,343,390,0,0,0,139264,147456,0,0,0,423,0,0,0,2408,2409,0,0,0,0,0,2413,0,0,0,0,0,0,0,3153,0,0,0,0,0,0,0,0,378,0,0,0,0,0,0,0,0,2419,528,528,528,528,528,528,2426,528,528,528,528,528,528,528,1394,528,528,528,528,528,528,528,528,2886,528,528,528,528,528,528,528,528,528,2450,528,528,528,528,528,528,528,528,2457,528,2459,528,2462,528,528,528,2476,528,528,528,528,528,528,528,528,528,528,528,528,528,61371,57893,57893,0,0,0,59849,57893,57893,57893,57893,57893,57893,57893,59857,57893,57893,57893,57893,57893,60301,57893,57893,57893,57893,57893,57893,57893,60306,57893,57893,59890,57893,59893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60304,57893,57893,57893,57893,59902,57893,57893,57893,57893,57893,59908,57893,57893,57893,57893,57893,57893,57893,57893,57893,60330,57893,57893,57893,60333,60334,57893,57893,57916,57916,59977,57916,59979,57916,59982,57916,57916,57916,57916,57916,57916,57916,57916,57916,60363,57916,60365,57916,57916,57916,57916,57916,57916,57916,57916,59991,57916,57916,57916,57916,57916,59997,57916,57916,57916,57916,57916,57916,61606,57943,57943,57943,57943,57943,57943,57943,0,0,57943,57943,60060,57943,60062,57943,60065,57943,57943,57943,57943,57943,57943,57943,57943,57943,59007,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60074,57943,57943,57943,57943,57943,60080,57943,57943,57943,57943,57943,57943,59612,57943,57943,57943,57943,57943,57943,57943,57943,57943,0,0,4240,0,0,0,528,0,0,0,2819,0,0,0,0,0,0,0,0,0,0,2827,0,0,0,0,131072,0,0,0,357,0,0,0,0,359,0,0,400,0,0,0,0,0,139264,147456,400,411,0,424,411,2841,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3187,528,2880,528,528,528,528,528,2885,528,528,528,528,528,528,528,528,3502,528,528,528,528,528,528,528,57893,57893,57893,60310,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60628,57893,57893,57893,57893,57916,60356,57916,57916,57916,57916,57916,60361,57916,57916,57916,57916,57916,57916,57916,57916,59953,57916,59955,57916,57916,57916,57916,57916,57916,57943,57943,57943,57943,60421,57943,57943,57943,57943,57943,60426,57943,57943,57943,57943,57943,57943,60064,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59566,57943,57943,57943,57943,57943,57893,60652,57893,57893,57893,57893,0,0,57916,57916,57916,57916,57916,60661,57916,60662,57916,57916,57916,57916,60701,57916,57916,57916,57916,57943,57943,57943,57943,57943,60710,57943,57943,57943,57943,57943,61481,57943,57943,61483,57943,0,0,0,0,0,0,0,2808,0,0,0,0,0,0,0,0,350,0,0,0,0,0,0,0,60711,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59587,528,3483,528,528,528,528,528,528,528,528,528,528,528,528,528,528,1978,528,60867,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59929,57916,60909,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60395,57916,57916,57943,60951,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60069,57943,57943,0,3670,0,0,0,0,0,0,0,0,0,0,0,0,0,0,278528,0,0,0,3675,0,0,0,3930,0,0,0,0,0,0,0,0,0,3476,0,0,0,0,0,0,3935,528,528,528,528,3939,528,528,528,528,528,528,528,528,528,3948,528,528,61294,57893,57893,57893,57893,61298,57893,57893,57893,57893,57893,57893,57893,57893,60342,57893,57893,0,0,0,3e3,0,57893,61307,57893,57893,57893,61310,57916,57916,57916,57916,61314,57916,57916,57916,57916,57916,57943,57943,57943,57943,57943,57943,0,0,0,0,528,528,528,3219,528,528,528,528,528,3224,528,528,57916,57916,57916,57916,61323,57916,57916,57916,61326,57943,57943,57943,57943,61330,57943,57943,57943,57943,57943,60089,60090,60091,57943,57943,57943,57943,57943,57943,57943,57943,57943,59615,57943,57943,57943,57943,59621,57943,4090,528,528,528,528,528,528,528,528,528,57893,57893,57893,57893,57893,61447,0,0,0,4149,0,528,528,528,528,528,528,528,528,528,528,528,528,528,3851,528,528,528,528,528,4248,528,57893,57893,57893,57893,57893,61598,57893,57893,57916,57916,57916,57916,58919,57916,57916,58923,57916,57916,57916,57916,57916,57916,57916,57916,61572,61573,57916,57916,57943,57943,57943,57943,57916,57916,57916,61604,57916,57916,57943,57943,57943,57943,57943,61610,57943,57943,0,0,0,0,363,0,0,0,0,139264,147456,0,0,0,0,0,0,1307,0,528,528,1339,528,1342,528,528,528,4269,0,4271,528,528,528,528,528,528,57893,57893,57893,57893,57893,57893,57916,0,0,0,0,57893,57943,57943,58413,57943,57943,57943,57943,57943,57943,57943,57943,61582,0,0,0,0,0,0,528,388,0,354,0,0,0,0,0,397,398,0,399,0,0,0,0,0,0,4208,528,528,528,528,528,528,528,528,528,1380,528,528,528,528,528,528,371,379,407,0,0,0,371,0,0,354,0,0,0,371,0,410,412,0,371,399,0,0,371,379,0,139264,147456,399,410,0,0,410,0,0,0,433,131072,0,433,433,443,0,0,433,0,412,433,0,0,0,0,131072,0,0,0,438,0,0,0,0,0,311,0,0,0,0,2796,0,0,0,0,0,0,0,0,0,0,0,450560,450560,0,0,0,465,0,0,0,493,493,493,493,493,493,493,493,493,493,515,515,515,515,515,527,515,515,515,527,515,515,515,515,515,515,544,57910,544,57910,544,544,57910,544,544,57933,57910,544,544,57910,57910,57910,57910,57960,57960,57910,57910,57910,57910,57960,57960,57910,624,57910,57975,57933,57910,57910,57910,57910,57910,57910,57910,57933,57933,57910,57910,57960,57910,57910,57910,57975,57975,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,0,0,0,131072,0,0,0,441,342,0,0,0,453,0,342,343,344,0,0,0,0,0,0,0,0,0,0,0,0,0,2853,0,0,0,306,307,0,0,0,643,0,0,0,0,0,0,0,0,0,3687,0,0,0,0,0,0,669,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3428,845,528,528,528,528,528,528,876,878,528,528,528,528,528,528,528,1415,528,528,528,528,528,528,1426,528,528,528,528,528,57893,57893,58264,57893,57893,57893,57893,57893,57893,58295,58297,57893,57893,57893,57893,58803,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59384,57893,57893,57893,57893,58448,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,528,528,528,528,528,57893,57893,57893,57893,57893,2290,1725,2291,0,0,0,0,0,1309,1335,1336,0,1309,528,528,528,528,528,528,1344,528,528,528,528,528,3706,528,528,528,528,528,528,528,528,528,528,528,1974,528,528,528,528,528,528,1348,528,528,1359,528,528,1363,528,528,528,528,528,528,528,1416,528,528,528,528,528,528,528,528,3709,528,528,528,528,528,528,528,58773,914,57893,57893,57893,57893,57893,57893,57893,58783,57893,57893,57893,58787,57893,57893,57893,57893,57893,60623,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,58845,57893,57893,57893,57893,57893,58798,57893,57893,58802,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60638,57893,57893,57893,57893,57916,58916,57916,57916,57916,58920,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59469,57916,57916,57916,57916,57916,58972,57943,57943,57943,58976,57943,57943,58987,57943,57943,58991,57943,57943,57943,57943,57943,57943,60076,60077,57943,57943,57943,57943,57943,57943,60084,57943,59014,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59604,1745,1746,0,0,0,0,0,0,0,0,0,0,0,0,0,0,507904,0,0,0,0,1778,0,0,0,0,0,0,0,0,0,0,0,0,1828,0,0,0,1791,0,1793,0,0,0,1797,0,0,0,1801,0,0,0,1805,0,0,0,0,131072,0,0,0,442,0,0,0,449,0,0,0,0,0,2846,0,0,0,0,0,0,0,0,0,0,1224,0,0,0,0,0,1980,528,528,528,58773,0,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60625,57893,57893,57893,57893,57893,57893,57893,57943,57943,57943,57943,59545,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60068,57943,57943,57943,0,0,2314,0,2315,0,0,0,0,0,0,0,0,0,0,0,262738,0,0,0,0,2377,0,0,0,0,0,0,2384,0,0,0,0,0,0,0,0,1326,1327,0,0,1167,0,0,0,0,528,528,2421,528,528,528,528,528,528,528,528,528,528,528,528,888,528,528,528,528,528,528,528,2489,528,528,528,528,528,528,528,528,528,528,0,0,57893,57893,57893,57893,60611,57893,57893,57893,57893,57893,57893,59868,57893,57893,57893,57893,57893,57893,57893,57893,57893,58330,0,57916,57916,57916,57916,58347,0,0,0,57893,57893,59851,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60901,57893,57893,57893,57893,57893,57893,57893,60113,0,0,1729,0,0,1736,0,0,0,0,0,0,0,0,0,139264,147456,0,0,0,0,0,0,0,2858,0,0,0,0,0,0,0,0,0,2864,0,0,0,0,0,3152,0,0,0,0,0,0,0,0,0,3158,57893,57893,57893,57893,60311,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60890,57893,60892,57893,57893,60323,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60295,60443,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60455,57943,57943,57943,57943,57943,59593,57943,57943,59596,57943,57943,57943,57943,57943,57943,57943,57943,59551,57943,57943,57943,57943,57943,57943,57943,57943,59565,57943,57943,57943,57943,57943,57943,57943,57943,59580,57943,57943,57943,57943,57943,57943,57943,57943,59614,57943,57943,57943,57943,57943,57943,57943,57943,60037,57943,57943,60041,57943,57943,57943,60045,0,0,3190,0,0,0,0,3195,0,0,0,0,0,0,0,0,1783,1784,1785,0,0,0,0,0,3250,528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,2472,57893,57893,60642,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,61385,57893,57916,57916,57916,0,3468,3469,0,0,0,0,3474,0,0,0,0,0,0,0,0,1799,0,0,0,0,0,0,0,0,0,3681,0,0,0,3684,0,0,0,0,0,0,0,0,3692,57893,61092,57893,57893,57893,57893,57893,57893,57893,57893,57893,57916,57916,57916,57916,57916,57943,57943,57943,57943,57943,57943,0,0,0,0,4290,528,3813,57893,57893,61159,3816,0,0,0,0,3820,0,0,0,0,0,0,1236,0,0,0,0,0,0,0,0,0,2799,0,0,0,0,0,0,0,3833,0,0,0,0,3837,0,0,0,0,0,0,0,0,3840,0,528,528,528,3842,528,528,528,3845,528,528,528,528,528,528,528,1938,528,528,528,528,528,528,528,528,3235,528,528,3238,528,528,528,528,57893,57893,57893,61207,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,61084,57893,57893,57893,57893,57893,57893,57893,61226,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60407,57916,528,528,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,61302,57893,61304,57893,57893,57893,57893,58819,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59913,57893,57893,57893,57893,57916,61320,57916,57916,57916,57916,57916,57916,57943,57943,57943,57943,57943,57943,57943,57943,4268,0,57943,57943,61334,57943,61336,57943,57943,57943,57943,57943,57943,528,57893,0,0,0,0,0,3164,0,0,0,0,3169,0,0,0,0,0,0,1220,0,0,0,0,0,1226,0,1228,0,4146,0,0,0,0,528,528,528,528,528,528,528,528,528,528,4160,528,528,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,61516,57893,57893,57893,0,2591,0,0,57916,57916,57916,57916,57916,57916,57916,57916,57916,59996,57916,57916,57916,57916,57916,57916,528,528,57893,57893,61560,57893,61561,57893,57893,57893,57893,57893,57893,57893,57893,57916,0,0,0,0,57893,57943,57943,58414,58420,57943,57943,57943,58436,58440,57943,57943,57943,57943,57943,61411,57943,61413,61414,57943,61416,57943,61418,0,0,0,0,0,1849,0,0,0,0,0,0,1748,0,0,0,0,0,1864,0,0,0,0,0,0,0,0,0,0,2401,0,0,0,0,0,57916,61568,57916,61569,57916,57916,57916,57916,57916,57916,57916,57916,57943,57943,61576,57943,57943,57943,57943,57943,61539,57943,61541,57943,57943,57943,57943,0,0,0,0,0,0,3435,0,0,0,0,0,0,0,0,0,1273,0,0,0,0,0,0,61577,57943,57943,57943,57943,57943,57943,57943,57943,0,0,0,0,0,0,528,528,528,2871,2872,528,528,528,528,528,528,528,528,528,528,3237,528,528,528,528,528,358,359,360,0,0,0,0,0,0,0,0,0,368,0,296,0,0,0,0,131072,0,352256,352256,0,0,0,352256,0,0,352256,0,352256,352256,352256,352256,352256,352256,352256,352256,352256,352256,352256,352256,352256,352256,352256,352256,0,482,482,482,0,0,0,0,0,0,0,0,0,0,516,516,520,520,520,520,520,516,520,520,520,516,520,520,520,520,520,520,545,57911,545,57911,545,545,57911,545,545,57934,57911,545,545,57911,57911,57911,57911,57961,57961,57911,57911,57911,57911,57961,57961,57911,625,57911,57976,57934,57911,57911,57911,57911,57911,57911,57911,57934,57934,57911,57911,57961,57911,57911,57911,57976,57976,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,0,0,0,245760,0,0,245760,0,0,245760,0,0,245760,0,245760,0,0,0,0,0,0,0,0,0,0,0,0,0,516567,516567,516567,0,306,307,0,0,0,0,644,0,0,0,0,0,0,0,0,1837,0,0,0,0,0,0,0,0,0,687,688,0,0,0,0,0,0,0,0,0,0,0,368,368,0,0,0,760,0,0,0,0,765,0,0,0,0,0,0,0,0,0,0,4841472,0,0,0,4898816,0,794,0,0,0,0,0,0,0,0,0,0,803,0,808,0,0,0,0,392,0,0,0,396,392,0,0,0,0,0,0,0,2823,0,0,0,0,0,0,0,0,677,0,0,0,0,0,0,0,0,0,0,820,0,0,0,0,0,644,0,0,0,0,0,0,0,3436,0,0,0,0,0,0,0,0,681,0,0,0,0,0,0,680,0,0,794,0,0,0,0,0,0,0,0,644,0,0,794,528,528,528,528,528,3717,528,528,528,528,528,528,528,528,528,528,1381,528,528,528,528,528,846,528,528,528,528,867,871,877,528,882,528,528,528,528,528,900,528,528,528,528,57893,57893,58265,57893,57893,57893,57893,58286,58290,58296,57893,58301,57916,57916,58362,58366,58372,57916,58377,57916,57916,57916,57916,57916,58395,57916,57916,57916,57916,57916,61231,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60686,57916,57916,57916,57916,57916,57943,58452,57943,57943,57943,57943,57943,58470,57943,57943,57943,57943,528,528,528,900,1215,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3441,1264,0,0,0,0,0,1269,0,0,0,0,0,1274,0,0,0,0,0,3179,0,0,0,0,0,0,0,0,0,0,679,0,0,0,0,0,0,1294,0,0,1165,0,0,0,1300,0,1302,0,0,0,0,0,0,1284,0,0,0,0,0,0,0,0,0,1301,0,0,0,0,0,0,0,1300,1319,0,1322,0,0,0,1196,0,0,0,0,1330,0,0,1215,1330,1337,528,528,528,528,1343,528,528,528,528,1349,528,528,528,528,528,528,528,528,528,528,1370,528,528,0,57893,57893,57893,57893,57893,57893,155942,0,0,0,0,0,0,0,1285,0,0,0,0,1290,0,0,0,58773,914,58775,57893,57893,57893,57893,57893,58782,57893,57893,57893,57893,58788,57893,57893,57893,57893,57893,60872,57893,57893,57893,57893,57893,60876,57893,57893,57893,57893,57893,58860,57893,57893,57893,57893,57893,50676,58773,990,57916,57916,57916,58917,57916,57916,57916,57916,58922,57916,57916,57916,57916,57916,57916,57916,57916,57916,60403,57916,57916,57916,60406,57916,57916,58930,57916,57916,57916,58937,58939,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59957,57916,57916,57916,57916,57916,57943,57943,57943,57943,58977,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,58998,57943,59016,57943,57943,57943,57943,57943,59021,57943,57943,57943,59025,57943,57943,57943,59032,59034,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59622,57943,59057,528,528,528,528,528,528,57893,57893,57893,57893,57893,57893,1151,0,0,0,0,385024,0,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,5259264,4358144,4358144,4358144,4358144,0,0,1729,0,0,0,0,1736,0,0,0,0,0,0,0,0,1880,0,0,0,0,0,0,0,0,0,1747,1748,0,0,0,0,0,1754,0,0,0,0,0,0,0,3447,0,0,0,0,0,3450,0,3452,0,1776,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5177344,0,0,0,0,0,1794,0,0,0,0,0,0,0,1802,1803,0,0,0,0,0,3207,0,0,0,0,0,0,0,0,0,0,3183,0,0,0,0,0,0,0,0,1810,0,0,0,0,0,0,0,0,0,0,0,0,1841,0,1843,0,0,0,1874,0,0,0,0,0,0,0,0,0,0,0,0,0,3213,0,0,528,528,528,1901,528,528,528,528,1907,528,528,528,528,528,528,528,2441,528,528,528,528,528,528,528,528,3720,528,528,528,528,528,528,528,528,528,528,1918,528,528,528,528,1922,528,528,528,528,528,528,528,2466,2467,528,528,528,528,528,528,528,1417,528,528,528,528,528,528,528,528,3856,528,528,528,57893,57893,57893,57893,528,528,528,528,1968,1969,528,528,528,528,528,528,528,528,528,528,1924,1925,528,528,528,528,57893,57893,59344,57893,57893,57893,57893,59350,57893,57893,57893,57893,57893,57893,57893,57893,61212,57893,57893,57893,57893,57893,57893,57893,57893,57893,59361,57893,57893,57893,57893,59365,57893,57893,57893,57893,57893,57893,57893,57893,59883,57893,57893,57893,59886,57893,57893,57893,57893,57893,57893,57893,57893,59378,57893,57893,57893,59383,57893,57893,57893,57893,57893,57893,57893,59909,57893,57893,57893,57893,57893,57893,57893,59915,57893,57893,57893,59412,59413,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59921,57893,57893,57893,57893,57893,57893,57893,57893,59351,57893,57893,57893,57893,57893,57893,57893,57916,59444,57916,57916,57916,57916,59450,57916,57916,57916,57916,57916,57916,57916,57916,57916,60685,57916,57916,57916,57916,57916,57916,57916,59461,57916,57916,57916,57916,59465,57916,57916,57916,57916,57916,57916,57916,57916,57916,60943,57916,57916,57916,57916,57916,57916,57916,57916,57916,59478,57916,57916,57916,59483,57916,57916,57916,57916,57916,57916,57916,57916,60021,57943,57943,57943,57943,57943,57943,57943,60029,57916,57916,59512,59513,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59470,57916,57916,57916,57943,57943,57943,57943,59546,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59557,57943,57943,57943,57943,59561,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60082,57943,57943,57943,57943,59574,57943,57943,57943,59579,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60735,57943,57943,57943,57943,57943,59608,59609,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60095,57943,57943,2302,2303,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5767168,0,2339,0,0,2341,2342,0,0,0,0,0,0,0,0,0,0,0,335872,0,0,0,0,528,2434,528,528,2438,528,528,528,2442,528,528,528,528,528,528,528,2912,528,528,528,528,528,528,528,528,528,3857,528,528,57893,57893,57893,57893,528,528,528,528,2452,528,528,528,2455,528,528,528,528,528,528,528,2925,528,528,528,2928,528,528,528,528,528,2487,528,528,528,528,528,2492,528,528,528,528,528,528,528,0,0,57893,57893,57893,60610,57893,57893,57893,57893,57893,60615,57893,0,2503,0,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60288,57893,57893,60291,60292,57893,57893,57893,57893,57893,57893,57893,57893,59865,57893,57893,59869,57893,57893,57893,59873,57893,57893,57893,57893,57893,60312,57893,57893,57893,57893,57893,57893,57893,60320,57893,57893,59916,57893,57893,57893,57893,59920,57893,57893,57893,57893,57893,59925,57893,57893,57893,57893,57893,60328,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,58867,50676,58773,990,58870,57916,57916,57916,57916,57916,60005,57916,57916,57916,57916,60009,57916,57916,57916,57916,57916,60014,57943,57943,57943,57943,60088,57943,57943,57943,57943,60092,57943,57943,57943,57943,57943,60097,2856,0,0,0,0,0,0,0,0,0,0,2863,0,0,0,0,0,0,212992,0,0,0,0,0,212992,212992,212992,212992,2893,528,528,528,528,2896,528,528,2898,528,2899,528,528,528,528,528,1356,528,1361,528,528,1365,528,528,1368,528,528,528,528,528,2907,528,528,2911,528,528,528,528,528,528,528,528,528,2494,528,528,2497,2498,528,0,2920,528,528,528,2923,528,528,528,528,528,528,528,528,528,528,528,528,3506,3507,528,528,57893,60308,57893,57893,57893,57893,57893,57893,57893,57893,57893,60317,57893,57893,60321,57893,57893,57893,57893,58835,57893,57893,57893,58842,58844,57893,57893,57893,57893,57893,57893,59381,57893,57893,57893,57893,57893,57893,57893,57893,57893,60902,57893,57893,60905,57893,57893,57893,0,57916,57916,60346,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60354,60369,57916,57916,57916,57916,60372,57916,57916,60374,57916,60375,57916,57916,57916,57916,57916,57943,57943,57943,57943,57943,57943,4288,0,0,0,528,57916,57916,57916,57916,60384,57916,57916,60388,57916,57916,57916,57916,57916,57916,57916,57916,60402,57916,57916,57916,57916,57916,57916,57916,57916,59995,57916,57916,57916,57916,6e4,57916,57916,57916,60397,57916,57916,57916,60400,60401,57916,57916,57916,57916,57916,57916,57916,57916,57916,60683,57916,57916,57916,57916,57916,57916,57916,57916,59452,57916,57916,57916,57916,57916,57916,57916,57943,57943,60419,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60469,57943,57943,57943,57943,57943,60434,57943,57943,57943,57943,60437,57943,57943,60439,57943,60440,57943,57943,57943,57943,57943,60422,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,61155,57943,57943,57943,528,57943,57943,57943,57943,60462,57943,57943,57943,60465,60466,57943,57943,57943,57943,57943,57943,57943,60752,57943,57943,528,528,528,57893,57893,57893,0,0,0,0,0,3658,0,0,3228,528,528,528,528,3233,528,528,528,3236,528,528,528,528,528,528,3255,528,528,528,528,528,528,528,528,528,528,2482,528,528,528,528,528,3261,528,528,0,0,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60616,57893,60619,57893,57893,57893,57893,60624,57893,57893,57893,60627,57893,57893,57893,57893,57893,58805,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57916,57916,57916,57916,61460,57916,57893,57893,57893,60654,57893,57893,0,0,57916,57916,57916,57916,57916,57916,57916,57916,60692,57916,57916,57916,57916,57916,57916,57916,57916,59499,57916,57916,57916,57916,57916,57916,57916,57916,57916,60665,57916,60668,57916,57916,57916,57916,60673,57916,57916,57916,60676,57916,57916,57916,57916,58935,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,58887,57916,57916,57916,57916,57943,57943,57943,60714,57943,60717,57943,57943,57943,57943,60722,57943,57943,57943,60725,57943,57943,57943,57943,57943,61580,61581,57943,57943,0,0,0,0,4242,0,528,528,528,528,528,528,528,528,2427,528,528,528,528,2431,528,0,3454,0,3455,0,0,0,0,0,0,0,0,0,0,0,0,1883,0,0,0,528,528,528,3485,528,528,528,528,528,528,528,528,528,528,528,528,1384,528,528,528,528,528,3497,528,528,528,528,528,528,528,528,3505,528,528,528,528,528,2453,528,528,528,528,528,528,528,528,528,528,1382,528,528,528,1386,528,57893,57893,60869,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60637,57893,57893,57893,57893,57893,57893,57893,57893,60314,57893,57893,57893,57893,57893,57893,57893,57893,60341,57893,57893,57893,0,2999,0,0,0,57893,60881,57893,57893,57893,57893,57893,57893,57893,57893,60889,57893,57893,57893,57893,57893,58820,57893,57893,57893,57893,57893,57893,57893,58829,57893,57893,57916,57916,57916,60911,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59503,57916,57916,57916,57916,57916,60923,57916,57916,57916,57916,57916,57916,57916,57916,60931,57916,57916,57916,57916,57916,59481,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,58911,57916,57916,57916,57916,57916,57916,57943,57943,57943,60953,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60094,57943,57943,57943,57943,57943,57943,60965,57943,57943,57943,57943,57943,57943,57943,57943,60973,57943,57943,57943,57943,57943,60050,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60745,57943,57943,57943,0,3680,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3439,0,0,0,0,0,3693,3694,0,0,0,0,528,528,528,528,528,528,528,2875,528,528,528,528,528,528,528,528,3704,528,528,528,528,528,528,528,528,528,528,528,528,528,528,3494,528,528,3714,528,528,528,528,528,3719,528,3721,528,528,528,528,528,528,3488,528,528,528,528,528,3492,528,528,528,61091,57893,61093,57893,57893,57893,57893,57893,57893,57893,57893,57916,57916,57916,57916,57916,57943,57943,57943,57943,57943,57943,57943,61131,61132,57943,57943,57916,57916,57916,57916,61104,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,61110,57916,57916,57916,57916,57916,57916,57916,61114,57916,57916,57916,57916,57916,57916,61120,57916,61122,57916,57916,57916,57916,57916,61324,57916,57916,57943,57943,57943,57943,57943,57943,57943,57943,57943,60970,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,61149,57943,61151,57943,57943,57943,57943,57943,57943,57943,57943,528,2761,528,528,528,57893,60110,57893,57893,528,528,57893,57893,57893,0,0,0,3818,0,0,0,0,0,0,0,722,0,724,0,0,0,0,0,0,0,0,3823,0,0,0,0,0,0,0,3675,0,0,0,0,3831,0,528,528,528,528,528,3843,528,528,528,3847,528,528,528,528,528,1357,528,528,528,528,528,528,528,528,528,528,528,1422,528,528,528,528,57893,61205,57893,57893,57893,61209,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60886,57893,57893,57893,57893,57893,57893,57893,57893,59896,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,61218,57893,57893,57893,57893,57916,57916,57916,57916,57916,61224,57916,0,0,0,0,57893,57943,57943,58415,57943,57943,57943,57943,57943,57943,58446,57916,57916,61228,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60697,57916,57916,57916,61237,57916,57916,57916,57916,57943,57943,57943,57943,57943,61243,57943,57943,57943,61247,528,4162,57893,57893,57893,61510,57893,57893,57893,57893,57893,57893,57893,57893,61518,57893,57893,57893,57893,58858,57893,57893,57893,57893,57893,57893,50676,58773,990,57916,57916,57916,57916,58903,57916,57916,57916,57916,57916,57916,57916,57916,57916,58913,57916,57916,57916,57916,61523,57916,57916,57916,57916,57916,57916,57916,57916,61531,57916,57943,57943,57943,57943,57943,60955,57943,57943,57943,57943,57943,57943,57943,57943,57943,59581,57943,57943,57943,57943,57943,57943,57943,61536,57943,57943,57943,57943,57943,57943,57943,57943,61544,57943,0,0,0,0,0,0,262144,262144,0,0,0,0,0,0,0,0,0,0,4203,4204,4205,0,4207,528,528,528,528,528,528,528,528,528,4213,4214,528,57893,57893,57893,57893,57893,57893,57893,57893,57893,61564,61565,57893,57893,57916,0,0,0,0,57893,57943,57943,58416,57943,57943,57943,57943,58437,58441,58447,528,528,528,57893,57893,57893,57893,57916,57916,57916,57916,57943,57943,57943,57943,4298,0,528,4299,57893,61644,57916,61645,57943,61646,0,528,57893,57916,57943,0,528,528,528,528,528,528,2425,528,528,528,528,528,528,528,528,528,3246,528,528,528,528,528,528,0,0,0,361,362,0,0,0,0,0,0,0,368,0,296,0,0,0,0,393685,0,393685,393685,393685,0,393685,393685,393685,393685,393685,393685,0,1,24578,3,0,0,4366336,0,0,0,0,0,302,303,0,0,0,0,1731,0,0,0,0,0,0,0,1741,1742,0,0,0,0,0,278528,278528,0,0,0,0,0,0,0,0,0,416,416,0,0,0,0,0,426,426,0,0,131072,426,0,0,0,0,426,0,0,454,0,426,0,483,483,483,0,0,362,362,362,502,362,362,362,362,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,483,546,57912,546,57912,546,546,57912,546,546,57935,57912,546,546,57912,57912,57912,57912,57962,57962,57912,57912,57912,57912,57962,57962,57912,546,57912,57912,57935,57912,57912,57912,57912,57912,57912,57912,57935,57935,57912,57912,57962,57912,57912,57912,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,368,368,0,703,0,0,0,0,0,0,0,0,0,0,0,0,2298,0,0,0,905,528,528,528,57893,57893,57893,57893,57893,57893,57893,58287,57893,57893,57893,57893,57893,60340,57893,57893,57893,57893,57893,0,2999,0,0,0,57893,58306,57893,57893,57893,57893,58324,57893,57893,57893,0,57916,57916,57916,57916,57916,57943,57943,57943,61129,57943,57943,57943,57943,57943,57943,57943,57943,60741,57943,57943,57943,57943,57943,57943,57943,57943,60753,57943,528,528,528,57893,57893,57893,57916,57916,58363,57916,57916,57916,57916,57916,58382,57916,57916,57916,57916,58400,57916,57916,57916,57916,58936,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60392,57916,57916,57916,57916,57916,0,0,0,0,58306,57943,57943,57943,57943,57943,57943,57943,58438,57943,57943,57943,57943,57943,60448,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60427,57943,57943,57943,57943,57943,57943,57943,58457,57943,57943,57943,57943,58475,57943,57943,57943,528,528,528,528,2284,57893,57893,57893,57893,59633,2290,0,2291,0,0,905,528,0,57893,57893,57893,57893,58324,57893,155942,1151,0,1152,0,0,1157,0,0,0,1266,0,0,0,0,0,0,0,1266,0,0,0,0,0,0,450560,0,0,450560,0,450560,450560,450560,450560,450560,450560,450560,450560,450560,450560,450560,450560,450560,450560,450560,450560,1346,528,528,528,1355,528,528,528,528,528,528,528,528,528,528,528,528,3711,528,528,528,58773,914,57893,57893,57893,57893,57893,57893,57893,57893,57893,58785,57893,57893,57893,58794,57893,57893,58855,57893,57893,57893,57893,57893,57893,57893,57893,50676,58773,990,57916,57916,57916,57916,58938,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,61121,57916,57916,57916,57916,57943,57943,58974,57943,57943,57943,58983,57943,57943,57943,57943,57943,57943,57943,57943,57943,59045,57943,57943,57943,57943,57943,57943,0,0,0,1730,0,0,0,0,1737,0,0,0,0,0,0,0,739,0,0,0,0,0,0,0,0,1271,0,0,0,0,0,0,0,0,0,0,1762,0,0,0,0,0,0,0,1770,1771,0,0,0,0,0,3422,0,0,0,0,0,0,0,3426,0,0,0,0,0,1834,0,0,0,0,0,0,0,1840,0,0,0,0,0,0,532480,0,0,0,0,0,0,0,0,0,694,0,0,0,0,0,368,0,0,1846,0,1848,0,0,0,0,0,0,0,0,0,0,0,376832,0,376832,0,0,1915,528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,2499,528,1930,528,528,528,528,528,528,528,528,528,528,528,1943,528,528,0,57893,57893,57893,57893,57893,57893,155942,1151,0,0,0,0,0,0,0,4857856,4874240,0,0,0,0,0,0,0,796,0,0,0,0,805,0,0,0,59373,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59386,57893,57893,57893,2588,0,0,0,57916,57916,57916,57916,57916,57916,57916,57916,57916,60352,57916,57916,57916,57916,57916,57893,57893,59411,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59422,57893,57893,57893,57893,57893,60884,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60903,57893,57893,57893,57893,57893,57916,59511,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59522,57916,57916,57916,57916,57916,61395,57916,61397,61398,57916,61400,57916,61402,57943,57943,57943,3916,528,61261,57893,0,0,0,0,0,0,0,0,0,0,2774,0,0,0,0,59607,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59618,57943,57943,57943,57943,57943,58978,57943,57943,57943,57943,57943,57943,57943,57943,57943,58997,0,0,2326,0,0,0,0,0,0,0,0,0,0,0,0,0,221652,221652,221652,0,0,2504,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,61097,57893,57893,57893,57916,57916,57916,57916,57916,528,3229,528,528,528,528,528,528,528,528,528,528,528,528,528,528,2447,528,60618,57893,60620,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,61211,57893,57893,57893,57893,57893,57893,57893,57893,59870,57893,57893,57893,57893,59875,57893,57893,57916,57916,57916,60667,57916,60669,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60404,57916,57916,57916,57916,57916,60698,57916,57916,57916,57916,57916,57916,57916,57916,57943,57943,57943,57943,60709,57943,57943,57943,57943,57943,60463,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59599,57943,57943,57943,59605,57943,57943,57943,57943,60716,57943,60718,57943,57943,57943,57943,57943,57943,57943,57943,57943,59046,57943,57943,57943,57943,57943,57943,57943,60747,57943,57943,57943,57943,57943,57943,57943,57943,528,528,528,57893,57893,57893,0,0,0,3656,0,0,0,0,0,0,0,3432,0,0,0,0,0,0,0,0,0,0,0,0,2323,2324,0,0,57943,57943,61250,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60724,57943,57943,0,4147,0,0,0,528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,0,4161,528,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,61517,57893,57893,57893,57893,57893,60898,60900,57893,57893,57893,57893,60904,57893,60906,60907,57893,57916,57916,57916,61627,57916,57943,57943,57943,57943,61631,57943,0,0,0,0,528,528,2870,528,528,528,528,528,528,528,528,528,528,2878,373,373,0,0,131072,373,0,0,0,0,373,0,0,0,0,373,547,57913,547,57913,547,547,57913,547,547,57936,57913,547,547,57913,57913,57913,57913,57963,57963,57913,57913,57913,57913,57963,57963,57913,547,57913,57913,57936,57913,57913,57913,57913,57913,57913,57913,57936,57936,57913,57913,57963,57913,57913,57913,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,528,528,528,528,861,528,528,528,528,528,528,528,528,528,528,528,528,3723,528,528,528,57916,58356,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60677,57916,57893,58799,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,61221,57893,57916,57916,57916,57916,57916,57916,57916,57943,57943,60023,57943,57943,57943,57943,57943,57943,528,528,1931,528,528,528,528,528,528,528,528,528,528,528,528,528,1401,528,528,57893,59374,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,59882,57893,57893,57893,57893,57893,57893,57893,57893,57893,60290,57893,57893,57893,57893,57893,57893,59474,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60920,57916,0,0,0,3824,0,3825,0,0,0,0,3675,0,0,0,0,0,0,0,0,0,0,0,0,0,1227,0,0,0,0,0,364,0,0,0,0,0,0,0,0,0,0,364,0,0,0,0,0,0,0,0,0,0,0,0,2335,0,0,0,365,0,0,0,0,364,0,0,0,139264,147456,0,0,0,0,0,0,1324,0,0,0,0,0,0,0,0,0,1166,0,0,0,0,0,0,0,0,0,434,131072,0,434,434,0,0,0,434,0,365,434,0,0,0,0,401408,0,0,0,0,0,0,0,0,0,0,0,0,6471680,0,0,0,466,0,0,0,494,494,497,497,497,497,503,504,497,497,517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,548,57914,548,57914,548,548,57914,548,548,57937,57914,548,548,57914,57914,57914,57914,57964,57964,57914,57914,57914,57914,57964,57964,57914,626,57914,57977,57937,57914,57914,57914,57914,57914,57914,57914,57937,57937,57914,57914,57964,57914,57914,57914,57977,57977,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,0,0,0,459187,0,0,0,0,0,0,0,0,0,0,0,528,528,528,528,528,528,528,528,0,528,2420,528,528,528,528,528,528,528,528,528,528,528,528,528,1402,528,528,0,0,0,57893,59850,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60287,57893,57893,57893,57893,57893,57893,57893,57893,57893,60302,57893,57893,57893,57893,60305,57893,57893,60307,528,528,528,528,2895,528,528,528,528,528,528,528,528,528,528,528,528,4026,57893,57893,57893,57893,60337,57893,57893,57893,57893,57893,57893,57893,57893,57893,0,0,0,0,0,0,1781,0,0,0,0,0,0,0,0,0,139264,147456,0,0,335872,0,0,57916,57916,57916,57916,60371,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,61401,57916,57943,57943,57943,368,368,0,0,0,0,705,0,0,0,0,0,0,0,0,0,139264,147456,0,0,540672,0,0,0,0,735,0,801,0,0,0,0,0,0,0,0,801,0,0,0,0,416,0,0,0,0,0,0,0,0,0,0,0,0,3464,0,0,0,528,528,528,528,862,528,528,528,528,528,528,528,528,528,528,528,528,61203,57893,57893,57893,57916,58357,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,61111,57916,1202,0,0,0,0,0,0,0,0,0,0,368,368,0,0,0,0,0,0,0,0,709,0,0,0,0,0,0,1251,0,0,0,0,0,0,0,0,0,2810,0,0,0,0,0,0,58853,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,50676,58773,990,57916,57916,57916,57916,59463,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60696,57916,57916,57916,57916,59015,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,60442,1726,0,0,0,0,1733,0,0,0,0,0,0,0,0,0,0,319488,319488,0,0,0,0,0,57916,57916,57916,59978,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59959,57916,57916,57916,57943,57943,57943,60061,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59011,57943,57943,57943,2779,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,245760,528,528,2881,528,528,528,528,528,528,528,528,528,528,528,528,528,1404,528,528,57916,57916,60357,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,60919,57916,57916,0,306,307,0,0,0,0,0,0,0,647,0,0,0,0,0,0,1813,0,0,0,0,0,0,0,0,0,787,0,0,0,0,0,0,906,528,528,528,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57916,57916,57916,57916,57916,57916,57916,906,528,0,57893,58490,57893,57893,58325,57893,155942,1151,0,0,0,0,0,0,1836,0,0,1838,0,0,0,0,0,0,0,2861,2813,0,0,0,0,0,2866,0,57893,57893,58856,57893,57893,57893,57893,57893,57893,57893,57893,50676,58773,990,57916,57916,57916,57916,59495,59496,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,61574,57943,57943,57943,57943,0,0,1862,0,0,0,0,0,0,0,0,0,0,0,0,0,327680,327680,327680,528,528,1948,528,528,528,528,528,528,528,528,528,528,528,528,528,1942,528,528,57893,59391,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60313,57893,57893,57893,57893,57893,57893,57893,57893,57893,59922,57893,57893,57893,57893,57893,57893,57893,59491,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,61123,57916,57916,0,0,0,57893,57893,57893,57893,59853,57893,57893,57893,57893,57893,57893,57893,57893,60329,57893,57893,57893,57893,57893,57893,57893,57893,57893,59367,59368,57893,57893,57893,57893,57893,59877,57893,59879,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60636,57893,57893,57893,57893,57893,57893,57893,57893,57893,60316,57893,57893,57893,57893,57893,57893,57916,57916,57916,57916,59966,57916,59968,57916,57916,57916,57916,57916,57916,57916,57916,57916,61117,57916,61119,57916,57916,57916,57916,57916,57916,57943,57943,57943,57943,60049,57943,60051,57943,57943,57943,57943,57943,57943,57943,57943,57943,59552,57943,57943,57943,57943,59556,57943,60381,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,61403,57943,57943,57943,57943,57943,60446,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,57943,59554,57943,57943,57943,0,3418,0,0,0,0,0,0,0,0,0,0,0,0,0,0,352256,352256,352256,57893,57893,57893,57893,60871,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,57893,60645,57893,57893,57893,57893,57893,57893,57893,57893,57893,59923,57893,57893,57893,57893,57893,57893,3713,528,528,528,528,528,528,528,528,528,528,528,528,528,528,528,2500,57916,57916,61113,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,57916,59973,57916,57916,57916,0,0,0,2310144,0,0,0,0,0,0,2310144,0,0,0,0,0,0,0,0,0,0,0,2310144,0,0,2310144,0,0,0,0,0,0,0,2310144,2310144,0,0,0,0,0,0,0,0,2310144,0,0,0,2310144,0,0,0,0,0,2310144,0,2310144,0,0,0,0,0,0,2310144,2310561,2310561,0,2310144,0,0,2310144,0,0,2310144,0,2310144,2310144,0,2310144,0,2310144,2310144,0,0,0,0,0,0,2310561,0,0,0,0,0,0,0,0,0,0,0,2359296,368,0,0,0,0,2310144,0,0,2310740,2310740,2310740,2310740,2310740,2310740,2310740,2310740,2310740,2310740,2310740,2310740,2310740,2310144,2310740,2310144,2310144,2310740,1,24578,3,0,0,4366336,0,0,0,0,0,302,303,0,0,0,0,459347,459347,459347,459347,459347,459347,459347,459347,459347,459347,459347,459347,459347,459222,459379,459222,2318336,0,0,0,4268032,0,0,0,0,0,0,0,0,0,0,0,4276224,0,0,0,0,4358144,4358144,4358144,4358144,0,914,0,0,0,0,0,0,0,0,0,0,4956160,4964352,0,0,0,0,0,467,2335204,2335204,2335204,467,467,467,467,467,467,467,467,467,467,2335238,2335238,1,24578,3,0,0,4366336,0,0,0,0,0,302,303,0,0,0,467,0,0,0,0,0,0,0,0,0,0,2335238,2335204,2335238,2335238,2335238,2335238,2335238,2335238,2335238,2335238,2335238,2335238,2335238,2335238,2335238,2335238,2335238,2335238,0,0,0,2342912,0,0,0,0,0,0,0,0,0,0,0,0,2348,0,0,0,0,0,0,2326528,0,0,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,4358144,5177344,4358144,4358144,4358144,4358144,0,0,0,2359296,0,2359296,0,0,0,2359296,0,2359296,2359296,2359296,2359296,2359296,2359296,2359296,2359296,2359296,2359296,2359296,2359296,2359296,2359296,2359296,2359296,2359296,2359296,1,24578,3,0,0,4366336,0,0,0,0,0,302,303,0,0,0,0,573440,0,573440,573440,573440,0,573440,573440,573440,573440,573440,573440,1,24578,3,0,0,4366336,0,0,0,0,0,302,303,0,0,2367488,0,0,4268032,0,0,0,0,0,0,0,0,0,0,0,4931584,0,0,0,0,0,0,2351104,0,0,0,0,0,0,0,0,0,0,0,0,0,507904,507904,507904,0,913,0,0,0,0,0,4857856,4874240,0,0,0,0,0,0,0,1180,0,0,0,0,1184,0,0,1187,0,6275072,0,0,0,0,0,0,0,0,0,0,0,989,0,0,0,0,913,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,4359057,5260177,4359057,4359057,0,0,1,24578,3,155942,155942,296,0,0,0,0,0,302,303,0,0,0,0,573440,573440,573440,573440,573440,573440,573440,573440,573440,573440,573440,573440,573440,573440,573440,573440,212992,0,212992,212992,212992,212992,212992,212992,212992,212992,212992,212992,212992,212992,212992,212992,212992,212992,212992,212992,0,0,0,0,0,4366336,0,0,0,0,0,0,0,0,2412,0,0,0,0,0,0,0,0,0,0,6275072,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6258688,6447104,0,0,6127616,0,6348800,5906432,0,5537792,0,4882432,0,0,0,0,0,0,4825088,0,0,5177344,0,0,0,0,5701632,0,0,0,0,0,4358144,4358144,4358144,4825088,4358144,4358144,4358144,4358144,0,0,913,913,913,4826001,913,913,913,913,913,913,0,0,989,989,4842461,989,989,989,4899805,989,0,0,5513216,5783552,0,0,0,0,0,0,0,0,0,0,4358144,4358144,4358144,4358144,4358144,4857856,4874240],r.EXPECTED=[169,185,215,1326,231,1001,278,928,942,1085,320,247,263,307,336,352,368,384,400,914,2264,430,2264,2264,2264,2264,2264,2264,2264,2264,2264,2264,2264,2268,1707,1603,1403,460,1356,1591,491,507,517,533,1816,1031,2119,564,475,580,596,625,684,700,1905,716,1114,747,778,788,1693,1145,762,804,820,836,852,868,884,900,958,988,1017,972,1997,1047,1057,1073,1101,1130,2028,1562,1190,1205,1221,1237,1253,1269,1298,1314,1342,1174,1446,1372,1876,2073,1633,668,1388,1419,1434,1467,1483,1499,1515,609,1531,1547,1578,444,654,640,1619,1649,1662,1678,1723,1738,1754,1770,1786,1802,1832,1848,291,1864,2228,1892,1921,1937,199,2149,1953,1969,1985,1282,2013,2044,2060,2089,2105,548,2135,2165,2181,2197,2213,1160,2244,731,2260,2264,1457,412,2264,2264,2264,2264,2264,2264,2264,2264,2264,2264,2264,2264,2264,2264,419,2284,2288,2290,2290,2290,2291,2295,2290,2297,2301,2304,2311,2307,2315,2318,2322,2326,2330,2334,2338,2345,2345,3446,2344,2345,3427,2352,3605,2345,4169,2345,2345,2345,3950,4664,4990,4059,4582,2828,4588,2345,4069,4598,2345,4069,4603,2734,3100,2397,2497,2359,2366,2466,2372,2376,2345,2345,4266,2345,2345,2383,3820,2359,2359,2392,2419,2419,2419,2419,2405,2427,2345,2345,2345,2345,2345,2409,2455,3819,2345,2345,3099,3100,3100,3100,2495,2398,2398,2398,2504,2359,2359,2359,2482,2419,2419,2419,2517,2345,2345,2345,2457,2345,3100,3100,3101,2398,2398,2398,2359,2359,2359,2359,2359,2418,2419,2419,2419,2419,2419,2424,2437,2345,2345,2345,2345,4505,2729,2345,2345,2345,2345,4509,5101,4513,2345,2345,3904,2359,2359,2484,2419,2419,2519,2345,3864,2345,4865,3100,3100,2501,2398,2538,2359,2359,2359,2359,2359,2548,2419,2419,2419,2419,2395,2490,2345,2345,2359,2483,2419,2549,2508,3755,2345,4867,4911,2398,2400,2359,2515,2419,2525,3605,3100,2476,2401,2547,2550,2816,4868,2399,2481,2485,2735,2532,2503,2361,2368,4866,2476,2360,2420,4909,2537,2546,2486,2533,2362,2542,2554,2567,2571,2575,2579,2583,2586,2586,2586,2598,2591,2586,2587,2595,2602,2606,2610,2614,2618,2622,2626,2630,4594,2634,2345,2345,2903,2640,2345,2345,2999,2345,2345,2645,2345,2345,2345,2345,2345,2345,4208,2345,2345,2345,2345,2345,2345,2345,2345,2345,2345,4460,2655,2345,2345,2345,2345,2345,2345,2345,2345,2345,2345,2345,2345,2655,2345,2345,2636,4128,2345,2345,2345,2345,2635,4127,2345,2345,2345,2345,2635,4127,2794,2345,2345,2345,3016,2798,2345,2345,2345,3017,2799,2345,2345,2345,2806,2729,2876,3308,2345,2915,2345,3310,2345,2922,2345,3536,2683,4475,3831,4927,2685,4422,2850,2345,2345,2345,2345,2345,2345,5004,2345,2345,2345,2345,4417,3024,3547,2854,5007,2861,2345,2345,2345,2345,4422,2869,2345,2345,2345,2345,2345,2868,2729,2345,2345,2345,2345,2345,2873,2345,2345,2345,4443,2345,3549,3338,2880,2345,2345,2345,2345,2887,2729,2345,2345,2345,2883,2880,2345,2345,4951,4956,2345,2345,2345,2345,4604,4971,4982,2345,2345,4805,4988,3762,2345,3965,2345,4436,4591,2907,2345,3192,2909,2345,4490,2345,3191,2908,2345,3491,4849,4476,4920,4920,4920,4849,2720,4477,4477,4477,4918,4922,2683,4476,4863,4478,2719,2684,2432,2429,2431,2563,2345,2345,2345,2345,2345,2345,2984,2345,2345,2345,2511,4068,4075,2345,2345,4081,2345,4085,2345,2345,4099,2345,3067,3768,2729,4088,2928,3046,2947,2932,2935,2938,2940,2940,2944,2345,2951,2956,2345,2345,5022,2729,2345,2345,2345,2345,4180,2345,2345,2345,2345,5023,2345,4654,2345,4496,2345,3077,4168,3570,5100,4176,2345,2345,2345,5024,2345,2345,4147,2345,2345,4258,2345,2345,2339,3845,2345,3726,3911,3122,3918,2345,4757,2345,4949,2345,2961,2974,2978,3641,3718,2988,2996,2722,3003,3008,2345,2998,4205,2345,2952,2345,2345,3697,2345,3015,4630,3021,3029,3033,2412,2991,2723,3040,3497,2345,2951,2956,2345,5067,4831,2345,3623,2964,3050,4101,2345,3156,3059,2345,2345,5115,3712,2387,4578,2345,5120,2458,2509,4221,2345,5107,2345,3202,2763,3060,2345,2345,2345,3733,2345,2951,2733,2345,4755,4856,3111,4236,2557,3086,2345,2348,3162,2345,2345,2527,3154,2345,2345,2347,3161,2345,2345,4684,3167,3432,4676,3096,2345,2345,2345,2345,2472,3106,2345,2345,2345,2345,2346,3105,2345,2345,2345,4878,3110,3119,2345,5067,4832,4234,3023,3126,4109,3602,3171,3176,2345,4069,3180,2345,4170,3176,2345,2345,3187,2345,4682,3217,4094,3257,3196,3972,3190,2345,3974,2345,3251,3209,2345,3973,2345,3214,3218,3223,3227,3231,4192,2345,3229,2345,3237,3606,3242,3246,4319,3250,3238,3230,3255,3261,3266,3266,3266,3274,3278,3262,3262,3262,3285,3289,4198,3290,4959,3294,4246,5038,3298,3302,3306,3316,3322,3329,2345,2345,2345,2345,3926,2345,2345,2875,3333,3337,4593,3342,3347,4397,3357,3361,3365,3366,3366,3370,2345,4118,3376,2345,4445,3382,4945,3392,2721,3398,2829,3406,3410,3417,3424,3004,3431,3947,2345,3426,2345,2345,3115,3658,4038,4560,2345,2345,2345,2345,2345,2345,2345,2650,2345,2345,2454,2345,2345,2345,4867,3100,3100,3100,3100,3101,2398,2398,2398,2398,2545,2359,2359,2359,2359,2359,2464,2419,2419,2419,2419,2419,2395,2470,4119,2345,2345,3437,3706,3578,3394,4115,2345,5085,3441,3522,4170,3451,2345,2345,3132,3489,2345,2345,2345,2345,3143,3495,2345,2345,2345,2345,4516,3484,2345,4070,3455,2345,2345,2345,4071,3456,2345,2345,2345,3460,3464,2345,2345,2345,3098,3100,3100,3100,3100,3100,2397,2398,2398,2398,2398,2398,2480,4118,3830,2345,3469,3584,3579,3476,4935,4215,3011,2345,2345,4515,3483,2345,2345,3191,2898,2345,2345,2345,2892,2345,2345,2345,2897,2345,2345,2345,3963,3232,2345,2345,2345,2345,3517,3490,2345,2345,2345,2345,4515,3520,2345,2345,2345,2345,3982,2345,3526,3585,3535,4117,2786,2345,2345,3541,2345,2345,2345,2345,4530,3545,2345,2345,2345,2345,3541,2345,2345,2345,2345,2456,2345,2345,4910,3100,3100,3100,3100,2476,2398,2398,2398,4531,3232,2345,2345,2345,3560,3565,3576,4115,3204,3583,2345,5095,2345,2345,2345,3163,3064,2345,2345,2345,2345,3219,3071,2345,2345,2345,2345,3157,5054,2345,2345,2345,5094,2345,2345,2345,5053,2345,2345,2345,3590,3966,3561,2345,2521,3137,2345,2345,3754,2981,3141,5078,4842,4667,2967,3147,2528,3155,2345,2751,5076,2686,5082,4996,5091,5099,2345,2345,5072,2345,2345,5105,2345,2345,4450,3818,2345,3825,2345,2460,3835,3839,2345,2345,2345,4069,3843,2345,4928,2345,3443,2345,3828,2345,4052,3148,2345,2386,3114,3150,4047,3149,3635,3635,4052,3113,3150,3150,3150,3980,3634,3112,3635,4053,3622,3635,3150,4974,4976,3627,4978,3631,3640,2345,2345,2345,2345,4428,3779,3723,2345,3595,3645,3649,4091,3655,3663,3667,3671,3675,3679,3680,3684,2345,2801,3689,2345,4841,3695,4295,2763,3350,3199,3691,5040,3485,3701,4584,3465,3705,4823,3710,3716,2345,2345,2802,3690,2345,4616,4756,3722,3731,3957,3201,3737,3750,3759,2345,3940,3766,2345,2345,2345,3312,4745,4749,4761,4765,4769,4773,4777,4781,4785,4788,4792,4795,3504,3232,2345,2345,2345,3505,2345,2345,2345,2646,3772,2345,2345,2345,4427,3778,2345,4164,4095,2345,3785,4903,2651,2345,3753,2345,2345,3793,2345,2345,2345,2345,3098,3100,3100,3100,3100,2398,2398,2398,2398,2478,2359,2359,2345,3797,2345,2345,2345,2345,2345,3801,2345,2345,2345,2345,2345,3805,2345,2345,3846,2810,5004,2345,2345,2345,2345,4151,2345,2815,2820,2833,4077,2838,3850,2345,2345,2345,2345,4737,2345,3855,2458,4716,3837,3863,2345,2345,3172,3871,3924,2345,2340,2345,2345,4149,2345,2339,3845,3723,3089,3789,2345,3930,4129,2345,2776,3914,4135,2728,2345,2345,2345,2345,3210,2345,2784,3082,3938,2345,2790,5046,2345,3935,2345,3944,2730,3877,2345,3352,2732,3955,2731,4157,4157,4157,3351,2732,2732,2732,3531,4156,4716,4157,4718,3878,4157,2732,2345,2345,2345,2345,3851,2345,2345,2345,2345,2345,3850,2345,2345,2345,2345,2345,2345,2345,3612,2663,2345,2345,2345,2345,2345,2345,2345,3780,3961,2345,2345,3920,3970,3978,3986,3990,3994,3998,4001,4005,4007,4011,2345,2345,2345,4015,2345,3606,4752,4107,3553,4020,4024,4643,4888,4028,2345,4851,2811,4032,4826,4037,4042,4046,2345,2345,4016,2345,3746,4051,3551,3877,4057,3636,4570,4063,2345,2345,2345,2780,2345,2345,2345,2510,4067,4105,2924,4156,4113,2386,4123,4538,2345,2345,2635,4127,2345,2345,2345,2345,2641,4133,2345,2345,2345,2345,2778,4181,2345,2457,2345,2345,4984,5025,2345,4139,2345,2855,3611,2345,2857,2345,2345,3386,2345,2856,2345,2345,3830,3616,2345,3445,2345,4145,2345,4670,3724,4155,3572,3114,4161,2345,2345,2345,3472,2729,2345,2345,2345,2345,2842,2345,2345,2345,2345,3081,2846,2345,2345,2345,2345,2345,2739,2692,3821,2749,2757,2345,2761,2767,2345,2771,4802,2345,4185,3077,3725,4231,3041,4220,2345,5087,2729,2345,2345,2911,4134,2345,2345,4172,2345,2345,2345,2354,3845,2345,3723,3606,2458,3787,3901,2345,3781,3537,4190,2345,2345,2910,4196,3378,3685,3607,4673,4202,2823,2345,4033,2729,2345,3931,2956,2345,3925,4214,4219,4225,4240,4244,4264,2345,4250,2345,4252,2345,2345,4256,2345,4251,3343,4538,4228,4262,2345,4270,3353,2345,4610,2345,3183,3130,2345,2345,2345,2346,3136,2345,2345,2345,2345,3183,3130,2345,2345,2673,2345,2345,2677,3814,2690,2696,2700,2704,2708,2712,2716,3744,2727,4275,4284,4288,4419,2668,3659,2733,4292,4308,4420,3556,3556,3556,4317,3530,4421,4335,4323,3555,3529,3568,3025,2669,3556,4330,4339,4341,4333,4326,4345,4349,4351,2345,2345,2345,2345,3897,2992,2345,4313,4355,4359,4390,4363,4367,4371,4375,4379,4381,4383,2345,2345,2345,4937,4387,4657,4394,4401,4460,2827,4636,4599,4278,4407,4411,5122,3727,4426,4432,2345,4440,4449,2345,2345,4938,3774,2657,4454,4458,3325,2345,3053,4464,4468,2345,2345,2345,5128,4474,2345,2345,2345,4482,2345,2345,4271,2888,2345,2345,2345,2345,3233,2345,2345,2345,4962,2864,3650,2893,2345,3727,4483,2345,2345,2345,3055,4487,4494,2345,2345,3890,4311,2433,2446,3618,2826,4186,5066,4947,2733,2345,2345,2345,3413,4500,2345,2345,2345,2345,3420,2800,4414,4622,4520,3318,2345,2970,5060,2345,2345,2345,2377,4524,2345,2345,2345,2345,3869,2345,2345,2345,2345,4171,3876,2345,2345,2345,4069,3870,2345,4952,4311,2443,4535,2827,3865,3433,2345,2345,2345,2379,4543,2345,2345,2345,3858,2345,2345,2345,2345,3859,2345,2345,2345,2957,3045,2345,2345,2377,4548,2345,2345,2345,2345,3281,4553,2345,2345,2345,2378,4549,4470,2345,4558,2440,4564,3203,4831,2345,2345,2377,4568,2345,2345,2345,3951,2345,2345,2345,4574,2345,4640,2345,4069,4647,2560,4651,4661,2345,4680,4539,4642,5031,2345,5014,4688,4830,4815,4403,3883,4642,4692,4628,4816,4696,4696,4702,4830,4706,4714,4714,4722,2414,2449,3808,4731,2414,4906,2450,4735,4725,4727,4741,4829,2345,2345,2345,2345,3925,2345,2772,3501,4141,3509,4115,4215,3074,2345,2345,3513,4799,2345,2345,2345,2345,4809,3015,4813,4820,4967,2388,2680,4210,4836,4554,2345,3372,2345,2345,3384,2345,2345,3372,2345,2345,2856,2345,2345,3589,3594,3599,4708,3872,4840,4846,2345,4710,4855,2345,2345,4544,4860,2834,3742,4965,3080,4872,4877,4882,2345,2345,2345,2345,3606,4886,2345,2345,2345,3478,4892,2345,2345,2345,3882,2663,2459,3092,3887,2345,2345,3894,2345,2345,2345,2355,2345,3479,2345,2345,2345,2345,4897,3616,2345,2345,4544,4915,3035,4280,2918,3446,4873,4698,4926,2345,2345,2345,2345,2345,4932,2345,2345,2345,2345,3606,4942,2345,2345,4435,3377,3907,2902,2345,4489,2729,2345,3651,2902,2345,3192,2909,2345,4994,5020,5001,3205,5011,2345,2345,2345,2345,2741,2745,2345,2345,2345,2345,4170,4608,2345,2345,4614,4989,4620,4626,3755,4950,2345,4634,2345,5013,2345,2744,2345,2345,2345,2345,2345,2743,2345,2345,2345,2345,2345,2743,4900,2345,4501,4915,3036,5018,3447,3864,5029,2345,2345,2345,4170,5035,2345,2345,2345,2345,4303,5044,2345,2345,2345,2345,5050,2345,2345,2345,2345,4304,4900,2345,3811,3740,4997,5058,5064,2345,2345,2345,5071,2345,2345,2345,3269,2345,2345,2345,4297,4301,2345,3402,2800,2345,2345,2345,2345,3401,4528,2345,2345,2345,2345,3401,4528,4470,4299,2345,2345,3270,2345,5111,4997,4577,2345,2345,2753,2345,4893,5116,2345,2752,2491,2458,2345,5126,2345,2345,2345,2345,2345,2345,2345,2345,2345,2345,2345,2345,2345,2345,2345,2345,2661,3388,2667,2345,7267,5893,5132,5144,5141,5151,5153,5153,5153,5153,5148,5176,5152,5153,5153,5153,5159,5163,5176,5153,5153,5169,5164,5153,5180,5155,5154,5168,5151,6159,5173,5199,5205,5205,5205,5209,5209,5201,5213,5217,5220,5224,5228,5245,5232,5242,5234,5238,5236,5249,5252,7269,7026,5260,5273,5276,5276,5276,5255,5821,5295,5276,5276,5276,5276,5268,5730,6588,6270,5301,5276,5276,5254,6597,5821,6646,6646,6646,6646,5394,5396,5325,5449,5322,5396,5396,5325,5276,5384,5428,5333,5409,5274,5276,5276,5276,5286,5290,7174,5276,6844,7218,6005,5276,5276,5276,6390,6115,6646,6647,5323,5396,5397,5400,5428,5428,5428,5428,6645,6646,6646,5398,5400,5428,5345,6844,7217,5353,5276,5266,5276,5276,5388,7455,5457,5396,5396,5396,5396,5276,5399,5402,6779,5408,6667,5275,5276,5275,5276,5276,6239,5276,6839,5410,6667,5275,5276,5275,6561,5276,5275,6839,6843,7454,7155,5276,5276,7229,5276,5276,6466,5276,5276,6526,5276,5276,5276,5302,5276,5276,6646,5393,5396,5396,5396,5400,5407,6668,5276,5276,5268,6066,5402,5428,5428,5428,5429,6646,6646,6646,5395,5396,5396,5396,5326,5368,5419,5276,5276,5276,5305,5401,5428,5428,5428,5430,6646,5427,5428,5428,5428,6644,6646,6646,5402,5387,5276,5276,5276,5307,6771,6646,5394,5396,5396,5398,5427,5276,5276,5268,6630,5397,5403,5276,5276,5269,5731,6036,5400,5400,5402,5428,6644,5402,5428,5428,6643,6646,5368,5400,5427,6643,6646,6646,6646,5396,5396,5396,5397,5387,6646,5395,5324,5368,5276,5999,5276,5276,7234,6237,5276,6239,6237,5401,6643,5393,5324,5415,5434,5460,5464,5463,5462,5461,5326,7445,6108,6418,5509,5541,5438,5442,5508,5508,5508,5508,5486,5515,5454,5468,5472,5491,5543,5496,5508,5508,5538,5446,5582,5487,5506,5581,5513,5475,5519,5535,6805,6808,5547,6811,6814,6815,6816,5551,5554,5558,5569,5573,5579,5492,5586,5590,5594,5598,5605,5604,5601,5609,5613,5561,6981,5276,5276,5276,5308,5312,7372,5276,5276,5276,5309,7137,5276,5276,5276,5329,5276,6389,5276,5276,6557,5276,6391,5276,5276,5275,5276,6392,6392,5276,5276,5279,5276,6282,5276,5276,5276,5366,5276,6e3,6885,5910,7281,5626,5297,5629,5276,5276,7348,5276,5276,7354,5276,5276,5276,5631,5640,5899,5276,5647,5276,6987,5263,5186,5654,5657,5659,5660,5664,5668,5673,5672,5677,5679,5680,5680,5684,5686,5693,5688,5700,5688,5697,5689,5704,5276,5276,7355,5276,5276,5276,5648,6027,6933,6281,5898,5276,5276,5276,5367,5276,5276,5276,5368,5400,5708,6023,5276,5276,5281,7411,7471,7426,5276,5276,6043,5135,5276,5276,5281,7468,6467,5276,5716,5276,5276,5721,6061,5339,5276,5276,5304,5276,5341,5737,5745,5751,5749,5276,5276,5276,5369,6219,5751,5276,5276,5306,5310,6765,5276,5276,6988,5276,6526,5277,6886,6113,5784,5276,5793,7239,5808,5855,5812,5831,7055,5318,5276,5276,5276,5372,5348,7452,5827,5832,7056,5137,5276,5276,5276,5376,5368,5276,6525,5276,5414,5276,7452,7443,5276,5276,7419,6200,5276,5925,5276,5276,5276,7249,5717,5276,5276,5276,5387,5795,7243,5854,5845,7241,5851,5855,5846,7242,5852,5856,5317,5850,5854,5845,5898,5860,5276,5276,5276,5388,6362,5276,5854,5876,5318,5276,5276,7441,6519,7240,5851,5855,5877,5898,5881,5839,5276,5276,5370,5276,5276,5853,5885,5318,5276,5276,7452,6134,7239,6135,5854,5886,5898,6404,5870,6865,5276,5276,6117,5869,6864,5898,5276,6867,5276,5276,5276,5617,6117,5890,6866,5276,5276,5276,5620,6857,5276,6719,6723,5276,5276,7455,6886,6721,5898,5276,5276,5373,5276,5914,5276,5898,7023,5934,5938,5942,5945,5948,5949,5949,5950,5954,5954,5954,5954,5954,5958,5961,5276,5277,5921,5930,5276,6659,6079,5966,6872,6872,5276,5276,5276,5650,6487,5276,5711,6194,7445,7444,5368,5276,6e3,6525,5276,7025,5302,6259,5276,5370,5979,6510,5997,5276,6523,5276,5276,6660,6080,5967,5898,6890,5997,5276,6889,5276,5276,5276,5841,6010,5276,6606,5276,5276,5276,5822,6016,5276,5276,5276,5787,5276,6605,6017,5276,5277,5962,6001,7450,5276,5276,5276,5826,5831,5712,6195,7052,5276,5368,5276,5276,5366,5369,6121,5276,6513,5276,6559,5276,5276,5386,5282,5276,6093,5276,5276,5276,5864,6029,5276,5276,5276,5896,6848,5998,5276,6523,6792,5276,5276,6397,7112,6033,6047,6053,5898,5276,6034,6048,6054,5276,5278,5281,6211,6035,6049,6055,5276,5278,5909,5276,5279,6836,6888,5276,5276,5276,7452,5761,6526,6233,6268,5276,5280,5303,6536,5276,6268,6140,6038,6070,5276,5276,5400,5400,5400,5400,5401,6066,6588,6039,5894,5276,7456,5276,5276,5276,6002,5276,5276,5276,5975,5277,6078,6084,5367,6266,7445,6236,5999,6524,5276,6100,6037,6070,5276,5276,5477,5481,6630,6587,6090,5894,5276,6080,6086,5276,5276,5478,5482,6099,5276,5276,5276,6003,5276,5276,6036,6107,5276,5276,5276,6072,6033,6588,6106,5276,5276,5276,6073,6085,5276,5276,7023,6099,5276,5276,5281,6583,5728,5732,6105,5894,5729,5733,6106,5276,5281,6629,6586,5727,5731,6104,6108,5276,5276,5276,6117,5890,5371,6e3,6125,6268,6456,5276,6388,5276,5276,5276,6523,5276,7417,6416,5276,5276,5276,6119,5276,6524,6525,6659,6322,5276,5276,5276,6074,5363,7445,5276,5370,6e3,6236,5276,6320,5799,5803,5276,5276,5276,6127,6319,5798,5802,5276,5276,6321,5276,7260,7446,5368,6001,6320,5799,5801,5276,5276,6319,5797,5276,7073,5276,7258,7447,5276,7447,5302,7075,5803,5276,5276,7072,7076,5276,5281,7468,7477,5276,5276,7073,7260,7446,5276,7074,5802,5276,5285,5289,7173,6339,7258,7447,6339,7077,5276,6117,7076,5276,6342,5276,6117,6342,6139,6117,6200,6978,5276,6978,5276,6978,5276,7445,6197,5276,6237,6722,5276,5276,5372,7365,6199,6197,5276,6199,5276,5925,7445,6198,6198,6198,5276,5276,5926,6198,5276,6896,6896,5389,6536,5368,5525,6145,5276,5276,5276,6133,6358,5367,5276,5276,6198,6537,6199,6536,6200,5276,6537,5276,5276,5276,6480,6167,6152,6171,6175,6179,6181,6185,6185,6181,6189,6189,6189,6189,6189,6191,5276,5276,5564,6363,6206,5276,5276,5276,6199,6200,6251,5898,5276,5276,5565,5371,5276,5276,5575,6934,6200,5276,7454,5803,7356,5276,6293,5276,5804,5276,5287,5291,7160,7066,6196,5276,5285,6217,6223,7106,6232,5276,5287,7149,7129,6243,5276,7260,5276,5288,7150,7141,6257,5276,5789,5276,5276,5276,6202,6263,5276,5276,5276,6201,5367,5369,5387,6274,6253,5278,6018,5276,5276,5642,5276,5276,5276,6388,6113,5193,6286,6935,6040,6287,6936,6041,5276,5276,5191,5195,6288,6937,6042,5276,5276,5276,6226,5385,6114,6252,5276,5307,5311,5315,7420,7354,5276,5276,5739,7397,7403,6298,6329,5803,5276,5276,6006,6299,6330,5276,5276,5276,6265,6300,6331,5276,5276,5753,5752,5387,6275,5897,5276,5328,6552,6547,5803,6197,7453,7421,6267,6392,5479,6312,6329,5276,6458,5480,6313,6330,5276,5276,5764,5276,5385,6246,6253,5276,5363,5367,5276,5276,6536,6317,6267,5276,5276,5276,5621,6392,7412,6327,6332,6301,5803,5276,5276,5815,7444,6522,5276,5276,5375,5276,5276,5365,5276,5276,5916,5276,5276,5276,6294,5368,5386,6336,5276,5365,5276,6535,5276,6820,7444,5276,5276,6519,6308,5276,6198,5276,7452,5280,5276,5276,5276,6307,6197,5276,6843,5276,6356,6250,6678,5276,5276,5276,6368,5276,6844,5894,5276,5369,5998,6524,5276,5276,5276,5277,6208,6362,5276,5276,5276,6371,5276,6846,5276,5276,5898,5276,6005,5276,5276,6005,5276,5276,6846,6004,6002,6846,6005,6005,6005,5276,5276,6004,5276,5276,6005,6847,5276,5276,5995,6375,5894,5276,6520,6383,5276,5276,5276,6404,5871,6112,7024,6387,6111,5276,5276,5276,5363,6401,6761,6409,6972,6429,6432,6433,6434,6438,6438,6438,6438,6441,6443,6444,6444,6451,6451,6451,6451,6448,6452,5276,5276,5276,6425,5348,6566,5276,5276,5276,6463,6370,6494,5276,5276,5973,5276,5362,6468,5276,6469,6475,5276,5276,5276,6519,5276,6484,5276,5276,6e3,5389,6228,6477,5276,5276,6012,5276,6112,5276,5276,5276,6520,5276,5276,5276,6396,5304,6197,5276,5276,6060,6059,5276,6499,6507,5276,5386,5283,5276,5276,6395,5276,5276,5279,6208,6518,5276,5276,5359,5276,5276,5276,6524,5276,5276,6534,6534,5276,5388,5276,5284,6546,6618,5276,5276,6109,5903,6553,6548,5276,5276,6116,5998,5349,6567,5276,5276,5276,6392,6611,5305,6199,5276,6537,6265,5276,6236,6525,5276,6830,6573,5818,5276,6831,5501,5819,5276,6832,5502,5820,6830,5500,5818,5276,5422,6847,5276,5522,7448,5276,5636,6001,5998,6565,5276,5276,5276,6525,5276,5276,7449,6887,6493,5276,5641,6843,5276,5276,5276,6237,6537,5276,6268,6140,5276,6390,5276,6459,6571,6577,5821,5276,5276,5276,6657,5276,7285,5499,6578,5276,5276,6886,5279,5276,5649,6028,6094,5276,6458,5276,5276,5276,6526,7024,6877,5256,6579,5276,5276,5276,6528,6598,5276,5276,5276,6536,5276,6592,5276,5276,5276,6620,5276,6391,6459,5276,5739,7123,6938,5281,6583,6579,5276,5741,7125,6332,6602,5276,6459,5276,5741,7125,6522,5276,6404,5871,5280,5276,5302,5276,5757,5276,5356,6392,6526,5276,5276,6118,5279,6610,5276,5276,5276,6783,5367,6615,5276,5276,5276,6784,5276,6919,6923,5276,5777,5276,5276,5327,6542,5280,6537,6266,5276,5788,6264,5276,5288,7184,7189,5276,5277,5276,5367,5276,6268,6141,6712,6424,5276,5276,6126,5898,5276,5276,5632,6626,6634,5276,5276,6131,6414,6108,5276,5276,6395,5276,6844,5276,5276,5917,5276,6521,5276,6395,6522,6729,6846,5276,5375,6502,6651,6664,6672,6682,6685,6689,6693,6693,6693,6695,6697,6697,6697,6697,6701,6702,6702,6702,6703,6707,5276,6711,6423,5276,5276,5276,6735,5276,6716,5276,7351,5276,6727,5276,7420,6268,6969,6745,5276,5276,5276,6785,5450,5276,5276,5276,6793,6743,6094,5276,6750,6751,5276,5276,5276,6844,6212,5276,5276,5276,6847,5276,5276,6755,5276,5276,6238,5276,6524,6798,6267,6759,6771,6766,5276,5276,5276,6877,5194,6287,5276,7275,5276,5276,6248,5276,5276,6776,6772,6767,6790,5276,6792,5276,5907,5276,6269,5894,7260,7023,5276,5276,5276,6111,6392,6422,6847,5276,6100,5276,6888,5276,5276,6521,5276,5276,6194,7446,5368,7418,5276,5276,6293,5276,5276,5276,6269,6206,7033,6523,6797,6266,5312,5316,5276,5276,5276,6921,5313,5317,5276,5276,5276,6933,6792,6791,5276,5276,6305,5304,6420,6424,5276,5276,6319,6922,5276,5276,6118,5276,5374,5276,5276,6535,5276,5276,7034,7452,6826,5276,5908,5278,6495,5276,6519,5276,5276,5276,5281,5255,6598,5276,7033,5863,6828,6852,5314,5318,5276,5276,6913,5276,5276,5276,6958,6858,5318,5276,5276,6321,5800,6857,5317,5276,5276,6340,5802,6535,5276,6862,5276,6022,5753,5276,5278,5276,5276,7210,5276,6871,5276,5276,5276,7191,6199,6200,5276,5276,5276,7042,6425,5276,5276,6876,6887,5276,5367,6820,7444,5276,6002,5276,6194,7052,5276,6637,6520,5276,6536,5276,6822,5276,5276,6341,5276,7204,5276,5276,5276,7203,5367,5276,6786,5276,5276,6392,6921,6821,5276,5276,6904,5276,5276,6388,6391,6480,5276,5276,5276,7239,5276,6478,5367,5276,6095,5276,5276,6394,5276,6897,5276,5276,6883,6535,5276,5371,6904,5364,5276,6894,5276,6110,5276,5276,5981,7461,7451,5276,5276,5276,5983,7470,5990,5283,6536,6901,5276,6114,5276,6001,6911,5374,6535,5368,5803,5276,6392,6412,5369,5276,5276,5366,5364,6537,6364,5364,5276,5367,5371,5366,5364,5276,5276,6536,5365,5276,5366,5276,5366,5367,6538,6538,6538,5773,5767,5769,5771,5771,5772,5276,7445,5183,5276,5282,5917,7454,6113,6917,6942,7063,5336,6951,6962,6966,5531,6992,6995,6995,6998,7003,7002,7002,7004,7008,7009,7015,7013,7013,7013,7013,7019,7022,7030,5276,5276,6115,5375,5528,6927,5276,7445,6842,7453,6149,6156,6163,7038,6983,5276,5276,6392,7229,5277,5276,5276,7046,7060,5276,7070,5276,6116,5999,5276,6117,5276,5276,5364,5276,5276,5276,7240,7085,5276,5276,5276,7337,5349,5276,6906,7086,5276,6117,5368,5276,5276,6907,5276,7090,5276,6120,5276,5368,5389,6113,7094,5276,5276,5276,7338,6840,5276,6782,7444,6985,5276,5896,5276,6197,5276,5276,7024,5276,7104,5277,5276,5276,6947,6946,5276,6378,5276,5276,5276,7356,5276,5276,7356,6396,7111,7118,6379,5276,7119,6094,5276,5276,6405,5872,5898,6956,6954,5276,5276,6422,6847,7144,5276,5276,5276,7363,5285,5289,7113,7142,5286,7148,7114,7143,6201,5367,5276,5276,6458,5480,6298,7452,7154,5276,5895,5290,7159,7164,5318,7066,5318,5276,5276,6458,5481,6301,6676,5276,5276,6199,5276,5276,5276,6879,7180,5276,5276,5276,7364,5290,7174,7179,5276,5276,7178,5276,5276,5276,7380,5740,7169,5276,5276,6467,5276,6677,6197,5276,5924,7196,6975,5276,5276,6467,7049,5285,7195,7185,6391,6116,5276,5276,5276,7208,7454,5276,5276,6473,6477,6526,5276,7449,5276,6197,6520,5276,7446,5276,5375,7224,5276,5276,5276,7381,7214,5276,5276,5276,7408,7223,6847,5276,5276,6479,5276,7222,6425,5276,6201,6886,6492,7200,5276,6237,5276,5276,6841,6675,5276,5276,5387,5276,5276,6488,5276,6878,6781,5276,5276,6514,5276,5276,6879,7230,5276,5276,5276,7446,7228,5276,5276,6249,7452,5276,5389,5276,6198,6197,5276,6e3,5276,6238,5276,6524,6201,5276,6201,7449,5276,6193,7445,5276,5280,6209,6213,5276,6520,5276,5281,6065,6587,6879,7455,5276,5276,6525,6526,6659,6079,7450,5276,6395,7455,6621,6847,5276,7238,5276,6622,5276,5276,6526,7416,5276,6622,5276,7247,6620,7455,5276,5276,6530,5276,7391,6527,6621,6847,5276,5276,6537,5276,5276,6536,6621,6847,7455,5387,5388,6847,5388,7344,5276,5276,7229,7453,5386,5423,5389,5276,5276,6593,5276,5388,5276,5386,5388,7253,5276,7258,7446,6196,5276,5363,5276,6210,6887,5276,5894,5276,5276,5276,5971,7257,5276,5916,6640,7264,6258,5276,5189,5276,7260,5916,7259,6503,7097,7283,7273,5724,7100,7135,7279,6930,7132,7289,7293,7302,7295,7297,7306,7298,7317,7310,7311,7315,7318,7326,7326,7328,7324,7322,7332,7335,5276,6218,5750,5276,5276,7362,7366,7364,7342,5276,6467,5389,5281,5276,5276,6621,5276,5276,6393,5276,5915,5276,6227,6476,5276,5377,6746,5276,5386,5276,5276,5276,7449,5276,5276,7360,7370,7376,7385,5276,5276,5276,7450,5276,5276,6529,7386,5276,6265,5276,5276,5378,6094,7392,5276,5276,5276,7451,7342,7445,6201,5276,6266,5276,5276,5382,5400,5400,5400,5427,6389,6113,5276,5276,6235,6234,5276,5276,5276,7457,5276,6526,6716,7433,7396,7402,5276,5276,6733,6739,7403,5276,5276,5276,7466,7408,7398,7404,6844,5276,6847,5276,6267,6140,5276,5388,7230,5276,5414,5400,5400,5400,5428,7342,7447,7451,5276,6268,5276,6237,6268,5276,5276,7356,6110,6268,5276,5276,5276,5643,7409,5986,7425,5276,6292,5276,5276,5740,7124,7030,7410,5987,7426,5276,6306,5305,5276,5276,6201,5276,5276,5276,5739,7168,7411,5988,7427,5276,6323,7446,6117,5276,5371,5276,5276,7454,5276,6887,5276,5985,5989,6236,6846,6003,5276,6004,5276,6004,6002,5276,6845,5276,5276,5276,6802,5311,6560,7449,5276,5276,5281,7200,5276,6393,5276,7452,5276,5276,5276,6388,6113,5276,6233,5836,5898,5276,5276,7387,5868,7434,5276,5276,5276,6877,7228,6201,5276,7452,5962,5276,5276,5276,6853,5315,5898,5276,5276,7431,5276,5276,5276,6878,7229,5984,7471,5991,5276,6340,5803,5276,5780,5276,5990,5276,5276,5276,6920,5821,5982,7469,5989,5276,6346,6351,5276,5276,6388,6113,5276,5276,6946,5276,5276,7438,5276,5276,7024,5276,5276,5276,7467,7476,5276,5276,7477,5276,5276,5276,7025,5276,7450,5276,5388,5281,6279,5276,5276,5622,5315,5276,6389,6114,5276,6347,6352,5276,5276,5276,7444,5276,5276,5276,6945,7466,7475,5276,5276,7041,5276,5631,5276,5388,5282,7466,7462,5276,5276,5276,7040,5276,5276,5276,7081,5276,5303,5276,5276,5276,7110,6654,0,0,1075838976,2097152,-1845493760,0,0,2147483648,16777216,4194560,4196352,270532608,2097152,2097152,268435456,4194432,16777216,4194432,3145728,541065216,-2143289344,4194304,4194304,4194304,4194304,541065216,4194304,4194304,4194432,37748736,-1606418432,541065216,541065216,541065216,541065216,4194304,4194304,4196352,-1606418432,-1606418432,541065216,541065216,4194304,4198144,541065216,541065216,-2143289344,-2143289344,8425488,4194304,4194304,4194304,1,32768,0,2147483648,16,33554432,33554432,0,2,4,112,128,256,3584,16384,37748736,742391808,239075328,775946240,775946240,775946240,171966464,171966464,171966464,171966464,239075328,171966464,775946240,239075328,4718592,64,4718592,2097216,4720640,541589504,4194368,541589504,4194400,4194368,-2142763008,541589504,541065280,4194368,4194368,541065312,541065280,-2143289280,4194368,-2143285408,-2143285408,-2143285440,-2143285440,-2143285440,-2143285440,-1605890240,-2142761152,-2109731008,-1606414528,-2142761152,-1606414528,-2143285440,-2143285440,-1606414528,-1606414528,-2143285440,-2109731008,776470528,-1908404416,775946304,-1908404416,2,4,8,16,512,1024,4194304,128,128,0,2147483648,524288,5242880,2147483648,0,0,2,12,64,256,2048,2048,0,0,0,0,1,0,0,0,2,0,0,0,3,4,16,224,256,512,1024,16777216,16777216,0,0,2147483648,65536,1792,0,0,0,8,0,0,0,12,32,64,1024,2048,57344,262144,50331648,268435456,1073741824,2147483648,0,0,1536,64,524352,524352,524352,0,0,0,62,64,128,64,262144,1048576,0,2147483648,2097152,0,-2113929216,0,0,-1979711488,-1912602624,64,64,1048576,128,256,2048,262144,524288,4096,1024,1024,0,-570425344,32505856,0,0,48,25165824,0,0,0,33554432,268435456,0,0,0,524288,0,0,0,32,0,0,0,44,64576,319029248,0,524288,524288,524288,0,64,0,0,0,64,0,96,96,96,524352,524352,524352,524352,524288,524288,524288,524288,64,64,0,64,128,128,128,128,2048,2048,0,0,524288,524288,64,64,128,2048,0,0,64,128,8388608,524288,64,64,64,64,32,96,64,96,96,524352,96,160,1056,262176,1048608,2097184,4194336,536870944,40,262176,32,96,0,0,0,60,40,48,1120,96,96,64,524352,0,524288,64,96,524352,0,524288,4195360,6291488,2097184,2097184,4194336,4194336,4194336,32,56,0,4,16,32,64,128,256,1536,2048,40,262184,40,40,40,40,40,262176,32,32,6292512,4195360,2097184,32,128,1792,8192,16384,131072,524288,4195104,6292512,32,32,32,32,4,40,262184,32,32,34,34,262184,40,4196128,32,262144,524288,0,0,64,256,0,2097152,135790592,131073,4,393233,262184,34,42,32,524320,32,1073872896,32,32,40,1120,96,1056,4194336,32,2098208,-322695456,-322695456,-322695456,-322695456,-322597152,-320598176,-322597152,-322597144,-321548576,-320598168,-322597144,-321548568,-37482773,0,0,64,1536,32768,-322588952,-321548568,-322588952,-321548568,-322597144,32,0,32,64,65536,0,96,32,32,56,262184,40,41,262184,32,42,224,40,262176,42,106,293601323,293601323,293863467,293699627,293617707,293716011,293702203,293702203,293702203,297896507,293702203,293702203,293702203,293702267,293964347,293702267,297896507,293964347,297896507,297896507,-322597144,-37744981,0,32,524288,0,0,64,2048,16384,32768,0,0,262144,65536,262144,262144,0,4096,0,8,0,2,65536,262656,328192,0,0,0,1536,32768,0,5242880,0,0,0,1998,518144,8388608,-2147418112,5242880,-1842937664,201330721,201330721,-2111369023,-2111369023,-2111369023,-2111369023,-2111360575,-2111369023,-2111369023,-2111369023,-1977151295,-1977151293,-1910042431,-1893265183,-2111368509,-1893265183,-1893265183,-1893265183,-1893265183,-2111368509,-1893265183,-1893265183,-553689472,-553656704,-553689472,-553689472,-553656704,-553656704,-553656704,-553656704,-553656704,-553656672,-553656672,-553656672,-553656672,-536912159,-553656672,-553656672,-553656664,-553656664,-553656672,-553656672,-553656670,-553656672,-553656672,-553656670,-553656608,-553656671,-536879391,-536879391,-536879391,0,0,262656,0,0,65,1024,0,1,4096,201326592,0,0,0,0,462976,-2113929216,100663296,100663296,2,4,8,64,128,512,2048,8192,16384,458752,18874368,463488,0,0,1,2,4,32,0,0,1007232,15728640,104e4,15728640,-570425344,0,0,0,2014,0,0,0,32505856,-570425344,196608,2097152,301989888,0,0,80,268435456,0,268435456,0,268435456,268435456,268435456,268435456,0,0,0,4096,201326592,0,0,96,2260992,12288,0,2147483648,0,0,118,577408,22020096,1040187392,0,0,167772160,234881024,128,512,2048,196608,262144,33554432,536870912,0,0,0,557056,7168,16384,196608,786432,503316480,1073741824,2147483648,0,0,128,131072,524288,58720256,402653184,0,0,0,318767104,128,512,7168,16384,32768,32768,196608,786432,1048576,2097152,4194304,33554432,268435456,536870912,2147483648,0,0,1,256,8388608,234881024,268435456,1073741824,2147483648,4096,16384,32768,131072,524288,1048576,2097152,4194304,8388608,234881024,0,0,201326592,0,0,128,536870912,4194304,512,3072,16384,131072,524288,1048576,4194304,134217728,8388608,33554432,201326592,268435456,1073741824,0,1048576,4194304,268435456,4194304,8388608,134217728,268435456,1073741824,3072,131072,524288,1048576,1073741824,0,0,0,2147483648,0,0,0,-2147483646,16384,18432,67108864,1073741824,16384,8192,0,0,65536,262144,0,0,67108864,0,0,0,32768,0,1,18952,1024,0,0,192,0,0,0,65,1024,1024,100663298,18952,65,268436480,2101248,524288,1024,19017,-1744550912,8388624,8388624,8388624,-1739308032,-1739308032,-1739308032,-1739308032,-1736162288,-1736162288,-1736162288,-1736162288,-7868466,-7868466,-7868466,-7868466,-7868466,-7868450,-7868450,-7868450,-7868450,0,0,0,65536,2048,16384,67108864,134217728,268435456,0,0,1073741824,18432,0,0,1,285212672,0,585,0,0,2,8,16,64,128,3072,4096,8192,65536,131072,0,0,1024,5521408,-1744830464,0,0,0,262144,0,0,0,1024,0,0,0,112,1040,0,0,-1744830464,0,-1744830464,59238400,-67108864,0,0,0,327680,2014,0,0,0,328192,518144,8388608,50331648,201326592,805306368,-1073741824,768,1024,10240,16384,32768,458752,50331648,67108864,134217728,805306368,0,0,0,458880,32768,458752,8388608,50331648,67108864,134217728,67108864,134217728,805306368,1073741824,2147483648,0,0,220,0,0,0,471424,12,192,768,1024,2048,805306368,1073741824,0,0,2,204,768,1024,4,8,32,64,512,2048,512,2048,16384,67108864,0,0,458752,50331648,67108864,805306368,-1073741824,0,0,0,393240,0,1048576,4194304,0,0,16384,458752,50331648,67108864,536870912,1073741824,0,0,16384,0,0,0,256,0,0,0,512,0,0,0,585,16,0,0,1048576,4194304,2147483648,4,8,128,512,3072,16384,32768,131072,512,0,0,4096,1048576,2147483648,8192,2097152,268435456,2147483648,537395200,537395200,0,4196352,51380242,51380242,51380242,0,537395200,4196352,4196352,276901888,8540160,-1606418432,0,32768,537395200,4196352,1082130432,0,4196352,537427968,22022147,22349827,22349827,22349827,22366219,22349843,22349827,22349827,22366219,22349827,55576594,55576594,55576594,55576594,55576594,324012114,55576594,55576594,1062785014,1062785014,1062785014,1062785014,0,0,2,33554432,0,0,0,131072,0,0,0,8192,8392704,32768,268435456,0,0,2,67108864,12,16384,0,65536,0,22020096,0,0,0,104e4,15728640,0,0,329728,0,0,254,1792,2809856,58720256,19,0,0,0,1048576,0,0,0,2048,0,0,0,18,33554432,0,0,256,8192,0,0,8192,2097152,0,2147483648,0,82,301989888,0,0,0,2101248,22020096,1040187392,0,0,0,4194304,0,0,0,16384,1536,0,256,0,8192,2097152,16,1048576,16777216,33554432,268435456,536870912,2147483648,3584,16384,32768,524288,1048576,4194304,0,0,8388608,1073741824,0,0,1536,2048,16384,32768,524288,4194304,134217728,0,0,134217728,4096,0,8,0,256,1536,16384,32768,524288,128,536870912,0,0,4,8,512,2048,0,0,1536,32768,524288,4194304,33554432,134217728,536870912,0,0,8192,2097152,2147483648,0,0,512,2048,131072,536870912,0,0,16,64,1536,32768,32768,524288,134217728,0,0,0,524288,0,64,64,16392,1536,32768,524288,0,0,33554432,8192,0,65536,0,0,1,1,0,1,67174400,33554432,536870912,-1073741824,0,0,0,0,524288,134217728,67174400,0,0,0,16777216,0,0,0,4,0,0,0,7,16,16384,8,8,0,0,512,3072,131072,131072,268435456,134217728,8,512,2048,196608,262144,50331648,536870912,1073741824,0,4,8,2048,8192,32768,8388608,0,0,134217736,16908320,547389524,547389524,555909216,555909216,555909216,555909216,564297840,564297844,564297844,564297844,564297844,1001055742,1001056254,1001055742,1001055742,1001056254,1001056254,1001056254,1001056254,1001055742,1001056254,1001056254,1001056254,1001056254,0,1052672,2147483648,0,0,4,16,0,0,84,2129920,8388608,4096,0,0,0,116,0,254,1280,2809856,58720256,939524096,0,0,0,50331648,268435456,0,0,0,939524096,0,0,520,1024,0,0,1,0,67108864,1073741824,0,0,0,20,64,32768,8192,0,2048,0,2097152,8388608,536870912,0,0,1024,278528,0,0,0,393232,163840,0,0,0,134217728,0,0,0,16,0,0,0,15,208,15360,1245184,52,0,0,0,268435456,0,0,33554432,64,128,1280,24576,163840,524288,2097152,58720256,402653184,536870912,128,1792,24576,163840,524288,0,4,16,8388608,0,0,4096,32768,262144,524288,33554432,134217728,0,0,24,32,128,1280,8192,16384,8192,524288,16777216,33554432,402653184,0,4,8,16,1024,2048,8192,16384,32768,458752,0,262144,33554432,134217728,0,512,1024,16777216,33554432,402653184,0,4096,1048576,0,0,1998,59238400,-67108864,4,8,16,402653184,0,0,8,16,402653184,536870912,0,0,4,64,128,8388608,0,0,67108866,12,64,128,512,1024,4,16384,65536,67108864,0,65536,0,0,2048,64,64,64,96,96,96,96,0,8192,8192,268435460,32768,65536,2490368,16777216,2147483648,0,0,1,4,8,2048,8192,3670016,2048,2048,2048,2048,0,8192,34816,9216,4096,0,128,0,2097152,0,0,4096,4096,29696,29712,29840,29712,29712,29840,29840,536900624,4224144,144384,144384,144384,144384,-754647956,-754647956,-754647956,-754647956,-754647956,-754647940,-754647940,-754647940,-754647940,-754516884,-754647956,-754516884,-754516884,-754516884,4,8,256,512,2048,0,0,3670016,0,0,2048,131072,524288,4194304,2147483648,0,0,9216,0,0,4,134217728,0,29696,0,0,4,268435456,0,16,0,29824,0,60,64576,319029248,-1073741824,0,0,319160320,0,0,0,319160320,0,0,524288,3145728,0,12288,131072,0,8,131072,61440,262144,318767104,-1073741824,0,0,64,1024,2048,61440,262144,0,28,32,64,64,64,128,0,0,16384,32768,50331648,268435456,0,0,0,393216,0,0,0,486539264,0,128,0,536870912,0,0,12,16,32,327155712,34,1056,32,32,42,4457568,-326784344,-322851160,-322698144,-322698144,-322698144,-322698144,-322695456,0,0,524288,1048576,0,0,0,536870912,4194304,131072,0,0,6,56,128,1792,2,67108864,16384,0,0,4096,4194304,32768,0,0,0,8388608,0,0,0,72,0,8,64,2048,57344,16384,32768,262144,50331648,268435456,0,524288,1048576,2097152,4194304,134217728,2147483648,0,0,50331648,268435456,2147483648,0,0,1,0,0,2,4,16,64,1,0,2,0,0,65536,0,0,0,1040,8667136,0,131072,131072,0,131072,0,131072,0,0,524288,536870912,131072,0,0,7,27756528,-503316480,0,256,0,2048,32768,8388608,262144,2113536,0,0,8,16,512,402653184,0,0,0,256,32768,0,0,4224,65536,262144,1048576,4194304,16777216,33554432,67108864,134217728,0,0,256,262144,0,0,8192,268435456,0,0,0,4,131073,0,0,9728,268435456,0,0,16,393216,0,131073,131073,33554624,4,0,131073,0,0,13312,131072,4194304,-2146430976,131072,2097152,16777216,0,0,512,131072,1048576,2097152,0,1572864,0,0,0,2147483648,524288,0,1610612736,1610612736,1610612736,393241,393241,393241,393241,805707793,805707793,1879449617,805708049,1879449617,1879449617,1879449617,1879449617,-483948553,-475559945,-483948553,-475559945,-483948553,-483948553,-475559945,-475559945,-475559945,-475559945,-483948553,-483948553,-215504905,-475559945,-207116297,-207116297,0,0,0,1073741824,0,0,2097152,67108864,134217728,536870912,0,0,24576,0,0,0,2113536,0,0,8,64,0,0,0,401424,805306368,0,0,28672,0,0,4096,2097152,4194304,8388608,503316480,1073741824,0,0,1879048192,0,0,32768,2097152,8388608,16777216,33554432,0,401680,0,0,8,512,2048,131072,33554432,536870912,0,0,7,19367920,-503316480,27756528,-503316480,0,0,0,0,0,19376112,-234881024,0,27764720,-234881024,0,0,32768,33554436,0,0,33554436,24,0,0,0,11,346112,7,16,480,1536,32768,65536,393216,10485760,65536,10878976,16777216,33554432,536870912,4,32,524288,1048576,33554432,67108864,65536,393216,2097152,16777216,262400,65536,4224,4224,0,65536,201326592,2147483648,393216,10485760,16777216,33554432,1073741824,2147483648,0,16,224,256,1536,32768,65536,0,16384,2097152,0,0,1024,32768,65536,131072,262144,262144,2097152,16777216,33554432,4,32,524288,134217728,0,512,32768,131072,262144,2097152,2097152,8388608,16777216,1073741824,0,0,512,32768,131072,2097152,8388608,8388608,16777216,0,0,16,33554432,4,16,224,512,32768,4,524288,134217728,0,0,32768,50331648,268435456,4096,32768,0,0,16,536870912,16,192,32768,8388608,4096,4096,4096,1536,2,4,16,192,32768,0,16,64,128,8388608,0,0,0,2,4,134217728,4,0,0,128,512,3072,4096,16384,131072,4,128,0,0,18,17825792,524288,8388608,33554432,2147483648,8192,0,33554432,0,0,33554432,0,0,0,268435456,2,4,8,262144,262144,1048576,2048,32768,0,0,28,0,100663296,4224,65536,65536,262144,33554432,0,2,4,24,-1072627712,805306384,-1342177264,-1342177264,-1070006272,-1070006272,-1069989376,-1069989376,-258932720,-258932720,-258932720,-258932720,-225378288,-1069989376,-1069989360,-1065795072,-1061600768,-258932720,-225378288,-258932720,-258932720,1260767,34815199,1260767,34815199,1260767,34815199,34815199,1260767,1260767,34815199,1260767,1260767,169032927,-1978450721,169032927,-1978450721,169032927,169032927,169032927,169032927,1242774751,-1978450721,-1978450721,-225231649,-1173144353,-225231649,-91013921,0,0,32,128,256,262144,524288,8388608,0,64,0,0,1114112,1073741824,0,0,34816,0,0,2048,4194304,0,0,0,3735552,0,0,32,512,2048,32768,262144,524288,3751936,0,0,0,48,0,0,528,7946240,12140544,9502720,1610612736,0,0,0,15360,1245184,0,0,134217728,128,15,9633792,0,0,0,2,12,80,128,7168,8192,7168,8192,196608,1048576,0,0,0,1,2,12,16,64,128,256,0,0,3145728,0,0,0,536870912,0,0,8192,65536,131072,1048576,0,0,0,2097152,0,16384,0,4194304,0,0,2097152,16384,0,0,131072,2097152,0,0,0,4096,0,0,8192,0,0,0,128,0,0,0,208,0,64,128,1024,4096,0,0,2,8,64,128,1024,2048,4096,8192,128,1024,4096,8192,0,0],r.TOKEN=["(0)","PragmaContents","DirCommentContents","DirPIContents","CDataSection","Wildcard","EQName","URILiteral","IntegerLiteral","DecimalLiteral","DoubleLiteral","StringLiteral","PredefinedEntityRef","'\"\"'","EscapeApos","ElementContentChar","QuotAttrContentChar","AposAttrContentChar","PITarget","NCName","QName","S","S","CharRef","CommentContents","EOF","'!'","'!='","'\"'","'#'","'#)'","'$'","'$$'","'%'","''''","'('","'(#'","'(:'","')'","'*'","'*'","'+'","','","'-'","'-->'","'.'","'..'","'/'","'//'","'/>'","':'","':)'","'::'","':='","';'","'<'","'<!--'","'</'","'<<'","'<='","'<?'","'='","'>'","'>='","'>>'","'?'","'?>'","'@'","'NaN'","'['","']'","'after'","'all'","'allowing'","'ancestor'","'ancestor-or-self'","'and'","'any'","'append'","'array'","'as'","'ascending'","'at'","'attribute'","'base-uri'","'before'","'boundary-space'","'break'","'by'","'case'","'cast'","'castable'","'catch'","'check'","'child'","'collation'","'collection'","'comment'","'constraint'","'construction'","'contains'","'content'","'context'","'continue'","'copy'","'copy-namespaces'","'count'","'decimal-format'","'decimal-separator'","'declare'","'default'","'delete'","'descendant'","'descendant-or-self'","'descending'","'diacritics'","'different'","'digit'","'distance'","'div'","'document'","'document-node'","'element'","'else'","'empty'","'empty-sequence'","'encoding'","'end'","'entire'","'eq'","'every'","'exactly'","'except'","'exit'","'external'","'false'","'first'","'following'","'following-sibling'","'for'","'foreach'","'foreign'","'from'","'ft-option'","'ftand'","'ftnot'","'ftor'","'function'","'ge'","'greatest'","'group'","'grouping-separator'","'gt'","'idiv'","'if'","'import'","'in'","'index'","'infinity'","'inherit'","'insensitive'","'insert'","'instance'","'integrity'","'intersect'","'into'","'is'","'item'","'json'","'json-item'","'jsoniq'","'key'","'language'","'last'","'lax'","'le'","'least'","'let'","'levels'","'loop'","'lowercase'","'lt'","'minus-sign'","'mod'","'modify'","'module'","'most'","'namespace'","'namespace-node'","'ne'","'next'","'no'","'no-inherit'","'no-preserve'","'node'","'nodes'","'not'","'null'","'object'","'occurs'","'of'","'on'","'only'","'option'","'or'","'order'","'ordered'","'ordering'","'paragraph'","'paragraphs'","'parent'","'pattern-separator'","'per-mille'","'percent'","'phrase'","'position'","'preceding'","'preceding-sibling'","'preserve'","'previous'","'processing-instruction'","'relationship'","'rename'","'replace'","'return'","'returning'","'revalidation'","'same'","'satisfies'","'schema'","'schema-attribute'","'schema-element'","'score'","'select'","'self'","'sensitive'","'sentence'","'sentences'","'skip'","'sliding'","'some'","'stable'","'start'","'stemming'","'stop'","'strict'","'strip'","'structured-item'","'switch'","'text'","'then'","'thesaurus'","'times'","'to'","'treat'","'true'","'try'","'tumbling'","'type'","'typeswitch'","'union'","'unique'","'unordered'","'updating'","'uppercase'","'using'","'validate'","'value'","'variable'","'version'","'weight'","'when'","'where'","'while'","'wildcards'","'window'","'with'","'without'","'word'","'words'","'zero-digit'","'{'","'{{'","'{|'","'|'","'||'","'|}'","'}'","'}}'"]},{}],10:[function(e,t,n){var r=n.XQueryParser=function i(e,t){function r(e,t){Vl=t,Ql=e,Gl=e.length,s(0,0,0)}function s(e,t,n){Dl=t,Pl=t,Hl=e,Bl=t,jl=n,Fl=0,Zl=n,Ul=-1,$l={},Vl.reset(Ql)}function o(){Vl.startNonterminal("Module",Pl);switch(Hl){case 274:Ll(199);break;default:_l=Hl}(_l==64274||_l==134930)&&u(),kl(275);switch(Hl){case 182:Ll(194);break;default:_l=Hl}switch(_l){case 94390:Nl(),a();break;default:Nl(),Ra()}Vl.endNonterminal("Module",Pl)}function u(){Vl.startNonterminal("VersionDecl",Pl),Sl(274),kl(116);switch(Hl){case 125:Sl(125),kl(17),Sl(11);break;default:Sl(263),kl(17),Sl(11),kl(109),Hl==125&&(Sl(125),kl(17),Sl(11))}kl(28),Nl(),c(),Vl.endNonterminal("VersionDecl",Pl)}function a(){Vl.startNonterminal("LibraryModule",Pl),f(),kl(138),Nl(),l(),Vl.endNonterminal("LibraryModule",Pl)}function f(){Vl.startNonterminal("ModuleDecl",Pl),Sl(182),kl(61),Sl(184),kl(249),Nl(),Ia(),kl(29),Sl(60),kl(15),Sl(7),kl(28),Nl(),c(),Vl.endNonterminal("ModuleDecl",Pl)}function l(){Vl.startNonterminal("Prolog",Pl);for(;;){kl(275);switch(Hl){case 108:Ll(214);break;case 153:Ll(202);break;default:_l=Hl}if(_l!=42604&&_l!=43628&&_l!=50284&&_l!=53356&&_l!=54380&&_l!=55916&&_l!=72300&&_l!=93337&&_l!=94316&&_l!=104044&&_l!=113772&&_l!=115353)break;switch(Hl){case 108:Ll(179);break;default:_l=Hl}if(_l==55916){_l=Kl(0,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{_(),_l=-1}catch(a){_l=-2}Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(0,Pl,_l)}}switch(_l){case-1:Nl(),M();break;case 94316:Nl(),O();break;case 153:Nl(),C();break;case 72300:Nl(),D();break;default:Nl(),h()}kl(28),Nl(),c()}for(;;){kl(275);switch(Hl){case 108:Ll(211);break;default:_l=Hl}if(_l!=16492&&_l!=48748&&_l!=51820&&_l!=74348&&_l!=79468&&_l!=82540&&_l!=101996&&_l!=131692&&_l!=134252)break;switch(Hl){case 108:Ll(175);break;default:_l=Hl}switch(_l){case 51820:Nl(),R();break;case 101996:Nl(),Q();break;default:Nl(),P()}kl(28),Nl(),c()}Vl.endNonterminal("Prolog",Pl)}function c(){Vl.startNonterminal("Separator",Pl),Sl(53),Vl.endNonterminal("Separator",Pl)}function h(){Vl.startNonterminal("Setter",Pl);switch(Hl){case 108:Ll(172);break;default:_l=Hl}if(_l==55916){_l=Kl(1,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{v(),_l=-2}catch(a){try{Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),w(),_l=-6}catch(f){_l=-9}}Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(1,Pl,_l)}}switch(_l){case 43628:p();break;case-2:d();break;case 42604:m();break;case 50284:g();break;case 104044:y();break;case-6:b();break;case 113772:ko();break;case 53356:E();break;default:T()}Vl.endNonterminal("Setter",Pl)}function p(){Vl.startNonterminal("BoundarySpaceDecl",Pl),Sl(108),kl(33),Sl(85),kl(133);switch(Hl){case 214:Sl(214);break;default:Sl(241)}Vl.endNonterminal("BoundarySpaceDecl",Pl)}function d(){Vl.startNonterminal("DefaultCollationDecl",Pl),Sl(108),kl(46),Sl(109),kl(38),Sl(94),kl(15),Sl(7),Vl.endNonterminal("DefaultCollationDecl",Pl)}function v(){xl(108),kl(46),xl(109),kl(38),xl(94),kl(15),xl(7)}function m(){Vl.startNonterminal("BaseURIDecl",Pl),Sl(108),kl(32),Sl(83),kl(15),Sl(7),Vl.endNonterminal("BaseURIDecl",Pl)}function g(){Vl.startNonterminal("ConstructionDecl",Pl),Sl(108),kl(41),Sl(98),kl(133);switch(Hl){case 241:Sl(241);break;default:Sl(214)}Vl.endNonterminal("ConstructionDecl",Pl)}function y(){Vl.startNonterminal("OrderingModeDecl",Pl),Sl(108),kl(68),Sl(203),kl(131);switch(Hl){case 202:Sl(202);break;default:Sl(256)}Vl.endNonterminal("OrderingModeDecl",Pl)}function b(){Vl.startNonterminal("EmptyOrderDecl",Pl),Sl(108),kl(46),Sl(109),kl(67),Sl(201),kl(49),Sl(123),kl(121);switch(Hl){case 147:Sl(147);break;default:Sl(173)}Vl.endNonterminal("EmptyOrderDecl",Pl)}function w(){xl(108),kl(46),xl(109),kl(67),xl(201),kl(49),xl(123),kl(121);switch(Hl){case 147:xl(147);break;default:xl(173)}}function E(){Vl.startNonterminal("CopyNamespacesDecl",Pl),Sl(108),kl(44),Sl(104),kl(128),Nl(),S(),kl(25),Sl(41),kl(123),Nl(),x(),Vl.endNonterminal("CopyNamespacesDecl",Pl)}function S(){Vl.startNonterminal("PreserveMode",Pl);switch(Hl){case 214:Sl(214);break;default:Sl(190)}Vl.endNonterminal("PreserveMode",Pl)}function x(){Vl.startNonterminal("InheritMode",Pl);switch(Hl){case 157:Sl(157);break;default:Sl(189)}Vl.endNonterminal("InheritMode",Pl)}function T(){Vl.startNonterminal("DecimalFormatDecl",Pl),Sl(108),kl(114);switch(Hl){case 106:Sl(106),kl(255),Nl(),Ha();break;default:Sl(109),kl(45),Sl(106)}for(;;){kl(181);if(Hl==53)break;Nl(),N(),kl(29),Sl(60),kl(17),Sl(11)}Vl.endNonterminal("DecimalFormatDecl",Pl)}function N(){Vl.startNonterminal("DFPropertyName",Pl);switch(Hl){case 107:Sl(107);break;case 149:Sl(149);break;case 156:Sl(156);break;case 179:Sl(179);break;case 67:Sl(67);break;case 209:Sl(209);break;case 208:Sl(208);break;case 275:Sl(275);break;case 116:Sl(116);break;default:Sl(207)}Vl.endNonterminal("DFPropertyName",Pl)}function C(){Vl.startNonterminal("Import",Pl);switch(Hl){case 153:Ll(126);break;default:_l=Hl}switch(_l){case 115353:k();break;default:A()}Vl.endNonterminal("Import",Pl)}function k(){Vl.startNonterminal("SchemaImport",Pl),Sl(153),kl(73),Sl(225),kl(137),Hl!=7&&(Nl(),L()),kl(15),Sl(7),kl(108);if(Hl==81){Sl(81),kl(15),Sl(7);for(;;){kl(103);if(Hl!=41)break;Sl(41),kl(15),Sl(7)}}Vl.endNonterminal("SchemaImport",Pl)}function L(){Vl.startNonterminal("SchemaPrefix",Pl);switch(Hl){case 184:Sl(184),kl(249),Nl(),Ia(),kl(29),Sl(60);break;default:Sl(109),kl(47),Sl(121),kl(61),Sl(184)}Vl.endNonterminal("SchemaPrefix",Pl)}function A(){Vl.startNonterminal("ModuleImport",Pl),Sl(153),kl(60),Sl(182),kl(90),Hl==184&&(Sl(184),kl(249),Nl(),Ia(),kl(29),Sl(60)),kl(15),Sl(7),kl(108);if(Hl==81){Sl(81),kl(15),Sl(7);for(;;){kl(103);if(Hl!=41)break;Sl(41),kl(15),Sl(7)}}Vl.endNonterminal("ModuleImport",Pl)}function O(){Vl.startNonterminal("NamespaceDecl",Pl),Sl(108),kl(61),Sl(184),kl(249),Nl(),Ia(),kl(29),Sl(60),kl(15),Sl(7),Vl.endNonterminal("NamespaceDecl",Pl)}function M(){Vl.startNonterminal("DefaultNamespaceDecl",Pl),Sl(108),kl(46),Sl(109),kl(115);switch(Hl){case 121:Sl(121);break;default:Sl(145)}kl(61),Sl(184),kl(15),Sl(7),Vl.endNonterminal("DefaultNamespaceDecl",Pl)}function _(){xl(108),kl(46),xl(109),kl(115);switch(Hl){case 121:xl(121);break;default:xl(145)}kl(61),xl(184),kl(15),xl(7)}function D(){Vl.startNonterminal("FTOptionDecl",Pl),Sl(108),kl(52),Sl(141),kl(81),Nl(),Fu(),Vl.endNonterminal("FTOptionDecl",Pl)}function P(){Vl.startNonterminal("AnnotatedDecl",Pl),Sl(108);for(;;){kl(170);if(Hl!=32&&Hl!=257)break;switch(Hl){case 257:Nl(),H();break;default:Nl(),B()}}switch(Hl){case 262:Nl(),F();break;case 145:Nl(),wl();break;case 95:Nl(),da();break;case 155:Nl(),xa();break;default:Nl(),Ta()}Vl.endNonterminal("AnnotatedDecl",Pl)}function H(){Vl.startNonterminal("CompatibilityAnnotation",Pl),Sl(257),Vl.endNonterminal("CompatibilityAnnotation",Pl)}function B(){Vl.startNonterminal("Annotation",Pl),Sl(32),kl(255),Nl(),Ha(),kl(171);if(Hl==34){Sl(34),kl(154),Nl(),oi();for(;;){kl(101);if(Hl!=41)break;Sl(41),kl(154),Nl(),oi()}Sl(37)}Vl.endNonterminal("Annotation",Pl)}function j(){xl(32),kl(255),Ba(),kl(171);if(Hl==34){xl(34),kl(154),ui();for(;;){kl(101);if(Hl!=41)break;xl(41),kl(154),ui()}xl(37)}}function F(){Vl.startNonterminal("VarDecl",Pl),Sl(262),kl(21),Sl(31),kl(255),Nl(),hi(),kl(147),Hl==79&&(Nl(),ds()),kl(106);switch(Hl){case 52:Sl(52),kl(267),Nl(),I();break;default:Sl(133),kl(104),Hl==52&&(Sl(52),kl(267),Nl(),q())}Vl.endNonterminal("VarDecl",Pl)}function I(){Vl.startNonterminal("VarValue",Pl),_f(),Vl.endNonterminal("VarValue",Pl)}function q(){Vl.startNonterminal("VarDefaultValue",Pl),_f(),Vl.endNonterminal("VarDefaultValue",Pl)}function R(){Vl.startNonterminal("ContextItemDecl",Pl),Sl(108),kl(43),Sl(101),kl(55),Sl(165),kl(147),Hl==79&&(Sl(79),kl(260),Nl(),ws()),kl(106);switch(Hl){case 52:Sl(52),kl(267),Nl(),I();break;default:Sl(133),kl(104),Hl==52&&(Sl(52),kl(267),Nl(),q())}Vl.endNonterminal("ContextItemDecl",Pl)}function U(){Vl.startNonterminal("ParamList",Pl),W();for(;;){kl(101);if(Hl!=41)break;Sl(41),kl(21),Nl(),W()}Vl.endNonterminal("ParamList",Pl)}function z(){X();for(;;){kl(101);if(Hl!=41)break;xl(41),kl(21),X()}}function W(){Vl.startNonterminal("Param",Pl),Sl(31),kl(255),Nl(),Ha(),kl(143),Hl==79&&(Nl(),ds()),Vl.endNonterminal("Param",Pl)}function X(){xl(31),kl(255),Ba(),kl(143),Hl==79&&vs()}function V(){Vl.startNonterminal("FunctionBody",Pl),J(),Vl.endNonterminal("FunctionBody",Pl)}function $(){K()}function J(){Vl.startNonterminal("EnclosedExpr",Pl),Sl(276),kl(267),Nl(),G(),Sl(282),Vl.endNonterminal("EnclosedExpr",Pl)}function K(){xl(276),kl(267),Y(),xl(282)}function Q(){Vl.startNonterminal("OptionDecl",Pl),Sl(108),kl(66),Sl(199),kl(255),Nl(),Ha(),kl(17),Sl(11),Vl.endNonterminal("OptionDecl",Pl)}function G(){Vl.startNonterminal("Expr",Pl),_f();for(;;){if(Hl!=41)break;Sl(41),kl(267),Nl(),_f()}Vl.endNonterminal("Expr",Pl)}function Y(){Df();for(;;){if(Hl!=41)break;xl(41),kl(267),Df()}}function Z(){Vl.startNonterminal("FLWORExpr",Pl),tt();for(;;){kl(173);if(Hl==220)break;Nl(),rt()}Nl(),rn(),Vl.endNonterminal("FLWORExpr",Pl)}function et(){nt();for(;;){kl(173);if(Hl==220)break;it()}sn()}function tt(){Vl.startNonterminal("InitialClause",Pl);switch(Hl){case 137:Ll(141);break;default:_l=Hl}switch(_l){case 16009:st();break;case 174:vt();break;default:bt()}Vl.endNonterminal("InitialClause",Pl)}function nt(){switch(Hl){case 137:Ll(141);break;default:_l=Hl}switch(_l){case 16009:ot();break;case 174:mt();break;default:wt()}}function rt(){Vl.startNonterminal("IntermediateClause",Pl);switch(Hl){case 137:case 174:tt();break;case 266:It();break;case 148:Rt();break;case 105:jt();break;default:Kt()}Vl.endNonterminal("IntermediateClause",Pl)}function it(){switch(Hl){case 137:case 174:nt();break;case 266:qt();break;case 148:Ut();break;case 105:Ft();break;default:Qt()}}function st(){Vl.startNonterminal("ForClause",Pl),Sl(137),kl(21),Nl(),ut();for(;;){if(Hl!=41)break;Sl(41),kl(21),Nl(),ut()}Vl.endNonterminal("ForClause",Pl)}function ot(){xl(137),kl(21),at();for(;;){if(Hl!=41)break;xl(41),kl(21),at()}}function ut(){Vl.startNonterminal("ForBinding",Pl),Sl(31),kl(255),Nl(),hi(),kl(164),Hl==79&&(Nl(),ds()),kl(158),Hl==72&&(Nl(),ft()),kl(150),Hl==81&&(Nl(),ct()),kl(122),Hl==228&&(Nl(),pt()),kl(53),Sl(154),kl(267),Nl(),_f(),Vl.endNonterminal("ForBinding",Pl)}function at(){xl(31),kl(255),pi(),kl(164),Hl==79&&vs(),kl(158),Hl==72&&lt(),kl(150),Hl==81&&ht(),kl(122),Hl==228&&dt(),kl(53),xl(154),kl(267),Df()}function ft(){Vl.startNonterminal("AllowingEmpty",Pl),Sl(72),kl(49),Sl(123),Vl.endNonterminal("AllowingEmpty",Pl)}function lt(){xl(72),kl(49),xl(123)}function ct(){Vl.startNonterminal("PositionalVar",Pl),Sl(81),kl(21),Sl(31),kl(255),Nl(),hi(),Vl.endNonterminal("PositionalVar",Pl)}function ht(){xl(81),kl(21),xl(31),kl(255),pi()}function pt(){Vl.startNonterminal("FTScoreVar",Pl),Sl(228),kl(21),Sl(31),kl(255),Nl(),hi(),Vl.endNonterminal("FTScoreVar",Pl)}function dt(){xl(228),kl(21),xl(31),kl(255),pi()}function vt(){Vl.startNonterminal("LetClause",Pl),Sl(174),kl(96),Nl(),gt();for(;;){if(Hl!=41)break;Sl(41),kl(96),Nl(),gt()}Vl.endNonterminal("LetClause",Pl)}function mt(){xl(174),kl(96),yt();for(;;){if(Hl!=41)break;xl(41),kl(96),yt()}}function gt(){Vl.startNonterminal("LetBinding",Pl);switch(Hl){case 31:Sl(31),kl(255),Nl(),hi(),kl(105),Hl==79&&(Nl(),ds());break;default:pt()}kl(27),Sl(52),kl(267),Nl(),_f(),Vl.endNonterminal("LetBinding",Pl)}function yt(){switch(Hl){case 31:xl(31),kl(255),pi(),kl(105),Hl==79&&vs();break;default:dt()}kl(27),xl(52),kl(267),Df()}function bt(){Vl.startNonterminal("WindowClause",Pl),Sl(137),kl(135);switch(Hl){case 251:Nl(),Et();break;default:Nl(),xt()}Vl.endNonterminal("WindowClause",Pl)}function wt(){xl(137),kl(135);switch(Hl){case 251:St();break;default:Tt()}}function Et(){Vl.startNonterminal("TumblingWindowClause",Pl),Sl(251),kl(85),Sl(269),kl(21),Sl(31),kl(255),Nl(),hi(),kl(110),Hl==79&&(Nl(),ds()),kl(53),Sl(154),kl(267),Nl(),_f(),Nl(),Nt();if(Hl==126||Hl==198)Nl(),kt();Vl.endNonterminal("TumblingWindowClause",Pl)}function St(){xl(251),kl(85),xl(269),kl(21),xl(31),kl(255),pi(),kl(110),Hl==79&&vs(),kl(53),xl(154),kl(267),Df(),Ct(),(Hl==126||Hl==198)&&Lt()}function xt(){Vl.startNonterminal("SlidingWindowClause",Pl),Sl(234),kl(85),Sl(269),kl(21),Sl(31),kl(255),Nl(),hi(),kl(110),Hl==79&&(Nl(),ds()),kl(53),Sl(154),kl(267),Nl(),_f(),Nl(),Nt(),Nl(),kt(),Vl.endNonterminal("SlidingWindowClause",Pl)}function Tt(){xl(234),kl(85),xl(269),kl(21),xl(31),kl(255),pi(),kl(110),Hl==79&&vs(),kl(53),xl(154),kl(267),Df(),Ct(),Lt()}function Nt(){Vl.startNonterminal("WindowStartCondition",Pl),Sl(237),kl(163),Nl(),At(),kl(83),Sl(265),kl(267),Nl(),_f(),Vl.endNonterminal("WindowStartCondition",Pl)}function Ct(){xl(237),kl(163),Ot(),kl(83),xl(265),kl(267),Df()}function kt(){Vl.startNonterminal("WindowEndCondition",Pl),Hl==198&&Sl(198),kl(50),Sl(126),kl(163),Nl(),At(),kl(83),Sl(265),kl(267),Nl(),_f(),Vl.endNonterminal("WindowEndCondition",Pl)}function Lt(){Hl==198&&xl(198),kl(50),xl(126),kl(163),Ot(),kl(83),xl(265),kl(267),Df()}function At(){Vl.startNonterminal("WindowVars",Pl),Hl==31&&(Sl(31),kl(255),Nl(),Mt()),kl(159),Hl==81&&(Nl(),ct()),kl(153),Hl==215&&(Sl(215),kl(21),Sl(31),kl(255),Nl(),Dt()),kl(127),Hl==187&&(Sl(187),kl(21),Sl(31),kl(255),Nl(),Ht()),Vl.endNonterminal("WindowVars",Pl)}function Ot(){Hl==31&&(xl(31),kl(255),_t()),kl(159),Hl==81&&ht(),kl(153),Hl==215&&(xl(215),kl(21),xl(31),kl(255),Pt()),kl(127),Hl==187&&(xl(187),kl(21),xl(31),kl(255),Bt())}function Mt(){Vl.startNonterminal("CurrentItem",Pl),Ha(),Vl.endNonterminal("CurrentItem",Pl)}function _t(){Ba()}function Dt(){Vl.startNonterminal("PreviousItem",Pl),Ha(),Vl.endNonterminal("PreviousItem",Pl)}function Pt(){Ba()}function Ht(){Vl.startNonterminal("NextItem",Pl),Ha(),Vl.endNonterminal("NextItem",Pl)}function Bt(){Ba()}function jt(){Vl.startNonterminal("CountClause",Pl),Sl(105),kl(21),Sl(31),kl(255),Nl(),hi(),Vl.endNonterminal("CountClause",Pl)}function Ft(){xl(105),kl(21),xl(31),kl(255),pi()}function It(){Vl.startNonterminal("WhereClause",Pl),Sl(266),kl(267),Nl(),_f(),Vl.endNonterminal("WhereClause",Pl)}function qt(){xl(266),kl(267),Df()}function Rt(){Vl.startNonterminal("GroupByClause",Pl),Sl(148),kl(34),Sl(87),kl(267),Nl(),zt(),Vl.endNonterminal("GroupByClause",Pl)}function Ut(){xl(148),kl(34),xl(87),kl(267),Wt()}function zt(){Vl.startNonterminal("GroupingSpecList",Pl),Xt();for(;;){kl(176);if(Hl!=41)break;Sl(41),kl(267),Nl(),Xt()}Vl.endNonterminal("GroupingSpecList",Pl)}function Wt(){Vt();for(;;){kl(176);if(Hl!=41)break;xl(41),kl(267),Vt()}}function Xt(){Vl.startNonterminal("GroupingSpec",Pl);switch(Hl){case 31:Ll(255);break;default:_l=Hl}if(_l==3103||_l==35871||_l==36895||_l==37407||_l==37919||_l==38431||_l==39455||_l==39967||_l==40479||_l==40991||_l==41503||_l==42015||_l==42527||_l==43039||_l==43551||_l==44063||_l==45087||_l==45599||_l==46111||_l==46623||_l==47647||_l==48159||_l==49183||_l==49695||_l==50207||_l==51743||_l==52255||_l==52767||_l==53279||_l==53791||_l==54303||_l==55327||_l==55839||_l==56351||_l==56863||_l==57375||_l==57887||_l==60447||_l==60959||_l==61471||_l==61983||_l==62495||_l==63007||_l==63519||_l==64031||_l==64543||_l==65567||_l==66079||_l==67103||_l==67615||_l==68127||_l==68639||_l==69151||_l==69663||_l==70175||_l==72223||_l==74271||_l==74783||_l==75807||_l==76831||_l==77343||_l==77855||_l==78367||_l==78879||_l==79391||_l==81439||_l==81951||_l==82463||_l==82975||_l==83487||_l==83999||_l==84511||_l==85023||_l==85535||_l==87071||_l==87583||_l==88095||_l==89119||_l==90143||_l==91167||_l==92191||_l==92703||_l==93215||_l==94239||_l==94751||_l==95263||_l==97823||_l==98335||_l==99359||_l==101407||_l==101919||_l==102431||_l==102943||_l==103455||_l==103967||_l==105503||_l==108575||_l==109087||_l==110623||_l==111647||_l==112159||_l==112671||_l==113183||_l==113695||_l==114719||_l==115231||_l==115743||_l==116255||_l==116767||_l==117279||_l==119839||_l==120351||_l==120863||_l==121375||_l==122911||_l==123935||_l==124447||_l==124959||_l==127007||_l==127519||_l==128031||_l==128543||_l==129055||_l==129567||_l==130079||_l==131103||_l==131615||_l==133151||_l==133663||_l==134175||_l==134687||_l==136223||_l==136735||_l==138271||_l==140319){_l=Kl(2,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{Jt(),kl(183);if(Hl==52||Hl==79)Hl==79&&vs(),kl(27),xl(52),kl(267),Df();Hl==94&&(xl(94),kl(15),xl(7)),_l=-1}catch(a){_l=-2}Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(2,Pl,_l)}}switch(_l){case-1:$t(),kl(183);if(Hl==52||Hl==79)Hl==79&&(Nl(),ds()),kl(27),Sl(52),kl(267),Nl(),_f();Hl==94&&(Sl(94),kl(15),Sl(7));break;default:_f()}Vl.endNonterminal("GroupingSpec",Pl)}function Vt(){switch(Hl){case 31:Ll(255);break;default:_l=Hl}if(_l==3103||_l==35871||_l==36895||_l==37407||_l==37919||_l==38431||_l==39455||_l==39967||_l==40479||_l==40991||_l==41503||_l==42015||_l==42527||_l==43039||_l==43551||_l==44063||_l==45087||_l==45599||_l==46111||_l==46623||_l==47647||_l==48159||_l==49183||_l==49695||_l==50207||_l==51743||_l==52255||_l==52767||_l==53279||_l==53791||_l==54303||_l==55327||_l==55839||_l==56351||_l==56863||_l==57375||_l==57887||_l==60447||_l==60959||_l==61471||_l==61983||_l==62495||_l==63007||_l==63519||_l==64031||_l==64543||_l==65567||_l==66079||_l==67103||_l==67615||_l==68127||_l==68639||_l==69151||_l==69663||_l==70175||_l==72223||_l==74271||_l==74783||_l==75807||_l==76831||_l==77343||_l==77855||_l==78367||_l==78879||_l==79391||_l==81439||_l==81951||_l==82463||_l==82975||_l==83487||_l==83999||_l==84511||_l==85023||_l==85535||_l==87071||_l==87583||_l==88095||_l==89119||_l==90143||_l==91167||_l==92191||_l==92703||_l==93215||_l==94239||_l==94751||_l==95263||_l==97823||_l==98335||_l==99359||_l==101407||_l==101919||_l==102431||_l==102943||_l==103455||_l==103967||_l==105503||_l==108575||_l==109087||_l==110623||_l==111647||_l==112159||_l==112671||_l==113183||_l==113695||_l==114719||_l==115231||_l==115743||_l==116255||_l==116767||_l==117279||_l==119839||_l==120351||_l==120863||_l==121375||_l==122911||_l==123935||_l==124447||_l==124959||_l==127007||_l==127519||_l==128031||_l==128543||_l==129055||_l==129567||_l==130079||_l==131103||_l==131615||_l==133151||_l==133663||_l==134175||_l==134687||_l==136223||_l==136735||_l==138271||_l==140319){_l=Kl(2,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{Jt(),kl(183);if(Hl==52||Hl==79)Hl==79&&vs(),kl(27),xl(52),kl(267),Df();Hl==94&&(xl(94),kl(15),xl(7)),Jl(2,t,-1),_l=-3}catch(a){_l=-2,Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(2,t,-2)}}}switch(_l){case-1:Jt(),kl(183);if(Hl==52||Hl==79)Hl==79&&vs(),kl(27),xl(52),kl(267),Df();Hl==94&&(xl(94),kl(15),xl(7));break;case-3:break;default:Df()}}function $t(){Vl.startNonterminal("GroupingVariable",Pl),Sl(31),kl(255),Nl(),hi(),Vl.endNonterminal("GroupingVariable",Pl)}function Jt(){xl(31),kl(255),pi()}function Kt(){Vl.startNonterminal("OrderByClause",Pl);switch(Hl){case 201:Sl(201),kl(34),Sl(87);break;default:Sl(236),kl(67),Sl(201),kl(34),Sl(87)}kl(267),Nl(),Gt(),Vl.endNonterminal("OrderByClause",Pl)}function Qt(){switch(Hl){case 201:xl(201),kl(34),xl(87);break;default:xl(236),kl(67),xl(201),kl(34),xl(87)}kl(267),Yt()}function Gt(){Vl.startNonterminal("OrderSpecList",Pl),Zt();for(;;){kl(176);if(Hl!=41)break;Sl(41),kl(267),Nl(),Zt()}Vl.endNonterminal("OrderSpecList",Pl)}function Yt(){en();for(;;){kl(176);if(Hl!=41)break;xl(41),kl(267),en()}}function Zt(){Vl.startNonterminal("OrderSpec",Pl),_f(),Nl(),tn(),Vl.endNonterminal("OrderSpec",Pl)}function en(){Df(),nn()}function tn(){Vl.startNonterminal("OrderModifier",Pl);if(Hl==80||Hl==113)switch(Hl){case 80:Sl(80);break;default:Sl(113)}kl(180);if(Hl==123){Sl(123),kl(121);switch(Hl){case 147:Sl(147);break;default:Sl(173)}}kl(177),Hl==94&&(Sl(94),kl(15),Sl(7)),Vl.endNonterminal("OrderModifier",Pl)}function nn(){if(Hl==80||Hl==113)switch(Hl){case 80:xl(80);break;default:xl(113)}kl(180);if(Hl==123){xl(123),kl(121);switch(Hl){case 147:xl(147);break;default:xl(173)}}kl(177),Hl==94&&(xl(94),kl(15),xl(7))}function rn(){Vl.startNonterminal("ReturnClause",Pl),Sl(220),kl(267),Nl(),_f(),Vl.endNonterminal("ReturnClause",Pl)}function sn(){xl(220),kl(267),Df()}function on(){Vl.startNonterminal("QuantifiedExpr",Pl);switch(Hl){case 235:Sl(235);break;default:Sl(129)}kl(21),Nl(),an();for(;;){if(Hl!=41)break;Sl(41),kl(21),Nl(),an()}Sl(224),kl(267),Nl(),_f(),Vl.endNonterminal("QuantifiedExpr",Pl)}function un(){switch(Hl){case 235:xl(235);break;default:xl(129)}kl(21),fn();for(;;){if(Hl!=41)break;xl(41),kl(21),fn()}xl(224),kl(267),Df()}function an(){Vl.startNonterminal("QuantifiedVarDecl",Pl),Sl(31),kl(255),Nl(),hi(),kl(110),Hl==79&&(Nl(),ds()),kl(53),Sl(154),kl(267),Nl(),_f(),Vl.endNonterminal("QuantifiedVarDecl",Pl)}function fn(){xl(31),kl(255),pi(),kl(110),Hl==79&&vs(),kl(53),xl(154),kl(267),Df()}function ln(){Vl.startNonterminal("SwitchExpr",Pl),Sl(243),kl(22),Sl(34),kl(267),Nl(),G(),Sl(37);for(;;){kl(35),Nl(),hn();if(Hl!=88)break}Sl(109),kl(70),Sl(220),kl(267),Nl(),_f(),Vl.endNonterminal("SwitchExpr",Pl)}function cn(){xl(243),kl(22),xl(34),kl(267),Y(),xl(37);for(;;){kl(35),pn();if(Hl!=88)break}xl(109),kl(70),xl(220),kl(267),Df()}function hn(){Vl.startNonterminal("SwitchCaseClause",Pl);for(;;){Sl(88),kl(267),Nl(),dn();if(Hl!=88)break}Sl(220),kl(267),Nl(),_f(),Vl.endNonterminal("SwitchCaseClause",Pl)}function pn(){for(;;){xl(88),kl(267),vn();if(Hl!=88)break}xl(220),kl(267),Df()}function dn(){Vl.startNonterminal("SwitchCaseOperand",Pl),_f(),Vl.endNonterminal("SwitchCaseOperand",Pl)}function vn(){Df()}function mn(){Vl.startNonterminal("TypeswitchExpr",Pl),Sl(253),kl(22),Sl(34),kl(267),Nl(),G(),Sl(37);for(;;){kl(35),Nl(),yn();if(Hl!=88)break}Sl(109),kl(95),Hl==31&&(Sl(31),kl(255),Nl(),hi()),kl(70),Sl(220),kl(267),Nl(),_f(),Vl.endNonterminal("TypeswitchExpr",Pl)}function gn(){xl(253),kl(22),xl(34),kl(267),Y(),xl(37);for(;;){kl(35),bn();if(Hl!=88)break}xl(109),kl(95),Hl==31&&(xl(31),kl(255),pi()),kl(70),xl(220),kl(267),Df()}function yn(){Vl.startNonterminal("CaseClause",Pl),Sl(88),kl(262),Hl==31&&(Sl(31),kl(255),Nl(),hi(),kl(30),Sl(79)),kl(260),Nl(),wn(),Sl(220),kl(267),Nl(),_f(),Vl.endNonterminal("CaseClause",Pl)}function bn(){xl(88),kl(262),Hl==31&&(xl(31),kl(255),pi(),kl(30),xl(79)),kl(260),En(),xl(220),kl(267),Df()}function wn(){Vl.startNonterminal("SequenceTypeUnion",Pl),ms();for(;;){kl(134);if(Hl!=279)break;Sl(279),kl(260),Nl(),ms()}Vl.endNonterminal("SequenceTypeUnion",Pl)}function En(){gs();for(;;){kl(134);if(Hl!=279)break;xl(279),kl(260),gs()}}function Sn(){Vl.startNonterminal("IfExpr",Pl),Sl(152),kl(22),Sl(34),kl(267),Nl(),G(),Sl(37),kl(77),Sl(245),kl(267),Nl(),_f(),Sl(122),kl(267),Nl(),_f(),Vl.endNonterminal("IfExpr",Pl)}function xn(){xl(152),kl(22),xl(34),kl(267),Y(),xl(37),kl(77),xl(245),kl(267),Df(),xl(122),kl(267),Df()}function Tn(){Vl.startNonterminal("TryCatchExpr",Pl),Cn();for(;;){kl(36),Nl(),On(),kl(184);if(Hl!=91)break}Vl.endNonterminal("TryCatchExpr",Pl)}function Nn(){kn();for(;;){kl(36),Mn(),kl(184);if(Hl!=91)break}}function Cn(){Vl.startNonterminal("TryClause",Pl),Sl(250),kl(87),Sl(276),kl(267),Nl(),Ln(),Sl(282),Vl.endNonterminal("TryClause",Pl)}function kn(){xl(250),kl(87),xl(276),kl(267),An(),xl(282)}function Ln(){Vl.startNonterminal("TryTargetExpr",Pl),G(),Vl.endNonterminal("TryTargetExpr",Pl)}function An(){Y()}function On(){Vl.startNonterminal("CatchClause",Pl),Sl(91),kl(257),Nl(),_n(),Sl(276),kl(267),Nl(),G(),Sl(282),Vl.endNonterminal("CatchClause",Pl)}function Mn(){xl(91),kl(257),Dn(),xl(276),kl(267),Y(),xl(282)}function _n(){Vl.startNonterminal("CatchErrorList",Pl),Qr();for(;;){kl(136);if(Hl!=279)break;Sl(279),kl(257),Nl(),Qr()}Vl.endNonterminal("CatchErrorList",Pl)}function Dn(){Gr();for(;;){kl(136);if(Hl!=279)break;xl(279),kl(257),Gr()}}function Pn(){Vl.startNonterminal("OrExpr",Pl),Bn();for(;;){if(Hl!=200)break;Sl(200),kl(267),Nl(),Bn()}Vl.endNonterminal("OrExpr",Pl)}function Hn(){jn();for(;;){if(Hl!=200)break;xl(200),kl(267),jn()}}function Bn(){Vl.startNonterminal("AndExpr",Pl),Fn();for(;;){if(Hl!=75)break;Sl(75),kl(267),Nl(),Fn()}Vl.endNonterminal("AndExpr",Pl)}function jn(){In();for(;;){if(Hl!=75)break;xl(75),kl(267),In()}}function Fn(){Vl.startNonterminal("ComparisonExpr",Pl),qn();if(Hl==27||Hl==54||Hl==57||Hl==58||Hl==60||Hl==61||Hl==62||Hl==63||Hl==128||Hl==146||Hl==150||Hl==164||Hl==172||Hl==178||Hl==186){switch(Hl){case 128:case 146:case 150:case 172:case 178:case 186:Nl(),mr();break;case 57:case 63:case 164:Nl(),yr();break;default:Nl(),dr()}kl(267),Nl(),qn()}Vl.endNonterminal("ComparisonExpr",Pl)}function In(){Rn();if(Hl==27||Hl==54||Hl==57||Hl==58||Hl==60||Hl==61||Hl==62||Hl==63||Hl==128||Hl==146||Hl==150||Hl==164||Hl==172||Hl==178||Hl==186){switch(Hl){case 128:case 146:case 150:case 172:case 178:case 186:gr();break;case 57:case 63:case 164:br();break;default:vr()}kl(267),Rn()}}function qn(){Vl.startNonterminal("FTContainsExpr",Pl),Un(),Hl==99&&(Sl(99),kl(76),Sl(244),kl(162),Nl(),Jo(),Hl==271&&(Nl(),ha())),Vl.endNonterminal("FTContainsExpr",Pl)}function Rn(){zn(),Hl==99&&(xl(99),kl(76),xl(244),kl(162),Ko(),Hl==271&&pa())}function Un(){Vl.startNonterminal("StringConcatExpr",Pl),Wn();for(;;){if(Hl!=280)break;Sl(280),kl(267),Nl(),Wn()}Vl.endNonterminal("StringConcatExpr",Pl)}function zn(){Xn();for(;;){if(Hl!=280)break;xl(280),kl(267),Xn()}}function Wn(){Vl.startNonterminal("RangeExpr",Pl),Vn(),Hl==248&&(Sl(248),kl(267),Nl(),Vn()),Vl.endNonterminal("RangeExpr",Pl)}function Xn(){$n(),Hl==248&&(xl(248),kl(267),$n())}function Vn(){Vl.startNonterminal("AdditiveExpr",Pl),Jn();for(;;){if(Hl!=40&&Hl!=42)break;switch(Hl){case 40:Sl(40);break;default:Sl(42)}kl(267),Nl(),Jn()}Vl.endNonterminal("AdditiveExpr",Pl)}function $n(){Kn();for(;;){if(Hl!=40&&Hl!=42)break;switch(Hl){case 40:xl(40);break;default:xl(42)}kl(267),Kn()}}function Jn(){Vl.startNonterminal("MultiplicativeExpr",Pl),Qn();for(;;){if(Hl!=38&&Hl!=118&&Hl!=151&&Hl!=180)break;switch(Hl){case 38:Sl(38);break;case 118:Sl(118);break;case 151:Sl(151);break;default:Sl(180)}kl(267),Nl(),Qn()}Vl.endNonterminal("MultiplicativeExpr",Pl)}function Kn(){Gn();for(;;){if(Hl!=38&&Hl!=118&&Hl!=151&&Hl!=180)break;switch(Hl){case 38:xl(38);break;case 118:xl(118);break;case 151:xl(151);break;default:xl(180)}kl(267),Gn()}}function Qn(){Vl.startNonterminal("UnionExpr",Pl),Yn();for(;;){if(Hl!=254&&Hl!=279)break;switch(Hl){case 254:Sl(254);break;default:Sl(279)}kl(267),Nl(),Yn()}Vl.endNonterminal("UnionExpr",Pl)}function Gn(){Zn();for(;;){if(Hl!=254&&Hl!=279)break;switch(Hl){case 254:xl(254);break;default:xl(279)}kl(267),Zn()}}function Yn(){Vl.startNonterminal("IntersectExceptExpr",Pl),er();for(;;){kl(223);if(Hl!=131&&Hl!=162)break;switch(Hl){case 162:Sl(162);break;default:Sl(131)}kl(267),Nl(),er()}Vl.endNonterminal("IntersectExceptExpr",Pl)}function Zn(){tr();for(;;){kl(223);if(Hl!=131&&Hl!=162)break;switch(Hl){case 162:xl(162);break;default:xl(131)}kl(267),tr()}}function er(){Vl.startNonterminal("InstanceofExpr",Pl),nr(),kl(224),Hl==160&&(Sl(160),kl(64),Sl(196),kl(260),Nl(),ms()),Vl.endNonterminal("InstanceofExpr",Pl)}function tr(){rr(),kl(224),Hl==160&&(xl(160),kl(64),xl(196),kl(260),gs())}function nr(){Vl.startNonterminal("TreatExpr",Pl),ir(),kl(225),Hl==249&&(Sl(249),kl(30),Sl(79),kl(260),Nl(),ms()),Vl.endNonterminal("TreatExpr",Pl)}function rr(){sr(),kl(225),Hl==249&&(xl(249),kl(30),xl(79),kl(260),gs())}function ir(){Vl.startNonterminal("CastableExpr",Pl),or(),kl(226),Hl==90&&(Sl(90),kl(30),Sl(79),kl(255),Nl(),hs()),Vl.endNonterminal("CastableExpr",Pl)}function sr(){ur(),kl(226),Hl==90&&(xl(90),kl(30),xl(79),kl(255),ps())}function or(){Vl.startNonterminal("CastExpr",Pl),ar(),kl(228),Hl==89&&(Sl(89),kl(30),Sl(79),kl(255),Nl(),hs()),Vl.endNonterminal("CastExpr",Pl)}function ur(){fr(),kl(228),Hl==89&&(xl(89),kl(30),xl(79),kl(255),ps())}function ar(){Vl.startNonterminal("UnaryExpr",Pl);for(;;){kl(267);if(Hl!=40&&Hl!=42)break;switch(Hl){case 42:Sl(42);break;default:Sl(40)}}Nl(),lr(),Vl.endNonterminal("UnaryExpr",Pl)}function fr(){for(;;){kl(267);if(Hl!=40&&Hl!=42)break;switch(Hl){case 42:xl(42);break;default:xl(40)}}cr()}function lr(){Vl.startNonterminal("ValueExpr",Pl);switch(Hl){case 260:Ll(248);break;default:_l=Hl}switch(_l){case 87812:case 123140:case 129284:case 141572:wr();break;case 35:Tr();break;default:hr()}Vl.endNonterminal("ValueExpr",Pl)}function cr(){switch(Hl){case 260:Ll(248);break;default:_l=Hl}switch(_l){case 87812:case 123140:case 129284:case 141572:Er();break;case 35:Nr();break;default:pr()}}function hr(){Vl.startNonterminal("SimpleMapExpr",Pl),Lr();for(;;){if(Hl!=26)break;Sl(26),kl(266),Nl(),Lr()}Vl.endNonterminal("SimpleMapExpr",Pl)}function pr(){Ar();for(;;){if(Hl!=26)break;xl(26),kl(266),Ar()}}function dr(){Vl.startNonterminal("GeneralComp",Pl);switch(Hl){case 60:Sl(60);break;case 27:Sl(27);break;case 54:Sl(54);break;case 58:Sl(58);break;case 61:Sl(61);break;default:Sl(62)}Vl.endNonterminal("GeneralComp",Pl)}function vr(){switch(Hl){case 60:xl(60);break;case 27:xl(27);break;case 54:xl(54);break;case 58:xl(58);break;case 61:xl(61);break;default:xl(62)}}function mr(){Vl.startNonterminal("ValueComp",Pl);switch(Hl){case 128:Sl(128);break;case 186:Sl(186);break;case 178:Sl(178);break;case 172:Sl(172);break;case 150:Sl(150);break;default:Sl(146)}Vl.endNonterminal("ValueComp",Pl)}function gr(){switch(Hl){case 128:xl(128);break;case 186:xl(186);break;case 178:xl(178);break;case 172:xl(172);break;case 150:xl(150);break;default:xl(146)}}function yr(){Vl.startNonterminal("NodeComp",Pl);switch(Hl){case 164:Sl(164);break;case 57:Sl(57);break;default:Sl(63)}Vl.endNonterminal("NodeComp",Pl)}function br(){switch(Hl){case 164:xl(164);break;case 57:xl(57);break;default:xl(63)}}function wr(){Vl.startNonterminal("ValidateExpr",Pl),Sl(260),kl(160);if(Hl!=276)switch(Hl){case 252:Sl(252),kl(255),Nl(),go();break;default:Nl(),Sr()}kl(87),Sl(276),kl(267),Nl(),G(),Sl(282),Vl.endNonterminal("ValidateExpr",Pl)}function Er(){xl(260),kl(160);if(Hl!=276)switch(Hl){case 252:xl(252),kl(255),yo();break;default:xr()}kl(87),xl(276),kl(267),Y(),xl(282)}function Sr(){Vl.startNonterminal("ValidationMode",Pl);switch(Hl){case 171:Sl(171);break;default:Sl(240)}Vl.endNonterminal("ValidationMode",Pl)}function xr(){switch(Hl){case 171:xl(171);break;default:xl(240)}}function Tr(){Vl.startNonterminal("ExtensionExpr",Pl);for(;;){Nl(),Cr(),kl(100);if(Hl!=35)break}Sl(276),kl(274),Hl!=282&&(Nl(),G()),Sl(282),Vl.endNonterminal("ExtensionExpr",Pl)}function Nr(){for(;;){kr(),kl(100);if(Hl!=35)break}xl(276),kl(274),Hl!=282&&Y(),xl(282)}function Cr(){Vl.startNonterminal("Pragma",Pl),Sl(35),Al(252),Hl==21&&Sl(21),Ha(),Al(10),Hl==21&&(Sl(21),Al(0),Sl(1)),Al(5),Sl(30),Vl.endNonterminal("Pragma",Pl)}function kr(){xl(35),Al(252),Hl==21&&xl(21),Ba(),Al(10),Hl==21&&(xl(21),Al(0),xl(1)),Al(5),xl(30)}function Lr(){Vl.startNonterminal("PathExpr",Pl);switch(Hl){case 46:Sl(46),kl(286);switch(Hl){case 25:case 26:case 27:case 37:case 38:case 40:case 41:case 42:case 49:case 53:case 57:case 58:case 60:case 61:case 62:case 63:case 69:case 87:case 99:case 205:case 232:case 247:case 273:case 279:case 280:case 281:case 282:break;default:Nl(),Or()}break;case 47:Sl(47),kl(265),Nl(),Or();break;default:Or()}Vl.endNonterminal("PathExpr",Pl)}function Ar(){switch(Hl){case 46:xl(46),kl(286);switch(Hl){case 25:case 26:case 27:case 37:case 38:case 40:case 41:case 42:case 49:case 53:case 57:case 58:case 60:case 61:case 62:case 63:case 69:case 87:case 99:case 205:case 232:case 247:case 273:case 279:case 280:case 281:case 282:break;default:Mr()}break;case 47:xl(47),kl(265),Mr();break;default:Mr()}}function Or(){Vl.startNonterminal("RelativePathExpr",Pl),_r();for(;;){switch(Hl){case 26:Ll(266);break;default:_l=Hl}if(_l!=25&&_l!=27&&_l!=37&&_l!=38&&_l!=40&&_l!=41&&_l!=42&&_l!=46&&_l!=47&&_l!=49&&_l!=53&&_l!=54&&_l!=57&&_l!=58&&_l!=60&&_l!=61&&_l!=62&&_l!=63&&_l!=69&&_l!=70&&_l!=75&&_l!=79&&_l!=80&&_l!=81&&_l!=84&&_l!=87&&_l!=88&&_l!=89&&_l!=90&&_l!=94&&_l!=99&&_l!=105&&_l!=109&&_l!=113&&_l!=118&&_l!=122&&_l!=123&&_l!=126&&_l!=128&&_l!=131&&_l!=137&&_l!=146&&_l!=148&&_l!=150&&_l!=151&&_l!=160&&_l!=162&&_l!=163&&_l!=164&&_l!=172&&_l!=174&&_l!=178&&_l!=180&&_l!=181&&_l!=186&&_l!=198&&_l!=200&&_l!=201&&_l!=205&&_l!=220&&_l!=224&&_l!=232&&_l!=236&&_l!=237&&_l!=247&&_l!=248&&_l!=249&&_l!=254&&_l!=266&&_l!=270&&_l!=273&&_l!=279&&_l!=280&&_l!=281&&_l!=282&&_l!=23578&&_l!=24090){_l=Kl(3,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{switch(Hl){case 46:xl(46);break;case 47:xl(47);break;default:xl(26)}kl(265),Dr(),_l=-1}catch(a){_l=-2}Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(3,Pl,_l)}}if(_l!=-1&&_l!=46&&_l!=47)break;switch(Hl){case 46:Sl(46);break;case 47:Sl(47);break;default:Sl(26)}kl(265),Nl(),_r()}Vl.endNonterminal("RelativePathExpr",Pl)}function Mr(){Dr();for(;;){switch(Hl){case 26:Ll(266);break;default:_l=Hl}if(_l!=25&&_l!=27&&_l!=37&&_l!=38&&_l!=40&&_l!=41&&_l!=42&&_l!=46&&_l!=47&&_l!=49&&_l!=53&&_l!=54&&_l!=57&&_l!=58&&_l!=60&&_l!=61&&_l!=62&&_l!=63&&_l!=69&&_l!=70&&_l!=75&&_l!=79&&_l!=80&&_l!=81&&_l!=84&&_l!=87&&_l!=88&&_l!=89&&_l!=90&&_l!=94&&_l!=99&&_l!=105&&_l!=109&&_l!=113&&_l!=118&&_l!=122&&_l!=123&&_l!=126&&_l!=128&&_l!=131&&_l!=137&&_l!=146&&_l!=148&&_l!=150&&_l!=151&&_l!=160&&_l!=162&&_l!=163&&_l!=164&&_l!=172&&_l!=174&&_l!=178&&_l!=180&&_l!=181&&_l!=186&&_l!=198&&_l!=200&&_l!=201&&_l!=205&&_l!=220&&_l!=224&&_l!=232&&_l!=236&&_l!=237&&_l!=247&&_l!=248&&_l!=249&&_l!=254&&_l!=266&&_l!=270&&_l!=273&&_l!=279&&_l!=280&&_l!=281&&_l!=282&&_l!=23578&&_l!=24090){_l=Kl(3,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{switch(Hl){case 46:xl(46);break;case 47:xl(47);break;default:xl(26)}kl(265),Dr(),Jl(3,t,-1);continue}catch(a){Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(3,t,-2);break}}}if(_l!=-1&&_l!=46&&_l!=47)break;switch(Hl){case 46:xl(46);break;case 47:xl(47);break;default:xl(26)}kl(265),Dr()}}function _r(){Vl.startNonterminal("StepExpr",Pl);switch(Hl){case 82:Ll(285);break;case 121:Ll(283);break;case 184:case 216:Ll(282);break;case 96:case 119:case 202:case 244:case 256:Ll(247);break;case 78:case 124:case 152:case 165:case 167:case 242:case 243:case 253:Ll(240);break;case 73:case 74:case 93:case 111:case 112:case 135:case 136:case 206:case 212:case 213:case 229:Ll(246);break;case 6:case 70:case 72:case 75:case 77:case 79:case 80:case 81:case 83:case 84:case 85:case 86:case 88:case 89:case 90:case 91:case 94:case 97:case 98:case 101:case 102:case 103:case 104:case 105:case 106:case 108:case 109:case 110:case 113:case 118:case 120:case 122:case 123:case 125:case 126:case 128:case 129:case 131:case 132:case 133:case 134:case 137:case 141:case 145:case 146:case 148:case 150:case 151:case 153:case 154:case 155:case 159:case 160:case 161:case 162:case 163:case 164:case 166:case 170:case 171:case 172:case 174:case 176:case 178:case 180:case 181:case 182:case 185:case 186:case 191:case 192:case 194:case 198:case 199:case 200:case 201:case 203:case 218:case 219:case 220:case 221:case 222:case 224:case 225:case 226:case 227:case 228:case 234:case 235:case 236:case 237:case 240:case 248:case 249:case 250:case 251:case 252:case 254:case 257:case 260:case 261:case 262:case 263:case 266:case 267:case 270:case 274:Ll(244);break;default:_l=Hl}if(_l==35922||_l==35961||_l==36024||_l==36056||_l==38482||_l==38521||_l==38584||_l==38616||_l==40530||_l==40569||_l==40632||_l==40664||_l==41042||_l==41081||_l==41144||_l==41176||_l==41554||_l==41593||_l==41656||_l==41688||_l==43090||_l==43129||_l==43192||_l==43224||_l==45138||_l==45177||_l==45240||_l==45272||_l==45650||_l==45689||_l==45752||_l==45784||_l==46162||_l==46201||_l==46264||_l==46296||_l==48210||_l==48249||_l==48312||_l==48344||_l==53842||_l==53881||_l==53944||_l==53976||_l==55890||_l==55929||_l==55992||_l==56024||_l==57938||_l==57977||_l==58040||_l==58072||_l==60498||_l==60537||_l==60600||_l==60632||_l==62546||_l==62585||_l==62648||_l==62680||_l==63058||_l==63097||_l==63160||_l==63192||_l==64594||_l==64633||_l==64696||_l==64728||_l==65618||_l==65657||_l==65720||_l==65752||_l==67154||_l==67193||_l==67256||_l==67288||_l==70226||_l==70265||_l==70328||_l==70360||_l==74834||_l==74873||_l==74936||_l==74968||_l==75858||_l==75897||_l==75960||_l==75992||_l==76882||_l==76921||_l==76984||_l==77016||_l==77394||_l==77433||_l==77496||_l==77528||_l==82002||_l==82041||_l==82104||_l==82136||_l==83026||_l==83065||_l==83128||_l==83160||_l==83538||_l==83577||_l==83640||_l==83672||_l==84050||_l==84089||_l==84152||_l==84184||_l==88146||_l==88185||_l==88248||_l==88280||_l==89170||_l==89209||_l==89272||_l==89304||_l==91218||_l==91257||_l==91320||_l==91352||_l==92242||_l==92281||_l==92344||_l==92376||_l==92754||_l==92793||_l==92856||_l==92888||_l==95314||_l==95353||_l==95416||_l==95448||_l==101458||_l==101497||_l==101560||_l==101592||_l==102482||_l==102521||_l==102584||_l==102616||_l==102994||_l==103033||_l==103096||_l==103128||_l==112722||_l==112761||_l==112824||_l==112856||_l==114770||_l==114809||_l==114872||_l==114904||_l==120914||_l==120953||_l==121016||_l==121048||_l==121426||_l==121465||_l==121528||_l==121560||_l==127058||_l==127097||_l==127160||_l==127192||_l==127570||_l==127609||_l==127672||_l==127704||_l==130130||_l==130169||_l==130232||_l==130264||_l==136274||_l==136313||_l==136376||_l==136408||_l==138322||_l==138361||_l==138424||_l==138456){_l=Kl(4,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{Zr(),_l=-1}catch(a){_l=-2}Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(4,Pl,_l)}}switch(_l){case-1:case 8:case 9:case 10:case 11:case 31:case 32:case 34:case 44:case 54:case 55:case 59:case 68:case 276:case 278:case 3154:case 3193:case 9912:case 9944:case 14854:case 14918:case 14920:case 14921:case 14922:case 14923:case 14925:case 14926:case 14927:case 14928:case 14929:case 14930:case 14931:case 14932:case 14933:case 14934:case 14936:case 14937:case 14938:case 14939:case 14941:case 14942:case 14944:case 14945:case 14946:case 14949:case 14950:case 14951:case 14952:case 14953:case 14954:case 14956:case 14957:case 14958:case 14959:case 14960:case 14961:case 14966:case 14967:case 14968:case 14969:case 14970:case 14971:case 14972:case 14973:case 14974:case 14976:case 14977:case 14979:case 14980:case 14981:case 14982:case 14983:case 14984:case 14985:case 14989:case 14993:case 14994:case 14996:case 14998:case 14999:case 15e3:case 15001:case 15002:case 15003:case 15007:case 15008:case 15009:case 15010:case 15011:case 15012:case 15013:case 15014:case 15015:case 15018:case 15019:case 15020:case 15022:case 15024:case 15026:case 15028:case 15029:case 15030:case 15032:case 15033:case 15034:case 15039:case 15040:case 15042:case 15046:case 15047:case 15048:case 15049:case 15050:case 15051:case 15054:case 15060:case 15061:case 15064:case 15066:case 15067:case 15068:case 15069:case 15070:case 15072:case 15073:case 15074:case 15075:case 15076:case 15077:case 15082:case 15083:case 15084:case 15085:case 15088:case 15090:case 15091:case 15092:case 15096:case 15097:case 15098:case 15099:case 15100:case 15101:case 15102:case 15104:case 15105:case 15108:case 15109:case 15110:case 15111:case 15114:case 15115:case 15118:case 15122:case 17414:case 17478:case 17480:case 17481:case 17482:case 17483:case 17485:case 17487:case 17488:case 17489:case 17491:case 17492:case 17493:case 17494:case 17496:case 17497:case 17498:case 17499:case 17501:case 17502:case 17505:case 17506:case 17509:case 17510:case 17511:case 17512:case 17513:case 17514:case 17516:case 17517:case 17518:case 17519:case 17520:case 17521:case 17526:case 17527:case 17530:case 17531:case 17533:case 17534:case 17536:case 17537:case 17539:case 17540:case 17541:case 17542:case 17543:case 17544:case 17545:case 17549:case 17553:case 17554:case 17556:case 17558:case 17559:case 17561:case 17562:case 17563:case 17567:case 17568:case 17569:case 17570:case 17571:case 17572:case 17574:case 17578:case 17579:case 17580:case 17582:case 17584:case 17586:case 17588:case 17589:case 17590:case 17592:case 17594:case 17600:case 17602:case 17606:case 17607:case 17608:case 17609:case 17610:case 17611:case 17614:case 17620:case 17621:case 17626:case 17627:case 17628:case 17629:case 17630:case 17632:case 17633:case 17636:case 17637:case 17642:case 17643:case 17644:case 17645:case 17648:case 17656:case 17657:case 17658:case 17659:case 17660:case 17662:case 17664:case 17665:case 17668:case 17669:case 17670:case 17671:case 17674:case 17675:case 17678:case 17682:case 36946:case 36985:case 37048:case 37080:case 37458:case 37497:case 37560:case 37592:case 37970:case 38009:case 38072:case 38104:case 39506:case 39545:case 39608:case 39640:case 40018:case 40057:case 42066:case 42105:case 42168:case 42200:case 42578:case 42617:case 42680:case 42712:case 43602:case 43641:case 43704:case 43736:case 44114:case 44153:case 44216:case 44248:case 46674:case 46713:case 46776:case 46808:case 47698:case 47737:case 47800:case 47832:case 49234:case 49273:case 49336:case 49368:case 49746:case 49785:case 49848:case 49880:case 50258:case 50297:case 50360:case 50392:case 51794:case 51833:case 51896:case 51928:case 52306:case 52345:case 52408:case 52440:case 52818:case 52857:case 52920:case 52952:case 53330:case 53369:case 53432:case 53464:case 54354:case 54393:case 54456:case 54488:case 55378:case 55417:case 55480:case 55512:case 56402:case 56441:case 56504:case 56536:case 56914:case 56953:case 57016:case 57048:case 57426:case 57465:case 57528:case 57560:case 61010:case 61049:case 61112:case 61144:case 61522:case 61561:case 61624:case 61656:case 62034:case 62073:case 62136:case 62168:case 63570:case 63609:case 63672:case 63704:case 64082:case 64121:case 64184:case 64216:case 66130:case 66169:case 66232:case 66264:case 67666:case 67705:case 67768:case 67800:case 68178:case 68217:case 68280:case 68312:case 68690:case 68729:case 68792:case 68824:case 69202:case 69241:case 69304:case 69336:case 69714:case 69753:case 69816:case 69848:case 72274:case 72313:case 72376:case 72408:case 74322:case 74361:case 74424:case 74456:case 77906:case 77945:case 78008:case 78040:case 78418:case 78457:case 78520:case 78552:case 78930:case 78969:case 79032:case 79064:case 79442:case 79481:case 79544:case 79576:case 81490:case 81529:case 81592:case 81624:case 82514:case 82553:case 82616:case 82648:case 84562:case 84601:case 84664:case 84696:case 85074:case 85113:case 85176:case 85208:case 85586:case 85625:case 87122:case 87161:case 87224:case 87256:case 87634:case 87673:case 87736:case 87768:case 90194:case 90233:case 90296:case 90328:case 93266:case 93305:case 93368:case 93400:case 94290:case 94329:case 94392:case 94424:case 94802:case 94841:case 94904:case 94936:case 97874:case 97913:case 97976:case 98008:case 98386:case 98425:case 98488:case 98520:case 99410:case 99449:case 99512:case 99544:case 101970:case 102009:case 102072:case 102104:case 103506:case 103545:case 103608:case 103640:case 104018:case 104057:case 104120:case 104152:case 105554:case 105593:case 105656:case 105688:case 108626:case 108665:case 108728:case 108760:case 109138:case 109177:case 109240:case 109272:case 110674:case 110713:case 110776:case 110808:case 111698:case 111737:case 111800:case 111832:case 112210:case 112249:case 112312:case 112344:case 113234:case 113273:case 113336:case 113368:case 113746:case 113785:case 113848:case 113880:case 115282:case 115321:case 115384:case 115416:case 115794:case 115833:case 115896:case 115928:case 116306:case 116345:case 116408:case 116440:case 116818:case 116857:case 116920:case 116952:case 117330:case 117369:case 117432:case 117464:case 119890:case 119929:case 119992:case 120024:case 120402:case 120441:case 120504:case 120536:case 122962:case 123001:case 123064:case 123096:case 123986:case 124025:case 124498:case 124537:case 124600:case 124632:case 125010:case 125049:case 125112:case 125144:case 128082:case 128121:case 128184:case 128216:case 128594:case 128633:case 128696:case 128728:case 129106:case 129145:case 129208:case 129240:case 129618:case 129657:case 129720:case 129752:case 131154:case 131193:case 131256:case 131288:case 131666:case 131705:case 131768:case 131800:case 133202:case 133241:case 133304:case 133336:case 133714:case 133753:case 133816:case 133848:case 134226:case 134265:case 134328:case 134360:case 134738:case 134777:case 134840:case 134872:case 136786:case 136825:case 136888:case 136920:case 140370:case 140409:case 140472:case 140504:case 141394:case 141408:case 141431:case 141433:case 141496:case 141514:case 141528:case 141556:case 141568:Yr();break;default:Pr()}Vl.endNonterminal("StepExpr",Pl)}function Dr(){switch(Hl){case 82:Ll(285);break;case 121:Ll(283);break;case 184:case 216:Ll(282);break;case 96:case 119:case 202:case 244:case 256:Ll(247);break;case 78:case 124:case 152:case 165:case 167:case 242:case 243:case 253:Ll(240);break;case 73:case 74:case 93:case 111:case 112:case 135:case 136:case 206:case 212:case 213:case 229:Ll(246);break;case 6:case 70:case 72:case 75:case 77:case 79:case 80:case 81:case 83:case 84:case 85:case 86:case 88:case 89:case 90:case 91:case 94:case 97:case 98:case 101:case 102:case 103:case 104:case 105:case 106:case 108:case 109:case 110:case 113:case 118:case 120:case 122:case 123:case 125:case 126:case 128:case 129:case 131:case 132:case 133:case 134:case 137:case 141:case 145:case 146:case 148:case 150:case 151:case 153:case 154:case 155:case 159:case 160:case 161:case 162:case 163:case 164:case 166:case 170:case 171:case 172:case 174:case 176:case 178:case 180:case 181:case 182:case 185:case 186:case 191:case 192:case 194:case 198:case 199:case 200:case 201:case 203:case 218:case 219:case 220:case 221:case 222:case 224:case 225:case 226:case 227:case 228:case 234:case 235:case 236:case 237:case 240:case 248:case 249:case 250:case 251:case 252:case 254:case 257:case 260:case 261:case 262:case 263:case 266:case 267:case 270:case 274:Ll(244);break;default:_l=Hl}if(_l==35922||_l==35961||_l==36024||_l==36056||_l==38482||_l==38521||_l==38584||_l==38616||_l==40530||_l==40569||_l==40632||_l==40664||_l==41042||_l==41081||_l==41144||_l==41176||_l==41554||_l==41593||_l==41656||_l==41688||_l==43090||_l==43129||_l==43192||_l==43224||_l==45138||_l==45177||_l==45240||_l==45272||_l==45650||_l==45689||_l==45752||_l==45784||_l==46162||_l==46201||_l==46264||_l==46296||_l==48210||_l==48249||_l==48312||_l==48344||_l==53842||_l==53881||_l==53944||_l==53976||_l==55890||_l==55929||_l==55992||_l==56024||_l==57938||_l==57977||_l==58040||_l==58072||_l==60498||_l==60537||_l==60600||_l==60632||_l==62546||_l==62585||_l==62648||_l==62680||_l==63058||_l==63097||_l==63160||_l==63192||_l==64594||_l==64633||_l==64696||_l==64728||_l==65618||_l==65657||_l==65720||_l==65752||_l==67154||_l==67193||_l==67256||_l==67288||_l==70226||_l==70265||_l==70328||_l==70360||_l==74834||_l==74873||_l==74936||_l==74968||_l==75858||_l==75897||_l==75960||_l==75992||_l==76882||_l==76921||_l==76984||_l==77016||_l==77394||_l==77433||_l==77496||_l==77528||_l==82002||_l==82041||_l==82104||_l==82136||_l==83026||_l==83065||_l==83128||_l==83160||_l==83538||_l==83577||_l==83640||_l==83672||_l==84050||_l==84089||_l==84152||_l==84184||_l==88146||_l==88185||_l==88248||_l==88280||_l==89170||_l==89209||_l==89272||_l==89304||_l==91218||_l==91257||_l==91320||_l==91352||_l==92242||_l==92281||_l==92344||_l==92376||_l==92754||_l==92793||_l==92856||_l==92888||_l==95314||_l==95353||_l==95416||_l==95448||_l==101458||_l==101497||_l==101560||_l==101592||_l==102482||_l==102521||_l==102584||_l==102616||_l==102994||_l==103033||_l==103096||_l==103128||_l==112722||_l==112761||_l==112824||_l==112856||_l==114770||_l==114809||_l==114872||_l==114904||_l==120914||_l==120953||_l==121016||_l==121048||_l==121426||_l==121465||_l==121528||_l==121560||_l==127058||_l==127097||_l==127160||_l==127192||_l==127570||_l==127609||_l==127672||_l==127704||_l==130130||_l==130169||_l==130232||_l==130264||_l==136274||_l==136313||_l==136376||_l==136408||_l==138322||_l==138361||_l==138424||_l==138456){_l=Kl(4,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{Zr(),Jl(4,t,-1),_l=-3}catch(a){_l=-2,Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(4,t,-2)}}}switch(_l){case-1:case 8:case 9:case 10:case 11:case 31:case 32:case 34:case 44:case 54:case 55:case 59:case 68:case 276:case 278:case 3154:case 3193:case 9912:case 9944:case 14854:case 14918:case 14920:case 14921:case 14922:case 14923:case 14925:case 14926:case 14927:case 14928:case 14929:case 14930:case 14931:case 14932:case 14933:case 14934:case 14936:case 14937:case 14938:case 14939:case 14941:case 14942:case 14944:case 14945:case 14946:case 14949:case 14950:case 14951:case 14952:case 14953:case 14954:case 14956:case 14957:case 14958:case 14959:case 14960:case 14961:case 14966:case 14967:case 14968:case 14969:case 14970:case 14971:case 14972:case 14973:case 14974:case 14976:case 14977:case 14979:case 14980:case 14981:case 14982:case 14983:case 14984:case 14985:case 14989:case 14993:case 14994:case 14996:case 14998:case 14999:case 15e3:case 15001:case 15002:case 15003:case 15007:case 15008:case 15009:case 15010:case 15011:case 15012:case 15013:case 15014:case 15015:case 15018:case 15019:case 15020:case 15022:case 15024:case 15026:case 15028:case 15029:case 15030:case 15032:case 15033:case 15034:case 15039:case 15040:case 15042:case 15046:case 15047:case 15048:case 15049:case 15050:case 15051:case 15054:case 15060:case 15061:case 15064:case 15066:case 15067:case 15068:case 15069:case 15070:case 15072:case 15073:case 15074:case 15075:case 15076:case 15077:case 15082:case 15083:case 15084:case 15085:case 15088:case 15090:case 15091:case 15092:case 15096:case 15097:case 15098:case 15099:case 15100:case 15101:case 15102:case 15104:case 15105:case 15108:case 15109:case 15110:case 15111:case 15114:case 15115:case 15118:case 15122:case 17414:case 17478:case 17480:case 17481:case 17482:case 17483:case 17485:case 17487:case 17488:case 17489:case 17491:case 17492:case 17493:case 17494:case 17496:case 17497:case 17498:case 17499:case 17501:case 17502:case 17505:case 17506:case 17509:case 17510:case 17511:case 17512:case 17513:case 17514:case 17516:case 17517:case 17518:case 17519:case 17520:case 17521:case 17526:case 17527:case 17530:case 17531:case 17533:case 17534:case 17536:case 17537:case 17539:case 17540:case 17541:case 17542:case 17543:case 17544:case 17545:case 17549:case 17553:case 17554:case 17556:case 17558:case 17559:case 17561:case 17562:case 17563:case 17567:case 17568:case 17569:case 17570:case 17571:case 17572:case 17574:case 17578:case 17579:case 17580:case 17582:case 17584:case 17586:case 17588:case 17589:case 17590:case 17592:case 17594:case 17600:case 17602:case 17606:case 17607:case 17608:case 17609:case 17610:case 17611:case 17614:case 17620:case 17621:case 17626:case 17627:case 17628:case 17629:case 17630:case 17632:case 17633:case 17636:case 17637:case 17642:case 17643:case 17644:case 17645:case 17648:case 17656:case 17657:case 17658:case 17659:case 17660:case 17662:case 17664:case 17665:case 17668:case 17669:case 17670:case 17671:case 17674:case 17675:case 17678:case 17682:case 36946:case 36985:case 37048:case 37080:case 37458:case 37497:case 37560:case 37592:case 37970:case 38009:case 38072:case 38104:case 39506:case 39545:case 39608:case 39640:case 40018:case 40057:case 42066:case 42105:case 42168:case 42200:case 42578:case 42617:case 42680:case 42712:case 43602:case 43641:case 43704:case 43736:case 44114:case 44153:case 44216:case 44248:case 46674:case 46713:case 46776:case 46808:case 47698:case 47737:case 47800:case 47832:case 49234:case 49273:case 49336:case 49368:case 49746:case 49785:case 49848:case 49880:case 50258:case 50297:case 50360:case 50392:case 51794:case 51833:case 51896:case 51928:case 52306:case 52345:case 52408:case 52440:case 52818:case 52857:case 52920:case 52952:case 53330:case 53369:case 53432:case 53464:case 54354:case 54393:case 54456:case 54488:case 55378:case 55417:case 55480:case 55512:case 56402:case 56441:case 56504:case 56536:case 56914:case 56953:case 57016:case 57048:case 57426:case 57465:case 57528:case 57560:case 61010:case 61049:case 61112:case 61144:case 61522:case 61561:case 61624:case 61656:case 62034:case 62073:case 62136:case 62168:case 63570:case 63609:case 63672:case 63704:case 64082:case 64121:case 64184:case 64216:case 66130:case 66169:case 66232:case 66264:case 67666:case 67705:case 67768:case 67800:case 68178:case 68217:case 68280:case 68312:case 68690:case 68729:case 68792:case 68824:case 69202:case 69241:case 69304:case 69336:case 69714:case 69753:case 69816:case 69848:case 72274:case 72313:case 72376:case 72408:case 74322:case 74361:case 74424:case 74456:case 77906:case 77945:case 78008:case 78040:case 78418:case 78457:case 78520:case 78552:case 78930:case 78969:case 79032:case 79064:case 79442:case 79481:case 79544:case 79576:case 81490:case 81529:case 81592:case 81624:case 82514:case 82553:case 82616:case 82648:case 84562:case 84601:case 84664:case 84696:case 85074:case 85113:case 85176:case 85208:case 85586:case 85625:case 87122:case 87161:case 87224:case 87256:case 87634:case 87673:case 87736:case 87768:case 90194:case 90233:case 90296:case 90328:case 93266:case 93305:case 93368:case 93400:case 94290:case 94329:case 94392:case 94424:case 94802:case 94841:case 94904:case 94936:case 97874:case 97913:case 97976:case 98008:case 98386:case 98425:case 98488:case 98520:case 99410:case 99449:case 99512:case 99544:case 101970:case 102009:case 102072:case 102104:case 103506:case 103545:case 103608:case 103640:case 104018:case 104057:case 104120:case 104152:case 105554:case 105593:case 105656:case 105688:case 108626:case 108665:case 108728:case 108760:case 109138:case 109177:case 109240:case 109272:case 110674:case 110713:case 110776:case 110808:case 111698:case 111737:case 111800:case 111832:case 112210:case 112249:case 112312:case 112344:case 113234:case 113273:case 113336:case 113368:case 113746:case 113785:case 113848:case 113880:case 115282:case 115321:case 115384:case 115416:case 115794:case 115833:case 115896:case 115928:case 116306:case 116345:case 116408:case 116440:case 116818:case 116857:case 116920:case 116952:case 117330:case 117369:case 117432:case 117464:case 119890:case 119929:case 119992:case 120024:case 120402:case 120441:case 120504:case 120536:case 122962:case 123001:case 123064:case 123096:case 123986:case 124025:case 124498:case 124537:case 124600:case 124632:case 125010:case 125049:case 125112:case 125144:case 128082:case 128121:case 128184:case 128216:case 128594:case 128633:case 128696:case 128728:case 129106:case 129145:case 129208:case 129240:case 129618:case 129657:case 129720:case 129752:case 131154:case 131193:case 131256:case 131288:case 131666:case 131705:case 131768:case 131800:case 133202:case 133241:case 133304:case 133336:case 133714:case 133753:case 133816:case 133848:case 134226:case 134265:case 134328:case 134360:case 134738:case 134777:case 134840:case 134872:case 136786:case 136825:case 136888:case 136920:case 140370:case 140409:case 140472:case 140504:case 141394:case 141408:case 141431:case 141433:case 141496:case 141514:case 141528:case 141556:case 141568:Zr();break;case-3:break;default:Hr()}}function Pr(){Vl.startNonterminal("AxisStep",Pl);switch(Hl){case 73:case 74:case 206:case 212:case 213:Ll(242);break;default:_l=Hl}switch(_l){case 45:case 26185:case 26186:case 26318:case 26324:case 26325:Ur();break;default:Br()}kl(238),Nl(),ni(),Vl.endNonterminal("AxisStep",Pl)}function Hr(){switch(Hl){case 73:case 74:case 206:case 212:case 213:Ll(242);break;default:_l=Hl}switch(_l){case 45:case 26185:case 26186:case 26318:case 26324:case 26325:zr();break;default:jr()}kl(238),ri()}function Br(){Vl.startNonterminal("ForwardStep",Pl);switch(Hl){case 82:Ll(245);break;case 93:case 111:case 112:case 135:case 136:case 229:Ll(242);break;default:_l=Hl}switch(_l){case 26194:case 26205:case 26223:case 26224:case 26247:case 26248:case 26341:Fr(),kl(257),Nl(),Jr();break;default:qr()}Vl.endNonterminal("ForwardStep",Pl)}function jr(){switch(Hl){case 82:Ll(245);break;case 93:case 111:case 112:case 135:case 136:case 229:Ll(242);break;default:_l=Hl}switch(_l){case 26194:case 26205:case 26223:case 26224:case 26247:case 26248:case 26341:Ir(),kl(257),Kr();break;default:Rr()}}function Fr(){Vl.startNonterminal("ForwardAxis",Pl);switch(Hl){case 93:Sl(93),kl(26),Sl(51);break;case 111:Sl(111),kl(26),Sl(51);break;case 82:Sl(82),kl(26),Sl(51);break;case 229:Sl(229),kl(26),Sl(51);break;case 112:Sl(112),kl(26),Sl(51);break;case 136:Sl(136),kl(26),Sl(51);break;default:Sl(135),kl(26),Sl(51)}Vl.endNonterminal("ForwardAxis",Pl)}function Ir(){switch(Hl){case 93:xl(93),kl(26),xl(51);break;case 111:xl(111),kl(26),xl(51);break;case 82:xl(82),kl(26),xl(51);break;case 229:xl(229),kl(26),xl(51);break;case 112:xl(112),kl(26),xl(51);break;case 136:xl(136),kl(26),xl(51);break;default:xl(135),kl(26),xl(51)}}function qr(){Vl.startNonterminal("AbbrevForwardStep",Pl),Hl==66&&Sl(66),kl(257),Nl(),Jr(),Vl.endNonterminal("AbbrevForwardStep",Pl)}function Rr(){Hl==66&&xl(66),kl(257),Kr()}function Ur(){Vl.startNonterminal("ReverseStep",Pl);switch(Hl){case 45:Vr();break;default:Wr(),kl(257),Nl(),Jr()}Vl.endNonterminal("ReverseStep",Pl)}function zr(){switch(Hl){case 45:$r();break;default:Xr(),kl(257),Kr()}}function Wr(){Vl.startNonterminal("ReverseAxis",Pl);switch(Hl){case 206:Sl(206),kl(26),Sl(51);break;case 73:Sl(73),kl(26),Sl(51);break;case 213:Sl(213),kl(26),Sl(51);break;case 212:Sl(212),kl(26),Sl(51);break;default:Sl(74),kl(26),Sl(51)}Vl.endNonterminal("ReverseAxis",Pl)}function Xr(){switch(Hl){case 206:xl(206),kl(26),xl(51);break;case 73:xl(73),kl(26),xl(51);break;case 213:xl(213),kl(26),xl(51);break;case 212:xl(212),kl(26),xl(51);break;default:xl(74),kl(26),xl(51)}}function Vr(){Vl.startNonterminal("AbbrevReverseStep",Pl),Sl(45),Vl.endNonterminal("AbbrevReverseStep",Pl)}function $r(){xl(45)}function Jr(){Vl.startNonterminal("NodeTest",Pl);switch(Hl){case 82:case 96:case 120:case 121:case 185:case 191:case 216:case 226:case 227:case 244:Ll(241);break;default:_l=Hl}switch(_l){case 17490:case 17504:case 17528:case 17529:case 17593:case 17599:case 17624:case 17634:case 17635:case 17652:Ps();break;default:Qr()}Vl.endNonterminal("NodeTest",Pl)}function Kr(){switch(Hl){case 82:case 96:case 120:case 121:case 185:case 191:case 216:case 226:case 227:case 244:Ll(241);break;default:_l=Hl}switch(_l){case 17490:case 17504:case 17528:case 17529:case 17593:case 17599:case 17624:case 17634:case 17635:case 17652:Hs();break;default:Gr()}}function Qr(){Vl.startNonterminal("NameTest",Pl);switch(Hl){case 5:Sl(5);break;default:Ha()}Vl.endNonterminal("NameTest",Pl)}function Gr(){switch(Hl){case 5:xl(5);break;default:Ba()}}function Yr(){Vl.startNonterminal("PostfixExpr",Pl),ol();for(;;){kl(241);if(Hl!=34&&Hl!=68)break;switch(Hl){case 68:Nl(),ii();break;default:Nl(),ei()}}Vl.endNonterminal("PostfixExpr",Pl)}function Zr(){ul();for(;;){kl(241);if(Hl!=34&&Hl!=68)break;switch(Hl){case 68:si();break;default:ti()}}}function ei(){Vl.startNonterminal("ArgumentList",Pl),Sl(34),kl(276);if(Hl!=37){Nl(),Ti();for(;;){kl(101);if(Hl!=41)break;Sl(41),kl(271),Nl(),Ti()}}Sl(37),Vl.endNonterminal("ArgumentList",Pl)}function ti(){xl(34),kl(276);if(Hl!=37){Ni();for(;;){kl(101);if(Hl!=41)break;xl(41),kl(271),Ni()}}xl(37)}function ni(){Vl.startNonterminal("PredicateList",Pl);for(;;){kl(238);if(Hl!=68)break;Nl(),ii()}Vl.endNonterminal("PredicateList",Pl)}function ri(){for(;;){kl(238);if(Hl!=68)break;si()}}function ii(){Vl.startNonterminal("Predicate",Pl),Sl(68),kl(267),Nl(),G(),Sl(69),Vl.endNonterminal("Predicate",Pl)}function si(){xl(68),kl(267),Y(),xl(69)}function oi(){Vl.startNonterminal("Literal",Pl);switch(Hl){case 11:Sl(11);break;default:ai()}Vl.endNonterminal("Literal",Pl)}function ui(){switch(Hl){case 11:xl(11);break;default:fi()}}function ai(){Vl.startNonterminal("NumericLiteral",Pl);switch(Hl){case 8:Sl(8);break;case 9:Sl(9);break;default:Sl(10)}Vl.endNonterminal("NumericLiteral",Pl)}function fi(){switch(Hl){case 8:xl(8);break;case 9:xl(9);break;default:xl(10)}}function li(){Vl.startNonterminal("VarRef",Pl),Sl(31),kl(255),Nl(),hi(),Vl.endNonterminal("VarRef",Pl)}function ci(){xl(31),kl(255),pi()}function hi(){Vl.startNonterminal("VarName",Pl),Ha(),Vl.endNonterminal("VarName",Pl)}function pi(){Ba()}function di(){Vl.startNonterminal("ParenthesizedExpr",Pl),Sl(34),kl(269),Hl!=37&&(Nl(),G()),Sl(37),Vl.endNonterminal("ParenthesizedExpr",Pl)}function vi(){xl(34),kl(269),Hl!=37&&Y(),xl(37)}function mi(){Vl.startNonterminal("ContextItemExpr",Pl),Sl(44),Vl.endNonterminal("ContextItemExpr",Pl)}function gi(){xl(44)}function yi(){Vl.startNonterminal("OrderedExpr",Pl),Sl(202),kl(87),Sl(276),kl(267),Nl(),G(),Sl(282),Vl.endNonterminal("OrderedExpr",Pl)}function bi(){xl(202),kl(87),xl(276),kl(267),Y(),xl(282)}function wi(){Vl.startNonterminal("UnorderedExpr",Pl),Sl(256),kl(87),Sl(276),kl(267),Nl(),G(),Sl(282),Vl.endNonterminal("UnorderedExpr",Pl)}function Ei(){xl(256),kl(87),xl(276),kl(267),Y(),xl(282)}function Si(){Vl.startNonterminal("FunctionCall",Pl),ja(),kl(22),Nl(),ei(),Vl.endNonterminal("FunctionCall",Pl)}function xi(){Fa(),kl(22),ti()}function Ti(){Vl.startNonterminal("Argument",Pl);switch(Hl){case 64:Ci();break;default:_f()}Vl.endNonterminal("Argument",Pl)}function Ni(){switch(Hl){case 64:ki();break;default:Df()}}function Ci(){Vl.startNonterminal("ArgumentPlaceholder",Pl),Sl(64),Vl.endNonterminal("ArgumentPlaceholder",Pl)}function ki(){xl(64)}function Li(){Vl.startNonterminal("Constructor",Pl);switch(Hl){case 54:case 55:case 59:Oi();break;default:Ji()}Vl.endNonterminal("Constructor",Pl)}function Ai(){switch(Hl){case 54:case 55:case 59:Mi();break;default:Ki()}}function Oi(){Vl.startNonterminal("DirectConstructor",Pl);switch(Hl){case 54:_i();break;case 55:Wi();break;default:Vi()}Vl.endNonterminal("DirectConstructor",Pl)}function Mi(){switch(Hl){case 54:Di();break;case 55:Xi();break;default:$i()}}function _i(){Vl.startNonterminal("DirElemConstructor",Pl),Sl(54),Al(4),Sl(20),Pi();switch(Hl){case 48:Sl(48);break;default:Sl(61);for(;;){Al(174);if(Hl==56)break;Ui()}Sl(56),Al(4),Sl(20),Al(12),Hl==21&&Sl(21),Al(8),Sl(61)}Vl.endNonterminal("DirElemConstructor",Pl)}function Di(){xl(54),Al(4),xl(20),Hi();switch(Hl){case 48:xl(48);break;default:xl(61);for(;;){Al(174);if(Hl==56)break;zi()}xl(56),Al(4),xl(20),Al(12),Hl==21&&xl(21),Al(8),xl(61)}}function Pi(){Vl.startNonterminal("DirAttributeList",Pl);for(;;){Al(19);if(Hl!=21)break;Sl(21),Al(91),Hl==20&&(Sl(20),Al(11),Hl==21&&Sl(21),Al(7),Sl(60),Al(18),Hl==21&&Sl(21),Bi())}Vl.endNonterminal("DirAttributeList",Pl)}function Hi(){for(;;){Al(19);if(Hl!=21)break;xl(21),Al(91),Hl==20&&(xl(20),Al(11),Hl==21&&xl(21),Al(7),xl(60),Al(18),Hl==21&&xl(21),ji())}}function Bi(){Vl.startNonterminal("DirAttributeValue",Pl),Al(14);switch(Hl){case 28:Sl(28);for(;;){Al(167);if(Hl==28)break;switch(Hl){case 13:Sl(13);break;default:Fi()}}Sl(28);break;default:Sl(33);for(;;){Al(168);if(Hl==33)break;switch(Hl){case 14:Sl(14);break;default:qi()}}Sl(33)}Vl.endNonterminal("DirAttributeValue",Pl)}function ji(){Al(14);switch(Hl){case 28:xl(28);for(;;){Al(167);if(Hl==28)break;switch(Hl){case 13:xl(13);break;default:Ii()}}xl(28);break;default:xl(33);for(;;){Al(168);if(Hl==33)break;switch(Hl){case 14:xl(14);break;default:Ri()}}xl(33)}}function Fi(){Vl.startNonterminal("QuotAttrValueContent",Pl);switch(Hl){case 16:Sl(16);break;default:Vf()}Vl.endNonterminal("QuotAttrValueContent",Pl)}function Ii(){switch(Hl){case 16:xl(16);break;default:$f()}}function qi(){Vl.startNonterminal("AposAttrValueContent",Pl);switch(Hl){case 17:Sl(17);break;default:Vf()}Vl.endNonterminal("AposAttrValueContent",Pl)}function Ri(){switch(Hl){case 17:xl(17);break;default:$f()}}function Ui(){Vl.startNonterminal("DirElemContent",Pl);switch(Hl){case 54:case 55:case 59:Oi();break;case 4:Sl(4);break;case 15:Sl(15);break;default:Vf()}Vl.endNonterminal("DirElemContent",Pl)}function zi(){switch(Hl){case 54:case 55:case 59:Mi();break;case 4:xl(4);break;case 15:xl(15);break;default:$f()}}function Wi(){Vl.startNonterminal("DirCommentConstructor",Pl),Sl(55),Al(1),Sl(2),Al(6),Sl(43),Vl.endNonterminal("DirCommentConstructor",Pl)}function Xi(){xl(55),Al(1),xl(2),Al(6),xl(43)}function Vi(){Vl.startNonterminal("DirPIConstructor",Pl),Sl(59),Al(3),Sl(18),Al(13),Hl==21&&(Sl(21),Al(2),Sl(3)),Al(9),Sl(65),Vl.endNonterminal("DirPIConstructor",Pl)}function $i(){xl(59),Al(3),xl(18),Al(13),Hl==21&&(xl(21),Al(2),xl(3)),Al(9),xl(65)}function Ji(){Vl.startNonterminal("ComputedConstructor",Pl);switch(Hl){case 119:Qf();break;case 121:Qi();break;case 82:Yf();break;case 184:Yi();break;case 244:il();break;case 96:nl();break;default:el()}Vl.endNonterminal("ComputedConstructor",Pl)}function Ki(){switch(Hl){case 119:Gf();break;case 121:Gi();break;case 82:Zf();break;case 184:Zi();break;case 244:sl();break;case 96:rl();break;default:tl()}}function Qi(){Vl.startNonterminal("CompElemConstructor",Pl),Sl(121),kl(258);switch(Hl){case 276:Sl(276),kl(267),Nl(),G(),Sl(282);break;default:Nl(),Ha()}kl(87),Sl(276),kl(277),Hl!=282&&(Nl(),Jf()),Sl(282),Vl.endNonterminal("CompElemConstructor",Pl)}function Gi(){xl(121),kl(258);switch(Hl){case 276:xl(276),kl(267),Y(),xl(282);break;default:Ba()}kl(87),xl(276),kl(277),Hl!=282&&Kf(),xl(282)}function Yi(){Vl.startNonterminal("CompNamespaceConstructor",Pl),Sl(184),kl(251);switch(Hl){case 276:Sl(276),kl(267),Nl(),ns(),Sl(282);break;default:Nl(),es()}kl(87),Sl(276),kl(267),Nl(),is(),Sl(282),Vl.endNonterminal("CompNamespaceConstructor",Pl)}function Zi(){xl(184),kl(251);switch(Hl){case 276:xl(276),kl(267),rs(),xl(282);break;default:ts()}kl(87),xl(276),kl(267),ss(),xl(282)}function es(){Vl.startNonterminal("Prefix",Pl),Ia(),Vl.endNonterminal("Prefix",Pl)}function ts(){qa()}function ns(){Vl.startNonterminal("PrefixExpr",Pl),G(),Vl.endNonterminal("PrefixExpr",Pl)}function rs(){Y()}function is(){Vl.startNonterminal("URIExpr",Pl),G(),Vl.endNonterminal("URIExpr",Pl)}function ss(){Y()}function os(){Vl.startNonterminal("FunctionItemExpr",Pl);switch(Hl){case 145:Ll(92);break;default:_l=Hl}switch(_l){case 32:case 17553:ls();break;default:as()}Vl.endNonterminal("FunctionItemExpr",Pl)}function us(){switch(Hl){case 145:Ll(92);break;default:_l=Hl}switch(_l){case 32:case 17553:cs();break;default:fs()}}function as(){Vl.startNonterminal("NamedFunctionRef",Pl),Ha(),kl(20),Sl(29),kl(16),Sl(8),Vl.endNonterminal("NamedFunctionRef",Pl)}function fs(){Ba(),kl(20),xl(29),kl(16),xl(8)}function ls(){Vl.startNonterminal("InlineFunctionExpr",Pl);for(;;){kl(97);if(Hl!=32)break;Nl(),B()}Sl(145),kl(22),Sl(34),kl(94),Hl==31&&(Nl(),U()),Sl(37),kl(111),Hl==79&&(Sl(79),kl(260),Nl(),ms()),kl(87),Nl(),V(),Vl.endNonterminal("InlineFunctionExpr",Pl)}function cs(){for(;;){kl(97);if(Hl!=32)break;j()}xl(145),kl(22),xl(34),kl(94),Hl==31&&z(),xl(37),kl(111),Hl==79&&(xl(79),kl(260),gs()),kl(87),$()}function hs(){Vl.startNonterminal("SingleType",Pl),vo(),kl(227),Hl==64&&Sl(64),Vl.endNonterminal("SingleType",Pl)}function ps(){mo(),kl(227),Hl==64&&xl(64)}function ds(){Vl.startNonterminal("TypeDeclaration",Pl),Sl(79),kl(260),Nl(),ms(),Vl.endNonterminal("TypeDeclaration",Pl)}function vs(){xl(79),kl(260),gs()}function ms(){Vl.startNonterminal("SequenceType",Pl);switch(Hl){case 124:Ll(243);break;default:_l=Hl}switch(_l){case 17532:Sl(124),kl(22),Sl(34),kl(23),Sl(37);break;default:ws(),kl(239);switch(Hl){case 39:case 40:case 64:Nl(),ys();break;default:}}Vl.endNonterminal("SequenceType",Pl)}function gs(){switch(Hl){case 124:Ll(243);break;default:_l=Hl}switch(_l){case 17532:xl(124),kl(22),xl(34),kl(23),xl(37);break;default:Es(),kl(239);switch(Hl){case 39:case 40:case 64:bs();break;default:}}}function ys(){Vl.startNonterminal("OccurrenceIndicator",Pl);switch(Hl){case 64:Sl(64);break;case 39:Sl(39);break;default:Sl(40)}Vl.endNonterminal("OccurrenceIndicator",Pl)}function bs(){switch(Hl){case 64:xl(64);break;case 39:xl(39);break;default:xl(40)}}function ws(){Vl.startNonterminal("ItemType",Pl);switch(Hl){case 78:case 82:case 96:case 120:case 121:case 145:case 165:case 167:case 185:case 191:case 194:case 216:case 226:case 227:case 242:case 244:Ll(243);break;default:_l=Hl}switch(_l){case 17490:case 17504:case 17528:case 17529:case 17593:case 17599:case 17624:case 17634:case 17635:case 17652:Ps();break;case 17573:Sl(165),kl(22),Sl(34),kl(23),Sl(37);break;case 32:case 17553:bo();break;case 34:No();break;case 17486:case 17575:case 17602:Ss();break;case 17650:Ts();break;default:_s()}Vl.endNonterminal("ItemType",Pl)}function Es(){switch(Hl){case 78:case 82:case 96:case 120:case 121:case 145:case 165:case 167:case 185:case 191:case 194:case 216:case 226:case 227:case 242:case 244:Ll(243);break;default:_l=Hl}switch(_l){case 17490:case 17504:case 17528:case 17529:case 17593:case 17599:case 17624:case 17634:case 17635:case 17652:Hs();break;case 17573:xl(165),kl(22),xl(34),kl(23),xl(37);break;case 32:case 17553:wo();break;case 34:Co();break;case 17486:case 17575:case 17602:xs();break;case 17650:Ns();break;default:Ds()}}function Ss(){Vl.startNonterminal("JSONTest",Pl);switch(Hl){case 167:Cs();break;case 194:Ls();break;default:Os()}Vl.endNonterminal("JSONTest",Pl)}function xs(){switch(Hl){case 167:ks();break;case 194:As();break;default:Ms()}}function Ts(){Vl.startNonterminal("StructuredItemTest",Pl),Sl(242),kl(22),Sl(34),kl(23),Sl(37),Vl.endNonterminal("StructuredItemTest",Pl)}function Ns(){xl(242),kl(22),xl(34),kl(23),xl(37)}function Cs(){Vl.startNonterminal("JSONItemTest",Pl),Sl(167),kl(22),Sl(34),kl(23),Sl(37),Vl.endNonterminal("JSONItemTest",Pl)}function ks(){xl(167),kl(22),xl(34),kl(23),xl(37)}function Ls(){Vl.startNonterminal("JSONObjectTest",Pl),Sl(194),kl(22),Sl(34),kl(23),Sl(37),Vl.endNonterminal("JSONObjectTest",Pl)}function As(){xl(194),kl(22),xl(34),kl(23),xl(37)}function Os(){Vl.startNonterminal("JSONArrayTest",Pl),Sl(78),kl(22),Sl(34),kl(23),Sl(37),Vl.endNonterminal("JSONArrayTest",Pl)}function Ms(){xl(78),kl(22),xl(34),kl(23),xl(37)}function _s(){Vl.startNonterminal("AtomicOrUnionType",Pl),Ha(),Vl.endNonterminal("AtomicOrUnionType",Pl)}function Ds(){Ba()}function Ps(){Vl.startNonterminal("KindTest",Pl);switch(Hl){case 120:Fs();break;case 121:no();break;case 82:Js();break;case 227:oo();break;case 226:Ys();break;case 216:Vs();break;case 96:Us();break;case 244:qs();break;case 185:Ws();break;default:Bs()}Vl.endNonterminal("KindTest",Pl)}function Hs(){switch(Hl){case 120:Is();break;case 121:ro();break;case 82:Ks();break;case 227:uo();break;case 226:Zs();break;case 216:$s();break;case 96:zs();break;case 244:Rs();break;case 185:Xs();break;default:js()}}function Bs(){Vl.startNonterminal("AnyKindTest",Pl),Sl(191),kl(22),Sl(34),kl(23),Sl(37),Vl.endNonterminal("AnyKindTest",Pl)}function js(){xl(191),kl(22),xl(34),kl(23),xl(37)}function Fs(){Vl.startNonterminal("DocumentTest",Pl),Sl(120),kl(22),Sl(34),kl(144);if(Hl!=37)switch(Hl){case 121:Nl(),no();break;default:Nl(),oo()}kl(23),Sl(37),Vl.endNonterminal("DocumentTest",Pl)}function Is(){xl(120),kl(22),xl(34),kl(144);if(Hl!=37)switch(Hl){case 121:ro();break;default:uo()}kl(23),xl(37)}function qs(){Vl.startNonterminal("TextTest",Pl),Sl(244),kl(22),Sl(34),kl(23),Sl(37),Vl.endNonterminal("TextTest",Pl)}function Rs(){xl(244),kl(22),xl(34),kl(23),xl(37)}function Us(){Vl.startNonterminal("CommentTest",Pl),Sl(96),kl(22),Sl(34),kl(23),Sl(37),Vl.endNonterminal("CommentTest",Pl)}function zs(){xl(96),kl(22),xl(34),kl(23),xl(37)}function Ws(){Vl.startNonterminal("NamespaceNodeTest",Pl),Sl(185),kl(22),Sl(34),kl(23),Sl(37),Vl.endNonterminal("NamespaceNodeTest",Pl)}function Xs(){xl(185),kl(22),xl(34),kl(23),xl(37)}function Vs(){Vl.startNonterminal("PITest",Pl),Sl(216),kl(22),Sl(34),kl(253);if(Hl!=37)switch(Hl){case 11:Sl(11);break;default:Nl(),Ia()}kl(23),Sl(37),Vl.endNonterminal("PITest",Pl)}function $s(){xl(216),kl(22),xl(34),kl(253);if(Hl!=37)switch(Hl){case 11:xl(11);break;default:qa()}kl(23),xl(37)}function Js(){Vl.startNonterminal("AttributeTest",Pl),Sl(82),kl(22),Sl(34),kl(261),Hl!=37&&(Nl(),Qs(),kl(101),Hl==41&&(Sl(41),kl(255),Nl(),go())),kl(23),Sl(37),Vl.endNonterminal("AttributeTest",Pl)}function Ks(){xl(82),kl(22),xl(34),kl(261),Hl!=37&&(Gs(),kl(101),Hl==41&&(xl(41),kl(255),yo())),kl(23),xl(37)}function Qs(){Vl.startNonterminal("AttribNameOrWildcard",Pl);switch(Hl){case 38:Sl(38);break;default:lo()}Vl.endNonterminal("AttribNameOrWildcard",Pl)}function Gs(){switch(Hl){case 38:xl(38);break;default:co()}}function Ys(){Vl.startNonterminal("SchemaAttributeTest",Pl),Sl(226),kl(22),Sl(34),kl(255),Nl(),eo(),kl(23),Sl(37),Vl.endNonterminal("SchemaAttributeTest",Pl)}function Zs(){xl(226),kl(22),xl(34),kl(255),to(),kl(23),xl(37)}function eo(){Vl.startNonterminal("AttributeDeclaration",Pl),lo(),Vl.endNonterminal("AttributeDeclaration",Pl)}function to(){co()}function no(){Vl.startNonterminal("ElementTest",Pl),Sl(121),kl(22),Sl(34),kl(261),Hl!=37&&(Nl(),io(),kl(101),Hl==41&&(Sl(41),kl(255),Nl(),go(),kl(102),Hl==64&&Sl(64))),kl(23),Sl(37),Vl.endNonterminal("ElementTest",Pl)}function ro(){xl(121),kl(22),xl(34),kl(261),Hl!=37&&(so(),kl(101),Hl==41&&(xl(41),kl(255),yo(),kl(102),Hl==64&&xl(64))),kl(23),xl(37)}function io(){Vl.startNonterminal("ElementNameOrWildcard",Pl);switch(Hl){case 38:Sl(38);break;default:ho()}Vl.endNonterminal("ElementNameOrWildcard",Pl)}function so(){switch(Hl){case 38:xl(38);break;default:po()}}function oo(){Vl.startNonterminal("SchemaElementTest",Pl),Sl(227),kl(22),Sl(34),kl(255),Nl(),ao(),kl(23),Sl(37),Vl.endNonterminal("SchemaElementTest",Pl)}function uo(){xl(227),kl(22),xl(34),kl(255),fo(),kl(23),xl(37)}function ao(){Vl.startNonterminal("ElementDeclaration",Pl),ho(),Vl.endNonterminal("ElementDeclaration",Pl)}function fo(){po()}function lo(){Vl.startNonterminal("AttributeName",Pl),Ha(),Vl.endNonterminal("AttributeName",Pl)}function co(){Ba()}function ho(){Vl.startNonterminal("ElementName",Pl),Ha(),Vl.endNonterminal("ElementName",Pl)}function po(){Ba()}function vo(){Vl.startNonterminal("SimpleTypeName",Pl),go(),Vl.endNonterminal("SimpleTypeName",Pl)}function mo(){yo()}function go(){Vl.startNonterminal("TypeName",Pl),Ha(),Vl.endNonterminal("TypeName",Pl)}function yo(){Ba()}function bo(){Vl.startNonterminal("FunctionTest",Pl);for(;;){kl(97);if(Hl!=32)break;Nl(),B()}switch(Hl){case 145:Ll(22);break;default:_l=Hl}_l=Kl(5,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{So(),_l=-1}catch(a){_l=-2}Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(5,Pl,_l)}switch(_l){case-1:Nl(),Eo();break;default:Nl(),xo()}Vl.endNonterminal("FunctionTest",Pl)}function wo(){for(;;){kl(97);if(Hl!=32)break;j()}switch(Hl){case 145:Ll(22);break;default:_l=Hl}_l=Kl(5,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{So(),Jl(5,t,-1),_l=-3}catch(a){_l=-2,Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(5,t,-2)}}switch(_l){case-1:So();break;case-3:break;default:To()}}function Eo(){Vl.startNonterminal("AnyFunctionTest",Pl),Sl(145),kl(22),Sl(34),kl(24),Sl(38),kl(23),Sl(37),Vl.endNonterminal("AnyFunctionTest",Pl)}function So(){xl(145),kl(22),xl(34),kl(24),xl(38),kl(23),xl(37)}function xo(){Vl.startNonterminal("TypedFunctionTest",Pl),Sl(145),kl(22),Sl(34),kl(263);if(Hl!=37){Nl(),ms();for(;;){kl(101);if(Hl!=41)break;Sl(41),kl(260),Nl(),ms()}}Sl(37),kl(30),Sl(79),kl(260),Nl(),ms(),Vl.endNonterminal("TypedFunctionTest",Pl)}function To(){xl(145),kl(22),xl(34),kl(263);if(Hl!=37){gs();for(;;){kl(101);if(Hl!=41)break;xl(41),kl(260),gs()}}xl(37),kl(30),xl(79),kl(260),gs()}function No(){Vl.startNonterminal("ParenthesizedItemType",Pl),Sl(34),kl(260),Nl(),ws(),kl(23),Sl(37),Vl.endNonterminal("ParenthesizedItemType",Pl)}function Co(){xl(34),kl(260),Es(),kl(23),xl(37)}function ko(){Vl.startNonterminal("RevalidationDecl",Pl),Sl(108),kl(72),Sl(222),kl(152);switch(Hl){case 240:Sl(240);break;case 171:Sl(171);break;default:Sl(233)}Vl.endNonterminal("RevalidationDecl",Pl)}function Lo(){Vl.startNonterminal("InsertExprTargetChoice",Pl);switch(Hl){case 70:Sl(70);break;case 84:Sl(84);break;default:if(Hl==79){Sl(79),kl(119);switch(Hl){case 134:Sl(134);break;default:Sl(170)}}kl(54),Sl(163)}Vl.endNonterminal("InsertExprTargetChoice",Pl)}function Ao(){switch(Hl){case 70:xl(70);break;case 84:xl(84);break;default:if(Hl==79){xl(79),kl(119);switch(Hl){case 134:xl(134);break;default:xl(170)}}kl(54),xl(163)}}function Oo(){Vl.startNonterminal("InsertExpr",Pl),Sl(159),kl(129);switch(Hl){case 191:Sl(191);break;default:Sl(192)}kl(267),Nl(),Fo(),Nl(),Lo(),kl(267),Nl(),qo(),Vl.endNonterminal("InsertExpr",Pl)}function Mo(){xl(159),kl(129);switch(Hl){case 191:xl(191);break;default:xl(192)}kl(267),Io(),Ao(),kl(267),Ro()}function _o(){Vl.startNonterminal("DeleteExpr",Pl),Sl(110),kl(129);switch(Hl){case 191:Sl(191);break;default:Sl(192)}kl(267),Nl(),qo(),Vl.endNonterminal("DeleteExpr",Pl)}function Do(){xl(110),kl(129);switch(Hl){case 191:xl(191);break;default:xl(192)}kl(267),Ro()}function Po(){Vl.startNonterminal("ReplaceExpr",Pl),Sl(219),kl(130),Hl==261&&(Sl(261),kl(64),Sl(196)),kl(62),Sl(191),kl(267),Nl(),qo(),Sl(270),kl(267),Nl(),_f(),Vl.endNonterminal("ReplaceExpr",Pl)}function Ho(){xl(219),kl(130),Hl==261&&(xl(261),kl(64),xl(196)),kl(62),xl(191),kl(267),Ro(),xl(270),kl(267),Df()}function Bo(){Vl.startNonterminal("RenameExpr",Pl),Sl(218),kl(62),Sl(191),kl(267),Nl(),qo(),Sl(79),kl(267),Nl(),Uo(),Vl.endNonterminal("RenameExpr",Pl)}function jo(){xl(218),kl(62),xl(191),kl(267),Ro(),xl(79),kl(267),zo()}function Fo(){Vl.startNonterminal("SourceExpr",Pl),_f(),Vl.endNonterminal("SourceExpr",Pl)}function Io(){Df()}function qo(){Vl.startNonterminal("TargetExpr",Pl),_f(),Vl.endNonterminal("TargetExpr",Pl)}function Ro(){Df()}function Uo(){Vl.startNonterminal("NewNameExpr",Pl),_f(),Vl.endNonterminal("NewNameExpr",Pl)}function zo(){Df()}function Wo(){Vl.startNonterminal("TransformExpr",Pl),Sl(103),kl(21),Nl(),Vo();for(;;){if(Hl!=41)break;Sl(41),kl(21),Nl(),Vo()}Sl(181),kl(267),Nl(),_f(),Sl(220),kl(267),Nl(),_f(),Vl.endNonterminal("TransformExpr",Pl)}function Xo(){xl(103),kl(21),$o();for(;;){if(Hl!=41)break;xl(41),kl(21),$o()}xl(181),kl(267),Df(),xl(220),kl(267),Df()}function Vo(){Vl.startNonterminal("TransformSpec",Pl),Sl(31),kl(255),Nl(),hi(),kl(27),Sl(52),kl(267),Nl(),_f(),Vl.endNonterminal("TransformSpec",Pl)}function $o(){xl(31),kl(255),pi(),kl(27),xl(52),kl(267),Df()}function Jo(){Vl.startNonterminal("FTSelection",Pl),Yo();for(;;){kl(212);switch(Hl){case 81:Ll(151);break;default:_l=Hl}if(_l!=115&&_l!=117&&_l!=127&&_l!=202&&_l!=223&&_l!=269&&_l!=64593&&_l!=121425)break;Nl(),Su()}Vl.endNonterminal("FTSelection",Pl)}function Ko(){Zo();for(;;){kl(212);switch(Hl){case 81:Ll(151);break;default:_l=Hl}if(_l!=115&&_l!=117&&_l!=127&&_l!=202&&_l!=223&&_l!=269&&_l!=64593&&_l!=121425)break;xu()}}function Qo(){Vl.startNonterminal("FTWeight",Pl),Sl(264),kl(87),Sl(276),kl(267),Nl(),G(),Sl(282),Vl.endNonterminal("FTWeight",Pl)}function Go(){xl(264),kl(87),xl(276),kl(267),Y(),xl(282)}function Yo(){Vl.startNonterminal("FTOr",Pl),eu();for(;;){if(Hl!=144)break;Sl(144),kl(162),Nl(),eu()}Vl.endNonterminal("FTOr",Pl)}function Zo(){tu();for(;;){if(Hl!=144)break;xl(144),kl(162),tu()}}function eu(){Vl.startNonterminal("FTAnd",Pl),nu();for(;;){if(Hl!=142)break;Sl(142),kl(162),Nl(),nu()}Vl.endNonterminal("FTAnd",Pl)}function tu(){ru();for(;;){if(Hl!=142)break;xl(142),kl(162),ru()}}function nu(){Vl.startNonterminal("FTMildNot",Pl),iu();for(;;){kl(213);if(Hl!=193)break;Sl(193),kl(53),Sl(154),kl(162),Nl(),iu()}Vl.endNonterminal("FTMildNot",Pl)}function ru(){su();for(;;){kl(213);if(Hl!=193)break;xl(193),kl(53),xl(154),kl(162),su()}}function iu(){Vl.startNonterminal("FTUnaryNot",Pl),Hl==143&&Sl(143),kl(155),Nl(),ou(),Vl.endNonterminal("FTUnaryNot",Pl)}function su(){Hl==143&&xl(143),kl(155),uu()}function ou(){Vl.startNonterminal("FTPrimaryWithOptions",Pl),au(),kl(215),Hl==259&&(Nl(),Fu()),Hl==264&&(Nl(),Qo()),Vl.endNonterminal("FTPrimaryWithOptions",Pl)}function uu(){fu(),kl(215),Hl==259&&Iu(),Hl==264&&Go()}function au(){Vl.startNonterminal("FTPrimary",Pl);switch(Hl){case 34:Sl(34),kl(162),Nl(),Jo(),Sl(37);break;case 35:du();break;default:lu(),kl(216),Hl==195&&(Nl(),yu())}Vl.endNonterminal("FTPrimary",Pl)}function fu(){switch(Hl){case 34:xl(34),kl(162),Ko(),xl(37);break;case 35:vu();break;default:cu(),kl(216),Hl==195&&bu()}}function lu(){Vl.startNonterminal("FTWords",Pl),hu(),kl(222);if(Hl==71||Hl==76||Hl==210)Nl(),mu();Vl.endNonterminal("FTWords",Pl)}function cu(){pu(),kl(222),(Hl==71||Hl==76||Hl==210)&&gu()}function hu(){Vl.startNonterminal("FTWordsValue",Pl);switch(Hl){case 11:Sl(11);break;default:Sl(276),kl(267),Nl(),G(),Sl(282)}Vl.endNonterminal("FTWordsValue",Pl)}function pu(){switch(Hl){case 11:xl(11);break;default:xl(276),kl(267),Y(),xl(282)}}function du(){Vl.startNonterminal("FTExtensionSelection",Pl);for(;;){Nl(),Cr(),kl(100);if(Hl!=35)break}Sl(276),kl(166),Hl!=282&&(Nl(),Jo()),Sl(282),Vl.endNonterminal("FTExtensionSelection",Pl)}function vu(){for(;;){kr(),kl(100);if(Hl!=35)break}xl(276),kl(166),Hl!=282&&Ko(),xl(282)}function mu(){Vl.startNonterminal("FTAnyallOption",Pl);switch(Hl){case 76:Sl(76),kl(219),Hl==272&&Sl(272);break;case 71:Sl(71),kl(220),Hl==273&&Sl(273);break;default:Sl(210)}Vl.endNonterminal("FTAnyallOption",Pl)}function gu(){switch(Hl){case 76:xl(76),kl(219),Hl==272&&xl(272);break;case 71:xl(71),kl(220),Hl==273&&xl(273);break;default:xl(210)}}function yu(){Vl.startNonterminal("FTTimes",Pl),Sl(195),kl(149),Nl(),wu(),Sl(247),Vl.endNonterminal("FTTimes",Pl)}function bu(){xl(195),kl(149),Eu(),xl(247)}function wu(){Vl.startNonterminal("FTRange",Pl);switch(Hl){case 130:Sl(130),kl(267),Nl(),Vn();break;case 81:Sl(81),kl(125);switch(Hl){case 173:Sl(173),kl(267),Nl(),Vn();break;default:Sl(183),kl(267),Nl(),Vn()}break;default:Sl(140),kl(267),Nl(),Vn(),Sl(248),kl(267),Nl(),Vn()}Vl.endNonterminal("FTRange",Pl)}function Eu(){switch(Hl){case 130:xl(130),kl(267),$n();break;case 81:xl(81),kl(125);switch(Hl){case 173:xl(173),kl(267),$n();break;default:xl(183),kl(267),$n()}break;default:xl(140),kl(267),$n(),xl(248),kl(267),$n()}}function Su(){Vl.startNonterminal("FTPosFilter",Pl);switch(Hl){case 202:Tu();break;case 269:Cu();break;case 117:Lu();break;case 115:case 223:_u();break;default:Bu()}Vl.endNonterminal("FTPosFilter",Pl)}function xu(){switch(Hl){case 202:Nu();break;case 269:ku();break;case 117:Au();break;case 115:case 223:Du();break;default:ju()}}function Tu(){Vl.startNonterminal("FTOrder",Pl),Sl(202),Vl.endNonterminal("FTOrder",Pl)}function Nu(){xl(202)}function Cu(){Vl.startNonterminal("FTWindow",Pl),Sl(269),kl(267),Nl(),Vn(),Nl(),Ou(),Vl.endNonterminal("FTWindow",Pl)}function ku(){xl(269),kl(267),$n(),Mu()}function Lu(){Vl.startNonterminal("FTDistance",Pl),Sl(117),kl(149),Nl(),wu(),Nl(),Ou(),Vl.endNonterminal("FTDistance",Pl)}function Au(){xl(117),kl(149),Eu(),Mu()}function Ou(){Vl.startNonterminal("FTUnit",Pl);switch(Hl){case 273:Sl(273);break;case 232:Sl(232);break;default:Sl(205)}Vl.endNonterminal("FTUnit",Pl)}function Mu(){switch(Hl){case 273:xl(273);break;case 232:xl(232);break;default:xl(205)}}function _u(){Vl.startNonterminal("FTScope",Pl);switch(Hl){case 223:Sl(223);break;default:Sl(115)}kl(132),Nl(),Pu(),Vl.endNonterminal("FTScope",Pl)}function Du(){switch(Hl){case 223:xl(223);break;default:xl(115)}kl(132),Hu()}function Pu(){Vl.startNonterminal("FTBigUnit",Pl);switch(Hl){case 231:Sl(231);break;default:Sl(204)}Vl.endNonterminal("FTBigUnit",Pl)}function Hu(){switch(Hl){case 231:xl(231);break;default:xl(204)}}function Bu(){Vl.startNonterminal("FTContent",Pl);switch(Hl){case 81:Sl(81),kl(117);switch(Hl){case 237:Sl(237);break;default:Sl(126)}break;default:Sl(127),kl(42),Sl(100)}Vl.endNonterminal("FTContent",Pl)}function ju(){switch(Hl){case 81:xl(81),kl(117);switch(Hl){case 237:xl(237);break;default:xl(126)}break;default:xl(127),kl(42),xl(100)}}function Fu(){Vl.startNonterminal("FTMatchOptions",Pl);for(;;){Sl(259),kl(182),Nl(),qu(),kl(215);if(Hl!=259)break}Vl.endNonterminal("FTMatchOptions",Pl)}function Iu(){for(;;){xl(259),kl(182),Ru(),kl(215);if(Hl!=259)break}}function qu(){Vl.startNonterminal("FTMatchOption",Pl);switch(Hl){case 188:Ll(161);break;default:_l=Hl}switch(_l){case 169:oa();break;case 268:case 137404:aa();break;case 246:case 126140:Ju();break;case 238:case 122044:Vu();break;case 114:Wu();break;case 239:case 122556:ea();break;case 199:la();break;default:Uu()}Vl.endNonterminal("FTMatchOption",Pl)}function Ru(){switch(Hl){case 188:Ll(161);break;default:_l=Hl}switch(_l){case 169:ua();break;case 268:case 137404:fa();break;case 246:case 126140:Ku();break;case 238:case 122044:$u();break;case 114:Xu();break;case 239:case 122556:ta();break;case 199:ca();break;default:zu()}}function Uu(){Vl.startNonterminal("FTCaseOption",Pl);switch(Hl){case 88:Sl(88),kl(124);switch(Hl){case 158:Sl(158);break;default:Sl(230)}break;case 177:Sl(177);break;default:Sl(258)}Vl.endNonterminal("FTCaseOption",Pl)}function zu(){switch(Hl){case 88:xl(88),kl(124);switch(Hl){case 158:xl(158);break;default:xl(230)}break;case 177:xl(177);break;default:xl(258)}}function Wu(){Vl.startNonterminal("FTDiacriticsOption",Pl),Sl(114),kl(124);switch(Hl){case 158:Sl(158);break;default:Sl(230)}Vl.endNonterminal("FTDiacriticsOption",Pl)}function Xu(){xl(114),kl(124);switch(Hl){case 158:xl(158);break;default:xl(230)}}function Vu(){Vl.startNonterminal("FTStemOption",Pl);switch(Hl){case 238:Sl(238);break;default:Sl(188),kl(74),Sl(238)}Vl.endNonterminal("FTStemOption",Pl)}function $u(){switch(Hl){case 238:xl(238);break;default:xl(188),kl(74),xl(238)}}function Ju(){Vl.startNonterminal("FTThesaurusOption",Pl);switch(Hl){case 246:Sl(246),kl(142);switch(Hl){case 81:Nl(),Qu();break;case 109:Sl(109);break;default:Sl(34),kl(112);switch(Hl){case 81:Nl(),Qu();break;default:Sl(109)}for(;;){kl(101);if(Hl!=41)break;Sl(41),kl(31),Nl(),Qu()}Sl(37)}break;default:Sl(188),kl(78),Sl(246)}Vl.endNonterminal("FTThesaurusOption",Pl)}function Ku(){switch(Hl){case 246:xl(246),kl(142);switch(Hl){case 81:Gu();break;case 109:xl(109);break;default:xl(34),kl(112);switch(Hl){case 81:Gu();break;default:xl(109)}for(;;){kl(101);if(Hl!=41)break;xl(41),kl(31),Gu()}xl(37)}break;default:xl(188),kl(78),xl(246)}}function Qu(){Vl.startNonterminal("FTThesaurusID",Pl),Sl(81),kl(15),Sl(7),kl(221),Hl==217&&(Sl(217),kl(17),Sl(11)),kl(217);switch(Hl){case 81:Ll(165);break;default:_l=Hl}if(_l==130||_l==140||_l==88657||_l==93777)Nl(),Yu(),kl(58),Sl(175);Vl.endNonterminal("FTThesaurusID",Pl)}function Gu(){xl(81),kl(15),xl(7),kl(221),Hl==217&&(xl(217),kl(17),xl(11)),kl(217);switch(Hl){case 81:Ll(165);break;default:_l=Hl}if(_l==130||_l==140||_l==88657||_l==93777)Zu(),kl(58),xl(175)}function Yu(){Vl.startNonterminal("FTLiteralRange",Pl);switch(Hl){case 130:Sl(130),kl(16),Sl(8);break;case 81:Sl(81),kl(125);switch(Hl){case 173:Sl(173),kl(16),Sl(8);break;default:Sl(183),kl(16),Sl(8)}break;default:Sl(140),kl(16),Sl(8),kl(79),Sl(248),kl(16),Sl(8)}Vl.endNonterminal("FTLiteralRange",Pl)}function Zu(){switch(Hl){case 130:xl(130),kl(16),xl(8);break;case 81:xl(81),kl(125);switch(Hl){case 173:xl(173),kl(16),xl(8);break;default:xl(183),kl(16),xl(8)}break;default:xl(140),kl(16),xl(8),kl(79),xl(248),kl(16),xl(8)}}function ea(){Vl.startNonterminal("FTStopWordOption",Pl);switch(Hl){case 239:Sl(239),kl(86),Sl(273),kl(142);switch(Hl){case 109:Sl(109);for(;;){kl(218);if(Hl!=131&&Hl!=254)break;Nl(),ia()}break;default:Nl(),na();for(;;){kl(218);if(Hl!=131&&Hl!=254)break;Nl(),ia()}}break;default:Sl(188),kl(75),Sl(239),kl(86),Sl(273)}Vl.endNonterminal("FTStopWordOption",Pl)}function ta(){switch(Hl){case 239:xl(239),kl(86),xl(273),kl(142);switch(Hl){case 109:xl(109);for(;;){kl(218);if(Hl!=131&&Hl!=254)break;sa()}break;default:ra();for(;;){kl(218);if(Hl!=131&&Hl!=254)break;sa()}}break;default:xl(188),kl(75),xl(239),kl(86),xl(273)}}function na(){Vl.startNonterminal("FTStopWords",Pl);switch(Hl){case 81:Sl(81),kl(15),Sl(7);break;default:Sl(34),kl(17),Sl(11);for(;;){kl(101);if(Hl!=41)break;Sl(41),kl(17),Sl(11)}Sl(37)}Vl.endNonterminal("FTStopWords",Pl)}function ra(){switch(Hl){case 81:xl(81),kl(15),xl(7);break;default:xl(34),kl(17),xl(11);for(;;){kl(101);if(Hl!=41)break;xl(41),kl(17),xl(11)}xl(37)}}function ia(){Vl.startNonterminal("FTStopWordsInclExcl",Pl);switch(Hl){case 254:Sl(254);break;default:Sl(131)}kl(99),Nl(),na(),Vl.endNonterminal("FTStopWordsInclExcl",Pl)}function sa(){switch(Hl){case 254:xl(254);break;default:xl(131)}kl(99),ra()}function oa(){Vl.startNonterminal("FTLanguageOption",Pl),Sl(169),kl(17),Sl(11),Vl.endNonterminal("FTLanguageOption",Pl)}function ua(){xl(169),kl(17),xl(11)}function aa(){Vl.startNonterminal("FTWildCardOption",Pl);switch(Hl){case 268:Sl(268);break;default:Sl(188),kl(84),Sl(268)}Vl.endNonterminal("FTWildCardOption",Pl)}function fa(){switch(Hl){case 268:xl(268);break;default:xl(188),kl(84),xl(268)}}function la(){Vl.startNonterminal("FTExtensionOption",Pl),Sl(199),kl(255),Nl(),Ha(),kl(17),Sl(11),Vl.endNonterminal("FTExtensionOption",Pl)}function ca(){xl(199),kl(255),Ba(),kl(17),xl(11)}function ha(){Vl.startNonterminal("FTIgnoreOption",Pl),Sl(271),kl(42),Sl(100),kl(267),Nl(),Qn(),Vl.endNonterminal("FTIgnoreOption",Pl)}function pa(){xl(271),kl(42),xl(100),kl(267),Gn()}function da(){Vl.startNonterminal("CollectionDecl",Pl),Sl(95),kl(255),Nl(),Ha(),kl(107),Hl==79&&(Nl(),va()),Vl.endNonterminal("CollectionDecl",Pl)}function va(){Vl.startNonterminal("CollectionTypeDecl",Pl),Sl(79),kl(178),Nl(),Ps(),kl(156),Hl!=53&&(Nl(),ys()),Vl.endNonterminal("CollectionTypeDecl",Pl)}function ma(){Vl.startNonterminal("IndexName",Pl),Ha(),Vl.endNonterminal("IndexName",Pl)}function ga(){Vl.startNonterminal("IndexDomainExpr",Pl),Lr(),Vl.endNonterminal("IndexDomainExpr",Pl)}function ya(){Vl.startNonterminal("IndexKeySpec",Pl),ba(),Hl==79&&(Nl(),wa()),kl(146),Hl==94&&(Nl(),Sa()),Vl.endNonterminal("IndexKeySpec",Pl)}function ba(){Vl.startNonterminal("IndexKeyExpr",Pl),Lr(),Vl.endNonterminal("IndexKeyExpr",Pl)}function wa(){Vl.startNonterminal("IndexKeyTypeDecl",Pl),Sl(79),kl(255),Nl(),Ea(),kl(169);if(Hl==39||Hl==40||Hl==64)Nl(),ys();Vl.endNonterminal("IndexKeyTypeDecl",Pl)}function Ea(){Vl.startNonterminal("AtomicType",Pl),Ha(),Vl.endNonterminal("AtomicType",Pl)}function Sa(){Vl.startNonterminal("IndexKeyCollation",Pl),Sl(94),kl(15),Sl(7),Vl.endNonterminal("IndexKeyCollation",Pl)}function xa(){Vl.startNonterminal("IndexDecl",Pl),Sl(155),kl(255),Nl(),ma(),kl(65),Sl(197),kl(63),Sl(192),kl(266),Nl(),ga(),Sl(87),kl(266),Nl(),ya();for(;;){kl(103);if(Hl!=41)break;Sl(41),kl(266),Nl(),ya()}Vl.endNonterminal("IndexDecl",Pl)}function Ta(){Vl.startNonterminal("ICDecl",Pl),Sl(161),kl(40),Sl(97),kl(255),Nl(),Ha(),kl(120);switch(Hl){case 197:Nl(),Na();break;default:Nl(),Aa()}Vl.endNonterminal("ICDecl",Pl)}function Na(){Vl.startNonterminal("ICCollection",Pl),Sl(197),kl(39),Sl(95),kl(255),Nl(),Ha(),kl(140);switch(Hl){case 31:Nl(),Ca();break;case 191:Nl(),ka();break;default:Nl(),La()}Vl.endNonterminal("ICCollection",Pl)}function Ca(){Vl.startNonterminal("ICCollSequence",Pl),li(),kl(37),Sl(92),kl(267),Nl(),_f(),Vl.endNonterminal("ICCollSequence",Pl)}function ka(){Vl.startNonterminal("ICCollSequenceUnique",Pl),Sl(191),kl(21),Nl(),li(),kl(37),Sl(92),kl(80),Sl(255),kl(57),Sl(168),kl(266),Nl(),Lr(),Vl.endNonterminal("ICCollSequenceUnique",Pl)}function La(){Vl.startNonterminal("ICCollNode",Pl),Sl(138),kl(62),Sl(191),kl(21),Nl(),li(),kl(37),Sl(92),kl(267),Nl(),_f(),Vl.endNonterminal("ICCollNode",Pl)}function Aa(){Vl.startNonterminal("ICForeignKey",Pl),Sl(139),kl(57),Sl(168),kl(51),Nl(),Oa(),Nl(),Ma(),Vl.endNonterminal("ICForeignKey",Pl)}function Oa(){Vl.startNonterminal("ICForeignKeySource",Pl),Sl(140),kl(39),Nl(),_a(),Vl.endNonterminal("ICForeignKeySource",Pl)}function Ma(){Vl.startNonterminal("ICForeignKeyTarget",Pl),Sl(248),kl(39),Nl(),_a(),Vl.endNonterminal("ICForeignKeyTarget",Pl)}function _a(){Vl.startNonterminal("ICForeignKeyValues",Pl),Sl(95),kl(255),Nl(),Ha(),kl(62),Sl(191),kl(21),Nl(),li(),kl(57),Sl(168),kl(266),Nl(),Lr(),Vl.endNonterminal("ICForeignKeyValues",Pl)}function Da(){xl(36);for(;;){Al(89);if(Hl==50)break;switch(Hl){case 24:xl(24);break;default:Da()}}xl(50)}function Pa(){switch(Hl){case 22:xl(22);break;default:Da()}}function Ha(){Vl.startNonterminal("EQName",Pl),Al(250);switch(Hl){case 82:Sl(82);break;case 96:Sl(96);break;case 120:Sl(120);break;case 121:Sl(121);break;case 124:Sl(124);break;case 145:Sl(145);break;case 152:Sl(152);break;case 165:Sl(165);break;case 185:Sl(185);break;case 191:Sl(191);break;case 216:Sl(216);break;case 226:Sl(226);break;case 227:Sl(227);break;case 243:Sl(243);break;case 244:Sl(244);break;case 253:Sl(253);break;case 78:Sl(78);break;case 167:Sl(167);break;case 242:Sl(242);break;default:ja()}Vl.endNonterminal("EQName",Pl)}function Ba(){Al(250);switch(Hl){case 82:xl(82);break;case 96:xl(96);break;case 120:xl(120);break;case 121:xl(121);break;case 124:xl(124);break;case 145:xl(145);break;case 152:xl(152);break;case 165:xl(165);break;case 185:xl(185);break;case 191:xl(191);break;case 216:xl(216);break;case 226:xl(226);break;case 227:xl(227);break;case 243:xl(243);break;case 244:xl(244);break;case 253:xl(253);break;case 78:xl(78);break;case 167:xl(167);break;case 242:xl(242);break;default:Fa()}}function ja(){Vl.startNonterminal("FunctionName",Pl);switch(Hl){case 6:Sl(6);break;case 70:Sl(70);break;case 73:Sl(73);break;case 74:Sl(74);break;case 75:Sl(75);break;case 79:Sl(79);break;case 80:Sl(80);break;case 84:Sl(84);break;case 88:Sl(88);break;case 89:Sl(89);break;case 90:Sl(90);break;case 93:Sl(93);break;case 94:Sl(94);break;case 103:Sl(103);break;case 105:Sl(105);break;case 108:Sl(108);break;case 109:Sl(109);break;case 110:Sl(110);break;case 111:Sl(111);break;case 112:Sl(112);break;case 113:Sl(113);break;case 118:Sl(118);break;case 119:Sl(119);break;case 122:Sl(122);break;case 123:Sl(123);break;case 126:Sl(126);break;case 128:Sl(128);break;case 129:Sl(129);break;case 131:Sl(131);break;case 134:Sl(134);break;case 135:Sl(135);break;case 136:Sl(136);break;case 137:Sl(137);break;case 146:Sl(146);break;case 148:Sl(148);break;case 150:Sl(150);break;case 151:Sl(151);break;case 153:Sl(153);break;case 159:Sl(159);break;case 160:Sl(160);break;case 162:Sl(162);break;case 163:Sl(163);break;case 164:Sl(164);break;case 170:Sl(170);break;case 172:Sl(172);break;case 174:Sl(174);break;case 178:Sl(178);break;case 180:Sl(180);break;case 181:Sl(181);break;case 182:Sl(182);break;case 184:Sl(184);break;case 186:Sl(186);break;case 198:Sl(198);break;case 200:Sl(200);break;case 201:Sl(201);break;case 202:Sl(202);break;case 206:Sl(206);break;case 212:Sl(212);break;case 213:Sl(213);break;case 218:Sl(218);break;case 219:Sl(219);break;case 220:Sl(220);break;case 224:Sl(224);break;case 229:Sl(229);break;case 235:Sl(235);break;case 236:Sl(236);break;case 237:Sl(237);break;case 248:Sl(248);break;case 249:Sl(249);break;case 250:Sl(250);break;case 254:Sl(254);break;case 256:Sl(256);break;case 260:Sl(260);break;case 266:Sl(266);break;case 270:Sl(270);break;case 274:Sl(274);break;case 72:Sl(72);break;case 81:Sl(81);break;case 83:Sl(83);break;case 85:Sl(85);break;case 86:Sl(86);break;case 91:Sl(91);break;case 98:Sl(98);break;case 101:Sl(101);break;case 102:Sl(102);break;case 104:Sl(104);break;case 106:Sl(106);break;case 125:Sl(125);break;case 132:Sl(132);break;case 133:Sl(133);break;case 141:Sl(141);break;case 154:Sl(154);break;case 155:Sl(155);break;case 161:Sl(161);break;case 171:Sl(171);break;case 192:Sl(192);break;case 199:Sl(199);break;case 203:Sl(203);break;case 222:Sl(222);break;case 225:Sl(225);break;case 228:Sl(228);break;case 234:Sl(234);break;case 240:Sl(240);break;case 251:Sl(251);break;case 252:Sl(252);break;case 257:Sl(257);break;case 261:Sl(261);break;case 262:Sl(262);break;case 263:Sl(263);break;case 267:Sl(267);break;case 97:Sl(97);break;case 176:Sl(176);break;case 221:Sl(221);break;case 77:Sl(77);break;case 166:Sl(166);break;default:Sl(194)}Vl.endNonterminal("FunctionName",Pl)}function Fa(){switch(Hl){case 6:xl(6);break;case 70:xl(70);break;case 73:xl(73);break;case 74:xl(74);break;case 75:xl(75);break;case 79:xl(79);break;case 80:xl(80);break;case 84:xl(84);break;case 88:xl(88);break;case 89:xl(89);break;case 90:xl(90);break;case 93:xl(93);break;case 94:xl(94);break;case 103:xl(103);break;case 105:xl(105);break;case 108:xl(108);break;case 109:xl(109);break;case 110:xl(110);break;case 111:xl(111);break;case 112:xl(112);break;case 113:xl(113);break;case 118:xl(118);break;case 119:xl(119);break;case 122:xl(122);break;case 123:xl(123);break;case 126:xl(126);break;case 128:xl(128);break;case 129:xl(129);break;case 131:xl(131);break;case 134:xl(134);break;case 135:xl(135);break;case 136:xl(136);break;case 137:xl(137);break;case 146:xl(146);break;case 148:xl(148);break;case 150:xl(150);break;case 151:xl(151);break;case 153:xl(153);break;case 159:xl(159);break;case 160:xl(160);break;case 162:xl(162);break;case 163:xl(163);break;case 164:xl(164);break;case 170:xl(170);break;case 172:xl(172);break;case 174:xl(174);break;case 178:xl(178);break;case 180:xl(180);break;case 181:xl(181);break;case 182:xl(182);break;case 184:xl(184);break;case 186:xl(186);break;case 198:xl(198);break;case 200:xl(200);break;case 201:xl(201);break;case 202:xl(202);break;case 206:xl(206);break;case 212:xl(212);break;case 213:xl(213);break;case 218:xl(218);break;case 219:xl(219);break;case 220:xl(220);break;case 224:xl(224);break;case 229:xl(229);break;case 235:xl(235);break;case 236:xl(236);break;case 237:xl(237);break;case 248:xl(248);break;case 249:xl(249);break;case 250:xl(250);break;case 254:xl(254);break;case 256:xl(256);break;case 260:xl(260);break;case 266:xl(266);break;case 270:xl(270);break;case 274:xl(274);break;case 72:xl(72);break;case 81:xl(81);break;case 83:xl(83);break;case 85:xl(85);break;case 86:xl(86);break;case 91:xl(91);break;case 98:xl(98);break;case 101:xl(101);break;case 102:xl(102);break;case 104:xl(104);break;case 106:xl(106);break;case 125:xl(125);break;case 132:xl(132);break;case 133:xl(133);break;case 141:xl(141);break;case 154:xl(154);break;case 155:xl(155);break;case 161:xl(161);break;case 171:xl(171);break;case 192:xl(192);break;case 199:xl(199);break;case 203:xl(203);break;case 222:xl(222);break;case 225:xl(225);break;case 228:xl(228);break;case 234:xl(234);break;case 240:xl(240);break;case 251:xl(251);break;case 252:xl(252);break;case 257:xl(257);break;case 261:xl(261);break;case 262:xl(262);break;case 263:xl(263);break;case 267:xl(267);break;case 97:xl(97);break;case 176:xl(176);break;case 221:xl(221);break;case 77:xl(77);break;case 166:xl(166);break;default:xl(194)}}function Ia(){Vl.startNonterminal("NCName",Pl);switch(Hl){case 19:Sl(19);break;case 70:Sl(70);break;case 75:Sl(75);break;case 79:Sl(79);break;case 80:Sl(80);break;case 84:Sl(84);break;case 88:Sl(88);break;case 89:Sl(89);break;case 90:Sl(90);break;case 94:Sl(94);break;case 105:Sl(105);break;case 109:Sl(109);break;case 113:Sl(113);break;case 118:Sl(118);break;case 122:Sl(122);break;case 123:Sl(123);break;case 126:Sl(126);break;case 128:Sl(128);break;case 131:Sl(131);break;case 137:Sl(137);break;case 146:Sl(146);break;case 148:Sl(148);break;case 150:Sl(150);break;case 151:Sl(151);break;case 160:Sl(160);break;case 162:Sl(162);break;case 163:Sl(163);break;case 164:Sl(164);break;case 172:Sl(172);break;case 174:Sl(174);break;case 178:Sl(178);break;case 180:Sl(180);break;case 181:Sl(181);break;case 186:Sl(186);break;case 198:Sl(198);break;case 200:Sl(200);break;case 201:Sl(201);break;case 220:Sl(220);break;case 224:Sl(224);break;case 236:Sl(236);break;case 237:Sl(237);break;case 248:Sl(248);break;case 249:Sl(249);break;case 254:Sl(254);break;case 266:Sl(266);break;case 270:Sl(270);break;case 73:Sl(73);break;case 74:Sl(74);break;case 82:Sl(82);break;case 93:Sl(93);break;case 96:Sl(96);break;case 103:Sl(103);break;case 108:Sl(108);break;case 110:Sl(110);break;case 111:Sl(111);break;case 112:Sl(112);break;case 119:Sl(119);break;case 120:Sl(120);break;case 121:Sl(121);break;case 124:Sl(124);break;case 129:Sl(129);break;case 134:Sl(134);break;case 135:Sl(135);break;case 136:Sl(136);break;case 145:Sl(145);break;case 152:Sl(152);break;case 153:Sl(153);break;case 159:Sl(159);break;case 165:Sl(165);break;case 170:Sl(170);break;case 182:Sl(182);break;case 184:Sl(184);break;case 185:Sl(185);break;case 191:Sl(191);break;case 202:Sl(202);break;case 206:Sl(206);break;case 212:Sl(212);break;case 213:Sl(213);break;case 216:Sl(216);break;case 218:Sl(218);break;case 219:Sl(219);break;case 226:Sl(226);break;case 227:Sl(227);break;case 229:Sl(229);break;case 235:Sl(235);break;case 243:Sl(243);break;case 244:Sl(244);break;case 250:Sl(250);break;case 253:Sl(253);break;case 256:Sl(256);break;case 260:Sl(260);break;case 262:Sl(262);break;case 274:Sl(274);break;case 72:Sl(72);break;case 81:Sl(81);break;case 83:Sl(83);break;case 85:Sl(85);break;case 86:Sl(86);break;case 91:Sl(91);break;case 98:Sl(98);break;case 101:Sl(101);break;case 102:Sl(102);break;case 104:Sl(104);break;case 106:Sl(106);break;case 125:Sl(125);break;case 132:Sl(132);break;case 133:Sl(133);break;case 141:Sl(141);break;case 154:Sl(154);break;case 155:Sl(155);break;case 161:Sl(161);break;case 171:Sl(171);break;case 192:Sl(192);break;case 199:Sl(199);break;case 203:Sl(203);break;case 222:Sl(222);break;case 225:Sl(225);break;case 228:Sl(228);break;case 234:Sl(234);break;case 240:Sl(240);break;case 251:Sl(251);break;case 252:Sl(252);break;case 257:Sl(257);break;case 261:Sl(261);break;case 263:Sl(263);break;case 267:Sl(267);break;case 97:Sl(97);break;case 176:Sl(176);break;case 221:Sl(221);break;case 77:Sl(77);break;case 166:Sl(166);break;default:Sl(194)}Vl.endNonterminal("NCName",Pl)}function qa(){switch(Hl){case 19:xl(19);break;case 70:xl(70);break;case 75:xl(75);break;case 79:xl(79);break;case 80:xl(80);break;case 84:xl(84);break;case 88:xl(88);break;case 89:xl(89);break;case 90:xl(90);break;case 94:xl(94);break;case 105:xl(105);break;case 109:xl(109);break;case 113:xl(113);break;case 118:xl(118);break;case 122:xl(122);break;case 123:xl(123);break;case 126:xl(126);break;case 128:xl(128);break;case 131:xl(131);break;case 137:xl(137);break;case 146:xl(146);break;case 148:xl(148);break;case 150:xl(150);break;case 151:xl(151);break;case 160:xl(160);break;case 162:xl(162);break;case 163:xl(163);break;case 164:xl(164);break;case 172:xl(172);break;case 174:xl(174);break;case 178:xl(178);break;case 180:xl(180);break;case 181:xl(181);break;case 186:xl(186);break;case 198:xl(198);break;case 200:xl(200);break;case 201:xl(201);break;case 220:xl(220);break;case 224:xl(224);break;case 236:xl(236);break;case 237:xl(237);break;case 248:xl(248);break;case 249:xl(249);break;case 254:xl(254);break;case 266:xl(266);break;case 270:xl(270);break;case 73:xl(73);break;case 74:xl(74);break;case 82:xl(82);break;case 93:xl(93);break;case 96:xl(96);break;case 103:xl(103);break;case 108:xl(108);break;case 110:xl(110);break;case 111:xl(111);break;case 112:xl(112);break;case 119:xl(119);break;case 120:xl(120);break;case 121:xl(121);break;case 124:xl(124);break;case 129:xl(129);break;case 134:xl(134);break;case 135:xl(135);break;case 136:xl(136);break;case 145:xl(145);break;case 152:xl(152);break;case 153:xl(153);break;case 159:xl(159);break;case 165:xl(165);break;case 170:xl(170);break;case 182:xl(182);break;case 184:xl(184);break;case 185:xl(185);break;case 191:xl(191);break;case 202:xl(202);break;case 206:xl(206);break;case 212:xl(212);break;case 213:xl(213);break;case 216:xl(216);break;case 218:xl(218);break;case 219:xl(219);break;case 226:xl(226);break;case 227:xl(227);break;case 229:xl(229);break;case 235:xl(235);break;case 243:xl(243);break;case 244:xl(244);break;case 250:xl(250);break;case 253:xl(253);break;case 256:xl(256);break;case 260:xl(260);break;case 262:xl(262);break;case 274:xl(274);break;case 72:xl(72);break;case 81:xl(81);break;case 83:xl(83);break;case 85:xl(85);break;case 86:xl(86);break;case 91:xl(91);break;case 98:xl(98);break;case 101:xl(101);break;case 102:xl(102);break;case 104:xl(104);break;case 106:xl(106);break;case 125:xl(125);break;case 132:xl(132);break;case 133:xl(133);break;case 141:xl(141);break;case 154:xl(154);break;case 155:xl(155);break;case 161:xl(161);break;case 171:xl(171);break;case 192:xl(192);break;case 199:xl(199);break;case 203:xl(203);break;case 222:xl(222);break;case 225:xl(225);break;case 228:xl(228);break;case 234:xl(234);break;case 240:xl(240);break;case 251:xl(251);break;case 252:xl(252);break;case 257:xl(257);break;case 261:xl(261);break;case 263:xl(263);break;case 267:xl(267);break;case 97:xl(97);break;case 176:xl(176);break;case 221:xl(221);break;case 77:xl(77);break;case 166:xl(166);break;default:xl(194)}}function Ra(){Vl.startNonterminal("MainModule",Pl),l(),Nl(),Ua(),Vl.endNonterminal("MainModule",Pl)}function Ua(){Vl.startNonterminal("Program",Pl),$a(),Vl.endNonterminal("Program",Pl)}function za(){Vl.startNonterminal("Statements",Pl);for(;;){kl(278);switch(Hl){case 34:Ll(269);break;case 35:Ol(252);break;case 46:Ll(284);break;case 47:Ll(265);break;case 54:Ol(4);break;case 55:Ol(1);break;case 59:Ol(3);break;case 66:Ll(257);break;case 68:Ll(272);break;case 77:Ll(200);break;case 82:Ll(281);break;case 121:Ll(280);break;case 132:Ll(203);break;case 137:Ll(208);break;case 174:Ll(205);break;case 218:Ll(206);break;case 219:Ll(207);break;case 260:Ll(210);break;case 276:Ll(277);break;case 278:Ll(273);break;case 5:case 45:Ll(186);break;case 31:case 32:Ll(255);break;case 40:case 42:Ll(267);break;case 86:case 102:Ll(201);break;case 110:case 159:Ll(209);break;case 184:case 216:Ll(268);break;case 103:case 129:case 235:case 262:Ll(197);break;case 8:case 9:case 10:case 11:case 44:Ll(192);break;case 78:case 124:case 165:case 167:case 242:Ll(191);break;case 96:case 119:case 202:case 244:case 250:case 256:Ll(204);break;case 73:case 74:case 93:case 111:case 112:case 135:case 136:case 206:case 212:case 213:case 229:Ll(198);break;case 6:case 70:case 72:case 75:case 79:case 80:case 81:case 83:case 84:case 85:case 88:case 89:case 90:case 91:case 94:case 97:case 98:case 101:case 104:case 105:case 106:case 108:case 109:case 113:case 118:case 120:case 122:case 123:case 125:case 126:case 128:case 131:case 133:case 134:case 141:case 145:case 146:case 148:case 150:case 151:case 152:case 153:case 154:case 155:case 160:case 161:case 162:case 163:case 164:case 166:case 170:case 171:case 172:case 176:case 178:case 180:case 181:case 182:case 185:case 186:case 191:case 192:case 194:case 198:case 199:case 200:case 201:case 203:case 220:case 221:case 222:case 224:case 225:case 226:case 227:case 228:case 234:case 236:case 237:case 240:case 243:case 248:case 249:case 251:case 252:case 253:case 254:case 257:case 261:case 263:case 266:case 267:case 270:case 274:Ll(195);break;default:_l=Hl}if(_l!=25&&_l!=53&&_l!=282&&_l!=12805&&_l!=12806&&_l!=12808&&_l!=12809&&_l!=12810&&_l!=12811&&_l!=12844&&_l!=12845&&_l!=12846&&_l!=12870&&_l!=12872&&_l!=12873&&_l!=12874&&_l!=12875&&_l!=12877&&_l!=12878&&_l!=12879&&_l!=12880&&_l!=12881&&_l!=12882&&_l!=12883&&_l!=12884&&_l!=12885&&_l!=12886&&_l!=12888&&_l!=12889&&_l!=12890&&_l!=12891&&_l!=12893&&_l!=12894&&_l!=12896&&_l!=12897&&_l!=12898&&_l!=12901&&_l!=12902&&_l!=12903&&_l!=12904&&_l!=12905&&_l!=12906&&_l!=12908&&_l!=12909&&_l!=12910&&_l!=12911&&_l!=12912&&_l!=12913&&_l!=12918&&_l!=12919&&_l!=12920&&_l!=12921&&_l!=12922&&_l!=12923&&_l!=12924&&_l!=12925&&_l!=12926&&_l!=12928&&_l!=12929&&_l!=12931&&_l!=12932&&_l!=12933&&_l!=12934&&_l!=12935&&_l!=12936&&_l!=12937&&_l!=12941&&_l!=12945&&_l!=12946&&_l!=12948&&_l!=12950&&_l!=12951&&_l!=12952&&_l!=12953&&_l!=12954&&_l!=12955&&_l!=12959&&_l!=12960&&_l!=12961&&_l!=12962&&_l!=12963&&_l!=12964&&_l!=12965&&_l!=12966&&_l!=12967&&_l!=12970&&_l!=12971&&_l!=12972&&_l!=12974&&_l!=12976&&_l!=12978&&_l!=12980&&_l!=12981&&_l!=12982&&_l!=12984&&_l!=12985&&_l!=12986&&_l!=12991&&_l!=12992&&_l!=12994&&_l!=12998&&_l!=12999&&_l!=13e3&&_l!=13001&&_l!=13002&&_l!=13003&&_l!=13006&&_l!=13012&&_l!=13013&&_l!=13016&&_l!=13018&&_l!=13019&&_l!=13020&&_l!=13021&&_l!=13022&&_l!=13024&&_l!=13025&&_l!=13026&&_l!=13027&&_l!=13028&&_l!=13029&&_l!=13034&&_l!=13035&&_l!=13036&&_l!=13037&&_l!=13040&&_l!=13042&&_l!=13043&&_l!=13044&&_l!=13048&&_l!=13049&&_l!=13050&&_l!=13051&&_l!=13052&&_l!=13053&&_l!=13054&&_l!=13056&&_l!=13057&&_l!=13060&&_l!=13061&&_l!=13062&&_l!=13063&&_l!=13066&&_l!=13067&&_l!=13070&&_l!=13074&&_l!=16134&&_l!=20997&&_l!=20998&&_l!=21e3&&_l!=21001&&_l!=21002&&_l!=21003&&_l!=21036&&_l!=21037&&_l!=21038&&_l!=21062&&_l!=21064&&_l!=21065&&_l!=21066&&_l!=21067&&_l!=21069&&_l!=21070&&_l!=21071&&_l!=21072&&_l!=21073&&_l!=21074&&_l!=21075&&_l!=21076&&_l!=21077&&_l!=21078&&_l!=21080&&_l!=21081&&_l!=21082&&_l!=21083&&_l!=21085&&_l!=21086&&_l!=21088&&_l!=21089&&_l!=21090&&_l!=21093&&_l!=21094&&_l!=21095&&_l!=21096&&_l!=21097&&_l!=21098&&_l!=21100&&_l!=21101&&_l!=21102&&_l!=21103&&_l!=21104&&_l!=21105&&_l!=21110&&_l!=21111&&_l!=21112&&_l!=21113&&_l!=21114&&_l!=21115&&_l!=21116&&_l!=21117&&_l!=21118&&_l!=21120&&_l!=21121&&_l!=21123&&_l!=21124&&_l!=21125&&_l!=21126&&_l!=21127&&_l!=21128&&_l!=21129&&_l!=21133&&_l!=21137&&_l!=21138&&_l!=21140&&_l!=21142&&_l!=21143&&_l!=21144&&_l!=21145&&_l!=21146&&_l!=21147&&_l!=21151&&_l!=21152&&_l!=21153&&_l!=21154&&_l!=21155&&_l!=21156&&_l!=21157&&_l!=21158&&_l!=21159&&_l!=21162&&_l!=21163&&_l!=21164&&_l!=21166&&_l!=21168&&_l!=21170&&_l!=21172&&_l!=21173&&_l!=21174&&_l!=21176&&_l!=21177&&_l!=21178&&_l!=21183&&_l!=21184&&_l!=21186&&_l!=21190&&_l!=21191&&_l!=21192&&_l!=21193&&_l!=21194&&_l!=21195&&_l!=21198&&_l!=21204&&_l!=21205&&_l!=21208&&_l!=21210&&_l!=21211&&_l!=21212&&_l!=21213&&_l!=21214&&_l!=21216&&_l!=21217&&_l!=21218&&_l!=21219&&_l!=21220&&_l!=21221&&_l!=21226&&_l!=21227&&_l!=21228&&_l!=21229&&_l!=21232&&_l!=21234&&_l!=21235&&_l!=21236&&_l!=21240&&_l!=21241&&_l!=21242&&_l!=21243&&_l!=21244&&_l!=21245&&_l!=21246&&_l!=21248&&_l!=21249&&_l!=21252&&_l!=21253&&_l!=21254&&_l!=21255&&_l!=21258&&_l!=21259&&_l!=21262&&_l!=21266&&_l!=27141&&_l!=27142&&_l!=27144&&_l!=27145&&_l!=27146&&_l!=27147&&_l!=27180&&_l!=27181&&_l!=27182&&_l!=27206&&_l!=27208&&_l!=27209&&_l!=27210&&_l!=27211&&_l!=27213&&_l!=27214&&_l!=27215&&_l!=27216&&_l!=27217&&_l!=27218&&_l!=27219&&_l!=27220&&_l!=27221&&_l!=27222&&_l!=27224&&_l!=27225&&_l!=27226&&_l!=27227&&_l!=27229&&_l!=27230&&_l!=27232&&_l!=27233&&_l!=27234&&_l!=27237&&_l!=27238&&_l!=27239&&_l!=27240&&_l!=27241&&_l!=27242&&_l!=27244&&_l!=27245&&_l!=27246&&_l!=27247&&_l!=27248&&_l!=27249&&_l!=27254&&_l!=27255&&_l!=27256&&_l!=27257&&_l!=27258&&_l!=27259&&_l!=27260&&_l!=27261&&_l!=27262&&_l!=27264&&_l!=27265&&_l!=27267&&_l!=27268&&_l!=27269&&_l!=27270&&_l!=27271&&_l!=27272&&_l!=27273&&_l!=27277&&_l!=27281&&_l!=27282&&_l!=27284&&_l!=27286&&_l!=27287&&_l!=27288&&_l!=27289&&_l!=27290&&_l!=27291&&_l!=27295&&_l!=27296&&_l!=27297&&_l!=27298&&_l!=27299&&_l!=27300&&_l!=27301&&_l!=27302&&_l!=27303&&_l!=27306&&_l!=27307&&_l!=27308&&_l!=27310&&_l!=27312&&_l!=27314&&_l!=27316&&_l!=27317&&_l!=27318&&_l!=27320&&_l!=27321&&_l!=27322&&_l!=27327&&_l!=27328&&_l!=27330&&_l!=27334&&_l!=27335&&_l!=27336&&_l!=27337&&_l!=27338&&_l!=27339&&_l!=27342&&_l!=27348&&_l!=27349&&_l!=27352&&_l!=27354&&_l!=27355&&_l!=27356&&_l!=27357&&_l!=27358&&_l!=27360&&_l!=27361&&_l!=27362&&_l!=27363&&_l!=27364&&_l!=27365&&_l!=27370&&_l!=27371&&_l!=27372&&_l!=27373&&_l!=27376&&_l!=27378&&_l!=27379&&_l!=27380&&_l!=27384&&_l!=27385&&_l!=27386&&_l!=27387&&_l!=27388&&_l!=27389&&_l!=27390&&_l!=27392&&_l!=27393&&_l!=27396&&_l!=27397&&_l!=27398&&_l!=27399&&_l!=27402&&_l!=27403&&_l!=27406&&_l!=27410&&_l!=90198&&_l!=90214&&_l!=113284&&_l!=144389&&_l!=144390&&_l!=144392&&_l!=144393&&_l!=144394&&_l!=144395&&_l!=144428&&_l!=144429&&_l!=144430&&_l!=144454&&_l!=144456&&_l!=144457&&_l!=144458&&_l!=144459&&_l!=144461&&_l!=144462&&_l!=144463&&_l!=144464&&_l!=144465&&_l!=144466&&_l!=144467&&_l!=144468&&_l!=144469&&_l!=144470&&_l!=144472&&_l!=144473&&_l!=144474&&_l!=144475&&_l!=144477&&_l!=144478&&_l!=144480&&_l!=144481&&_l!=144482&&_l!=144485&&_l!=144486&&_l!=144487&&_l!=144488&&_l!=144489&&_l!=144490&&_l!=144492&&_l!=144493&&_l!=144494&&_l!=144495&&_l!=144496&&_l!=144497&&_l!=144502&&_l!=144503&&_l!=144504&&_l!=144505&&_l!=144506&&_l!=144507&&_l!=144508&&_l!=144509&&_l!=144510&&_l!=144512&&_l!=144513&&_l!=144515&&_l!=144516&&_l!=144517&&_l!=144518&&_l!=144519&&_l!=144520&&_l!=144521&&_l!=144525&&_l!=144529&&_l!=144530&&_l!=144532&&_l!=144534&&_l!=144535&&_l!=144536&&_l!=144537&&_l!=144538&&_l!=144539&&_l!=144543&&_l!=144544&&_l!=144545&&_l!=144546&&_l!=144547&&_l!=144548&&_l!=144549&&_l!=144550&&_l!=144551&&_l!=144554&&_l!=144555&&_l!=144556&&_l!=144558&&_l!=144560&&_l!=144562&&_l!=144564&&_l!=144565&&_l!=144566&&_l!=144568&&_l!=144569&&_l!=144570&&_l!=144575&&_l!=144576&&_l!=144578&&_l!=144582&&_l!=144583&&_l!=144584&&_l!=144585&&_l!=144586&&_l!=144587&&_l!=144590&&_l!=144596&&_l!=144597&&_l!=144600&&_l!=144602&&_l!=144603&&_l!=144604&&_l!=144605&&_l!=144606&&_l!=144608&&_l!=144609&&_l!=144610&&_l!=144611&&_l!=144612&&_l!=144613&&_l!=144618&&_l!=144619&&_l!=144620&&_l!=144621&&_l!=144624&&_l!=144626&&_l!=144627&&_l!=144628&&_l!=144632&&_l!=144633&&_l!=144634&&_l!=144635&&_l!=144636&&_l!=144637&&_l!=144638&&_l!=144640&&_l!=144641&&_l!=144644&&_l!=144645&&_l!=144646&&_l!=144647&&_l!=144650&&_l!=144651&&_l!=144654&&_l!=144658){_l=Kl(6,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{Qa(),_l=-1}catch(a){_l=-2}Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(6,Pl,_l)}}if(_l!=-1&&_l!=53&&_l!=16134&&_l!=27141&&_l!=27142&&_l!=27144&&_l!=27145&&_l!=27146&&_l!=27147&&_l!=27180&&_l!=27181&&_l!=27182&&_l!=27206&&_l!=27208&&_l!=27209&&_l!=27210&&_l!=27211&&_l!=27213&&_l!=27214&&_l!=27215&&_l!=27216&&_l!=27217&&_l!=27218&&_l!=27219&&_l!=27220&&_l!=27221&&_l!=27222&&_l!=27224&&_l!=27225&&_l!=27226&&_l!=27227&&_l!=27229&&_l!=27230&&_l!=27232&&_l!=27233&&_l!=27234&&_l!=27237&&_l!=27238&&_l!=27239&&_l!=27240&&_l!=27241&&_l!=27242&&_l!=27244&&_l!=27245&&_l!=27246&&_l!=27247&&_l!=27248&&_l!=27249&&_l!=27254&&_l!=27255&&_l!=27256&&_l!=27257&&_l!=27258&&_l!=27259&&_l!=27260&&_l!=27261&&_l!=27262&&_l!=27264&&_l!=27265&&_l!=27267&&_l!=27268&&_l!=27269&&_l!=27270&&_l!=27271&&_l!=27272&&_l!=27273&&_l!=27277&&_l!=27281&&_l!=27282&&_l!=27284&&_l!=27286&&_l!=27287&&_l!=27288&&_l!=27289&&_l!=27290&&_l!=27291&&_l!=27295&&_l!=27296&&_l!=27297&&_l!=27298&&_l!=27299&&_l!=27300&&_l!=27301&&_l!=27302&&_l!=27303&&_l!=27306&&_l!=27307&&_l!=27308&&_l!=27310&&_l!=27312&&_l!=27314&&_l!=27316&&_l!=27317&&_l!=27318&&_l!=27320&&_l!=27321&&_l!=27322&&_l!=27327&&_l!=27328&&_l!=27330&&_l!=27334&&_l!=27335&&_l!=27336&&_l!=27337&&_l!=27338&&_l!=27339&&_l!=27342&&_l!=27348&&_l!=27349&&_l!=27352&&_l!=27354&&_l!=27355&&_l!=27356&&_l!=27357&&_l!=27358&&_l!=27360&&_l!=27361&&_l!=27362&&_l!=27363&&_l!=27364&&_l!=27365&&_l!=27370&&_l!=27371&&_l!=27372&&_l!=27373&&_l!=27376&&_l!=27378&&_l!=27379&&_l!=27380&&_l!=27384&&_l!=27385&&_l!=27386&&_l!=27387&&_l!=27388&&_l!=27389&&_l!=27390&&_l!=27392&&_l!=27393&&_l!=27396&&_l!=27397&&_l!=27398&&_l!=27399&&_l!=27402&&_l!=27403&&_l!=27406&&_l!=27410&&_l!=90198&&_l!=90214&&_l!=113284)break;Nl(),Ka()}Vl.endNonterminal("Statements",Pl)}function Wa(){for(;;){kl(278);switch(Hl){case 34:Ll(269);break;case 35:Ol(252);break;case 46:Ll(284);break;case 47:Ll(265);break;case 54:Ol(4);break;case 55:Ol(1);break;case 59:Ol(3);break;case 66:Ll(257);break;case 68:Ll(272);break;case 77:Ll(200);break;case 82:Ll(281);break;case 121:Ll(280);break;case 132:Ll(203);break;case 137:Ll(208);break;case 174:Ll(205);break;case 218:Ll(206);break;case 219:Ll(207);break;case 260:Ll(210);break;case 276:Ll(277);break;case 278:Ll(273);break;case 5:case 45:Ll(186);break;case 31:case 32:Ll(255);break;case 40:case 42:Ll(267);break;case 86:case 102:Ll(201);break;case 110:case 159:Ll(209);break;case 184:case 216:Ll(268);break;case 103:case 129:case 235:case 262:Ll(197);break;case 8:case 9:case 10:case 11:case 44:Ll(192);break;case 78:case 124:case 165:case 167:case 242:Ll(191);break;case 96:case 119:case 202:case 244:case 250:case 256:Ll(204);break;case 73:case 74:case 93:case 111:case 112:case 135:case 136:case 206:case 212:case 213:case 229:Ll(198);break;case 6:case 70:case 72:case 75:case 79:case 80:case 81:case 83:case 84:case 85:case 88:case 89:case 90:case 91:case 94:case 97:case 98:case 101:case 104:case 105:case 106:case 108:case 109:case 113:case 118:case 120:case 122:case 123:case 125:case 126:case 128:case 131:case 133:case 134:case 141:case 145:case 146:case 148:case 150:case 151:case 152:case 153:case 154:case 155:case 160:case 161:case 162:case 163:case 164:case 166:case 170:case 171:case 172:case 176:case 178:case 180:case 181:case 182:case 185:case 186:case 191:case 192:case 194:case 198:case 199:case 200:case 201:case 203:case 220:case 221:case 222:case 224:case 225:case 226:case 227:case 228:case 234:case 236:case 237:case 240:case 243:case 248:case 249:case 251:case 252:case 253:case 254:case 257:case 261:case 263:case 266:case 267:case 270:case 274:Ll(195);break;default:_l=Hl}if(_l!=25&&_l!=53&&_l!=282&&_l!=12805&&_l!=12806&&_l!=12808&&_l!=12809&&_l!=12810&&_l!=12811&&_l!=12844&&_l!=12845&&_l!=12846&&_l!=12870&&_l!=12872&&_l!=12873&&_l!=12874&&_l!=12875&&_l!=12877&&_l!=12878&&_l!=12879&&_l!=12880&&_l!=12881&&_l!=12882&&_l!=12883&&_l!=12884&&_l!=12885&&_l!=12886&&_l!=12888&&_l!=12889&&_l!=12890&&_l!=12891&&_l!=12893&&_l!=12894&&_l!=12896&&_l!=12897&&_l!=12898&&_l!=12901&&_l!=12902&&_l!=12903&&_l!=12904&&_l!=12905&&_l!=12906&&_l!=12908&&_l!=12909&&_l!=12910&&_l!=12911&&_l!=12912&&_l!=12913&&_l!=12918&&_l!=12919&&_l!=12920&&_l!=12921&&_l!=12922&&_l!=12923&&_l!=12924&&_l!=12925&&_l!=12926&&_l!=12928&&_l!=12929&&_l!=12931&&_l!=12932&&_l!=12933&&_l!=12934&&_l!=12935&&_l!=12936&&_l!=12937&&_l!=12941&&_l!=12945&&_l!=12946&&_l!=12948&&_l!=12950&&_l!=12951&&_l!=12952&&_l!=12953&&_l!=12954&&_l!=12955&&_l!=12959&&_l!=12960&&_l!=12961&&_l!=12962&&_l!=12963&&_l!=12964&&_l!=12965&&_l!=12966&&_l!=12967&&_l!=12970&&_l!=12971&&_l!=12972&&_l!=12974&&_l!=12976&&_l!=12978&&_l!=12980&&_l!=12981&&_l!=12982&&_l!=12984&&_l!=12985&&_l!=12986&&_l!=12991&&_l!=12992&&_l!=12994&&_l!=12998&&_l!=12999&&_l!=13e3&&_l!=13001&&_l!=13002&&_l!=13003&&_l!=13006&&_l!=13012&&_l!=13013&&_l!=13016&&_l!=13018&&_l!=13019&&_l!=13020&&_l!=13021&&_l!=13022&&_l!=13024&&_l!=13025&&_l!=13026&&_l!=13027&&_l!=13028&&_l!=13029&&_l!=13034&&_l!=13035&&_l!=13036&&_l!=13037&&_l!=13040&&_l!=13042&&_l!=13043&&_l!=13044&&_l!=13048&&_l!=13049&&_l!=13050&&_l!=13051&&_l!=13052&&_l!=13053&&_l!=13054&&_l!=13056&&_l!=13057&&_l!=13060&&_l!=13061&&_l!=13062&&_l!=13063&&_l!=13066&&_l!=13067&&_l!=13070&&_l!=13074&&_l!=16134&&_l!=20997&&_l!=20998&&_l!=21e3&&_l!=21001&&_l!=21002&&_l!=21003&&_l!=21036&&_l!=21037&&_l!=21038&&_l!=21062&&_l!=21064&&_l!=21065&&_l!=21066&&_l!=21067&&_l!=21069&&_l!=21070&&_l!=21071&&_l!=21072&&_l!=21073&&_l!=21074&&_l!=21075&&_l!=21076&&_l!=21077&&_l!=21078&&_l!=21080&&_l!=21081&&_l!=21082&&_l!=21083&&_l!=21085&&_l!=21086&&_l!=21088&&_l!=21089&&_l!=21090&&_l!=21093&&_l!=21094&&_l!=21095&&_l!=21096&&_l!=21097&&_l!=21098&&_l!=21100&&_l!=21101&&_l!=21102&&_l!=21103&&_l!=21104&&_l!=21105&&_l!=21110&&_l!=21111&&_l!=21112&&_l!=21113&&_l!=21114&&_l!=21115&&_l!=21116&&_l!=21117&&_l!=21118&&_l!=21120&&_l!=21121&&_l!=21123&&_l!=21124&&_l!=21125&&_l!=21126&&_l!=21127&&_l!=21128&&_l!=21129&&_l!=21133&&_l!=21137&&_l!=21138&&_l!=21140&&_l!=21142&&_l!=21143&&_l!=21144&&_l!=21145&&_l!=21146&&_l!=21147&&_l!=21151&&_l!=21152&&_l!=21153&&_l!=21154&&_l!=21155&&_l!=21156&&_l!=21157&&_l!=21158&&_l!=21159&&_l!=21162&&_l!=21163&&_l!=21164&&_l!=21166&&_l!=21168&&_l!=21170&&_l!=21172&&_l!=21173&&_l!=21174&&_l!=21176&&_l!=21177&&_l!=21178&&_l!=21183&&_l!=21184&&_l!=21186&&_l!=21190&&_l!=21191&&_l!=21192&&_l!=21193&&_l!=21194&&_l!=21195&&_l!=21198&&_l!=21204&&_l!=21205&&_l!=21208&&_l!=21210&&_l!=21211&&_l!=21212&&_l!=21213&&_l!=21214&&_l!=21216&&_l!=21217&&_l!=21218&&_l!=21219&&_l!=21220&&_l!=21221&&_l!=21226&&_l!=21227&&_l!=21228&&_l!=21229&&_l!=21232&&_l!=21234&&_l!=21235&&_l!=21236&&_l!=21240&&_l!=21241&&_l!=21242&&_l!=21243&&_l!=21244&&_l!=21245&&_l!=21246&&_l!=21248&&_l!=21249&&_l!=21252&&_l!=21253&&_l!=21254&&_l!=21255&&_l!=21258&&_l!=21259&&_l!=21262&&_l!=21266&&_l!=27141&&_l!=27142&&_l!=27144&&_l!=27145&&_l!=27146&&_l!=27147&&_l!=27180&&_l!=27181&&_l!=27182&&_l!=27206&&_l!=27208&&_l!=27209&&_l!=27210&&_l!=27211&&_l!=27213&&_l!=27214&&_l!=27215&&_l!=27216&&_l!=27217&&_l!=27218&&_l!=27219&&_l!=27220&&_l!=27221&&_l!=27222&&_l!=27224&&_l!=27225&&_l!=27226&&_l!=27227&&_l!=27229&&_l!=27230&&_l!=27232&&_l!=27233&&_l!=27234&&_l!=27237&&_l!=27238&&_l!=27239&&_l!=27240&&_l!=27241&&_l!=27242&&_l!=27244&&_l!=27245&&_l!=27246&&_l!=27247&&_l!=27248&&_l!=27249&&_l!=27254&&_l!=27255&&_l!=27256&&_l!=27257&&_l!=27258&&_l!=27259&&_l!=27260&&_l!=27261&&_l!=27262&&_l!=27264&&_l!=27265&&_l!=27267&&_l!=27268&&_l!=27269&&_l!=27270&&_l!=27271&&_l!=27272&&_l!=27273&&_l!=27277&&_l!=27281&&_l!=27282&&_l!=27284&&_l!=27286&&_l!=27287&&_l!=27288&&_l!=27289&&_l!=27290&&_l!=27291&&_l!=27295&&_l!=27296&&_l!=27297&&_l!=27298&&_l!=27299&&_l!=27300&&_l!=27301&&_l!=27302&&_l!=27303&&_l!=27306&&_l!=27307&&_l!=27308&&_l!=27310&&_l!=27312&&_l!=27314&&_l!=27316&&_l!=27317&&_l!=27318&&_l!=27320&&_l!=27321&&_l!=27322&&_l!=27327&&_l!=27328&&_l!=27330&&_l!=27334&&_l!=27335&&_l!=27336&&_l!=27337&&_l!=27338&&_l!=27339&&_l!=27342&&_l!=27348&&_l!=27349&&_l!=27352&&_l!=27354&&_l!=27355&&_l!=27356&&_l!=27357&&_l!=27358&&_l!=27360&&_l!=27361&&_l!=27362&&_l!=27363&&_l!=27364&&_l!=27365&&_l!=27370&&_l!=27371&&_l!=27372&&_l!=27373&&_l!=27376&&_l!=27378&&_l!=27379&&_l!=27380&&_l!=27384&&_l!=27385&&_l!=27386&&_l!=27387&&_l!=27388&&_l!=27389&&_l!=27390&&_l!=27392&&_l!=27393&&_l!=27396&&_l!=27397&&_l!=27398&&_l!=27399&&_l!=27402&&_l!=27403&&_l!=27406&&_l!=27410&&_l!=90198&&_l!=90214&&_l!=113284&&_l!=144389&&_l!=144390&&_l!=144392&&_l!=144393&&_l!=144394&&_l!=144395&&_l!=144428&&_l!=144429&&_l!=144430&&_l!=144454&&_l!=144456&&_l!=144457&&_l!=144458&&_l!=144459&&_l!=144461&&_l!=144462&&_l!=144463&&_l!=144464&&_l!=144465&&_l!=144466&&_l!=144467&&_l!=144468&&_l!=144469&&_l!=144470&&_l!=144472&&_l!=144473&&_l!=144474&&_l!=144475&&_l!=144477&&_l!=144478&&_l!=144480&&_l!=144481&&_l!=144482&&_l!=144485&&_l!=144486&&_l!=144487&&_l!=144488&&_l!=144489&&_l!=144490&&_l!=144492&&_l!=144493&&_l!=144494&&_l!=144495&&_l!=144496&&_l!=144497&&_l!=144502&&_l!=144503&&_l!=144504&&_l!=144505&&_l!=144506&&_l!=144507&&_l!=144508&&_l!=144509&&_l!=144510&&_l!=144512&&_l!=144513&&_l!=144515&&_l!=144516&&_l!=144517&&_l!=144518&&_l!=144519&&_l!=144520&&_l!=144521&&_l!=144525&&_l!=144529&&_l!=144530&&_l!=144532&&_l!=144534&&_l!=144535&&_l!=144536&&_l!=144537&&_l!=144538&&_l!=144539&&_l!=144543&&_l!=144544&&_l!=144545&&_l!=144546&&_l!=144547&&_l!=144548&&_l!=144549&&_l!=144550&&_l!=144551&&_l!=144554&&_l!=144555&&_l!=144556&&_l!=144558&&_l!=144560&&_l!=144562&&_l!=144564&&_l!=144565&&_l!=144566&&_l!=144568&&_l!=144569&&_l!=144570&&_l!=144575&&_l!=144576&&_l!=144578&&_l!=144582&&_l!=144583&&_l!=144584&&_l!=144585&&_l!=144586&&_l!=144587&&_l!=144590&&_l!=144596&&_l!=144597&&_l!=144600&&_l!=144602&&_l!=144603&&_l!=144604&&_l!=144605&&_l!=144606&&_l!=144608&&_l!=144609&&_l!=144610&&_l!=144611&&_l!=144612&&_l!=144613&&_l!=144618&&_l!=144619&&_l!=144620&&_l!=144621&&_l!=144624&&_l!=144626&&_l!=144627&&_l!=144628&&_l!=144632&&_l!=144633&&_l!=144634&&_l!=144635&&_l!=144636&&_l!=144637&&_l!=144638&&_l!=144640&&_l!=144641&&_l!=144644&&_l!=144645&&_l!=144646&&_l!=144647&&_l!=144650&&_l!=144651&&_l!=144654&&_l!=144658){_l=Kl(6,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{Qa(),Jl(6,t,-1);continue}catch(a){Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(6,t,-2);break}}}if(_l!=-1&&_l!=53&&_l!=16134&&_l!=27141&&_l!=27142&&_l!=27144&&_l!=27145&&_l!=27146&&_l!=27147&&_l!=27180&&_l!=27181&&_l!=27182&&_l!=27206&&_l!=27208&&_l!=27209&&_l!=27210&&_l!=27211&&_l!=27213&&_l!=27214&&_l!=27215&&_l!=27216&&_l!=27217&&_l!=27218&&_l!=27219&&_l!=27220&&_l!=27221&&_l!=27222&&_l!=27224&&_l!=27225&&_l!=27226&&_l!=27227&&_l!=27229&&_l!=27230&&_l!=27232&&_l!=27233&&_l!=27234&&_l!=27237&&_l!=27238&&_l!=27239&&_l!=27240&&_l!=27241&&_l!=27242&&_l!=27244&&_l!=27245&&_l!=27246&&_l!=27247&&_l!=27248&&_l!=27249&&_l!=27254&&_l!=27255&&_l!=27256&&_l!=27257&&_l!=27258&&_l!=27259&&_l!=27260&&_l!=27261&&_l!=27262&&_l!=27264&&_l!=27265&&_l!=27267&&_l!=27268&&_l!=27269&&_l!=27270&&_l!=27271&&_l!=27272&&_l!=27273&&_l!=27277&&_l!=27281&&_l!=27282&&_l!=27284&&_l!=27286&&_l!=27287&&_l!=27288&&_l!=27289&&_l!=27290&&_l!=27291&&_l!=27295&&_l!=27296&&_l!=27297&&_l!=27298&&_l!=27299&&_l!=27300&&_l!=27301&&_l!=27302&&_l!=27303&&_l!=27306&&_l!=27307&&_l!=27308&&_l!=27310&&_l!=27312&&_l!=27314&&_l!=27316&&_l!=27317&&_l!=27318&&_l!=27320&&_l!=27321&&_l!=27322&&_l!=27327&&_l!=27328&&_l!=27330&&_l!=27334&&_l!=27335&&_l!=27336&&_l!=27337&&_l!=27338&&_l!=27339&&_l!=27342&&_l!=27348&&_l!=27349&&_l!=27352&&_l!=27354&&_l!=27355&&_l!=27356&&_l!=27357&&_l!=27358&&_l!=27360&&_l!=27361&&_l!=27362&&_l!=27363&&_l!=27364&&_l!=27365&&_l!=27370&&_l!=27371&&_l!=27372&&_l!=27373&&_l!=27376&&_l!=27378&&_l!=27379&&_l!=27380&&_l!=27384&&_l!=27385&&_l!=27386&&_l!=27387&&_l!=27388&&_l!=27389&&_l!=27390&&_l!=27392&&_l!=27393&&_l!=27396&&_l!=27397&&_l!=27398&&_l!=27399&&_l!=27402&&_l!=27403&&_l!=27406&&_l!=27410&&_l!=90198&&_l!=90214&&_l!=113284)break;Qa()}}function Xa(){Vl.startNonterminal("StatementsAndExpr",Pl),za(),Nl(),G(),Vl.endNonterminal("StatementsAndExpr",Pl)}function Va(){Wa(),Y()}function $a(){Vl.startNonterminal("StatementsAndOptionalExpr",Pl),za(),Hl!=25&&Hl!=282&&(Nl(),G()),Vl.endNonterminal("StatementsAndOptionalExpr",Pl)}function Ja(){Wa(),Hl!=25&&Hl!=282&&Y()}function Ka(){Vl.startNonterminal("Statement",Pl);switch(Hl){case 132:Ll(189);break;case 137:Ll(196);break;case 174:Ll(193);break;case 250:Ll(190);break;case 262:Ll(187);break;case 276:Ll(277);break;case 31:case 32:Ll(255);break;case 86:case 102:Ll(188);break;case 152:case 243:case 253:case 267:Ll(185);break;default:_l=Hl}if(_l==2836||_l==3103||_l==3104||_l==3348||_l==4372||_l==4884||_l==5396||_l==5908||_l==16148||_l==16660||_l==17675||_l==17684||_l==18196||_l==20756||_l==21780||_l==22804||_l==23316||_l==23828||_l==24340||_l==27412||_l==27924||_l==28436||_l==30484||_l==34068||_l==35092||_l==35871||_l==35872||_l==36116||_l==36895||_l==36896||_l==37140||_l==37407||_l==37408||_l==37652||_l==37919||_l==37920||_l==38164||_l==38431||_l==38432||_l==38676||_l==39455||_l==39456||_l==39700||_l==39967||_l==39968||_l==40212||_l==40479||_l==40480||_l==40724||_l==40991||_l==40992||_l==41236||_l==41503||_l==41504||_l==41748||_l==42015||_l==42016||_l==42260||_l==42527||_l==42528||_l==42772||_l==43039||_l==43040||_l==43284||_l==43551||_l==43552||_l==43796||_l==44063||_l==44064||_l==44308||_l==45087||_l==45088||_l==45332||_l==45599||_l==45600||_l==45844||_l==46111||_l==46112||_l==46356||_l==46623||_l==46624||_l==46868||_l==47647||_l==47648||_l==47892||_l==48159||_l==48160||_l==48404||_l==49183||_l==49184||_l==49428||_l==49695||_l==49696||_l==49940||_l==50207||_l==50208||_l==50452||_l==51743||_l==51744||_l==51988||_l==52255||_l==52256||_l==52500||_l==52767||_l==52768||_l==53012||_l==53279||_l==53280||_l==53524||_l==53791||_l==53792||_l==54036||_l==54303||_l==54304||_l==54548||_l==55327||_l==55328||_l==55572||_l==55839||_l==55840||_l==56084||_l==56351||_l==56352||_l==56596||_l==56863||_l==56864||_l==57108||_l==57375||_l==57376||_l==57620||_l==57887||_l==57888||_l==58132||_l==60447||_l==60448||_l==60692||_l==60959||_l==60960||_l==61204||_l==61471||_l==61472||_l==61716||_l==61983||_l==61984||_l==62228||_l==62495||_l==62496||_l==62740||_l==63007||_l==63008||_l==63252||_l==63519||_l==63520||_l==63764||_l==64031||_l==64032||_l==64276||_l==64543||_l==64544||_l==64788||_l==65567||_l==65568||_l==65812||_l==66079||_l==66080||_l==66324||_l==67103||_l==67104||_l==67348||_l==67615||_l==67616||_l==67860||_l==68127||_l==68128||_l==68372||_l==68639||_l==68640||_l==68884||_l==69151||_l==69152||_l==69396||_l==69663||_l==69664||_l==69908||_l==70175||_l==70176||_l==70420||_l==72223||_l==72224||_l==72468||_l==74271||_l==74272||_l==74516||_l==74783||_l==74784||_l==75028||_l==75807||_l==75808||_l==76052||_l==76831||_l==76832||_l==77076||_l==77343||_l==77344||_l==77588||_l==77855||_l==77856||_l==78100||_l==78367||_l==78368||_l==78612||_l==78879||_l==78880||_l==79124||_l==79391||_l==79392||_l==79636||_l==81439||_l==81440||_l==81684||_l==81951||_l==81952||_l==82196||_l==82463||_l==82464||_l==82708||_l==82975||_l==82976||_l==83220||_l==83487||_l==83488||_l==83732||_l==83999||_l==84e3||_l==84244||_l==84511||_l==84512||_l==84756||_l==85023||_l==85024||_l==85268||_l==85535||_l==85536||_l==85780||_l==87071||_l==87072||_l==87316||_l==87583||_l==87584||_l==87828||_l==88095||_l==88096||_l==88340||_l==89119||_l==89120||_l==89364||_l==90143||_l==90144||_l==90388||_l==91167||_l==91168||_l==91412||_l==92191||_l==92192||_l==92436||_l==92703||_l==92704||_l==92948||_l==93215||_l==93216||_l==93460||_l==94239||_l==94240||_l==94484||_l==94751||_l==94752||_l==94996||_l==95263||_l==95264||_l==95508||_l==97823||_l==97824||_l==98068||_l==98335||_l==98336||_l==98580||_l==99359||_l==99360||_l==99604||_l==101407||_l==101408||_l==101652||_l==101919||_l==101920||_l==102164||_l==102431||_l==102432||_l==102676||_l==102943||_l==102944||_l==103188||_l==103455||_l==103456||_l==103700||_l==103967||_l==103968||_l==104212||_l==105503||_l==105504||_l==105748||_l==108575||_l==108576||_l==108820||_l==109087||_l==109088||_l==109332||_l==110623||_l==110624||_l==110868||_l==111647||_l==111648||_l==111892||_l==112159||_l==112160||_l==112404||_l==112671||_l==112672||_l==112916||_l==113183||_l==113184||_l==113428||_l==113695||_l==113696||_l==113940||_l==114719||_l==114720||_l==114964||_l==115231||_l==115232||_l==115476||_l==115743||_l==115744||_l==115988||_l==116255||_l==116256||_l==116500||_l==116767||_l==116768||_l==117012||_l==117279||_l==117280||_l==117524||_l==119839||_l==119840||_l==120084||_l==120351||_l==120352||_l==120596||_l==120863||_l==120864||_l==121108||_l==121375||_l==121376||_l==121620||_l==122911||_l==122912||_l==123156||_l==123935||_l==123936||_l==124180||_l==124447||_l==124448||_l==124692||_l==124959||_l==124960||_l==125204||_l==127007||_l==127008||_l==127252||_l==127519||_l==127520||_l==127764||_l==128031||_l==128032||_l==128276||_l==128543||_l==128544||_l==128788||_l==129055||_l==129056||_l==129300||_l==129567||_l==129568||_l==129812||_l==130079||_l==130080||_l==130324||_l==131103||_l==131104||_l==131348||_l==131615||_l==131616||_l==131860||_l==133151||_l==133152||_l==133396||_l==133663||_l==133664||_l==133908||_l==134175||_l==134176||_l==134420||_l==134687||_l==134688||_l==134932||_l==136223||_l==136224||_l==136468||_l==136735||_l==136736||_l==136980||_l==138271||_l==138272||_l==138516||_l==140319||_l==140320||_l==140564||_l==141588||_l==142612||_l==144660){_l=Kl(7,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{Ya(),_l=-1}catch(a){try{Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),ef(),_l=-2}catch(f){try{Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),nf(),_l=-3}catch(l){try{Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),kf(),_l=-12}catch(c){_l=-13}}}}Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(7,Pl,_l)}}switch(_l){case-2:Za();break;case-3:tf();break;case 90198:rf();break;case 90214:of();break;case 113284:af();break;case 16009:case 16046:case 116910:case 119945:case 128649:lf();break;case 17560:df();break;case 17651:mf();break;case 141562:wf();break;case 17661:Sf();break;case-12:case 16134:Cf();break;case-13:Lf();break;case 53:Of();break;default:Ga()}Vl.endNonterminal("Statement",Pl)}function Qa(){switch(Hl){case 132:Ll(189);break;case 137:Ll(196);break;case 174:Ll(193);break;case 250:Ll(190);break;case 262:Ll(187);break;case 276:Ll(277);break;case 31:case 32:Ll(255);break;case 86:case 102:Ll(188);break;case 152:case 243:case 253:case 267:Ll(185);break;default:_l=Hl}if(_l==2836||_l==3103||_l==3104||_l==3348||_l==4372||_l==4884||_l==5396||_l==5908||_l==16148||_l==16660||_l==17675||_l==17684||_l==18196||_l==20756||_l==21780||_l==22804||_l==23316||_l==23828||_l==24340||_l==27412||_l==27924||_l==28436||_l==30484||_l==34068||_l==35092||_l==35871||_l==35872||_l==36116||_l==36895||_l==36896||_l==37140||_l==37407||_l==37408||_l==37652||_l==37919||_l==37920||_l==38164||_l==38431||_l==38432||_l==38676||_l==39455||_l==39456||_l==39700||_l==39967||_l==39968||_l==40212||_l==40479||_l==40480||_l==40724||_l==40991||_l==40992||_l==41236||_l==41503||_l==41504||_l==41748||_l==42015||_l==42016||_l==42260||_l==42527||_l==42528||_l==42772||_l==43039||_l==43040||_l==43284||_l==43551||_l==43552||_l==43796||_l==44063||_l==44064||_l==44308||_l==45087||_l==45088||_l==45332||_l==45599||_l==45600||_l==45844||_l==46111||_l==46112||_l==46356||_l==46623||_l==46624||_l==46868||_l==47647||_l==47648||_l==47892||_l==48159||_l==48160||_l==48404||_l==49183||_l==49184||_l==49428||_l==49695||_l==49696||_l==49940||_l==50207||_l==50208||_l==50452||_l==51743||_l==51744||_l==51988||_l==52255||_l==52256||_l==52500||_l==52767||_l==52768||_l==53012||_l==53279||_l==53280||_l==53524||_l==53791||_l==53792||_l==54036||_l==54303||_l==54304||_l==54548||_l==55327||_l==55328||_l==55572||_l==55839||_l==55840||_l==56084||_l==56351||_l==56352||_l==56596||_l==56863||_l==56864||_l==57108||_l==57375||_l==57376||_l==57620||_l==57887||_l==57888||_l==58132||_l==60447||_l==60448||_l==60692||_l==60959||_l==60960||_l==61204||_l==61471||_l==61472||_l==61716||_l==61983||_l==61984||_l==62228||_l==62495||_l==62496||_l==62740||_l==63007||_l==63008||_l==63252||_l==63519||_l==63520||_l==63764||_l==64031||_l==64032||_l==64276||_l==64543||_l==64544||_l==64788||_l==65567||_l==65568||_l==65812||_l==66079||_l==66080||_l==66324||_l==67103||_l==67104||_l==67348||_l==67615||_l==67616||_l==67860||_l==68127||_l==68128||_l==68372||_l==68639||_l==68640||_l==68884||_l==69151||_l==69152||_l==69396||_l==69663||_l==69664||_l==69908||_l==70175||_l==70176||_l==70420||_l==72223||_l==72224||_l==72468||_l==74271||_l==74272||_l==74516||_l==74783||_l==74784||_l==75028||_l==75807||_l==75808||_l==76052||_l==76831||_l==76832||_l==77076||_l==77343||_l==77344||_l==77588||_l==77855||_l==77856||_l==78100||_l==78367||_l==78368||_l==78612||_l==78879||_l==78880||_l==79124||_l==79391||_l==79392||_l==79636||_l==81439||_l==81440||_l==81684||_l==81951||_l==81952||_l==82196||_l==82463||_l==82464||_l==82708||_l==82975||_l==82976||_l==83220||_l==83487||_l==83488||_l==83732||_l==83999||_l==84e3||_l==84244||_l==84511||_l==84512||_l==84756||_l==85023||_l==85024||_l==85268||_l==85535||_l==85536||_l==85780||_l==87071||_l==87072||_l==87316||_l==87583||_l==87584||_l==87828||_l==88095||_l==88096||_l==88340||_l==89119||_l==89120||_l==89364||_l==90143||_l==90144||_l==90388||_l==91167||_l==91168||_l==91412||_l==92191||_l==92192||_l==92436||_l==92703||_l==92704||_l==92948||_l==93215||_l==93216||_l==93460||_l==94239||_l==94240||_l==94484||_l==94751||_l==94752||_l==94996||_l==95263||_l==95264||_l==95508||_l==97823||_l==97824||_l==98068||_l==98335||_l==98336||_l==98580||_l==99359||_l==99360||_l==99604||_l==101407||_l==101408||_l==101652||_l==101919||_l==101920||_l==102164||_l==102431||_l==102432||_l==102676||_l==102943||_l==102944||_l==103188||_l==103455||_l==103456||_l==103700||_l==103967||_l==103968||_l==104212||_l==105503||_l==105504||_l==105748||_l==108575||_l==108576||_l==108820||_l==109087||_l==109088||_l==109332||_l==110623||_l==110624||_l==110868||_l==111647||_l==111648||_l==111892||_l==112159||_l==112160||_l==112404||_l==112671||_l==112672||_l==112916||_l==113183||_l==113184||_l==113428||_l==113695||_l==113696||_l==113940||_l==114719||_l==114720||_l==114964||_l==115231||_l==115232||_l==115476||_l==115743||_l==115744||_l==115988||_l==116255||_l==116256||_l==116500||_l==116767||_l==116768||_l==117012||_l==117279||_l==117280||_l==117524||_l==119839||_l==119840||_l==120084||_l==120351||_l==120352||_l==120596||_l==120863||_l==120864||_l==121108||_l==121375||_l==121376||_l==121620||_l==122911||_l==122912||_l==123156||_l==123935||_l==123936||_l==124180||_l==124447||_l==124448||_l==124692||_l==124959||_l==124960||_l==125204||_l==127007||_l==127008||_l==127252||_l==127519||_l==127520||_l==127764||_l==128031||_l==128032||_l==128276||_l==128543||_l==128544||_l==128788||_l==129055||_l==129056||_l==129300||_l==129567||_l==129568||_l==129812||_l==130079||_l==130080||_l==130324||_l==131103||_l==131104||_l==131348||_l==131615||_l==131616||_l==131860||_l==133151||_l==133152||_l==133396||_l==133663||_l==133664||_l==133908||_l==134175||_l==134176||_l==134420||_l==134687||_l==134688||_l==134932||_l==136223||_l==136224||_l==136468||_l==136735||_l==136736||_l==136980||_l==138271||_l==138272||_l==138516||_l==140319||_l==140320||_l==140564||_l==141588||_l==142612||_l==144660){_l=Kl(7,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{Ya(),Jl(7,t,-1),_l=-15}catch(a){try{Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),ef(),Jl(7,t,-2),_l=-15}catch(f){try{Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),nf(),Jl(7,t,-3),_l=-15}catch(l){try{Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),kf(),Jl(7,t,-12),_l=-15}catch(c){_l=-13,Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(7,t,-13)}}}}}}switch(_l){case-2:ef();break;case-3:nf();break;case 90198:sf();break;case 90214:uf();break;case 113284:ff();break;case 16009:case 16046:case 116910:case 119945:case 128649:cf();break;case 17560:vf();break;case 17651:gf();break;case 141562:Ef();break;case 17661:xf();break;case-12:case 16134:kf();break;case-13:Af();break;case 53:Mf();break;case-15:break;default:Ya()}}function Ga(){Vl.startNonterminal("ApplyStatement",Pl),Pf(),Sl(53),Vl.endNonterminal("ApplyStatement",Pl)}function Ya(){Hf(),xl(53)}function Za(){Vl.startNonterminal("AssignStatement",Pl),Sl(31),kl(255),Nl(),hi(),kl(27),Sl(52),kl(267),Nl(),_f(),Sl(53),Vl.endNonterminal("AssignStatement",Pl)}function ef(){xl(31),kl(255),pi(),kl(27),xl(52),kl(267),Df(),xl(53)}function tf(){Vl.startNonterminal("BlockStatement",Pl),Sl(276),kl(277),Nl(),za(),Sl(282),Vl.endNonterminal("BlockStatement",Pl)}function nf(){xl(276),kl(277),Wa(),xl(282)}function rf(){Vl.startNonterminal("BreakStatement",Pl),Sl(86),kl(59),Sl(176),kl(28),Sl(53),Vl.endNonterminal("BreakStatement",Pl)}function sf(){xl(86),kl(59),xl(176),kl(28),xl(53)}function of(){Vl.startNonterminal("ContinueStatement",Pl),Sl(102),kl(59),Sl(176),kl(28),Sl(53),Vl.endNonterminal("ContinueStatement",Pl)}function uf(){xl(102),kl(59),xl(176),kl(28),xl(53)}function af(){Vl.startNonterminal("ExitStatement",Pl),Sl(132),kl(71),Sl(221),kl(267),Nl(),_f(),Sl(53),Vl.endNonterminal("ExitStatement",Pl)}function ff(){xl(132),kl(71),xl(221),kl(267),Df(),xl(53)}function lf(){Vl.startNonterminal("FLWORStatement",Pl),tt();for(;;){kl(173);if(Hl==220)break;Nl(),rt()}Nl(),hf(),Vl.endNonterminal("FLWORStatement",Pl)}function cf(){nt();for(;;){kl(173);if(Hl==220)break;it()}pf()}function hf(){Vl.startNonterminal("ReturnStatement",Pl),Sl(220),kl(270),Nl(),Ka(),Vl.endNonterminal("ReturnStatement",Pl)}function pf(){xl(220),kl(270),Qa()}function df(){Vl.startNonterminal("IfStatement",Pl),Sl(152),kl(22),Sl(34),kl(267),Nl(),G(),Sl(37),kl(77),Sl(245),kl(270),Nl(),Ka(),kl(48),Sl(122),kl(270),Nl(),Ka(),Vl.endNonterminal("IfStatement",Pl)}function vf(){xl(152),kl(22),xl(34),kl(267),Y(),xl(37),kl(77),xl(245),kl(270),Qa(),kl(48),xl(122),kl(270),Qa()}function mf(){Vl.startNonterminal("SwitchStatement",Pl),Sl(243),kl(22),Sl(34),kl(267),Nl(),G(),Sl(37);for(;;){kl(35),Nl(),yf(),kl(113);if(Hl!=88)break}Sl(109),kl(70),Sl(220),kl(270),Nl(),Ka(),Vl.endNonterminal("SwitchStatement",Pl)}function gf(){xl(243),kl(22),xl(34),kl(267),Y(),xl(37);for(;;){kl(35),bf(),kl(113);if(Hl!=88)break}xl(109),kl(70),xl(220),kl(270),Qa()}function yf(){Vl.startNonterminal("SwitchCaseStatement",Pl);for(;;){Sl(88),kl(267),Nl(),dn();if(Hl!=88)break}Sl(220),kl(270),Nl(),Ka(),Vl.endNonterminal("SwitchCaseStatement",Pl)}function bf(){for(;;){xl(88),kl(267),vn();if(Hl!=88)break}xl(220),kl(270),Qa()}function wf(){Vl.startNonterminal("TryCatchStatement",Pl),Sl(250),kl(87),Nl(),tf();for(;;){kl(36),Sl(91),kl(257),Nl(),_n(),Nl(),tf(),kl(278);switch(Hl){case 91:Ll(279);break;default:_l=Hl}if(_l==38491||_l==45659||_l==46171||_l==60507||_l==65627||_l==67163||_l==74843||_l==76891||_l==77403||_l==82011||_l==83035||_l==84059||_l==88155||_l==91227||_l==92251||_l==95323||_l==102491||_l==127067||_l==127579||_l==130139){_l=Kl(8,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{kl(36),xl(91),kl(257),Dn(),nf(),_l=-1}catch(a){_l=-2}Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(8,Pl,_l)}}if(_l!=-1&&_l!=2651&&_l!=3163&&_l!=35931&&_l!=36955&&_l!=37467&&_l!=37979&&_l!=39515&&_l!=40027&&_l!=40539&&_l!=41051&&_l!=41563&&_l!=42075&&_l!=42587&&_l!=43099&&_l!=43611&&_l!=44123&&_l!=45147&&_l!=46683&&_l!=47707&&_l!=48219&&_l!=49243&&_l!=49755&&_l!=50267&&_l!=51803&&_l!=52315&&_l!=52827&&_l!=53339&&_l!=53851&&_l!=54363&&_l!=55387&&_l!=55899&&_l!=56411&&_l!=56923&&_l!=57435&&_l!=57947&&_l!=61019&&_l!=61531&&_l!=62043&&_l!=62555&&_l!=63067&&_l!=63579&&_l!=64091&&_l!=64603&&_l!=66139&&_l!=67675&&_l!=68187&&_l!=68699&&_l!=69211&&_l!=69723&&_l!=70235&&_l!=72283&&_l!=74331&&_l!=75867&&_l!=77915&&_l!=78427&&_l!=78939&&_l!=79451&&_l!=81499&&_l!=82523&&_l!=83547&&_l!=84571&&_l!=85083&&_l!=85595&&_l!=87131&&_l!=87643&&_l!=89179&&_l!=90203&&_l!=92763&&_l!=93275&&_l!=94299&&_l!=94811&&_l!=97883&&_l!=98395&&_l!=99419&&_l!=101467&&_l!=101979&&_l!=103003&&_l!=103515&&_l!=104027&&_l!=105563&&_l!=108635&&_l!=109147&&_l!=110683&&_l!=111707&&_l!=112219&&_l!=112731&&_l!=113243&&_l!=113755&&_l!=114779&&_l!=115291&&_l!=115803&&_l!=116315&&_l!=116827&&_l!=117339&&_l!=119899&&_l!=120411&&_l!=120923&&_l!=121435&&_l!=122971&&_l!=123995&&_l!=124507&&_l!=125019&&_l!=128091&&_l!=128603&&_l!=129115&&_l!=129627&&_l!=131163&&_l!=131675&&_l!=133211&&_l!=133723&&_l!=134235&&_l!=134747&&_l!=136283&&_l!=136795&&_l!=138331&&_l!=140379)break}Vl.endNonterminal("TryCatchStatement",Pl)}function Ef(){xl(250),kl(87),nf(),kl(36),xl(91),kl(257),Dn(),nf();for(;;){kl(278);switch(Hl){case 91:Ll(279);break;default:_l=Hl}if(_l==38491||_l==45659||_l==46171||_l==60507||_l==65627||_l==67163||_l==74843||_l==76891||_l==77403||_l==82011||_l==83035||_l==84059||_l==88155||_l==91227||_l==92251||_l==95323||_l==102491||_l==127067||_l==127579||_l==130139){_l=Kl(8,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{kl(36),xl(91),kl(257),Dn(),nf(),Jl(8,t,-1);continue}catch(a){Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(8,t,-2);break}}}if(_l!=-1&&_l!=2651&&_l!=3163&&_l!=35931&&_l!=36955&&_l!=37467&&_l!=37979&&_l!=39515&&_l!=40027&&_l!=40539&&_l!=41051&&_l!=41563&&_l!=42075&&_l!=42587&&_l!=43099&&_l!=43611&&_l!=44123&&_l!=45147&&_l!=46683&&_l!=47707&&_l!=48219&&_l!=49243&&_l!=49755&&_l!=50267&&_l!=51803&&_l!=52315&&_l!=52827&&_l!=53339&&_l!=53851&&_l!=54363&&_l!=55387&&_l!=55899&&_l!=56411&&_l!=56923&&_l!=57435&&_l!=57947&&_l!=61019&&_l!=61531&&_l!=62043&&_l!=62555&&_l!=63067&&_l!=63579&&_l!=64091&&_l!=64603&&_l!=66139&&_l!=67675&&_l!=68187&&_l!=68699&&_l!=69211&&_l!=69723&&_l!=70235&&_l!=72283&&_l!=74331&&_l!=75867&&_l!=77915&&_l!=78427&&_l!=78939&&_l!=79451&&_l!=81499&&_l!=82523&&_l!=83547&&_l!=84571&&_l!=85083&&_l!=85595&&_l!=87131&&_l!=87643&&_l!=89179&&_l!=90203&&_l!=92763&&_l!=93275&&_l!=94299&&_l!=94811&&_l!=97883&&_l!=98395&&_l!=99419&&_l!=101467&&_l!=101979&&_l!=103003&&_l!=103515&&_l!=104027&&_l!=105563&&_l!=108635&&_l!=109147&&_l!=110683&&_l!=111707&&_l!=112219&&_l!=112731&&_l!=113243&&_l!=113755&&_l!=114779&&_l!=115291&&_l!=115803&&_l!=116315&&_l!=116827&&_l!=117339&&_l!=119899&&_l!=120411&&_l!=120923&&_l!=121435&&_l!=122971&&_l!=123995&&_l!=124507&&_l!=125019&&_l!=128091&&_l!=128603&&_l!=129115&&_l!=129627&&_l!=131163&&_l!=131675&&_l!=133211&&_l!=133723&&_l!=134235&&_l!=134747&&_l!=136283&&_l!=136795&&_l!=138331&&_l!=140379)break;kl(36),xl(91),kl(257),Dn(),nf()}}function Sf(){Vl.startNonterminal("TypeswitchStatement",Pl),Sl(253),kl(22),Sl(34),kl(267),Nl(),G(),Sl(37);for(;;){kl(35),Nl(),Tf(),kl(113);if(Hl!=88)break}Sl(109),kl(95),Hl==31&&(Sl(31),kl(255),Nl(),hi()),kl(70),Sl(220),kl(270),Nl(),Ka(),Vl.endNonterminal("TypeswitchStatement",Pl)}function xf(){xl(253),kl(22),xl(34),kl(267),Y(),xl(37);for(;;){kl(35),Nf(),kl(113);if(Hl!=88)break}xl(109),kl(95),Hl==31&&(xl(31),kl(255),pi()),kl(70),xl(220),kl(270),Qa()}function Tf(){Vl.startNonterminal("CaseStatement",Pl),Sl(88),kl(262),Hl==31&&(Sl(31),kl(255),Nl(),hi(),kl(30),Sl(79)),kl(260),Nl(),ms(),kl(70),Sl(220),kl(270),Nl(),Ka(),Vl.endNonterminal("CaseStatement",Pl)}function Nf(){xl(88),kl(262),Hl==31&&(xl(31),kl(255),pi(),kl(30),xl(79)),kl(260),gs(),kl(70),xl(220),kl(270),Qa()}function Cf(){Vl.startNonterminal("VarDeclStatement",Pl);for(;;){kl(98);if(Hl!=32)break;Nl(),B()}Sl(262),kl(21),Sl(31),kl(255),Nl(),hi(),kl(157),Hl==79&&(Nl(),ds()),kl(145),Hl==52&&(Sl(52),kl(267),Nl(),_f());for(;;){if(Hl!=41)break;Sl(41),kl(21),Sl(31),kl(255),Nl(),hi(),kl(157),Hl==79&&(Nl(),ds()),kl(145),Hl==52&&(Sl(52),kl(267),Nl(),_f())}Sl(53),Vl.endNonterminal("VarDeclStatement",Pl)}function kf(){for(;;){kl(98);if(Hl!=32)break;j()}xl(262),kl(21),xl(31),kl(255),pi(),kl(157),Hl==79&&vs(),kl(145),Hl==52&&(xl(52),kl(267),Df());for(;;){if(Hl!=41)break;xl(41),kl(21),xl(31),kl(255),pi(),kl(157),Hl==79&&vs(),kl(145),Hl==52&&(xl(52),kl(267),Df())}xl(53)}function Lf(){Vl.startNonterminal("WhileStatement",Pl),Sl(267),kl(22),Sl(34),kl(267),Nl(),G(),Sl(37),kl(270),Nl(),Ka(),Vl.endNonterminal("WhileStatement",Pl)}function Af(){xl(267),kl(22),xl(34),kl(267),Y(),xl(37),kl(270),Qa()}function Of(){Vl.startNonterminal("VoidStatement",Pl),Sl(53),Vl.endNonterminal("VoidStatement",Pl)}function Mf(){xl(53)}function _f(){Vl.startNonterminal("ExprSingle",Pl);switch(Hl){case 137:Ll(236);break;case 174:Ll(233);break;case 250:Ll(232);break;case 152:case 243:case 253:Ll(229);break;default:_l=Hl}switch(_l){case 16009:case 16046:case 116910:case 119945:case 128649:Z();break;case 17560:Sn();break;case 17651:ln();break;case 141562:Tn();break;case 17661:mn();break;default:Pf()}Vl.endNonterminal("ExprSingle",Pl)}function Df(){switch(Hl){case 137:Ll(236);break;case 174:Ll(233);break;case 250:Ll(232);break;case 152:case 243:case 253:Ll(229);break;default:_l=Hl}switch(_l){case 16009:case 16046:case 116910:case 119945:case 128649:et();break;case 17560:xn();break;case 17651:cn();break;case 141562:Nn();break;case 17661:gn();break;default:Hf()}}function Pf(){Vl.startNonterminal("ExprSimple",Pl);switch(Hl){case 77:Ll(231);break;case 218:Ll(234);break;case 219:Ll(235);break;case 110:case 159:Ll(237);break;case 103:case 129:case 235:Ll(230);break;default:_l=Hl}if(_l==133851){_l=Kl(9,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{Ho(),_l=-6}catch(a){_l=-11}Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(9,Pl,_l)}}switch(_l){case 16001:case 16107:on();break;case 97951:case 98463:Oo();break;case 97902:case 98414:_o();break;case 98010:Bo();break;case-6:case 98011:Po();break;case 15975:Wo();break;case 85102:Bf();break;case 85151:Ff();break;case 85210:qf();break;case-11:Uf();break;case 85069:Wf();break;default:Pn()}Vl.endNonterminal("ExprSimple",Pl)}function Hf(){switch(Hl){case 77:Ll(231);break;case 218:Ll(234);break;case 219:Ll(235);break;case 110:case 159:Ll(237);break;case 103:case 129:case 235:Ll(230);break;default:_l=Hl}if(_l==133851){_l=Kl(9,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{Ho(),Jl(9,t,-6),_l=-13}catch(a){_l=-11,Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(9,t,-11)}}}switch(_l){case 16001:case 16107:un();break;case 97951:case 98463:Mo();break;case 97902:case 98414:Do();break;case 98010:jo();break;case-6:case 98011:Ho();break;case 15975:Xo();break;case 85102:jf();break;case 85151:If();break;case 85210:Rf();break;case-11:zf();break;case 85069:Xf();break;case-13:break;default:Hn()}}function Bf(){Vl.startNonterminal("JSONDeleteExpr",Pl),Sl(110),kl(56),Sl(166),kl(264),Nl(),Yr(),Vl.endNonterminal("JSONDeleteExpr",Pl)}function jf(){xl(110),kl(56),xl(166),kl(264),Zr()}function Ff(){Vl.startNonterminal("JSONInsertExpr",Pl);switch(Hl){case 159:Ll(56);break;default:_l=Hl}_l=Kl(10,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{xl(159),kl(56),xl(166),kl(267),Df(),xl(163),kl(267),Df();switch(Hl){case 81:Ll(69);break;default:_l=Hl}if(_l==108113){_l=Kl(11,Pl);if(_l==0){var a=Dl,f=Pl,l=Hl,c=Bl,h=jl,p=Fl,d=Il,v=ql;try{xl(81),kl(69),xl(211),kl(267),Df(),Jl(11,f,-1)}catch(m){Dl=a,Pl=f,Hl=l,Hl==0?Zl=f:(Bl=c,jl=h,Fl=p,Fl==0?Zl=h:(Il=d,ql=v,Zl=v)),Jl(11,f,-2)}_l=-2}}_l==-1&&(xl(81),kl(69),xl(211),kl(267),Df()),_l=-1}catch(g){_l=-2}Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(10,Pl,_l)}switch(_l){case-1:Sl(159),kl(56),Sl(166),kl(267),Nl(),_f(),Sl(163),kl(267),Nl(),_f();switch(Hl){case 81:Ll(69);break;default:_l=Hl}if(_l==108113){_l=Kl(11,Pl);if(_l==0){var a=Dl,f=Pl,l=Hl,c=Bl,h=jl,p=Fl,d=Il,v=ql;try{xl(81),kl(69),xl(211),kl(267),Df(),_l=-1}catch(m){_l=-2}Dl=a,Pl=f,Hl=l,Hl==0?Zl=f:(Bl=c,jl=h,Fl=p,Fl==0?Zl=h:(Il=d,ql=v,Zl=v)),Jl(11,Pl,_l)}}_l==-1&&(Sl(81),kl(69),Sl(211),kl(267),Nl(),_f());break;default:Sl(159),kl(56),Sl(166),kl(267),Nl(),hl(),Sl(163),kl(267),Nl(),_f()}Vl.endNonterminal("JSONInsertExpr",Pl)}function If(){switch(Hl){case 159:Ll(56);break;default:_l=Hl}_l=Kl(10,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{xl(159),kl(56),xl(166),kl(267),Df(),xl(163),kl(267),Df();switch(Hl){case 81:Ll(69);break;default:_l=Hl}if(_l==108113){_l=Kl(11,Pl);if(_l==0){var a=Dl,f=Pl,l=Hl,c=Bl,h=jl,p=Fl,d=Il,v=ql;try{xl(81),kl(69),xl(211),kl(267),Df(),Jl(11,f,-1)}catch(m){Dl=a,Pl=f,Hl=l,Hl==0?Zl=f:(Bl=c,jl=h,Fl=p,Fl==0?Zl=h:(Il=d,ql=v,Zl=v)),Jl(11,f,-2)}_l=-2}}_l==-1&&(xl(81),kl(69),xl(211),kl(267),Df()),Jl(10,t,-1),_l=-3}catch(g){_l=-2,Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(10,t,-2)}}switch(_l){case-1:xl(159),kl(56),xl(166),kl(267),Df(),xl(163),kl(267),Df();switch(Hl){case 81:Ll(69);break;default:_l=Hl}if(_l==108113){_l=Kl(11,Pl);if(_l==0){var a=Dl,f=Pl,l=Hl,c=Bl,h=jl,p=Fl,d=Il,v=ql;try{xl(81),kl(69),xl(211),kl(267),Df(),Jl(11,f,-1)}catch(m){Dl=a,Pl=f,Hl=l,Hl==0?Zl=f:(Bl=c,jl=h,Fl=p,Fl==0?Zl=h:(Il=d,ql=v,Zl=v)),Jl(11,f,-2)}_l=-2}}_l==-1&&(xl(81),kl(69),xl(211),kl(267),Df());break;case-3:break;default:xl(159),kl(56),xl(166),kl(267),pl(),xl(163),kl(267),Df()}}function qf(){Vl.startNonterminal("JSONRenameExpr",Pl),Sl(218),kl(56),Sl(166),kl(264),Nl(),Yr(),Sl(79),kl(267),Nl(),_f(),Vl.endNonterminal("JSONRenameExpr",Pl)}function Rf(){xl(218),kl(56),xl(166),kl(264),Zr(),xl(79),kl(267),Df()}function Uf(){Vl.startNonterminal("JSONReplaceExpr",Pl),Sl(219),kl(82),Sl(261),kl(64),Sl(196),kl(56),Sl(166),kl(264),Nl(),Yr(),Sl(270),kl(267),Nl(),_f(),Vl.endNonterminal("JSONReplaceExpr",Pl)}function zf(){xl(219),kl(82),xl(261),kl(64),xl(196),kl(56),xl(166),kl(264),Zr(),xl(270),kl(267),Df()}function Wf(){Vl.startNonterminal("JSONAppendExpr",Pl),Sl(77),kl(56),Sl(166),kl(267),Nl(),_f(),Sl(163),kl(267),Nl(),_f(),Vl.endNonterminal("JSONAppendExpr",Pl)}function Xf(){xl(77),kl(56),xl(166),kl(267),Df(),xl(163),kl(267),Df()}function Vf(){Vl.startNonterminal("CommonContent",Pl);switch(Hl){case 12:Sl(12);break;case 23:Sl(23);break;case 277:Sl(277);break;case 283:Sl(283);break;default:yl()}Vl.endNonterminal("CommonContent",Pl)}function $f(){switch(Hl){case 12:xl(12);break;case 23:xl(23);break;case 277:xl(277);break;case 283:xl(283);break;default:bl()}}function Jf(){Vl.startNonterminal("ContentExpr",Pl),Xa(),Vl.endNonterminal("ContentExpr",Pl)}function Kf(){Va()}function Qf(){Vl.startNonterminal("CompDocConstructor",Pl),Sl(119),kl(87),Nl(),yl(),Vl.endNonterminal("CompDocConstructor",Pl)}function Gf(){xl(119),kl(87),bl()}function Yf(){Vl.startNonterminal("CompAttrConstructor",Pl),Sl(82),kl(258);switch(Hl){case 276:Sl(276),kl(267),Nl(),G(),Sl(282);break;default:Nl(),Ha()}kl(87);switch(Hl){case 276:Ll(277);break;default:_l=Hl}if(_l==144660){_l=Kl(12,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{xl(276),kl(88),xl(282),_l=-1}catch(a){_l=-2}Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(12,Pl,_l)}}switch(_l){case-1:Sl(276),kl(88),Sl(282);break;default:Nl(),yl()}Vl.endNonterminal("CompAttrConstructor",Pl)}function Zf(){xl(82),kl(258);switch(Hl){case 276:xl(276),kl(267),Y(),xl(282);break;default:Ba()}kl(87);switch(Hl){case 276:Ll(277);break;default:_l=Hl}if(_l==144660){_l=Kl(12,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{xl(276),kl(88),xl(282),Jl(12,t,-1),_l=-3}catch(a){_l=-2,Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(12,t,-2)}}}switch(_l){case-1:xl(276),kl(88),xl(282);break;case-3:break;default:bl()}}function el(){Vl.startNonterminal("CompPIConstructor",Pl),Sl(216),kl(251);switch(Hl){case 276:Sl(276),kl(267),Nl(),G(),Sl(282);break;default:Nl(),Ia()}kl(87);switch(Hl){case 276:Ll(277);break;default:_l=Hl}if(_l==144660){_l=Kl(13,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{xl(276),kl(88),xl(282),_l=-1}catch(a){_l=-2}Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(13,Pl,_l)}}switch(_l){case-1:Sl(276),kl(88),Sl(282);break;default:Nl(),yl()}Vl.endNonterminal("CompPIConstructor",Pl)}function tl(){xl(216),kl(251);switch(Hl){case 276:xl(276),kl(267),Y(),xl(282);break;default:qa()}kl(87);switch(Hl){case 276:Ll(277);break;default:_l=Hl}if(_l==144660){_l=Kl(13,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{xl(276),kl(88),xl(282),Jl(13,t,-1),_l=-3}catch(a){_l=-2,Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(13,t,-2)}}}switch(_l){case-1:xl(276),kl(88),xl(282);break;case-3:break;default:bl()}}function nl(){Vl.startNonterminal("CompCommentConstructor",Pl),Sl(96),kl(87),Nl(),yl(),Vl.endNonterminal("CompCommentConstructor",Pl)}function rl(){xl(96),kl(87),bl()}function il(){Vl.startNonterminal("CompTextConstructor",Pl),Sl(244),kl(87),Nl(),yl(),Vl.endNonterminal("CompTextConstructor",Pl)}function sl(){xl(244),kl(87),bl()}function ol(){Vl.startNonterminal("PrimaryExpr",Pl);switch(Hl){case 184:Ll(256);break;case 216:Ll(254);break;case 276:Ll(277);break;case 82:case 121:Ll(259);break;case 96:case 244:Ll(93);break;case 119:case 202:case 256:Ll(139);break;case 6:case 70:case 72:case 73:case 74:case 75:case 77:case 79:case 80:case 81:case 83:case 84:case 85:case 86:case 88:case 89:case 90:case 91:case 93:case 94:case 97:case 98:case 101:case 102:case 103:case 104:case 105:case 106:case 108:case 109:case 110:case 111:case 112:case 113:case 118:case 122:case 123:case 125:case 126:case 128:case 129:case 131:case 132:case 133:case 134:case 135:case 136:case 137:case 141:case 146:case 148:case 150:case 151:case 153:case 154:case 155:case 159:case 160:case 161:case 162:case 163:case 164:case 166:case 170:case 171:case 172:case 174:case 176:case 178:case 180:case 181:case 182:case 186:case 192:case 194:case 198:case 199:case 200:case 201:case 203:case 206:case 212:case 213:case 218:case 219:case 220:case 221:case 222:case 224:case 225:case 228:case 229:case 234:case 235:case 236:case 237:case 240:case 248:case 249:case 250:case 251:case 252:case 254:case 257:case 260:case 261:case 262:case 263:case 266:case 267:case 270:case 274:Ll(92);break;default:_l=Hl}if(_l==2836||_l==3348||_l==4372||_l==4884||_l==5396||_l==5908||_l==16148||_l==16660||_l==17684||_l==18196||_l==20756||_l==21780||_l==22804||_l==23316||_l==23828||_l==24340||_l==27924||_l==28436||_l==30484||_l==34068||_l==35092||_l==36116||_l==37140||_l==37652||_l==38164||_l==38676||_l==39700||_l==40212||_l==40724||_l==41236||_l==41748||_l==42260||_l==42772||_l==43284||_l==43796||_l==44308||_l==45332||_l==45844||_l==46356||_l==46868||_l==47892||_l==48404||_l==49428||_l==49940||_l==50452||_l==51988||_l==52500||_l==53012||_l==53524||_l==54036||_l==54548||_l==55572||_l==56084||_l==56596||_l==57108||_l==57620||_l==58132||_l==60692||_l==61204||_l==61716||_l==62228||_l==62740||_l==63252||_l==63764||_l==64276||_l==64788||_l==65812||_l==66324||_l==67348||_l==67860||_l==68372||_l==68884||_l==69396||_l==69908||_l==70420||_l==72468||_l==74516||_l==75028||_l==76052||_l==77076||_l==77588||_l==78100||_l==78612||_l==79124||_l==79636||_l==81684||_l==82196||_l==82708||_l==83220||_l==83732||_l==84244||_l==84756||_l==85268||_l==85780||_l==87316||_l==87828||_l==88340||_l==89364||_l==90388||_l==91412||_l==92436||_l==92948||_l==93460||_l==94484||_l==94996||_l==95508||_l==98068||_l==98580||_l==99604||_l==101652||_l==102164||_l==102676||_l==103188||_l==103700||_l==104212||_l==105748||_l==108820||_l==109332||_l==110868||_l==111892||_l==112404||_l==112916||_l==113428||_l==113940||_l==114964||_l==115476||_l==115988||_l==116500||_l==117012||_l==117524||_l==120084||_l==120596||_l==121108||_l==121620||_l==123156||_l==124180||_l==124692||_l==125204||_l==127252||_l==127764||_l==128276||_l==128788||_l==129300||_l==129812||_l==130324||_l==131348||_l==131860||_l==133396||_l==133908||_l==134420||_l==134932||_l==136468||_l==136980||_l==138516||_l==140564||_l==141588||_l==142612||_l==144660){_l=Kl(14,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{bl(),_l=-10}catch(a){_l=-11}Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(14,Pl,_l)}}switch(_l){case 8:case 9:case 10:case 11:oi();break;case 31:li();break;case 34:di();break;case 44:mi();break;case 17414:case 17478:case 17480:case 17481:case 17482:case 17483:case 17485:case 17487:case 17488:case 17489:case 17491:case 17492:case 17493:case 17494:case 17496:case 17497:case 17498:case 17499:case 17501:case 17502:case 17505:case 17506:case 17509:case 17510:case 17511:case 17512:case 17513:case 17514:case 17516:case 17517:case 17518:case 17519:case 17520:case 17521:case 17526:case 17527:case 17530:case 17531:case 17533:case 17534:case 17536:case 17537:case 17539:case 17540:case 17541:case 17542:case 17543:case 17544:case 17545:case 17549:case 17554:case 17556:case 17558:case 17559:case 17561:case 17562:case 17563:case 17567:case 17568:case 17569:case 17570:case 17571:case 17572:case 17574:case 17578:case 17579:case 17580:case 17582:case 17584:case 17586:case 17588:case 17589:case 17590:case 17592:case 17594:case 17600:case 17602:case 17606:case 17607:case 17608:case 17609:case 17610:case 17611:case 17614:case 17620:case 17621:case 17626:case 17627:case 17628:case 17629:case 17630:case 17632:case 17633:case 17636:case 17637:case 17642:case 17643:case 17644:case 17645:case 17648:case 17656:case 17657:case 17658:case 17659:case 17660:case 17662:case 17664:case 17665:case 17668:case 17669:case 17670:case 17671:case 17674:case 17675:case 17678:case 17682:Si();break;case 141514:yi();break;case 141568:wi();break;case 32:case 78:case 120:case 124:case 145:case 152:case 165:case 167:case 185:case 191:case 226:case 227:case 242:case 243:case 253:case 14854:case 14918:case 14920:case 14921:case 14922:case 14923:case 14925:case 14927:case 14928:case 14929:case 14930:case 14931:case 14932:case 14933:case 14934:case 14936:case 14937:case 14938:case 14939:case 14941:case 14942:case 14944:case 14945:case 14946:case 14949:case 14950:case 14951:case 14952:case 14953:case 14954:case 14956:case 14957:case 14958:case 14959:case 14960:case 14961:case 14966:case 14967:case 14969:case 14970:case 14971:case 14973:case 14974:case 14976:case 14977:case 14979:case 14980:case 14981:case 14982:case 14983:case 14984:case 14985:case 14989:case 14994:case 14996:case 14998:case 14999:case 15001:case 15002:case 15003:case 15007:case 15008:case 15009:case 15010:case 15011:case 15012:case 15014:case 15018:case 15019:case 15020:case 15022:case 15024:case 15026:case 15028:case 15029:case 15030:case 15032:case 15034:case 15040:case 15042:case 15046:case 15047:case 15048:case 15049:case 15050:case 15051:case 15054:case 15060:case 15061:case 15064:case 15066:case 15067:case 15068:case 15069:case 15070:case 15072:case 15073:case 15076:case 15077:case 15082:case 15083:case 15084:case 15085:case 15088:case 15092:case 15096:case 15097:case 15098:case 15099:case 15100:case 15102:case 15104:case 15105:case 15108:case 15109:case 15110:case 15111:case 15114:case 15115:case 15118:case 15122:os();break;case-10:case 27412:yl();break;case-11:ll();break;case 68:ml();break;case 278:al();break;default:Li()}Vl.endNonterminal("PrimaryExpr",Pl)}function ul(){switch(Hl){case 184:Ll(256);break;case 216:Ll(254);break;case 276:Ll(277);break;case 82:case 121:Ll(259);break;case 96:case 244:Ll(93);break;case 119:case 202:case 256:Ll(139);break;case 6:case 70:case 72:case 73:case 74:case 75:case 77:case 79:case 80:case 81:case 83:case 84:case 85:case 86:case 88:case 89:case 90:case 91:case 93:case 94:case 97:case 98:case 101:case 102:case 103:case 104:case 105:case 106:case 108:case 109:case 110:case 111:case 112:case 113:case 118:case 122:case 123:case 125:case 126:case 128:case 129:case 131:case 132:case 133:case 134:case 135:case 136:case 137:case 141:case 146:case 148:case 150:case 151:case 153:case 154:case 155:case 159:case 160:case 161:case 162:case 163:case 164:case 166:case 170:case 171:case 172:case 174:case 176:case 178:case 180:case 181:case 182:case 186:case 192:case 194:case 198:case 199:case 200:case 201:case 203:case 206:case 212:case 213:case 218:case 219:case 220:case 221:case 222:case 224:case 225:case 228:case 229:case 234:case 235:case 236:case 237:case 240:case 248:case 249:case 250:case 251:case 252:case 254:case 257:case 260:case 261:case 262:case 263:case 266:case 267:case 270:case 274:Ll(92);break;default:_l=Hl}if(_l==2836||_l==3348||_l==4372||_l==4884||_l==5396||_l==5908||_l==16148||_l==16660||_l==17684||_l==18196||_l==20756||_l==21780||_l==22804||_l==23316||_l==23828||_l==24340||_l==27924||_l==28436||_l==30484||_l==34068||_l==35092||_l==36116||_l==37140||_l==37652||_l==38164||_l==38676||_l==39700||_l==40212||_l==40724||_l==41236||_l==41748||_l==42260||_l==42772||_l==43284||_l==43796||_l==44308||_l==45332||_l==45844||_l==46356||_l==46868||_l==47892||_l==48404||_l==49428||_l==49940||_l==50452||_l==51988||_l==52500||_l==53012||_l==53524||_l==54036||_l==54548||_l==55572||_l==56084||_l==56596||_l==57108||_l==57620||_l==58132||_l==60692||_l==61204||_l==61716||_l==62228||_l==62740||_l==63252||_l==63764||_l==64276||_l==64788||_l==65812||_l==66324||_l==67348||_l==67860||_l==68372||_l==68884||_l==69396||_l==69908||_l==70420||_l==72468||_l==74516||_l==75028||_l==76052||_l==77076||_l==77588||_l==78100||_l==78612||_l==79124||_l==79636||_l==81684||_l==82196||_l==82708||_l==83220||_l==83732||_l==84244||_l==84756||_l==85268||_l==85780||_l==87316||_l==87828||_l==88340||_l==89364||_l==90388||_l==91412||_l==92436||_l==92948||_l==93460||_l==94484||_l==94996||_l==95508||_l==98068||_l==98580||_l==99604||_l==101652||_l==102164||_l==102676||_l==103188||_l==103700||_l==104212||_l==105748||_l==108820||_l==109332||_l==110868||_l==111892||_l==112404||_l==112916||_l==113428||_l==113940||_l==114964||_l==115476||_l==115988||_l==116500||_l==117012||_l==117524||_l==120084||_l==120596||_l==121108||_l==121620||_l==123156||_l==124180||_l==124692||_l==125204||_l==127252||_l==127764||_l==128276||_l==128788||_l==129300||_l==129812||_l==130324||_l==131348||_l==131860||_l==133396||_l==133908||_l==134420||_l==134932||_l==136468||_l==136980||_l==138516||_l==140564||_l==141588||_l==142612||_l==144660){_l=Kl(14,Pl);if(_l==0){var e=Dl,t=Pl,n=Hl,r=Bl,i=jl,s=Fl,o=Il,u=ql;try{bl(),Jl(14,t,-10),_l=-14}catch(a){_l=-11,Dl=e,Pl=t,Hl=n,Hl==0?Zl=t:(Bl=r,jl=i,Fl=s,Fl==0?Zl=i:(Il=o,ql=u,Zl=u)),Jl(14,t,-11)}}}switch(_l){case 8:case 9:case 10:case 11:ui();break;case 31:ci();break;case 34:vi();break;case 44:gi();break;case 17414:case 17478:case 17480:case 17481:case 17482:case 17483:case 17485:case 17487:case 17488:case 17489:case 17491:case 17492:case 17493:case 17494:case 17496:case 17497:case 17498:case 17499:case 17501:case 17502:case 17505:case 17506:case 17509:case 17510:case 17511:case 17512:case 17513:case 17514:case 17516:case 17517:case 17518:case 17519:case 17520:case 17521:case 17526:case 17527:case 17530:case 17531:case 17533:case 17534:case 17536:case 17537:case 17539:case 17540:case 17541:case 17542:case 17543:case 17544:case 17545:case 17549:case 17554:case 17556:case 17558:case 17559:case 17561:case 17562:case 17563:case 17567:case 17568:case 17569:case 17570:case 17571:case 17572:case 17574:case 17578:case 17579:case 17580:case 17582:case 17584:case 17586:case 17588:case 17589:case 17590:case 17592:case 17594:case 17600:case 17602:case 17606:case 17607:case 17608:case 17609:case 17610:case 17611:case 17614:case 17620:case 17621:case 17626:case 17627:case 17628:case 17629:case 17630:case 17632:case 17633:case 17636:case 17637:case 17642:case 17643:case 17644:case 17645:case 17648:case 17656:case 17657:case 17658:case 17659:case 17660:case 17662:case 17664:case 17665:case 17668:case 17669:case 17670:case 17671:case 17674:case 17675:case 17678:case 17682:xi();break;case 141514:bi();break;case 141568:Ei();break;case 32:case 78:case 120:case 124:case 145:case 152:case 165:case 167:case 185:case 191:case 226:case 227:case 242:case 243:case 253:case 14854:case 14918:case 14920:case 14921:case 14922:case 14923:case 14925:case 14927:case 14928:case 14929:case 14930:case 14931:case 14932:case 14933:case 14934:case 14936:case 14937:case 14938:case 14939:case 14941:case 14942:case 14944:case 14945:case 14946:case 14949:case 14950:case 14951:case 14952:case 14953:case 14954:case 14956:case 14957:case 14958:case 14959:case 14960:case 14961:case 14966:case 14967:case 14969:case 14970:case 14971:case 14973:case 14974:case 14976:case 14977:case 14979:case 14980:case 14981:case 14982:case 14983:case 14984:case 14985:case 14989:case 14994:case 14996:case 14998:case 14999:case 15001:case 15002:case 15003:case 15007:case 15008:case 15009:case 15010:case 15011:case 15012:case 15014:case 15018:case 15019:case 15020:case 15022:case 15024:case 15026:case 15028:case 15029:case 15030:case 15032:case 15034:case 15040:case 15042:case 15046:case 15047:case 15048:case 15049:case 15050:case 15051:case 15054:case 15060:case 15061:case 15064:case 15066:case 15067:case 15068:case 15069:case 15070:case 15072:case 15073:case 15076:case 15077:case 15082:case 15083:case 15084:case 15085:case 15088:case 15092:case 15096:case 15097:case 15098:case 15099:case 15100:case 15102:case 15104:case 15105:case 15108:case 15109:case 15110:case 15111:case 15114:case 15115:case 15118:case 15122:us();break;case-10:case 27412:bl();break;case-11:cl();break;case 68:gl();break;case 278:fl();break;case-14:break;default:Ai()}}function al(){Vl.startNonterminal("JSONSimpleObjectUnion",Pl),Sl(278),kl(273),Hl!=281&&(Nl(),G()),Sl(281),Vl.endNonterminal("JSONSimpleObjectUnion",Pl)}function fl(){xl(278),kl(273),Hl!=281&&Y(),xl(281)}function ll(){Vl.startNonterminal("ObjectConstructor",Pl),Sl(276),kl(274),Hl!=282&&(Nl(),hl()),Sl(282),Vl.endNonterminal("ObjectConstructor",Pl)}function cl(){xl(276),kl(274),Hl!=282&&pl(),xl(282)}function hl(){Vl.startNonterminal("PairConstructorList",Pl),dl();for(;;){if(Hl!=41)break;Sl(41),kl(267),Nl(),dl()}Vl.endNonterminal("PairConstructorList",Pl)}function pl(){vl();for(;;){if(Hl!=41)break;xl(41),kl(267),vl()}}function dl(){Vl.startNonterminal("PairConstructor",Pl),_f(),Sl(49),kl(267),Nl(),_f(),Vl.endNonterminal("PairConstructor",Pl)}function vl(){Df(),xl(49),kl(267),Df()}function ml(){Vl.startNonterminal("ArrayConstructor",Pl),Sl(68),kl(272),Hl!=69&&(Nl(),G()),Sl(69),Vl.endNonterminal("ArrayConstructor",Pl)}function gl(){xl(68),kl(272),Hl!=69&&Y(),xl(69)}function yl(){Vl.startNonterminal("BlockExpr",Pl),Sl(276),kl(277),Nl(),$a(),Sl(282),Vl.endNonterminal("BlockExpr",Pl)}function bl(){xl(276),kl(277),Ja(),xl(282)}function wl(){Vl.startNonterminal("FunctionDecl",Pl),Sl(145),kl(255),Nl(),Ha(),kl(22),Sl(34),kl(94),Hl==31&&(Nl(),U()),Sl(37),kl(148),Hl==79&&(Nl(),El()),kl(118);switch(Hl){case 276:Sl(276),kl(277),Nl(),$a(),Sl(282);break;default:Sl(133)}Vl.endNonterminal("FunctionDecl",Pl)}function El(){Vl.startNonterminal("ReturnType",Pl),Sl(79),kl(260),Nl(),ms(),Vl.endNonterminal("ReturnType",Pl)}function Sl(e){Hl==e?(Nl(),Vl.terminal(i.TOKEN[Hl],Bl,jl>Gl?Gl:jl),Dl=Bl,Pl=jl,Hl=Fl,Hl!=0&&(Bl=Il,jl=ql,Fl=0)):Ml(Bl,jl,0,Hl,e)}function xl(e){Hl==e?(Dl=Bl,Pl=jl,Hl=Fl,Hl!=0&&(Bl=Il,jl=ql,Fl=0)):Ml(Bl,jl,0,Hl,e)}function Tl(e){var t=Dl,n=Pl,r=Hl,i=Bl,s=jl;Hl=e,Bl=Yl,jl=Zl,Fl=0,Pa(),Dl=t,Pl=n,Hl=r,Hl!=0&&(Bl=i,jl=s)}function Nl(){Pl!=Bl&&(Dl=Pl,Pl=Bl,Vl.whitespace(Dl,Pl))}function Cl(e){var t;for(;;){t=ec(e);if(t!=22){if(t!=36)break;Tl(t)}}return t}function kl(e){Hl==0&&(Hl=Cl(e),Bl=Yl,jl=Zl)}function Ll(e){Fl==0&&(Fl=Cl(e),Il=Yl,ql=Zl),_l=Fl<<9|Hl}function Al(e){Hl==0&&(Hl=ec(e),Bl=Yl,jl=Zl)}function Ol(e){Fl==0&&(Fl=ec(e),Il=Yl,ql=Zl),_l=Fl<<9|Hl}function Ml(e,t,r,i,s){throw t>Ul&&(Rl=e,Ul=t,zl=r,Wl=i,Xl=s),new n.ParseException(Rl,Ul,zl,Wl,Xl)}function Jl(e,t,n){$l[(t<<4)+e]=n}function Kl(e,t){var n=$l[(t<<4)+e];return typeof n!="undefined"?n:0}function ec(e){var t=!1;Yl=Zl;var n=Zl,r=i.INITIAL[e],s=0;for(var o=r&4095;o!=0;){var u,a=n<Gl?Ql.charCodeAt(n):0;++n;if(a<128)u=i.MAP0[a];else if(a<55296){var f=a>>4;u=i.MAP1[(a&15)+i.MAP1[(f&31)+i.MAP1[f>>5]]]}else{if(a<56320){var f=n<Gl?Ql.charCodeAt(n):0;f>=56320&&f<57344&&(++n,a=((a&1023)<<10)+(f&1023)+65536,t=!0)}var l=0,c=5;for(var h=3;;h=c+l>>1){if(i.MAP2[h]>a)c=h-1;else{if(!(i.MAP2[6+h]<a)){u=i.MAP2[12+h];break}l=h+1}if(l>c){u=0;break}}}s=o;var p=(u<<12)+o-1;o=i.TRANSITION[(p&15)+i.TRANSITION[p>>4]],o>4095&&(r=o,o&=4095,Zl=n)}r>>=12;if(r==0){Zl=n-1;var f=Zl<Gl?Ql.charCodeAt(Zl):0;return f>=56320&&f<57344&&--Zl,Ml(Yl,Zl,s,-1,-1)}if(t)for(var d=r>>9;d>0;--d){--Zl;var f=Zl<Gl?Ql.charCodeAt(Zl):0;f>=56320&&f<57344&&--Zl}else Zl-=r>>9;return(r&511)-1}r(e,t);var n=this;this.ParseException=function(e,t,n,r,i){var s=e,o=t,u=n,a=r,f=i;this.getBegin=function(){return s},this.getEnd=function(){return o},this.getState=function(){return u},this.getExpected=function(){return f},this.getOffending=function(){return a},this.getMessage=function(){return a<0?"lexical analysis failed":"syntax error"}},this.getInput=function(){return Ql},this.getOffendingToken=function(e){var t=e.getOffending();return t>=0?i.TOKEN[t]:null},this.getExpectedTokenSet=function(e){var t;return e.getExpected()<0?t=i.getTokenSet(-e.getState()):t=[i.TOKEN[e.getExpected()]],t},this.getErrorMessage=function(e){var t=this.getExpectedTokenSet(e),n=this.getOffendingToken(e),r=Ql.substring(0,e.getBegin()),i=r.split("\n"),s=i.length,o=i[s-1].length+1,u=e.getEnd()-e.getBegin();return e.getMessage()+(n==null?"":", found "+n)+"\nwhile expecting "+(t.length==1?t[0]:"["+t.join(", ")+"]")+"\n"+(u==0||n!=null?"":"after successfully scanning "+u+" characters beginning ")+"at line "+s+", column "+o+":\n..."+Ql.substring(e.getBegin(),Math.min(Ql.length,e.getBegin()+64))+"..."},this.parse_XQuery=function(){Vl.startNonterminal("XQuery",Pl),kl(275),Nl(),o(),Sl(25),Vl.endNonterminal("XQuery",Pl)};var _l,Dl,Pl,Hl,Bl,jl,Fl,Il,ql,Rl,Ul,zl,Wl,Xl,Vl,$l,Ql,Gl,Yl,Zl};r.getTokenSet=function(e){var t=[],n=e<0?-e:INITIAL[e]&4095;for(var i=0;i<284;i+=32){var s=i,o=(i>>5)*3694+n-1,u=o>>1,a=u>>2,f=r.EXPECTED[(o&1)+r.EXPECTED[(u&3)+r.EXPECTED[(a&3)+r.EXPECTED[a>>2]]]];for(;f!=0;f>>>=1,++s)(f&1)!=0&&t.push(r.TOKEN[s])}return t},r.MAP0=[70,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,17,17,17,17,17,17,17,17,17,18,19,20,21,22,23,24,25,26,27,28,29,26,30,30,30,30,30,31,32,33,30,30,34,30,30,35,30,30,30,36,30,30,37,38,39,38,30,38,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,38,38],r.MAP1=[108,124,214,214,214,214,214,214,214,214,214,214,214,214,214,214,156,181,181,181,181,181,214,215,213,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,247,261,277,293,309,355,371,387,423,423,423,415,339,331,339,331,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,440,440,440,440,440,440,440,324,339,339,339,339,339,339,339,339,401,423,423,424,422,423,423,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,423,338,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,339,423,70,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,17,17,17,17,17,17,17,17,17,18,19,20,21,22,23,24,25,26,27,28,29,26,30,30,30,30,30,31,32,33,30,30,30,30,30,30,30,30,30,30,30,30,30,30,38,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,34,30,30,35,30,30,30,36,30,30,37,38,39,38,30,38,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,38,38,38,38,38,38,38,38,38,38,38,38,30,30,38,38,38,38,38,38,38,69,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69],r.MAP2=[57344,63744,64976,65008,65536,983040,63743,64975,65007,65533,983039,1114111,38,30,38,30,30,38],r.INITIAL=[1,12290,3,4,5,6,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,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287],r.TRANSITION=[42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,25651,25666,25670,25670,25670,18189,25670,25670,25670,25670,18201,25670,25670,25670,25670,18176,25670,25671,18217,42516,42516,42516,27632,42516,42516,51474,42516,42516,42516,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,18919,18270,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,42516,42516,42516,42516,48069,42516,42516,42516,42516,25917,18730,20976,20988,20999,21015,25420,18732,21040,42516,42516,42516,27632,42516,42516,51474,31122,42516,42516,42516,42516,42516,42516,32629,20505,21066,18953,21068,21056,21084,18270,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,23286,21107,42516,42516,42516,39416,42516,42516,43470,47286,25568,42516,42516,42516,42516,23672,41495,21126,21160,42516,42516,42516,27632,42516,42516,35938,42516,42516,42516,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,25556,18270,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21176,21248,42516,42516,42516,50595,42516,42516,42445,42516,25917,23619,21211,21279,21269,21226,21240,44419,21040,42516,42516,42516,27632,21302,42516,32247,42516,42516,42516,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,19871,21321,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,21344,26008,18612,18632,18596,21349,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,42510,42516,42516,42516,48894,42515,42516,51366,42516,21365,42504,21403,42515,21410,42516,27599,27612,21040,42516,42516,42516,27632,42516,42516,51474,42516,42516,42516,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,18919,18270,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,42516,42516,42516,42516,48069,21426,42516,42516,42516,22170,42516,42516,21445,42516,42516,21468,21481,21040,42516,42516,42516,27632,42516,42516,51474,42516,42516,42516,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,18919,18270,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,42516,42516,42516,42516,48069,42516,42516,42516,42516,24484,42516,42516,42516,42516,42516,42516,42517,21497,42516,42516,42516,27632,42516,42516,51474,42516,42516,42516,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,18919,18270,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,21513,25598,18486,18508,51408,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,25358,21538,42516,42516,42516,29996,42516,42516,26519,46446,25383,42516,42516,42516,42516,25736,28473,18232,21557,42516,42516,42516,27632,42516,42516,51474,21573,42516,42516,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,19060,21591,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,23074,23089,21619,21619,21619,21672,21614,21619,21624,23096,21640,21745,21688,21665,21655,21732,21703,21716,21040,42516,42516,42516,33326,42516,42516,51474,42516,42516,42516,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,18919,18270,40105,18293,21761,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,45317,42516,42516,42516,49458,21798,42516,22640,21804,25917,45316,42516,21821,21844,21828,21860,21869,21885,42516,42516,42516,29550,42516,42516,51474,42516,42516,42516,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,18919,18270,40105,18293,21901,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,21944,42516,42516,42516,48069,42516,42516,42516,26308,36543,25445,25454,21937,25455,21960,21985,21998,21040,42516,42516,42516,27632,42516,42516,51474,42516,42516,42516,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,18919,18270,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,18888,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,42516,42516,42516,42516,48069,42516,42516,42516,26329,37275,42655,22014,22031,22014,22046,42653,22015,21040,42516,42516,42516,27632,42516,42516,51474,42516,42516,42516,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,18919,18270,40105,18293,18315,42516,42516,22071,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,26891,42516,42516,42516,48069,22092,42516,23653,22130,40293,22116,22186,22191,22191,22207,26888,44587,21040,42516,42516,42516,27632,42516,42516,51474,42516,42516,42516,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,18919,18270,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,18247,42516,42516,42516,42516,48069,42516,42516,42516,42516,25917,35843,22232,22249,22232,22264,35841,22233,22289,42516,42516,42516,27632,42516,42516,51474,42516,42516,42516,42516,42516,42516,42516,28241,22657,46314,35273,38147,34810,46363,42516,33841,42516,34304,43899,22305,22071,36154,42516,42516,42516,42516,28243,22657,22322,22657,22657,22341,33347,46316,46316,39789,38147,35514,38147,38147,22359,22382,42516,42516,42516,42516,42516,28815,42516,22405,22426,42516,42516,38368,22657,22657,22657,22657,38374,22541,46316,46316,46316,46316,44805,38147,38147,38147,38147,38147,32923,22444,47355,26569,42516,42516,42516,42516,42516,45225,42516,42516,32981,50880,22657,22657,22657,30360,22467,39622,46316,22501,46316,22343,36422,42625,38147,22520,38147,27826,41766,42516,42516,42516,42516,42516,49148,42516,23255,22657,44467,22657,22657,30361,22539,42077,46316,46316,46316,30525,38147,40186,38147,38147,34440,41769,42516,42516,20027,37487,42516,28242,22657,22657,36250,37745,46316,46316,44329,37798,38147,38147,43834,27827,30836,42516,42516,19405,22558,38368,22576,22657,40730,22597,46316,36583,22617,38147,40469,22638,42516,25905,42516,34153,22656,33064,46073,46316,22674,22710,27827,22690,51145,42516,32408,22729,37572,22752,32120,22683,29050,30609,22771,38961,22813,36803,22874,22893,22911,28238,43147,27775,22913,22451,22736,46400,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,42516,42516,42516,42516,48069,42516,42516,42516,50215,25917,42516,42516,42516,42516,42516,45715,23059,23112,42516,42516,42516,27632,42516,42516,37325,42516,42516,42516,42516,42516,42516,42516,28241,22657,46314,35273,38147,23128,46363,42516,42516,42516,34304,42516,42516,18360,42516,42516,42516,42516,42516,28243,22657,22657,22657,22657,22341,46316,46316,46316,39789,38147,38147,38147,38147,40896,22382,42516,42516,42516,42516,42516,28815,42516,42516,42516,42516,42516,38368,22657,22657,22657,22657,38374,22541,46316,46316,46316,46316,44805,38147,38147,38147,38147,38147,32923,22444,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38370,22657,22657,22657,22657,30360,22540,46316,46316,46316,46316,22343,30533,38147,38147,38147,38147,27826,41766,42516,42516,42516,42516,42516,42516,42516,23255,22657,22657,22657,22657,30361,22539,46316,46316,46316,46316,30525,38147,38147,38147,38147,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,37745,46316,46316,46316,37798,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,23154,42516,42516,42516,46371,42516,42516,42516,42516,25917,35960,23175,23206,23195,23229,35959,23179,21040,42516,42516,42516,27632,42516,42516,51474,27227,42516,43023,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,18919,18270,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,23254,42516,42516,42516,48069,42516,42516,42516,19968,25917,42516,42516,42516,42516,42516,42762,23271,23302,42516,42516,42516,27632,42516,42516,21380,42516,42516,42516,42516,42516,42516,42516,28241,22657,46314,35273,38147,23318,46363,42516,42516,42516,34304,42516,42516,23344,42516,42516,42516,42516,42516,28243,22657,22657,22657,22657,22341,46316,46316,46316,39789,38147,38147,38147,38147,40896,23370,23409,42516,42516,42516,42516,38331,23429,42516,42516,42516,42516,38368,22657,22657,22657,22657,38374,22541,46316,46316,46316,46316,44805,38147,38147,38147,38147,38147,32923,23450,23383,42516,42516,42516,42516,42516,23487,42516,42516,42516,38370,22657,22657,22657,22657,50700,22540,46316,46316,46316,46316,47852,30533,38147,38147,38147,38147,27826,35762,23510,42516,42516,42516,42516,42516,42516,23255,22657,22657,22657,22657,29796,22539,46316,46316,46316,46316,23533,38147,38147,38147,38147,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,46191,46316,46316,46316,32038,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,48371,42516,42516,42516,31492,32078,42516,42516,23557,25917,18721,49121,23587,23594,23610,42516,43878,23635,23651,42516,42516,33439,23669,42516,51474,42516,42516,42516,42516,42516,42516,42516,32629,20505,25038,24355,23991,25028,23804,18270,40105,18293,23688,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,23724,24084,23749,23789,24317,23827,23849,23904,24015,23917,23946,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,23969,24689,24310,25086,25092,23974,23990,24416,24845,24007,23833,24977,24993,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,24031,23930,24046,24073,24057,24100,24137,24664,24240,24198,24251,24225,24986,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,24267,24283,24299,24348,24333,24371,24167,24428,24402,23773,24444,24474,35639,19379,39467,19401,41728,19421,19500,24458,19544,24500,24558,24572,24588,24604,24182,24745,24620,24636,24767,19696,19712,19728,19753,19773,19830,19435,19514,24680,24514,19528,24705,24152,24757,19947,19984,20043,20080,20119,20157,20667,24542,24528,24731,24830,24209,24939,20235,20264,20301,24783,24799,24815,24715,24861,20381,20397,19814,23733,24877,24893,20503,25039,24968,23864,24927,24955,25015,20652,18443,23763,24386,25055,24651,25071,25108,25159,25175,25191,25243,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,27003,42516,42516,42516,48069,25296,42516,42516,25291,40518,25312,25320,25320,25320,25327,27168,25343,21040,42516,42516,42516,27632,42516,42516,51474,42516,42516,42516,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,18919,18270,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25399,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,18963,25373,18652,18689,18711,18748,18695,25415,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,19337,25436,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,25471,25509,25525,20579,19301,19596,25541,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,25584,19614,19632,19650,25620,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,42516,42516,42516,42516,48069,42516,42516,42516,42516,21541,28730,28739,28739,28739,28746,47533,25636,21040,42516,42516,42516,27632,42516,42516,51474,42516,42516,27653,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,25687,18270,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51268,23158,42516,42516,42516,48069,42516,42516,42516,42516,25917,22795,25710,25710,25710,25717,23159,22797,21040,25733,42516,42516,27632,42516,42516,51474,42516,42516,44769,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,25752,18270,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,26066,26075,42516,42516,42516,42907,42516,42516,42516,42516,25917,26405,25775,25775,25775,25782,28588,26407,25798,25814,42516,42516,27632,42516,42516,51474,42516,42516,23413,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,25831,18270,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,25857,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,25891,42516,42516,42516,42516,48069,25942,42516,42516,28970,33768,42516,42516,42516,25933,25960,26180,25944,25980,42516,42516,42516,27632,42516,42516,51474,27927,42516,42516,42516,42516,42516,42516,32629,20505,21066,18953,21068,25996,26028,18270,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,42516,42516,42516,42516,48069,42516,42516,42516,42516,25917,42516,42516,42516,42516,42516,41865,26051,21040,42516,42516,42516,27632,42516,42516,51474,42516,42516,42516,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,18919,18270,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,42516,51537,42516,42516,42516,42516,25917,42516,42516,42516,42516,46741,49861,51029,26099,42516,42516,42516,27632,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,28241,22657,46314,35273,38147,34810,28721,42516,42516,42516,34304,42516,42516,42516,42516,42516,42516,42516,42516,28243,22657,22657,22657,22657,27401,46316,46316,46316,48318,38147,38147,38147,38147,40896,22382,42516,42516,42516,42516,42516,42516,23487,42516,42516,42516,42516,38368,22657,22657,22657,22657,38374,22541,46316,46316,46316,46316,44805,38147,38147,38147,38147,38147,32923,26115,26152,42516,42516,42516,42516,42516,23487,42516,42516,42516,38370,22657,22657,22657,22657,30360,22540,46316,46316,46316,46316,22343,30533,38147,38147,38147,38147,27826,35762,23510,42516,42516,42516,42516,26178,42516,23255,22657,22657,22657,22657,22877,22539,46316,46316,46316,46316,32774,38147,38147,38147,38147,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,46191,46316,46316,46316,32038,38147,38147,38147,27827,22690,42516,42516,23464,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,42516,51537,42516,42516,42516,42516,25917,42516,42516,42516,42516,46741,49861,51029,26099,42516,42516,42516,27632,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,28241,22657,46314,35273,38147,34810,28721,42516,42516,42516,34304,42516,42516,42516,42516,42516,42516,42516,42516,28243,22657,22657,22657,22657,27401,46316,46316,46316,48318,38147,38147,38147,38147,40896,22382,42516,42516,42516,42516,42516,42516,23487,42516,42516,42516,42516,38368,22657,22657,22657,22657,38374,22541,46316,46316,46316,46316,44805,38147,38147,38147,38147,38147,32923,26115,26152,42516,42516,42516,42516,42516,23487,42516,42516,42516,38370,22657,22657,22657,22657,30360,22540,46316,46316,46316,46316,22343,30533,38147,38147,38147,38147,27826,35762,23510,42516,42516,42516,42516,42516,42516,23255,22657,22657,22657,22657,22877,22539,46316,46316,46316,46316,32774,38147,38147,38147,38147,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,46191,46316,46316,46316,32038,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,42516,51537,42516,42516,42516,42516,25917,42516,42516,42516,42516,46741,49861,51029,26099,42516,42516,42516,27632,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,28241,22657,46314,35273,38147,34810,28721,42516,42516,42516,34304,42516,42516,42516,42516,42516,42516,42516,42516,28243,22657,22657,22657,22657,27401,46316,46316,46316,48318,38147,38147,38147,38147,40896,22382,42516,42516,42516,42516,42516,42516,23487,26196,42516,42516,42516,38368,22657,22657,22657,22657,38374,22541,46316,46316,46316,46316,44805,38147,38147,38147,38147,38147,32923,26115,26152,42516,42516,42516,42516,42516,23487,42516,42516,42516,38370,22657,22657,22657,22657,30360,22540,46316,46316,46316,46316,22343,30533,38147,38147,38147,38147,27826,35762,23510,42516,42516,42516,42516,42516,42516,23255,22657,22657,22657,22657,22877,22539,46316,46316,46316,46316,32774,38147,38147,38147,38147,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,46191,46316,46316,46316,32038,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,42516,51537,42516,42516,42516,42516,25917,42516,42516,42516,42516,46741,49861,51029,26099,42516,42516,42516,27632,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,28241,22657,46314,35273,38147,34810,28721,42516,42516,42516,34304,42516,42516,42516,42516,42516,42516,42516,42516,28243,22657,22657,22657,22657,27401,46316,46316,46316,48318,38147,38147,38147,38147,40896,22382,42516,42516,42516,42516,42516,42516,23487,42516,42516,42516,42516,38368,22657,22657,22657,22657,38374,22541,46316,46316,46316,46316,44805,38147,38147,38147,38147,38147,32923,26115,26152,42516,42516,42516,42516,42516,26216,42516,42516,42516,38370,22657,22657,22657,22657,30360,22540,46316,46316,46316,46316,22343,30533,38147,38147,38147,38147,27826,35762,23510,42516,42516,42516,42516,42516,42516,23255,22657,22657,22657,22657,22877,22539,46316,46316,46316,46316,32774,38147,38147,38147,38147,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,46191,46316,46316,46316,32038,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,42516,51537,42516,42516,42516,42516,25917,42516,42516,42516,42516,46741,49861,51029,26099,42516,42516,42516,27632,42516,42516,31151,42516,42516,42516,42516,42516,42516,42516,28241,22657,46314,35273,38147,34810,28721,42516,42516,42516,34304,42516,42516,31154,42516,42516,42516,42516,42516,28243,22657,22657,22657,22657,27401,46316,46316,46316,48318,38147,38147,38147,38147,40896,22382,42516,42516,42516,42516,42516,42516,23487,42516,42516,42516,42516,38368,22657,22657,22657,22657,38374,22541,46316,46316,46316,46316,44805,38147,38147,38147,38147,38147,32923,26115,26152,42516,42516,42516,42516,42516,23487,42516,42516,42516,38370,22657,22657,22657,22657,30360,22540,46316,46316,46316,46316,22343,30533,38147,38147,38147,38147,27826,35762,23510,42516,42516,42516,42516,42516,42516,23255,22657,22657,22657,22657,22877,22539,46316,46316,46316,46316,32774,38147,38147,38147,38147,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,46191,46316,46316,46316,32038,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,42516,51537,42516,42516,42516,42516,25917,42516,42516,42516,42516,46741,49861,51029,26099,42516,42516,42516,27632,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,28241,22657,46314,35273,38147,34810,28721,42516,42516,42516,34304,42516,42516,42516,42516,42516,42516,42516,42516,28243,22657,22657,22657,22657,27401,46316,46316,46316,48318,38147,38147,38147,38147,40896,22382,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38368,22657,22657,22657,22657,38374,22541,46316,46316,46316,46316,44805,38147,38147,38147,38147,38147,32923,22444,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38370,22657,22657,22657,22657,30360,22540,46316,46316,46316,46316,22343,30533,38147,38147,38147,38147,27826,41766,42516,42516,42516,42516,42516,42516,42516,23255,22657,22657,22657,22657,30361,22539,46316,46316,46316,46316,30525,38147,38147,38147,38147,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,37745,46316,46316,46316,37798,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,42516,51537,42516,42516,42516,42516,25917,42516,42516,42516,42516,46741,49861,51029,26099,42516,42516,42516,27632,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,28241,22657,46314,35273,38147,34810,22786,42516,42516,42516,34304,42516,42516,42516,42516,42516,42516,42516,42516,28243,22657,22657,22657,22657,27401,46316,46316,46316,48318,38147,38147,38147,38147,40896,22382,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38368,22657,22657,22657,22657,38374,22541,46316,46316,46316,46316,44805,38147,38147,38147,38147,38147,32923,22444,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38370,22657,22657,22657,22657,30360,22540,46316,46316,46316,46316,22343,30533,38147,38147,38147,38147,27826,41766,42516,42516,42516,42516,42516,42516,42516,23255,22657,22657,22657,22657,30361,22539,46316,46316,46316,46316,30525,38147,38147,38147,38147,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,37745,46316,46316,46316,37798,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,42516,51537,42516,42516,42516,42516,25917,42516,42516,42516,42516,46741,49861,51029,26258,42516,42516,42516,27632,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,28241,22657,46314,35273,38147,34810,28721,42516,42516,42516,34304,42516,42516,42516,42516,42516,42516,42516,42516,28243,22657,22657,22657,22657,27401,46316,46316,46316,48318,38147,38147,38147,38147,40896,22382,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38368,22657,22657,22657,22657,38374,22541,46316,46316,46316,46316,44805,38147,38147,38147,38147,38147,32923,22444,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38370,22657,22657,22657,22657,30360,22540,46316,46316,46316,46316,22343,30533,38147,38147,38147,38147,27826,41766,42516,42516,42516,42516,42516,42516,42516,23255,22657,22657,22657,22657,30361,22539,46316,46316,46316,46316,30525,38147,38147,38147,38147,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,37745,46316,46316,46316,37798,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,42516,51537,42516,42516,42516,42516,25917,48694,42516,42516,42516,46741,49861,51029,26099,42516,42516,42516,27632,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,28241,22657,46314,35273,38147,34810,28721,42516,42516,42516,34304,42516,42516,42516,28605,42516,42516,42516,42516,28243,22657,22657,22657,22657,27401,46316,46316,46316,48318,38147,38147,38147,38147,40896,22382,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38368,22657,22657,22657,22657,38374,22541,46316,46316,46316,46316,44805,38147,38147,38147,38147,38147,32923,22444,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38370,22657,22657,22657,22657,30360,22540,46316,46316,46316,46316,22343,30533,38147,38147,38147,38147,27826,41766,42516,42516,42516,42516,42516,42516,42516,23255,22657,22657,22657,22657,30361,22539,46316,46316,46316,46316,30525,38147,38147,38147,38147,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,37745,46316,46316,46316,37798,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,42516,51537,42516,42516,42516,42516,25917,42516,42516,42516,42516,47769,26274,26287,26099,42516,42516,42516,27632,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,28241,22657,46314,35273,38147,34810,28721,42516,42516,42516,34304,42516,42516,42516,42516,42516,42516,42516,42516,28243,22657,22657,22657,22657,27401,46316,46316,46316,48318,38147,38147,38147,38147,40896,22382,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38368,22657,22657,22657,22657,38374,22541,46316,46316,46316,46316,44805,38147,38147,38147,38147,38147,32923,22444,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38370,22657,22657,22657,22657,30360,22540,46316,46316,46316,46316,22343,30533,38147,38147,38147,38147,27826,41766,42516,42516,42516,42516,42516,42516,42516,23255,22657,22657,22657,22657,30361,22539,46316,46316,46316,46316,30525,38147,38147,38147,38147,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,37745,46316,46316,46316,37798,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,42516,51537,42516,42516,42516,42516,25917,42516,42516,42516,42516,46741,49861,51029,26099,42516,42516,42516,27632,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,28241,22657,46314,35273,38147,34810,28721,42516,42516,42516,34304,42516,42516,42516,42516,42516,42516,42516,42516,28243,22657,22657,22657,22657,27401,46316,46316,46316,48318,38147,38147,38147,38147,40896,22382,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38368,22657,22657,22657,22657,38374,22541,46316,46316,46316,46316,44805,38147,38147,38147,38147,38147,32923,22444,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38370,22657,22657,22657,22657,30360,22540,46316,46316,46316,46316,22343,30533,38147,38147,38147,38147,27826,41766,42516,42516,42516,42516,42516,42516,42516,23255,22657,22657,22657,22657,30361,22539,46316,46316,46316,46316,30525,38147,38147,38147,38147,34440,41769,42516,42516,42516,26303,42516,28242,22657,22657,22657,37745,46316,46316,46316,37798,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,26324,42516,42516,42516,42516,51537,42516,42516,42516,42516,25917,42516,42516,42516,42516,46741,49861,51029,26099,42516,42516,42516,27632,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,28241,22657,46314,35273,38147,34810,28721,42516,42516,42516,34304,42516,42516,42516,42516,42516,42516,42516,42516,28243,22657,22657,22657,22657,27401,46316,46316,46316,48318,38147,38147,38147,38147,40896,22382,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38368,22657,22657,22657,22657,38374,22541,46316,46316,46316,46316,44805,38147,38147,38147,38147,38147,32923,22444,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38370,22657,22657,22657,22657,30360,22540,46316,46316,46316,46316,22343,30533,38147,38147,38147,38147,27826,41766,42516,42516,42516,42516,42516,42516,42516,23255,22657,22657,22657,22657,30361,22539,46316,46316,46316,46316,30525,38147,38147,38147,38147,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,37745,46316,46316,46316,37798,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,42516,42516,42516,42516,48069,42516,42516,42516,42516,25917,35004,26345,26373,26362,26396,35005,26346,21040,42516,42516,42516,27632,42516,42516,51474,42516,42516,42516,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,18919,18270,40105,18293,18315,42516,42516,18360,37963,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,26423,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,42516,42516,42516,42516,48069,42516,42516,42516,42516,25917,42516,42516,42516,42516,42516,42516,42517,21040,42516,42516,42516,27632,42516,42516,51474,42516,42516,42516,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,18919,18270,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,42516,42516,42516,42516,48069,42516,42516,42516,42516,25917,47727,42516,26460,26483,26467,42516,47735,21040,42516,42516,42516,27632,42516,42516,51474,42516,42516,42516,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,18919,18270,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,26499,20264,20301,20317,20346,20333,20349,20365,26535,20397,20422,20606,20438,26551,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,29068,42516,42516,42516,51537,26585,26616,29663,26601,26633,26690,26699,26715,26730,26742,26758,26771,26099,19999,42516,26787,26162,26806,41856,26832,26883,26907,26946,30733,26962,26998,27019,27054,46783,31896,27070,46885,46348,36728,27120,42516,42516,34304,27137,37896,42516,27163,34995,39190,42516,27184,43650,22657,22657,22657,27203,27401,46316,46316,41985,48318,38147,38147,38147,37213,40896,22382,42516,27222,48046,42516,27243,27263,27280,42516,42516,27038,20763,27308,27328,22657,22657,27363,27386,27419,35266,46316,30482,27448,27495,27524,27566,38147,35889,38740,46095,27585,26152,27628,42516,45564,42516,47310,23487,42516,46936,27648,27669,27685,34339,22657,27729,22984,44673,27748,45967,46316,27773,39768,32782,27791,37607,38147,27824,22485,27843,27859,27882,27899,42516,27922,31758,27943,23255,33056,27962,22657,42185,33093,27982,30091,46316,35423,43042,32774,28017,38147,38147,42363,28033,23138,28062,40096,28115,41486,28137,21969,22956,28160,22657,46191,35558,28176,28197,32038,49740,47969,28214,27827,28233,42899,42516,21253,42516,38368,42934,43766,40730,37393,48025,36583,51021,44713,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,28260,28298,33550,28320,28341,28379,28401,28421,26921,40729,36585,44924,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,28445,42516,42516,51537,42516,42516,42516,42516,31409,28464,42516,28489,28496,28512,28528,28541,26099,42516,42516,42516,27632,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,28241,42942,46314,28557,30860,34810,28721,42516,42516,42516,34304,42516,42516,42516,42516,42516,42516,42516,42516,28243,22657,22657,22657,22657,27401,46316,46316,46316,48318,38147,38147,38147,38147,40896,22382,42516,42516,42516,42516,42516,28583,23487,28604,45602,42516,42516,38368,22657,22657,22657,44648,28621,22541,46316,46316,46316,40008,44805,38147,38147,38147,38147,41449,32923,26115,26152,42516,42516,42516,42516,42516,23487,42516,42516,42516,38370,22657,22657,22657,22657,30360,22540,46316,46316,46316,46316,22343,30533,38147,38147,38147,38147,27826,35762,23510,42516,32305,42516,42516,28652,43395,23255,28671,22657,22657,22657,28690,28706,46316,46316,46316,37589,32774,28762,38147,38147,38147,44356,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,46191,46316,46316,46316,32038,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,23013,26674,44310,41661,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,28784,42516,42516,51537,42516,28813,42516,28831,36313,28851,28860,28876,28891,28903,28919,28932,26099,42516,42516,33807,29427,42516,42516,28948,42516,28965,42516,42516,42516,25275,42516,28986,44283,46314,29021,22622,37863,32069,42516,29066,42516,34304,29084,49128,42516,45291,29103,36853,42516,39408,30216,37513,22657,22657,22657,29138,29162,46316,46316,48917,29187,29203,38147,38147,40896,22382,23471,42516,42516,37970,42516,41320,23487,39926,29222,42516,42516,38368,29257,38293,22657,29296,38374,29315,31567,38618,38779,46316,44805,42631,29346,29367,48610,38147,32923,26115,26152,42516,42516,35359,42516,36267,23487,42516,42516,42516,38370,22657,22657,38875,29587,30360,22540,46316,46316,49716,48753,22343,30533,38147,38147,47896,47206,27826,35762,29388,42516,42516,42516,29423,42516,29443,23255,22657,22657,22657,43545,22877,22539,46316,46316,49625,46316,32774,38147,38147,38147,29464,34440,41769,42516,42516,19074,42516,46902,29483,22657,45738,22657,46191,46316,28001,46316,32038,38147,48630,38147,27827,29518,29546,42516,39530,20864,38368,29566,29583,46250,46316,29603,36583,29623,29640,40469,42516,42516,42516,29661,38373,22657,29679,46316,51108,36586,38147,50541,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,29702,29722,29738,29754,28244,40729,36585,22448,28385,36584,34366,22755,31692,34720,29778,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,26790,42516,42516,51537,42516,29812,25227,42516,31450,29831,29840,29856,29871,29878,29894,29907,26099,42516,42516,42516,27632,42516,42516,42516,42516,42516,42516,31072,31070,42516,32276,32283,40826,29686,35273,29923,34810,28721,42516,35352,29943,34304,42516,29968,36872,42516,42516,29988,30012,34471,30028,22581,34160,30064,24121,30107,48780,30128,30172,30191,29624,22523,47650,28217,40896,22382,42516,42516,42516,42735,42516,30232,23487,42516,42516,42516,27906,38368,22657,22657,22657,26867,38374,22541,46316,46316,46316,37425,44805,38147,38147,38147,38147,30252,50615,30272,30304,42516,42516,42516,30320,30338,23487,42516,42516,27104,21782,30358,30377,22657,22657,30395,30434,30481,30498,46316,46316,30515,51071,30551,30568,38147,38147,30585,35762,23510,42516,42516,42516,42516,42516,30625,23255,30648,22657,22657,30668,22877,30687,46316,46316,34855,46316,32837,38147,38147,43217,38147,34440,41769,45029,42516,30729,42516,21024,28242,29299,22657,30749,46191,50174,46316,30776,32038,38147,30812,48472,27827,22690,23708,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,37071,42516,42516,38373,22657,31523,46316,43307,36586,38147,39352,22690,34920,42516,38372,43148,46316,38137,38147,30829,36804,38368,28385,28404,30535,27085,28354,31634,30852,30600,30074,38197,42103,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,21805,30876,42516,51537,49762,30895,42516,30918,43094,30942,30951,30967,30982,30994,31010,31023,26099,42516,31039,39573,31055,20844,31088,31151,40795,31438,31118,31138,31170,31208,31224,31259,31325,39316,31341,31357,42305,39859,31243,31397,39944,31425,33906,31466,31484,36903,42516,42516,38844,42516,28243,31508,40831,43064,26242,31546,31583,49551,32501,35578,43001,31607,35023,30465,31623,22382,40777,39e3,31658,40711,31716,41838,31747,42230,41234,31783,31813,31829,31873,31912,31936,31952,31988,32019,35868,32054,38034,47598,32094,32110,32136,39813,32152,32186,47170,32233,26152,32263,42516,49503,42516,32299,32321,32337,32365,32386,32406,32424,22657,35078,32463,30760,22540,32487,46316,47681,50971,43200,30533,32517,38147,37625,38481,40265,32560,23510,18666,32576,32596,39698,32624,37664,32645,31965,32706,47478,32693,32731,32762,40433,46316,32798,32825,32774,32853,32872,49013,32893,32919,41769,42516,21429,46706,42516,42516,32939,25143,43551,27695,46191,47568,50517,33128,32038,44391,37914,44027,27827,22690,51501,22158,32960,23571,32997,33045,33080,33109,33144,33160,33196,33225,33259,33289,25257,41794,33305,33321,22943,47433,44826,33342,33363,33392,45913,37247,22690,23238,33434,38372,47456,46316,49977,38147,33455,33478,32944,28385,33515,33536,30206,38372,33571,38971,31372,39304,33587,33611,33627,33643,33674,33720,28385,36584,33273,33742,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,33784,42516,51537,33805,33823,29972,43389,33866,33897,42516,33882,33940,33947,33963,33976,26099,42516,42516,20279,27632,42516,42516,42516,42516,42516,41269,42516,41261,42516,41268,25123,41628,38176,37400,33992,34810,28721,42516,34012,42516,34304,34012,42516,42516,42516,34029,34013,37295,42516,28243,34045,22657,22657,22657,34069,34103,46316,46316,48318,47159,38147,38147,38147,40896,22382,42516,42516,42516,42516,42516,42516,23487,42516,42516,45931,42516,38368,22657,22657,22657,44213,38374,22541,46316,46316,46316,42968,44805,38147,38147,38147,38147,34120,32923,26115,26152,42516,42516,42516,42516,42516,23487,42516,46602,42516,38370,22657,22657,30041,22657,30360,22540,46316,46316,42268,46316,22343,30533,38147,38147,44e3,38147,27826,35762,23510,42516,42516,42516,42516,42516,39273,23255,22657,22657,22657,37139,22877,22539,46316,46316,49643,46316,32774,38147,38147,38147,48815,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,46191,46316,46316,46316,32038,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,46733,42516,42516,42516,36647,22657,28384,27995,46316,49984,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,44874,43254,31692,29762,34139,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,42516,51537,42516,38852,42516,42516,51280,34176,34185,34201,34208,34215,34231,34244,26099,42516,42516,42516,27632,42516,42516,34401,42516,42516,42516,42516,42516,42516,42516,28241,22657,46314,35273,38147,34810,37878,42057,42516,42516,34304,42516,42516,42516,42516,34260,42516,42516,42516,28243,22657,22657,22657,22657,27401,46316,46316,46316,48318,38147,38147,38147,38147,40896,22382,42516,42516,42516,42516,42516,42516,42516,42516,34278,42516,28081,38368,22657,22657,22657,22657,38374,42076,46316,46316,46316,46316,46212,38147,38147,38147,38147,38147,32923,22444,42516,42516,42516,47761,42516,34299,19108,42516,42516,19113,34320,22657,22657,34338,22657,30360,22540,46316,34104,46316,46316,22343,30533,38147,42837,38147,38147,27826,34355,42516,42516,42516,34399,42516,42516,42516,23255,22657,22657,22657,22657,30361,22539,46316,46316,46316,46316,30525,38147,38147,38147,38147,34440,41769,42516,42516,38663,42516,34417,28242,22657,22657,38760,37745,46316,46316,50996,37798,38147,38147,38147,34438,22690,34456,18364,34487,34538,24114,31309,31274,34559,34565,27432,34581,44559,30458,34604,22076,42516,19757,34657,29792,34679,47804,33555,31559,34736,35451,34758,22690,41150,39051,35676,32439,38610,34776,34795,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,34833,34871,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,42516,51537,42516,42516,42516,42516,25917,42516,42516,42516,42516,46741,49861,51029,26099,18277,42516,42516,34899,42516,42516,42516,36062,42516,36065,42516,42516,34947,34936,36697,22657,34963,27757,38148,48007,34986,42516,42516,29815,34304,21387,19116,42516,38636,42516,42516,42516,42516,28243,22657,22657,43325,22657,27401,46316,46316,30705,48318,38147,38147,38147,35021,40896,22382,42516,42516,42516,42516,42516,42516,42516,42516,35376,42516,35039,38368,22657,22657,22657,22657,50945,22541,46316,46316,46316,46316,38717,38147,38147,38147,38147,38147,41757,22444,42516,35059,42516,42516,42516,42516,42516,42516,42516,39196,38370,35077,22657,22657,22657,30360,46821,46316,46316,46316,46316,22343,23541,38147,38147,38147,38147,27826,41766,42516,42516,42516,50318,42516,42516,42516,23255,22657,22657,22657,46040,30361,22539,46316,46316,46316,34080,30525,38147,38147,38147,42204,34440,41769,42516,42516,46608,42516,42516,28242,22657,22657,22657,37745,46316,46316,46316,37798,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,23434,42516,22428,38373,22657,28384,46316,46316,36586,38147,27827,35094,34920,22560,38372,50497,46316,40393,38147,43581,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,44978,42516,51537,30322,33499,42482,50012,50022,18763,18772,35115,35131,35143,35159,35172,26099,42516,42516,42516,36498,41847,42516,42516,42516,31671,41803,35188,36161,35205,35221,43491,35237,35256,29171,35289,37464,35305,42516,42516,42516,35339,42516,28090,35375,42516,42516,28949,35314,39266,28243,48989,48108,22657,35392,47509,37433,35422,34970,35439,27808,35467,38147,35501,35536,22382,42516,35594,39908,48509,34515,35614,42516,18299,18417,42516,35655,35672,48116,22657,43129,29280,37184,22541,48019,46316,38117,35692,47637,38147,35719,38147,35737,27472,35753,22444,42516,42516,42516,42516,35778,48535,35820,42516,42516,42516,23024,36244,22657,22657,29502,38418,35859,41980,46316,46316,48733,41934,49389,35884,38147,38147,40673,49832,35905,42516,36909,35924,35976,35997,18673,36033,34522,36081,47410,36098,36117,36141,36177,46316,36198,32809,43953,30446,38147,43626,42012,36214,36230,23328,20636,45205,36266,36283,36301,35981,36329,26662,46771,36350,36390,48253,35703,36411,36456,40231,38454,41461,37653,42516,42516,37028,36479,40577,43121,45398,22366,37772,48725,38205,36432,50457,40469,42516,25485,42516,36514,38373,22657,28384,46316,46316,36586,38147,27827,36626,36531,42516,28996,31885,36559,36579,36602,36619,36804,36642,28385,28404,30535,42423,49897,44263,36663,36694,43147,27775,22913,28244,40729,36585,22448,36713,36744,34366,22755,31692,28429,36774,36790,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,39935,42516,51537,42516,42516,42516,42516,25917,42516,29952,39942,19158,38671,36820,36833,26099,42516,42516,42516,27632,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,28241,22657,46314,35273,38147,34810,28721,42516,42516,42516,34304,42516,42516,42516,42516,42516,42516,42516,42516,28243,22657,22657,44206,22657,27401,46316,46317,46316,48318,38147,38147,34588,38147,40896,22382,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38368,22657,22657,22657,22657,38374,22541,46316,46316,46316,46316,44805,38147,38147,38147,38147,38147,32923,22444,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38370,22657,22657,22657,22657,30360,22540,46316,46316,46316,46316,22343,30533,38147,38147,38147,38147,27826,41766,42516,42516,42516,42516,42516,42516,42516,23255,22657,22657,22657,22657,30361,22539,46316,46316,46316,46316,30525,38147,38147,38147,38147,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,37745,46316,46316,46316,37798,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,19484,42516,51537,42516,42516,42516,42516,25917,42516,42516,42516,42516,46741,49861,51029,26099,42516,42516,42516,27632,42516,42516,36849,42516,42516,42516,42516,42516,42516,42516,28241,22657,46314,35273,38147,34810,28721,42516,42516,42516,34304,42516,42516,42516,42516,42516,42516,42516,42516,28243,22657,22657,22657,22657,27401,46316,46316,46316,48318,38147,38147,38147,38147,40896,22382,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38368,22657,22657,22657,22657,38374,22541,46316,46316,46316,46316,44805,38147,38147,38147,38147,38147,32923,22444,42516,36869,42516,42516,42516,42516,42516,42516,42516,42516,46294,22657,22657,22657,22657,30360,49232,46316,46316,46316,46316,22343,30796,38147,38147,38147,38147,27826,41766,42516,42516,42516,42516,42516,42516,42516,23255,22657,22657,22657,22657,30361,22539,46316,46316,46316,46316,30525,38147,38147,38147,38147,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,37745,46316,46316,46316,37798,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,46996,42516,51537,42516,23354,42516,42753,36888,36925,36938,36954,36961,36977,36993,37006,26099,42516,37022,42516,27632,42516,41516,26816,42516,42516,37044,42516,37049,18537,37065,37087,37117,44086,37200,37235,39844,33658,37263,42516,42516,35791,42516,42516,34914,28072,42516,37291,22389,37311,18926,37716,37348,43712,48153,37366,37382,46316,37416,40607,40193,49587,35520,37449,27508,37480,37934,42516,42516,42516,42516,41144,42516,42516,42516,42516,42516,38368,37503,36125,22657,37529,39594,37550,37566,48265,46316,37588,30713,29645,37605,37623,38799,38147,37641,22444,42516,42516,37688,42516,42516,49494,24999,42516,42516,42516,38370,22657,22657,29494,37704,37740,22540,46316,46316,40001,37761,37795,30533,38147,38147,37825,37814,37848,41766,42516,37894,42516,42516,51139,42516,42516,23255,22657,41398,22657,22657,30361,22539,42274,46316,46316,46316,30525,38147,37912,38147,38147,34440,41769,37930,36490,42516,34663,37950,28242,37986,22657,22657,46812,38013,46316,46316,45485,49261,38147,38147,48821,22690,49311,42516,42516,38050,38368,41404,22657,40730,47057,46316,36583,48937,38147,40469,42516,21575,42516,42516,38373,22657,38069,46316,45780,36586,38147,40463,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,38089,46273,22694,23034,40134,34366,22755,38105,38164,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,26200,42516,51537,42516,27946,42516,42516,47834,20951,20960,38221,38236,38243,38259,38272,26258,42516,38551,42516,27632,42516,34262,42516,42516,42516,38553,42516,38546,21091,38552,21774,38288,31700,35273,38309,34810,28721,42516,42516,38329,34304,42516,29241,23811,23953,42516,42516,42516,38347,38364,33022,22657,38390,38410,28636,46316,29607,39628,38434,42370,38147,48603,38470,47663,38504,38541,39253,39681,42516,42516,42516,42516,41197,42516,42516,42516,38368,31857,22657,38569,22657,38374,22541,38589,28198,46316,46316,44805,29206,27800,32877,38147,38147,32923,22444,42516,28144,42516,38634,42516,45188,42516,38652,42516,42516,38370,39723,22657,22657,38687,30379,22540,23043,46316,46316,38710,22895,30533,49398,38147,38147,38733,27826,41766,42516,42516,42516,42516,42516,42516,42516,23255,22657,22657,22657,22657,30361,22539,46316,46316,46316,46316,30525,38147,38147,38147,38147,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,37745,46316,46316,46316,37798,38147,38147,38147,27827,33462,42516,42516,42516,42516,38368,38756,22657,40730,38776,46316,36583,38795,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,38815,36586,49663,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,49485,38368,44256,40047,45820,38834,38868,32210,38891,28238,43147,27775,22913,28244,40729,36585,22448,28385,38914,38935,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,27187,42516,30926,42516,34543,38987,37672,39016,39067,39107,39092,39111,39076,39127,39140,26099,42516,25841,23701,20829,39222,20009,42516,39156,41252,39175,39212,32746,21195,39238,26847,39289,45668,39332,39368,34810,28721,32390,42516,42516,26444,30879,36010,28099,40787,39398,38525,26035,39432,39483,44460,39503,41633,22657,32003,22601,46316,49709,48318,47976,47889,30552,38147,33209,39523,39917,39159,42516,39546,42516,42516,40976,42516,42516,42516,39568,39487,37157,22657,39589,22657,38374,39610,45436,46316,39644,46316,44805,27542,39661,38313,38147,38147,32923,22444,42516,42516,42516,42516,30632,42516,42516,21187,39678,39697,39714,22657,22657,50559,22657,39739,39760,46316,46316,38818,46316,39784,39805,38147,38147,32856,38147,39829,41766,46006,39893,48391,49682,42516,39960,34641,39976,38394,40024,37997,33010,30361,22539,40063,40121,43817,40157,30525,40868,40175,40209,40247,34760,44916,20285,40281,34623,40309,51090,50324,48429,40325,40344,40364,39645,40409,40428,40449,38147,40485,49825,39382,22690,40506,42516,42516,22216,40534,39507,48098,30083,50926,38024,33595,45640,28567,40469,40559,42516,40087,26129,45371,31289,28384,40593,41927,40637,40665,40689,34614,41203,40707,27312,43148,48295,28405,40861,22683,50287,38368,40727,40746,40649,40767,40811,22827,40847,33407,49334,48207,33243,28244,40729,36585,22448,28385,36584,41673,40884,31692,28429,22929,40922,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,40951,51537,42516,42744,40972,42516,27292,40992,41001,41017,41032,41039,41055,41068,26099,20248,41084,41102,41129,21286,41166,42516,41182,41219,41286,31731,41302,41336,41352,41368,41384,34883,41420,41436,48349,41477,42516,42240,27121,34422,42516,41511,25267,41532,41575,42516,42516,41594,28243,22657,31843,41613,34053,27401,40159,35568,34847,41649,38147,27550,41689,41744,40896,22382,42516,26380,42516,41578,42516,44762,41785,42516,41828,27866,41270,19255,22657,41881,41897,22657,35406,41916,43971,44095,46316,46316,41950,22851,37219,42001,38147,29467,32923,42028,42044,42516,46644,19385,42516,42516,42516,42516,42516,34632,38370,22657,27339,43920,22657,30360,22540,46316,44514,36395,46316,22343,30533,38147,35478,49592,38147,27826,41766,42516,42516,21305,42516,31235,42516,42516,23255,22657,22657,22657,22657,20064,42074,46316,46316,46316,46316,42093,38147,38147,38147,38147,50734,41769,50664,35952,42516,42516,42516,41113,22657,42177,22657,45759,46316,43945,46316,45799,38147,45843,38147,27827,29041,42127,42516,42516,42516,48412,30671,22657,38073,44692,46316,33520,45533,38147,40469,42146,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,43588,34920,42516,42166,40348,33173,48271,42201,22683,42220,41559,42256,42290,42321,33756,44448,35547,42352,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,32531,22755,42386,28429,22929,42410,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,39045,51537,42516,42516,42439,19363,42461,42498,42516,31468,42533,42547,42563,42576,26099,42516,42516,25867,27632,42516,42516,42516,42592,26617,42516,42516,26436,25867,42516,30236,31920,49620,42612,36440,34810,28721,42516,42647,42516,34304,42516,44608,36046,42516,35598,42516,42516,36057,51481,44194,32471,36334,37148,42671,32033,42687,33121,42706,38488,30256,30569,29372,32199,42722,42778,42516,42799,42516,49524,50043,35835,42516,42516,42516,42516,38368,22657,22657,37175,22657,38374,22541,46316,46316,47563,46316,44805,38147,38147,38147,42836,38147,32923,42853,42888,35656,42516,42516,42516,50763,30902,39460,48700,42516,38370,22657,42923,22657,22657,37350,22540,46316,42958,46316,46316,27403,30533,38147,42991,38147,38147,27826,41766,42516,29233,42516,42516,42516,43017,42516,23255,22657,22657,49093,22657,22325,22539,46316,46316,43039,46316,30788,38147,38147,35485,38147,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,37745,46316,46316,46316,37798,38147,38147,38147,27827,22690,42516,36017,42516,42516,43058,22657,22657,40730,46316,46316,36583,38147,38147,48843,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,46409,43080,43110,32715,30112,30535,40935,43145,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,42516,51537,42516,42516,42516,42516,25917,42516,42516,42516,42516,46741,49861,51029,26099,42516,42516,42516,27632,42516,42516,35061,42516,42516,42516,28279,28282,18254,28275,31684,43164,43182,29146,43216,43233,29330,43270,42516,42516,34304,42516,42516,42516,42516,42516,42516,42516,42516,28243,22657,22657,22657,22657,27401,46316,46316,46316,48318,38147,38147,38147,38147,40896,22382,42516,42516,42516,43287,42516,42516,42516,42516,42516,42516,42516,38368,22657,22657,22657,22657,38374,43306,46316,46316,46316,46316,50852,38147,38147,38147,38147,38147,32923,22444,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38370,22657,22657,22657,22657,30360,22540,46316,46316,46316,46316,22343,30533,38147,38147,38147,38147,27826,41766,42516,42516,42516,42516,42516,42516,42516,23255,22657,22657,22657,22657,30361,22539,46316,46316,46316,46316,30525,38147,38147,38147,38147,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,37745,46316,46316,46316,37798,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,43323,28384,43789,46316,36586,43341,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,50278,22100,42516,42516,50243,42516,29530,43375,33789,43361,43411,43418,43434,43447,26099,42516,33915,33924,27632,40956,43463,43486,41243,43507,26512,26972,26982,27147,41812,42783,43531,49966,43567,43604,44058,40078,42516,42516,42516,23213,43642,34502,43666,43684,38517,42516,42516,35323,43702,22657,43728,30048,43746,43782,42975,46316,43805,34708,43833,43850,27569,49274,49874,43871,42516,42516,42516,45270,35189,42516,42516,43894,43668,42516,42814,33726,22657,43915,22657,37724,49041,43936,46316,43969,46316,45680,43987,44022,33996,38147,38147,44043,44074,22444,42516,42516,19081,42516,44111,44127,42516,43290,44154,44166,44182,22657,37101,44229,44279,30652,44299,46316,42336,45461,44326,40412,44345,38147,44372,45987,44388,34123,41766,28121,42516,42516,24911,44407,50085,42516,44435,27732,44483,22975,22657,30361,22539,44504,42690,46316,46316,30525,28768,44537,44554,38147,40691,44575,42516,44603,44624,42516,42516,28242,44645,22657,22657,44664,44689,46316,46316,49378,44708,38147,38147,49798,22690,42516,44729,42516,42516,20056,22657,22657,34376,46316,51047,22477,38147,44538,40469,42516,22273,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,44749,26230,34694,49922,44785,36803,38372,46315,38146,47702,44821,44842,44862,21913,40729,36585,22448,28385,36584,40621,44890,44940,42111,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,46959,51537,45028,47264,44964,45002,45045,45083,45015,45108,45123,45139,45155,45168,26099,45184,28448,42516,28797,42516,42516,30342,42516,42516,45204,45221,31185,28655,31192,26648,48147,38948,50978,45241,34810,28721,45262,45286,25875,34304,35804,42516,42516,42516,42516,45307,45333,42516,45362,45387,27370,22657,22657,45422,45457,45477,46316,48318,45501,22713,45531,38147,40896,22382,41086,42516,42516,45549,45580,42516,42516,42516,42516,42516,41312,38368,32670,37166,22657,22657,33029,22541,45618,47052,46316,46316,45690,35721,38147,45637,38147,38147,45656,22444,42516,42516,45593,44733,42516,45600,35835,45706,27030,38348,45731,22657,22657,40543,26861,45754,45775,46316,46316,43191,44800,45796,45815,38147,38147,40256,45836,45859,28046,42867,49429,42516,25220,42516,19477,43271,20461,22657,22657,27347,45890,30361,22539,46316,48577,44521,46316,30525,38147,38147,46850,45910,34440,41769,42516,50831,45929,19737,42516,28242,22657,45947,43759,50887,46316,45965,46065,28181,38147,45983,46857,27827,22690,42516,42516,46003,44138,38368,22657,22657,40730,46316,46316,36583,38147,38147,29031,51383,46022,26136,47337,46039,22657,46056,46316,34383,36586,38147,46089,46111,34920,46149,46173,43148,46207,44846,46228,32903,36804,38368,46247,46266,45515,36803,38372,46315,38146,35099,35240,22504,22913,46289,46310,46333,36758,46387,47879,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,27247,51537,42516,42516,23393,42516,46425,46462,46474,46490,46505,46521,46537,46550,26099,46566,25493,25815,46587,26561,21328,46624,21598,42516,46636,46660,46669,46685,46722,46757,46799,32544,46837,46873,41704,47524,33832,37332,35627,34304,46901,42516,44629,46918,39031,46952,46975,47012,47022,48184,31972,27713,43730,47038,31642,47073,47098,47607,47121,47145,47186,47202,47222,47250,47280,47302,42058,42516,47326,47353,42516,42516,47371,47388,46928,47404,47426,47449,47472,29567,47494,47549,47584,47623,47679,36182,44805,36463,37832,40141,38147,32161,32170,47697,42516,45060,42596,50682,47718,42130,47751,46440,36515,21144,38370,47785,29270,22657,44488,47820,47850,47868,40376,46316,45441,47912,47938,47958,43617,38147,38919,47992,41766,29407,48041,42516,27096,48062,42516,50062,40568,48085,38573,48132,48169,30361,48200,48223,48241,48287,48311,47922,47129,22858,48334,43855,34440,40906,48365,50193,42516,22144,48387,48407,44243,48428,22657,49223,47234,48445,46316,47082,50795,48488,38147,33704,22690,42516,48504,48525,42516,20103,22966,48559,32447,40385,48575,48593,50156,48626,48646,48680,42516,33850,39552,21921,26930,48716,48749,48769,48802,45246,48837,48960,48859,48887,32658,28363,48910,33376,48933,48953,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,45621,46231,48976,39991,49005,49029,40039,49057,44903,22755,31692,28429,49073,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,42516,49109,42516,42516,49144,42516,32608,18328,18337,49164,18337,18344,49180,49193,26099,42516,42516,42516,27632,20863,28835,42516,42516,42516,42516,28834,42516,20857,42516,28241,49209,31530,22841,49248,36678,30143,33493,42516,42516,34304,42516,42516,35043,49290,42516,42516,42516,38053,28243,49327,22657,22657,22658,49350,46316,46316,46316,31591,33687,38147,38147,38147,49366,49414,49451,42516,49474,49519,42516,42516,43686,45346,42516,46571,46157,38368,45949,40328,45406,25137,29005,22541,48786,34087,38601,49540,48459,38147,33697,39345,49573,33236,49608,22444,42516,19180,42516,50588,42516,42516,42516,18791,42516,42516,38370,38694,22657,22657,22657,30360,49641,32217,46316,46316,46316,22343,49659,38898,38147,38147,38147,27826,41766,46990,42516,49679,42516,42516,42516,42516,20094,31303,22657,22657,22657,30361,49698,46316,46316,46316,46316,30525,49732,38147,38147,38147,34440,35908,42516,42516,46023,49756,42516,29706,37130,22657,22657,39744,38128,46316,46316,49778,49814,38147,38147,49848,22690,22055,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,34322,43148,47105,28405,38446,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,49890,49913,49938,22448,28385,36584,34366,34779,33418,49954,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,42516,5e4,50082,50038,50059,42516,32349,42516,20487,50078,34283,44986,50101,50114,26099,42516,42516,42516,27632,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,28241,50130,42394,35273,50148,34810,28721,42516,36285,32580,34304,42516,42516,42516,42516,42516,25759,42516,42516,28243,27704,22657,37534,22657,27401,50172,46316,38188,48318,29351,38147,30813,38147,40896,22382,42516,42516,42516,42516,42516,41597,42516,42516,42516,42476,42516,38368,22657,50132,22657,22657,38374,22541,46316,49557,46316,46316,44805,38147,38147,50449,38147,38147,32923,22444,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38370,22657,22657,22657,22657,30360,22540,46316,46316,46316,46316,22343,30533,38147,38147,38147,38147,27826,41766,42516,42516,42516,42516,42516,42516,42516,23255,22657,22657,22657,22657,30361,22539,46316,46316,46316,46316,30525,38147,38147,38147,38147,34440,41769,42516,42516,50190,42516,42516,28242,22657,22657,22657,37745,46316,46316,46316,37798,38147,38147,38147,27827,22690,42516,50209,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,50231,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,42516,50266,42516,22306,42516,45067,50303,50340,42516,50365,50380,50394,50410,50423,26099,42516,42516,42516,27632,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,28241,45894,46314,50439,28325,41965,36365,42516,42516,42516,34304,42516,42516,42516,42516,25694,42516,42516,42516,28243,22657,22657,22657,22657,27401,46316,46316,46316,48318,38147,38147,38147,38147,40896,22382,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38368,22657,22657,22657,22657,38374,22541,46316,46316,46316,46316,44805,38147,38147,38147,38147,38147,32923,22444,42516,42516,42516,42516,42516,42516,50473,42516,42516,42516,50491,22657,22657,22657,22657,30360,50513,46316,46316,46316,46316,22343,50533,38147,38147,38147,38147,27826,41766,42516,42516,29399,42516,42516,42516,42516,23255,22657,22657,50557,22657,50575,22539,46316,43245,46316,33180,30525,38147,47942,38147,38147,50611,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,37745,46316,46316,46316,37798,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,26324,42516,42516,42516,42516,51537,42516,42516,42516,42516,25917,42516,42516,42516,42516,48543,50631,50644,26099,42516,42516,42516,27632,50660,42516,50680,42516,42516,42516,29122,42516,21452,29118,32973,50698,44948,35273,50716,34810,28721,42516,42516,42516,50750,27264,27883,43515,42516,42516,42516,42516,42516,28243,22657,43166,22657,49088,27401,46316,30696,30175,48318,38147,38147,50786,27533,40896,50811,50827,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38368,22657,22657,22657,22657,38374,22541,46316,46316,46316,46316,44805,38147,38147,38147,38147,38147,32923,22444,42516,42516,42516,42516,42516,42516,51530,42516,42516,42516,38370,22657,27966,22657,22657,27206,22540,46316,36563,46316,46316,48225,30533,38147,43345,38147,38147,27826,41766,21110,42516,42516,42516,42516,42516,42516,23255,36082,22657,22657,22657,30361,22539,50847,46316,46316,46316,30525,40490,38147,38147,38147,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,37745,46316,46316,46316,37798,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,42516,51537,42516,42516,42516,42516,25917,42516,42516,42516,42516,46741,49861,51029,26099,24903,42516,42516,27632,42516,42516,20017,42516,42516,42516,42516,20023,42516,42516,50868,36101,46314,27462,29927,45874,41719,42516,29087,42516,34304,42516,42516,42516,42516,42516,42516,42516,42872,28243,22657,22657,22657,47797,27401,46316,46316,22542,48318,38147,38147,38147,27479,40896,22382,42516,50903,42516,42516,42516,42516,42516,42516,42150,42516,42516,38368,46183,22657,41900,22657,38374,22541,50922,46316,37779,46316,44805,36603,38147,38147,40222,38147,32923,22444,42516,50475,42516,42516,42516,42516,42516,42516,42516,42516,38370,22657,50942,22657,22657,30360,50961,30499,50994,46316,46316,22343,49789,39662,51012,38147,38147,27826,41766,42516,42516,42516,42516,42516,42516,48664,23255,22657,22657,32677,22657,28304,22539,46316,46316,51045,46316,51063,38147,38147,50725,38147,44006,41769,42516,42516,50906,42516,42516,28242,22657,22657,22657,37745,46316,46316,46316,37798,38147,38147,38147,27827,48656,42516,42516,47372,42516,31381,22657,22657,34817,46316,46316,40751,38147,38147,40469,42516,42516,51087,42516,38373,28681,28384,46316,51106,36586,34742,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,51361,42516,42516,42516,42516,51537,42516,42516,42516,42516,25917,19962,42516,42516,42516,46741,49861,51029,26099,42516,42516,42516,27632,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,28241,22657,46314,35273,38147,34810,28721,42516,42516,42516,34304,42516,42516,42516,42516,42516,42516,42516,42516,28243,22657,22657,22657,22657,27401,46316,46316,46316,48318,38147,38147,38147,38147,40896,22382,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38368,22657,22657,22657,22657,38374,22541,46316,46316,46316,46316,44805,38147,38147,38147,38147,38147,32923,22444,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38370,22657,22657,22657,22657,30360,22540,46316,46316,46316,46316,22343,30533,38147,38147,38147,38147,27826,41766,42516,42516,42516,42516,42516,42516,42516,23255,22657,22657,22657,22657,30361,22539,46316,46316,46316,46316,30525,38147,38147,38147,38147,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,37745,46316,46316,46316,37798,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,42516,42516,42516,42516,46123,30288,30286,49299,30156,51124,22408,22410,49308,30152,46133,51161,51174,21040,42516,42516,42516,27632,42516,42516,31797,42516,42516,42516,42516,42516,42516,42516,32629,20505,20792,18990,21068,19019,18919,18270,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,51190,25598,18486,18508,19308,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,42516,42516,42516,42516,48069,42516,42516,30409,42516,25917,39868,39877,51215,51230,51237,29448,51253,21040,42516,42516,42516,27632,42516,42516,51474,42516,42516,42516,23517,42516,42516,23514,32629,20505,21066,18953,21068,18866,18919,18270,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,18459,25598,18486,18508,51199,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,42516,42516,42516,42516,36374,42516,42516,42516,42516,31102,50349,51296,51323,51307,51330,32370,51346,21040,42516,42516,42516,27632,42516,42516,51474,51382,42516,26083,42516,42516,42516,26079,32629,20505,21066,18953,21068,19019,18919,18270,40105,18293,18315,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,51399,25598,18486,18508,21522,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,20235,20264,20301,20317,20346,20333,20349,20365,20381,20397,20422,20606,20438,20477,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,21141,42516,42516,42516,42516,48069,42516,42516,42516,42516,25917,42516,42516,42516,42516,42516,42516,42517,26099,42516,42516,42516,27632,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,28241,22657,46314,35273,38147,34810,46363,42516,42516,42516,34304,42516,42516,42516,42516,42516,42516,42516,42516,28243,22657,22657,22657,22657,22341,46316,46316,46316,39789,38147,38147,38147,38147,40896,22382,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38368,22657,22657,22657,22657,38374,22541,46316,46316,46316,46316,44805,38147,38147,38147,38147,38147,32923,22444,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,38370,22657,22657,22657,22657,30360,22540,46316,46316,46316,46316,22343,30533,38147,38147,38147,38147,27826,41766,42516,42516,42516,42516,42516,42516,42516,23255,22657,22657,22657,22657,30361,22539,46316,46316,46316,46316,30525,38147,38147,38147,38147,34440,41769,42516,42516,42516,42516,42516,28242,22657,22657,22657,37745,46316,46316,46316,37798,38147,38147,38147,27827,22690,42516,42516,42516,42516,38368,22657,22657,40730,46316,46316,36583,38147,38147,40469,42516,42516,42516,42516,38373,22657,28384,46316,46316,36586,38147,27827,22690,34920,42516,38372,43148,46316,28405,38147,22683,36804,38368,28385,28404,30535,36803,38372,46315,38146,28238,43147,27775,22913,28244,40729,36585,22448,28385,36584,34366,22755,31692,28429,22929,23e3,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,23494,42516,42516,45092,51424,51429,51429,51451,23492,51445,51467,42516,42516,42516,42516,42516,42516,51474,42516,42516,42516,42516,42516,42516,42516,32629,20505,21066,18953,21068,19019,18919,18270,40105,18293,51497,42516,42516,18360,42516,49435,42820,18380,18411,18395,18574,19226,18433,20169,51190,25598,18486,18508,19308,18465,25604,18492,18514,20728,18530,42516,30418,42516,42516,42516,50250,25964,50770,42516,18553,39446,18564,20175,20411,20131,20505,23879,18590,26008,18612,18632,18596,18470,18594,26012,18616,18636,20798,20741,20757,42516,18652,18689,18711,18748,18695,18788,42516,41546,48871,18807,18835,19802,18823,19840,25206,18851,18904,18942,18979,19680,19006,18851,18904,18942,18979,19680,19045,20750,46697,19097,19132,20936,31767,19148,19174,19196,20141,20921,19788,19212,19242,19278,25525,20579,19301,19596,19271,25518,20572,19294,19589,19324,19353,35639,19379,39467,19401,41728,19421,19500,24458,19544,19575,19614,19632,19650,19559,19612,19630,19648,19666,19029,19696,19712,19728,19753,19773,19830,19435,19449,19888,19905,19856,19887,19904,19921,19947,19984,20043,20080,20119,20157,20536,20191,20213,20542,20197,20219,19931,51517,20264,20301,20317,20346,20333,20349,20365,51553,20397,20422,20606,20438,20453,20503,21067,21068,20521,20558,20595,20622,20652,23888,18878,20683,20699,20715,20779,20814,20880,20890,20906,19463,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,42516,94506,94506,94506,94506,94506,94506,94506,94506,94506,94506,0,94506,90409,94506,94506,94506,94506,94506,94506,94506,94506,94506,365,94506,90409,94506,94506,94506,94506,94506,94506,94506,69632,73728,94506,94506,94506,94506,94506,65536,94506,12290,3,0,0,2183168,0,0,0,90409,94506,299,300,0,2134016,303,304,304,304,304,304,304,304,0,0,0,0,0,304,0,304,1,289,3,0,0,0,295,0,0,0,0,0,0,0,0,0,0,796,0,796,0,0,0,0,0,2424832,2433024,0,0,2457600,0,0,0,0,0,0,0,0,0,0,650,0,0,0,0,0,0,0,0,0,2904064,2908160,0,0,0,0,0,0,0,0,0,0,0,1685,1686,0,1688,0,0,0,0,3117056,0,0,0,0,0,0,0,365,365,0,0,0,0,0,0,448,0,0,474,474,474,474,474,474,474,474,474,474,474,474,474,474,474,474,559,582,559,582,559,559,582,0,0,0,2138112,0,0,0,0,0,0,0,0,0,0,0,0,0,2991,0,0,0,2772992,2805760,2830336,0,2863104,2920448,0,0,0,0,0,0,0,2805760,2920448,0,0,0,0,0,0,0,2732032,0,2179072,2179072,2179072,2179072,2424832,2433024,0,0,0,0,0,2920448,0,0,0,0,0,0,0,0,0,0,0,1702,0,1704,0,0,2179072,2830336,2179072,2179072,2863104,2179072,2179072,2179072,2179072,2920448,2179072,2179072,2179072,2179072,2179072,2179072,2126737,2126737,2126737,2126737,2126737,2593681,2126737,2126737,2126737,2126737,0,914,2125824,2125824,2125824,2125824,2125824,2424832,2433024,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,0,0,2125824,2125824,2125824,2125824,2723840,2125824,2732032,2772992,2125824,2125824,2125824,2805760,2125824,2830336,2125824,2125824,2863104,2125824,2125824,2125824,2125824,2920448,2125824,2125824,2125824,2125824,2125824,2920448,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,3117056,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2457600,2125824,2125824,2125824,2125824,2183168,0,0,0,0,0,0,0,0,0,0,661,0,661,0,0,0,2408448,0,0,2584576,0,0,0,0,2838528,0,0,2838528,0,0,0,0,0,2179072,2179072,2179072,2408448,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2625536,2179072,2179072,0,2125824,2125824,2125824,2408448,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,3125248,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2662400,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2801664,2813952,2125824,2125824,2801664,2813952,2125824,2838528,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2461696,0,0,0,0,0,0,0,0,0,0,0,0,2600960,0,0,0,0,0,0,2441,0,0,0,0,0,0,0,0,0,0,2493,2494,0,0,2497,0,2768896,2777088,2781184,0,2822144,0,0,2883584,0,0,0,0,0,0,0,0,0,0,0,0,3055616,0,0,0,3080192,3100672,3104768,0,0,0,0,3186688,0,0,0,0,0,0,0,307,204800,0,0,0,0,0,0,0,0,0,111051,111051,111051,111051,111051,111051,111051,111051,1,0,0,0,0,0,2797568,0,0,0,0,0,0,0,2850816,2867200,0,0,0,0,0,441,0,0,332,468,468,468,468,468,468,468,468,468,468,468,468,468,468,468,468,0,0,3133440,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2131,0,0,0,0,0,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2461696,2465792,2179072,2768896,2777088,2781184,2797568,2822144,2179072,2179072,2179072,2883584,2179072,2912256,2179072,2179072,2179072,2179072,2179072,2179072,2523136,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2600960,0,0,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2461696,2465792,2125824,0,1142784,0,2179072,2125824,2125824,2179072,2179072,2179072,2179072,2179072,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2592768,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,0,24576,988,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2523136,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2600960,2125824,0,2125824,2125824,2125824,2125824,2125824,0,0,0,0,0,0,0,0,0,0,541,1272,541,541,541,541,2125824,2125824,2125824,2641920,2125824,2125824,2125824,2125824,2125824,2125824,2719744,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,0,2125824,2125824,2125824,2125824,2125824,2125824,299,0,0,0,299,0,300,0,0,0,2768896,2777088,2781184,2797568,2822144,2125824,2125824,2125824,2883584,2125824,2912256,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,0,2125824,2126812,2125824,2125824,2125824,2125824,2125824,2125824,3133440,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,3207168,2125824,0,0,0,2179072,2125824,2125824,2179072,2179072,2179072,2179072,2179072,2125824,2125824,2125824,2125824,0,0,0,0,0,0,2510848,2514944,0,0,2125824,2125824,3133440,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,3207168,2125824,2179072,2125824,0,2125824,2125824,2125824,2125824,2125824,0,0,0,0,0,0,300,0,0,0,0,0,0,2764,0,0,0,0,0,0,0,0,0,0,2059,2060,0,2062,2063,0,0,0,0,2605056,0,0,0,0,2887680,0,2924544,0,0,0,0,0,0,0,2108,0,0,0,0,0,0,0,0,0,0,0,0,0,1177,0,0,0,0,0,0,3162112,3170304,0,0,3219456,3035136,0,0,0,0,0,3072e3,3190784,0,0,0,0,0,0,0,0,2576384,0,0,0,0,0,0,0,334,0,0,334,0,0,334,0,0,0,0,0,0,0,2387968,0,0,0,0,0,0,0,0,0,0,0,2050,0,0,0,0,3121152,3141632,0,0,0,2924544,0,2682880,0,0,0,0,0,0,3112960,2387968,2924544,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,3035136,2179072,2179072,3072e3,2179072,2179072,2179072,2179072,2699264,2179072,2715648,2179072,2723840,2179072,2732032,2772992,2179072,2179072,2179072,2805760,3121152,2179072,2179072,3141632,2179072,2179072,2179072,3170304,2179072,2179072,3190784,3194880,2179072,0,0,0,0,0,0,541,1734,541,541,541,541,541,541,1740,541,2125824,3190784,3194880,2125824,0,0,0,0,0,0,2387968,2125824,2125824,2125824,2420736,2125824,2125824,2125824,2125824,2125824,2453504,2125824,2473984,2125824,2736128,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2887680,2125824,2125824,2924544,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,0,0,0,2125824,2125824,2125824,2125824,2125824,3141632,2125824,2125824,2125824,3170304,2125824,2125824,3190784,3194880,2125824,2179072,2125824,2125824,2179072,2179072,2179072,2179072,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,299,0,300,3112960,3219456,2125824,2125824,3112960,3219456,2125824,2125824,3112960,3219456,0,0,0,0,0,0,0,347,0,405,0,0,0,0,0,405,3022848,0,0,3145728,0,3203072,0,0,0,0,0,0,0,0,0,0,0,2072,0,0,0,0,0,0,0,3067904,0,0,0,0,0,0,0,0,0,0,0,0,0,3003,0,0,0,0,0,2621440,0,3182592,2899968,0,2961408,0,0,2179072,2179072,2416640,2179072,2179072,2179072,2179072,2928640,2179072,2179072,2179072,2998272,2179072,2179072,2179072,2179072,3059712,2179072,2179072,2179072,2179072,3178496,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2494464,2125824,2125824,0,2179072,2125824,2125824,0,2179072,2125824,2125824,2985984,2985984,2985984,2985984,0,0,0,0,0,0,2490,0,0,0,0,0,0,0,0,0,335,0,0,0,0,0,0,2179072,2445312,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2551808,2179072,2179072,2179072,2179072,3178496,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2495377,2126737,2126737,2126737,2126737,2126737,3179409,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2495451,2126811,2895872,2916352,2179072,2179072,2945024,2179072,2179072,2994176,2179072,3002368,2179072,2179072,3022848,2179072,3067904,3084288,2125824,3096576,2125824,2125824,2125824,2125824,2125824,2125824,2125824,3223552,0,0,2125824,2125824,2416640,3096576,2179072,2179072,2179072,2179072,2179072,2179072,2179072,3223552,0,0,2125824,2125824,2416640,2125824,2125824,2125824,2125824,2125824,2125824,2125824,3035136,2125824,2125824,3072e3,2125824,2125824,2125824,3121152,2125824,2125824,3141632,2125824,2125824,2125824,3170304,2125824,2125824,2125824,2125824,2445312,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2551808,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2637824,2125824,2125824,2125824,2125824,2727936,2752512,2125824,2125824,2125824,2125824,2842624,2846720,2842624,2846720,2125824,2895872,2916352,2125824,2125824,2945024,2125824,2125824,2994176,2125824,3002368,2125824,2125824,3022848,2125824,3067904,2125824,3067904,3084288,2125824,3096576,2125824,2125824,2125824,2125824,2125824,2125824,2125824,3223552,2179072,2125824,2125824,2125824,2125824,2125824,2125824,2125824,3039232,2125824,3063808,2125824,2125824,2125824,2125824,2125824,3100672,2547712,2596864,0,0,0,0,0,0,0,0,0,0,0,0,0,3178496,2670592,0,2744320,0,0,0,0,0,2928640,0,0,0,3059712,0,2543616,2666496,0,2633728,0,0,0,0,0,0,2494464,0,0,0,0,0,0,0,0,0,2780,0,0,0,0,2785,0,0,0,0,2957312,0,0,0,0,0,0,0,0,0,0,0,0,0,3188,0,0,0,0,3211264,0,0,0,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2494464,2179072,2179072,2179072,2707456,2179072,2736128,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2887680,2179072,2179072,2179072,2179072,2641920,2179072,2179072,2179072,2179072,2179072,2179072,2719744,2179072,2179072,2179072,2179072,2179072,2179072,2179072,3137536,2126737,2126737,2499473,2126737,2126737,2126737,2556817,2565009,2179072,2514944,2179072,2179072,2179072,2543616,2547712,2179072,2179072,2596864,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,3039232,2179072,3063808,2179072,2179072,2179072,2179072,3100672,2125824,2125824,2125824,2125824,2125824,3178496,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2494464,2125824,0,2125824,2125824,2125824,2125824,2125824,0,0,0,0,1080,1084,0,0,1088,2125824,2514944,2125824,2125824,2125824,2543616,2547712,2125824,2125824,2596864,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2928640,2125824,2125824,2125824,2998272,2125824,2125824,2125824,2125824,3059712,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,3178496,2179072,2125824,2125824,2179072,2179072,2125824,2125824,2125824,2125824,0,2486272,0,0,0,0,0,2678784,2854912,3006464,2441216,0,0,0,0,0,0,0,0,0,2932736,2965504,0,0,3076096,0,0,0,0,0,444,0,0,0,0,0,0,0,0,0,0,407,0,0,0,0,0,0,2695168,3174400,2646016,2613248,2703360,0,0,0,0,2977792,0,0,3047424,3129344,0,0,0,0,0,645,0,0,648,649,0,0,0,0,0,0,0,725,0,0,0,0,0,0,0,0,0,743,0,0,0,0,0,0,0,0,0,0,0,0,2769,0,0,0,2981888,2396160,0,3153920,0,0,0,0,0,0,0,0,2740224,0,0,0,0,0,0,541,3027,541,541,541,541,541,541,541,541,541,2584,541,541,541,0,0,0,0,0,2793472,0,0,0,0,0,2469888,2506752,2756608,0,0,2580480,0,0,0,0,0,0,2517,0,0,0,0,0,0,0,0,541,541,541,3029,541,541,541,541,541,541,0,2396160,2400256,2179072,2179072,2441216,2179072,2469888,2179072,2179072,2179072,2519040,2179072,2179072,2179072,2179072,2179072,2179072,2801664,2813952,2179072,2838528,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2453504,2179072,2473984,2482176,2179072,2179072,2179072,2179072,2588672,2179072,2613248,2646016,2179072,2179072,2695168,2756608,2179072,2179072,2179072,2932736,2179072,2179072,2179072,2179072,2179072,3117056,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2584576,2179072,2179072,2125824,2125824,2125824,2519040,2125824,2125824,2125824,2125824,2588672,2125824,2613248,2646016,2125824,2125824,2695168,2756608,2125824,2125824,2125824,2125824,2932736,2125824,2125824,2125824,2125824,2125824,2932736,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,3129344,2125824,2125824,3153920,3166208,3174400,2506752,2506752,2506752,0,3108864,3198976,0,0,3043328,0,3149824,2936832,0,2760704,3180,2437120,0,0,0,0,0,0,646,0,0,0,0,651,652,653,654,655,0,0,0,0,0,2953216,0,0,2826240,3158016,2428928,0,3018752,2764800,2572288,0,0,0,0,0,677,0,0,0,0,0,0,0,0,0,0,0,2741,0,0,0,0,0,3051520,2179072,2428928,2437120,2179072,2486272,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2654208,2678784,2760704,2764800,2854912,2969600,2179072,3006464,2179072,3018752,2179072,2179072,2179072,3149824,2125824,2428928,2437120,2969600,2125824,3006464,2125824,3018752,2125824,2125824,2125824,2125824,3149824,2125824,2428928,2437120,2125824,2486272,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2654208,2678784,2760704,2764800,2785280,2854912,2969600,2125824,3006464,2125824,3018752,2125824,2125824,2125824,2125824,3149824,2179072,3051520,2125824,3051520,2125824,3051520,0,2490368,2498560,0,0,0,0,2875392,0,0,0,3180,0,0,0,0,0,0,2834432,0,3227648,2568192,2564096,0,2940928,2179072,2179072,2498560,2179072,2179072,2179072,2555904,2564096,2179072,2179072,2179072,2617344,2179072,2179072,2179072,2179072,2179072,2179072,2662400,2179072,2179072,2179072,2179072,2179072,2179072,2179072,3137536,2125824,2125824,2498560,2125824,2125824,2125824,2555904,2564096,2125824,2555904,2564096,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,3137536,2940928,2940928,0,0,0,0,0,2748416,2879488,0,0,0,0,0,0,0,0,0,2519,0,0,0,0,0,541,2940928,0,0,0,0,0,2748416,2879488,0,3180,0,0,0,0,0,0,0,375,0,0,0,0,0,0,0,360,0,0,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2125824,0,2502656,0,0,3010560,0,0,0,0,0,0,0,0,2990080,2179072,2179072,2179072,3129344,2179072,2179072,3153920,3166208,3174400,2396160,2400256,2125824,2125824,2441216,2125824,2469888,2125824,2125824,2125824,2519040,2125824,2125824,2179072,2502656,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,3010560,2179072,2179072,2125824,2125824,2125824,2125824,2125824,2125824,2605056,2125824,2629632,2125824,2125824,2650112,2125824,2125824,2125824,2707456,2125824,2736128,2125824,2125824,2125824,2125824,2125824,2502656,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,3010560,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,3137536,2125824,2125824,2498560,2125824,2125824,2502656,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,3010560,2125824,2125824,2125824,0,0,0,0,0,0,2739,0,0,0,0,0,0,0,2743,0,0,0,2592768,0,0,0,0,0,0,2179072,2179072,2179072,2179072,2179072,2592768,2179072,2179072,2179072,3129344,2179072,2179072,3153920,3166208,3174400,2397073,2401169,2126737,2126737,2442129,2126737,2470801,2125824,2125824,2449408,0,2535424,3031040,2859008,0,0,0,0,0,2179072,2449408,2179072,2535424,2179072,2609152,2179072,2859008,2179072,2179072,2179072,3031040,2125824,2449408,2125824,2535424,2125824,2609152,2125824,2859008,2125824,2125824,2125824,3031040,2125824,2125824,2449408,2125824,2535424,2125824,2609152,2125824,2859008,2125824,2125824,2125824,0,2179072,2125824,2125824,2457600,2179072,2179072,2179072,2179072,2457600,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2179072,2125824,2125824,2179072,2179072,2179072,2179072,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,0,0,0,0,0,0,0,0,0,0,0,1727,0,0,1728,0,3031040,2125824,2527232,0,0,0,0,0,2179072,2527232,2179072,2179072,2179072,2179072,2179072,2125824,2126738,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,3125248,2125824,2125824,2125824,2125824,2125824,2527232,2125824,2125824,2125824,2125824,2125824,3092480,2125824,2527232,2125824,2125824,2125824,2125824,2125824,3092480,0,0,0,0,0,693,0,0,0,0,0,0,365,365,365,0,0,0,0,0,707,708,0,0,0,0,0,714,0,0,0,0,0,0,703,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3020,3026944,0,0,0,2404352,2179072,2179072,2179072,2179072,3026944,2404352,2125824,2125824,2125824,2125824,3026944,0,2539520,0,2949120,2179072,2658304,2973696,2179072,2125824,2658304,2973696,2125824,2125824,2658304,2973696,2125824,0,2711552,256e4,2179072,256e4,2125824,256e4,2125824,0,2179072,2179072,2531328,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2605056,2179072,2629632,2179072,2179072,2650112,0,0,2809856,0,0,0,0,0,0,0,0,0,0,3088384,0,0,0,0,0,442,0,0,454,470,470,470,470,470,470,470,470,470,470,480,470,470,470,470,470,111051,111051,111051,111051,111051,111051,111051,111051,111051,111051,111051,111051,111051,111051,111051,111051,459,459,111051,459,459,459,459,459,459,459,459,459,111051,111051,111051,111051,111051,111051,111051,111051,111051,111051,459,111051,111051,111051,459,111051,111051,111051,111051,111051,0,0,0,0,0,0,0,0,0,2795,0,0,0,0,0,0,12290,3,0,0,2183168,0,0,0,0,0,299,300,0,2134016,303,304,2125824,1060,0,0,2179072,2125824,2125824,2179072,2179072,2179072,2179072,2179072,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,1060,2125824,2125824,2125824,2125824,2125824,0,0,0,0,0,0,0,0,0,0,662,0,662,0,0,0,0,303,118784,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2434,0,303,303,303,303,303,303,303,0,0,0,0,0,303,0,303,1,12290,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2155,0,12290,3,0,0,2183168,0,0,0,0,0,33403,300,0,2134016,49791,304,2105632,12290,3,0,0,294,0,0,0,0,294,0,0,0,0,0,0,0,2124,0,0,0,0,0,0,0,0,0,788,814,0,814,809,0,0,0,122880,122880,122880,122880,122880,122880,122880,122880,122880,122880,122880,122880,122880,122880,122880,0,0,0,122880,0,122880,122880,122880,0,0,0,0,0,122880,0,0,122880,0,0,0,0,0,0,0,0,122880,0,0,0,0,0,0,0,0,0,0,0,0,3002,0,0,0,0,0,0,0,0,122880,122880,122880,122880,122880,122880,122880,122880,122880,0,0,122880,0,0,0,0,0,0,0,0,0,0,712,0,0,0,716,0,0,0,147456,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2459,0,1092,0,2424832,2433024,0,0,2457600,0,0,0,0,0,0,0,0,0,0,728,0,0,0,0,0,1823,2125824,2125824,2125824,2408448,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,0,1919,2125824,2125824,2125824,0,0,0,131072,0,0,0,69632,73728,0,0,0,0,0,65536,0,0,0,0,0,740,407,0,0,0,0,0,0,0,0,0,0,1158,0,0,0,0,0,0,131072,0,0,131072,131072,0,0,0,0,0,0,0,131072,0,0,131072,0,0,131072,0,0,0,0,135168,135168,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2756,0,0,0,0,135168,0,0,135168,0,0,0,0,0,0,0,0,0,0,735,0,797,0,0,0,0,0,0,0,135168,0,135168,135168,135168,135168,135168,135168,0,135168,135168,135168,135168,135168,135168,135168,0,0,0,0,0,135168,0,135168,1,12290,3,0,0,2183168,0,0,0,0,0,636,637,0,2134016,640,641,0,1361,2125824,2125824,2125824,2125824,2125824,2424832,2433024,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,0,0,987,2125824,2125824,2125824,2125824,0,304,139264,0,0,0,0,0,0,0,0,0,0,0,0,0,0,225709,0,12290,3,0,0,2183168,0,0,0,0,0,299,33406,0,2134016,303,49794,0,61440,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3178,0,304,2424832,2433024,0,0,2457600,0,0,0,0,0,0,0,0,0,0,757,0,0,0,0,762,301,301,301,143661,371,301,301,301,301,301,301,301,301,301,301,301,301,301,301,301,301,143661,301,301,143661,301,301,301,143731,301,301,301,143731,69632,73728,301,301,143661,301,301,65536,301,301,301,301,301,143661,143661,143661,143661,143661,143661,143661,143661,143661,301,301,143661,301,301,301,301,301,301,301,301,301,366,301,0,143661,301,301,301,143661,143661,143661,143661,143661,143661,143661,143661,143661,143661,143661,143661,143661,143661,143661,143661,301,301,301,143661,301,143661,143661,143661,143661,143661,143731,143661,143731,143731,143731,143731,143731,143731,143731,143661,143661,143661,143661,143661,143661,143661,143661,1,301,143661,301,143661,143661,143661,143661,143661,143661,301,0,301,0,301,301,301,301,301,301,301,301,301,143661,301,143661,143661,143661,143661,301,0,0,0,3117056,0,0,0,0,0,0,0,2200252,2200252,0,0,0,0,0,0,662,0,0,0,0,0,541,541,541,541,541,541,541,541,2168,541,541,541,0,0,0,0,0,155648,155648,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,325,0,0,0,0,155648,155648,0,155648,155648,155648,155648,155648,155648,155648,155648,155648,0,0,0,0,155648,0,0,155648,155648,155648,155648,155648,155648,155648,155648,155648,155648,155648,155648,155648,155648,155648,155648,0,0,0,0,0,155648,0,155648,0,0,0,0,0,155648,0,0,0,0,0,155648,155648,0,155648,155648,0,12290,3,0,0,2183168,126976,0,0,0,0,299,300,0,2134016,303,304,0,0,0,3117056,0,0,0,0,0,0,0,365,0,0,0,0,0,0,0,3563,0,541,541,541,541,541,541,541,541,541,3209,541,541,541,541,541,159744,159744,159744,159744,0,0,159744,0,0,0,0,0,0,0,0,159744,0,0,0,0,0,0,0,159744,159744,159744,163840,159744,159744,159744,159744,159744,0,0,0,0,0,0,0,0,0,2805,0,541,541,541,541,541,0,25162,0,0,0,159744,0,0,0,25162,25162,25162,159744,25162,25162,25162,25162,25162,25162,25162,25162,159744,159744,159744,159744,25162,159744,25162,1,167936,167936,167936,167936,167936,167936,167936,167936,167936,167936,167936,167936,167936,167936,167936,167936,1,167936,167936,167936,167936,0,0,167936,0,0,0,0,0,0,0,0,167936,167936,167936,167936,167936,167936,167936,167936,167936,0,0,0,0,0,0,0,0,0,2976,0,0,0,0,0,0,0,0,0,2138112,1183,0,0,0,0,0,0,0,0,0,0,0,0,3168,0,0,0,0,0,0,0,0,172032,0,172032,0,0,0,0,0,0,0,0,0,365,0,293,0,0,0,348,172032,172032,0,0,172032,0,0,172032,172032,0,172032,0,0,0,0,172032,172032,0,0,0,0,0,0,0,0,0,0,172032,0,0,0,0,0,0,2777,0,0,0,0,0,0,2784,0,0,0,0,0,0,2986,2987,0,2988,0,2990,0,0,0,0,0,0,0,69632,73728,0,135168,135168,0,0,65536,135168,172032,0,172032,172032,0,172032,172032,172032,172032,172032,172032,172032,172032,172032,172032,172032,172032,172032,172032,172032,172032,172032,172032,172032,172032,172032,172032,172032,172032,172032,0,0,0,0,0,0,0,0,0,3014,0,0,0,0,0,0,176128,176128,176128,176128,176128,176128,176128,176128,176128,176128,176128,176128,176128,176128,176128,176128,1,176128,176128,176128,176128,0,0,176128,0,0,0,0,0,0,0,0,176128,176128,176128,176128,176128,176128,176128,176128,176128,0,0,0,0,0,0,0,0,0,3175,0,0,0,0,0,0,0,3,78115,78115,293,0,634,0,0,0,299,300,0,2134016,303,304,1164,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,361,541,541,1308,541,541,541,541,541,541,541,541,541,541,541,541,541,0,0,2242,0,914,563,563,563,563,563,563,563,563,563,563,563,563,563,563,0,0,587,587,587,1203,541,587,563,541,541,541,541,541,563,563,563,563,3070,563,563,563,563,3074,563,563,587,587,587,587,587,1079,0,0,0,0,0,0,0,0,0,0,1102,0,0,0,0,0,0,0,229376,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1134592,0,0,0,0,1691,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3201,563,563,587,587,587,587,0,0,0,0,0,0,0,0,0,0,541,541,541,541,3569,541,541,0,0,563,563,563,563,563,563,563,2251,563,563,563,563,563,563,587,3109,587,587,587,587,587,587,587,587,2407,587,587,587,587,587,2412,2413,563,563,2288,563,563,563,563,563,563,563,563,563,563,563,563,563,563,3541,587,587,587,2375,587,587,587,587,587,587,587,587,587,587,587,587,587,1497,587,587,0,0,0,563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,1439,0,3007,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3317,541,541,541,541,3038,541,541,541,541,541,541,541,541,541,541,541,541,1300,541,541,541,563,563,563,3078,563,563,563,563,563,563,563,563,563,563,563,563,1401,563,563,563,587,587,587,587,3120,587,587,587,587,587,587,587,587,587,587,587,1042,587,587,587,587,0,3159,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,155648,3214,541,541,541,541,541,541,541,541,541,541,541,541,541,541,541,541,1359,563,563,563,587,3259,587,587,587,3262,587,587,587,587,587,587,587,541,541,563,563,587,587,0,0,0,0,0,0,0,0,0,0,3609,541,541,541,587,587,3270,587,587,587,587,587,587,587,587,587,587,587,587,587,1498,587,587,541,541,541,3330,3331,541,541,541,541,541,541,541,541,563,563,563,563,3581,563,563,563,563,563,3349,563,563,563,563,563,563,563,563,563,587,587,587,587,587,587,587,587,0,541,541,541,3406,541,541,541,541,563,563,563,563,563,563,3415,563,0,587,587,587,587,587,291,1079,0,0,0,0,0,0,0,0,0,249856,249856,249856,249856,249856,249856,249856,249856,1,587,3431,587,587,587,587,587,587,3437,587,587,587,3441,587,541,563,563,3473,563,563,563,563,3478,563,563,563,563,3483,563,563,563,563,977,563,563,563,563,0,587,587,587,587,587,587,1931,587,587,587,587,587,587,587,587,587,2678,587,587,587,2681,587,587,0,0,3456,541,541,541,541,541,541,541,541,541,541,541,541,541,0,2586,0,541,3471,563,563,563,563,563,563,563,563,563,563,563,563,563,563,0,2327,563,3487,587,587,587,587,587,587,587,587,587,587,587,587,587,587,0,0,563,563,587,587,587,587,0,0,541,541,563,563,587,587,0,541,541,541,3205,541,541,541,541,541,541,541,3210,541,541,541,541,541,541,2816,541,541,2820,541,541,541,541,541,541,541,541,3041,541,541,541,541,541,541,541,541,2556,541,541,541,541,541,541,541,541,2233,541,541,541,541,541,0,0,563,587,0,541,563,587,0,541,563,587,0,541,563,587,0,0,0,0,0,0,0,0,0,3510,0,0,0,0,541,541,541,541,541,2165,541,541,541,541,541,541,541,541,3616,563,563,563,563,563,563,563,2265,563,563,563,563,2270,563,563,563,184932,184932,184932,184932,184932,184932,184932,0,0,0,0,0,184932,0,184932,1,12290,3,0,0,0,0,0,0,0,0,0,0,0,0,301,301,0,0,301,301,143661,301,301,301,301,301,301,301,301,301,301,301,143731,301,301,301,301,12290,3,78115,78115,293,0,0,0,0,0,299,300,0,2134016,303,304,587,0,0,188416,541,587,563,541,541,541,541,541,563,563,563,563,587,587,587,587,0,0,0,0,2731,0,0,0,0,305,0,0,0,0,0,0,0,0,0,0,0,0,0,249856,0,0,0,192972,192972,192972,192972,192972,192972,192972,192972,192972,192972,192972,192972,192972,192972,192972,192972,0,192972,0,1,0,0,0,0,0,192972,192972,192972,192972,192972,192972,192972,192972,192972,192972,0,0,192972,0,0,0,0,0,0,0,0,0,0,1145,365,365,0,0,1148,192972,192972,192972,0,192972,192972,192972,192972,192972,0,0,0,0,0,0,0,0,0,3304,0,3180,0,0,0,0,302,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,541,407,407,407,407,407,407,407,0,0,0,0,0,407,0,407,1,12290,3,0,0,0,0,0,0,0,0,0,0,0,118784,299,12290,3,78115,78115,293,0,0,0,0,0,299,300,0,302,303,304,587,0,0,740,541,587,563,541,541,541,541,541,563,563,563,563,587,587,587,587,0,0,2729,0,0,0,0,0,0,740,1184,0,0,0,0,1188,0,0,0,0,0,0,0,378,0,381,0,0,0,381,0,0,563,587,587,587,587,587,1079,1559,0,0,0,1565,0,0,0,1571,2034,0,0,0,0,1577,2036,0,0,0,0,0,0,0,397,0,0,0,0,0,397,0,0,0,0,0,1577,0,0,0,0,0,0,0,0,0,0,0,0,0,262144,0,0,0,0,0,1188,1669,0,0,0,0,0,0,0,0,0,0,0,0,3177,0,0,0,563,563,587,587,587,587,1559,2030,0,0,0,0,1565,2032,0,0,0,0,0,0,2997,0,0,0,0,0,0,0,0,0,0,1586,1587,0,0,0,0,0,0,0,0,1669,0,0,0,0,0,0,0,0,0,0,0,0,106496,0,0,0,0,0,0,2034,0,2036,0,0,0,0,0,0,0,0,0,0,0,0,0,1150976,0,0,0,0,0,563,563,563,563,2325,2652,0,0,0,0,587,587,587,587,587,587,587,587,587,587,587,587,587,2343,0,307,0,307,0,0,0,0,0,0,0,0,0,307,0,0,0,0,0,0,3011,0,0,0,0,3016,3017,0,3019,0,0,0,0,0,204800,204800,0,204800,204800,204800,204800,204800,204800,204800,204800,204800,204800,204800,204800,204800,204800,204800,205107,204800,204800,205106,205107,204800,205106,205106,204800,204800,0,0,0,0,0,0,0,0,0,122880,0,122880,122880,122880,122880,122880,12290,3,0,0,2183801,0,0,0,0,0,299,300,151552,2134016,303,304,0,212992,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,172032,0,0,151552,0,0,0,0,0,0,0,0,0,0,0,0,0,303,0,0,0,0,0,3117056,0,0,0,0,0,0,0,0,2200253,0,0,0,0,0,0,678,0,0,0,0,0,0,0,0,0,0,2977,0,0,0,0,0,0,914,2126737,2126737,2126737,2126737,2126737,2425745,2433937,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,3138449,2126811,2126811,2499547,2126811,2126811,2126737,2724753,2126737,2732945,2773905,2126737,2126737,2126737,2806673,2126737,2831249,2126737,2126737,2864017,2126737,2126737,2126737,2126737,2126811,2126811,2126811,2126811,2126811,2593755,2126811,2126811,2126811,2126811,2126811,2126811,2126811,3036123,2126811,2126811,3072987,2126811,2126811,2126811,3122139,2126811,2126737,2126737,2921361,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,3117969,2126737,0,2126811,2126811,2126811,2126811,2126811,0,0,0,0,0,0,0,0,0,0,1190,0,0,0,0,0,2126811,2425819,2434011,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,3126235,2126811,2126811,2126811,2126811,2126811,2626523,2126811,2126811,2126811,2126811,2126811,2126811,2700251,2126811,2716635,2126811,2724827,2126811,2733019,2773979,2126811,0,2502656,0,0,3010560,0,0,0,0,0,0,0,0,2990080,2179072,2179072,3125248,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2125824,2125824,2125824,2125824,2125824,2592768,2125824,2125824,2125824,2125824,2126811,2126811,2806747,2126811,2831323,2126811,2126811,2864091,2126811,2126811,2126811,2126811,2921435,2126811,2126811,2126811,0,2179072,2126811,2126737,2457600,2179072,2179072,2179072,2179072,2458513,2126737,2126737,2126737,2126737,2126737,2524049,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2601873,2126737,2126737,2458587,2126811,2126811,2126811,2126811,2183168,0,0,0,0,0,0,0,0,0,0,1206,0,1208,0,0,0,0,2126737,2126737,2126737,2409361,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,0,0,2126811,2126811,2126811,2409435,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2839515,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,3118043,2126811,2126811,2126811,2126811,2126811,2126811,2126811,0,0,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2462609,2466705,2126737,2126737,2126737,2642833,2126737,2126737,2126737,2126737,2126737,2126737,2720657,2126737,2126737,2126737,2126737,2126737,2126737,2126737,3040145,2126737,3064721,2126737,2126737,2126737,2126737,2126737,3101585,2769809,2778001,2782097,2798481,2823057,2126737,2126737,2126737,2884497,2126737,2913169,2126737,2126737,2126737,2126737,2126737,2126737,2626449,2126737,2126737,2126737,2126737,2126737,2126737,2700177,2126737,2716561,2126737,2126737,3134353,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,3208081,2126737,0,0,0,0,0,0,3026,541,541,541,541,541,541,541,541,541,541,1352,541,541,541,541,541,0,0,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2462683,2466779,2126811,2126811,2126811,2126811,2126811,2929627,2126811,2126811,2126811,2999259,2126811,2126811,2126811,2126811,3060699,2126811,2126811,2126811,2126811,2454491,2126811,2474971,2483163,2126811,2126811,2126811,2126811,2126811,2126811,2532315,2126811,2126811,2126811,2446299,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2552795,2769883,2778075,2782171,2798555,2823131,2126811,2126811,2126811,2884571,2126811,2913243,2126811,2126811,2126811,2126811,2126811,2126811,2126811,3130331,2126811,2126811,3154907,3167195,3175387,2506752,2507739,2507665,2126811,2126811,3134427,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,3208155,2126811,2179072,2126811,2126811,2126811,2642907,2126811,2126811,2126811,2126811,2126811,2126811,2720731,2126811,2126811,2126811,2126811,2126811,2126811,2126811,3040219,2126811,3064795,2126811,2126811,2126811,2126811,2126811,3101659,0,0,0,2388881,2126737,2126737,2126737,2421649,2126737,2126737,2126737,2126737,2126737,2454417,2126737,2474897,2483089,2126737,2126737,2126737,2126737,2126737,2126737,2532241,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2605969,2126737,2630545,2126737,2126737,2651025,2126737,2126737,2126737,2708369,2126737,2737041,2126737,2126737,2126737,2126737,2126737,2126737,2663313,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,0,0,988,2126811,2126811,2126811,2126811,3036049,2126737,2126737,3072913,2126737,2126737,2126737,3122065,2126737,2126737,3142545,2126737,2126737,2126737,3171217,2126737,2126737,2126737,2888593,2126737,2126737,2925457,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,986,2126811,2126811,2126811,2126811,2126811,2126811,2126737,3191697,3195793,2126737,0,0,0,0,0,0,2388955,2126811,2126811,2126811,2421723,2126811,2126811,2449408,0,2535424,3031040,2859008,0,0,0,0,0,2179072,2449408,2179072,2535424,2126811,2737115,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2888667,2126811,2126811,2925531,2126811,2126811,2126811,2126811,2126811,2585563,2126811,2126811,2126811,2126811,2126811,2618331,2126811,2126811,2126811,2126811,2126811,2126811,2606043,2126811,2630619,2126811,2126811,2651099,2126811,2126811,2126811,2708443,2126811,3142619,2126811,2126811,2126811,3171291,2126811,2126811,3191771,3195867,2126811,2179072,2126811,2126737,2179072,2179072,2179072,2637824,2179072,2179072,2179072,2179072,2727936,2752512,2179072,2179072,2179072,2842624,2846720,2179072,3112960,3219456,2126737,2126737,3113873,3220369,2126811,2126811,3113947,3220443,0,0,0,0,0,0,0,415,415,0,0,0,0,0,415,0,3096576,2179072,2179072,2179072,2179072,2179072,2179072,2179072,3223552,0,0,2126737,2126737,2417553,2126737,2126737,2126737,2126737,2929553,2126737,2126737,2126737,2999185,2126737,2126737,2126737,2126737,3060625,2126737,2126737,2126737,2126737,2933649,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,3130257,2126737,2126737,2126737,2519953,2126737,2126737,2126737,2126737,2589585,2126737,2614161,2646929,2126737,2126737,2696081,2757521,2126737,2446225,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2552721,2126737,2126737,2126737,2638737,2126737,2126737,2126737,2126737,2728849,2753425,2126737,2126737,2126737,2126737,2843537,2847633,2126737,2896785,2917265,2126737,2126737,2945937,2126737,2126737,2995089,2126737,3003281,2126737,2126737,3023761,2126737,3068817,3085201,2126737,3097489,2126737,2126737,2126737,2126737,2126737,2126737,2126737,3224465,0,0,2126811,2126811,2417627,2843611,2847707,2126811,2896859,2917339,2126811,2126811,2946011,2126811,2126811,2995163,2126811,3003355,2126811,2126811,3023835,2126811,3068891,3085275,2126811,3097563,2126811,2126811,2126811,2126811,2126811,2126811,2126811,3224539,2179072,2126811,2126737,2126737,2126737,3031953,2126737,2126811,2450395,2126811,2536411,2126811,2610139,2126811,2859995,2126811,2126811,2126811,2126811,2126811,2524123,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2601947,2126811,2515857,2126737,2126737,2126737,2544529,2548625,2126737,2126737,2597777,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2585489,2126737,2126737,2126737,2126737,2126737,2618257,2126811,2515931,2126811,2126811,2126811,2544603,2548699,2126811,2126811,2597851,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2655195,2679771,2761691,2765787,2786267,2855899,2970587,2126811,3007451,3154833,3167121,3175313,2397147,2401243,2126811,2126811,2442203,2126811,2470875,2126811,2126811,2126811,2520027,2126811,2126811,2126811,2126811,2126811,2638811,2126811,2126811,2126811,2126811,2728923,2753499,2126811,2126811,2126811,2126811,2126811,2126811,3179483,2179072,2126811,2126737,2179072,2179072,2126737,2126737,2126811,2126811,0,0,0,0,0,0,2510848,2514944,0,0,2678784,2760704,2764800,2854912,2969600,2179072,3006464,2179072,3018752,2179072,2179072,2179072,3149824,2126737,2429841,2438033,2126737,2487185,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2655121,2679697,2761617,2765713,2786193,2855825,2970513,2126737,3007377,2126737,3019665,2126737,2126737,2126737,2126737,3150737,2126811,2429915,2438107,2126811,2487259,2126811,2126811,2589659,2126811,2614235,2647003,2126811,2126811,2696155,2757595,2126811,2126811,2126811,2126811,2933723,2126811,2126811,2663387,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2802651,2814939,2126811,3019739,2126811,2126811,2126811,2126811,3150811,2179072,3051520,2126737,3052433,2126811,3052507,0,2490368,2498560,2126811,2556891,2565083,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,3138523,2940928,2941841,2941915,0,0,0,0,0,2748416,2879488,0,3180,0,0,0,0,0,0,0,647,0,0,0,0,0,0,0,0,0,2467,0,0,2470,0,0,0,2179072,2502656,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,3010560,2179072,2179072,2126737,2126737,2126811,2126811,0,2486272,0,0,0,0,0,2678784,2854912,3006464,2503569,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,3011473,2126737,2126737,2126737,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2179072,2126811,2126737,2179072,2179072,2179072,2179072,2126737,2126737,2126737,2126737,2126811,2126811,2126811,2126811,0,0,0,0,0,0,0,0,0,0,0,2112,0,0,0,0,2503643,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,2126811,3011547,2126811,2126811,2126811,0,0,0,2179072,2126811,2126737,2179072,2179072,2179072,2179072,2179072,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2179072,2609152,2179072,2859008,2179072,2179072,2179072,3031040,2126737,2450321,2126737,2536337,2126737,2610065,2126737,2859921,3032027,2126811,2527232,0,0,0,0,0,2179072,2527232,2179072,2179072,2179072,2179072,2179072,2126737,2126737,2802577,2814865,2126737,2839441,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,2126737,3126161,2126737,2528145,2126737,2126737,2126737,2126737,2126737,3093393,2126811,2528219,2126811,2126811,2126811,2126811,2126811,3093467,0,0,0,0,0,782,0,0,0,0,0,0,541,843,541,541,541,541,541,1796,541,541,541,541,541,541,541,541,541,541,541,2822,541,541,541,541,3026944,0,0,0,2404352,2179072,2179072,2179072,2179072,3026944,2405265,2126737,2126737,2126737,2126737,3027857,2405339,2126811,2126811,2126811,2126811,3027931,0,2539520,0,2949120,2179072,2658304,2973696,2179072,2126737,2659217,2974609,2126737,2126811,2659291,2974683,2126811,0,2711552,256e4,2179072,2560913,2126737,2560987,2126811,0,2179072,2179072,3133440,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,2179072,3207168,2179072,0,0,0,0,0,0,2464,0,0,0,0,0,0,0,0,0,324,398,0,0,0,324,0,2126737,2126811,0,2179072,2126737,2126811,0,2179072,2126737,2126811,2985984,2985984,2986897,2986971,0,0,0,0,0,0,3164,0,0,3167,0,0,0,0,0,0,0,1135,0,0,0,0,0,0,0,0,0,824,0,0,0,0,0,0,0,221184,221184,0,0,0,0,0,0,0,0,0,221184,221184,0,0,221184,221184,221184,0,0,0,0,0,0,0,221184,0,0,221184,221184,221184,221184,221184,221184,221184,221184,221184,221184,221184,221184,221184,221184,221184,221184,0,0,0,0,0,0,0,0,0,0,221184,0,221184,221184,221184,221184,221184,221184,221184,221184,221184,221184,1,12290,3,0,0,0,0,0,0,0,0,0,0,0,139264,300,0,303,0,0,0,303,0,304,0,0,0,304,0,0,0,304,69632,139682,0,0,0,0,0,65536,0,0,0,0,98304,0,0,0,53248,0,0,0,0,0,2662400,0,2813952,0,0,3133440,0,98304,0,0,0,0,0,0,0,0,0,0,0,0,111051,0,0,0,0,303,0,304,0,0,0,2473984,2478080,0,0,0,0,0,0,0,0,0,159744,159744,159744,159744,159744,159744,159744,159744,159744,159744,159744,159744,159744,159744,159744,159744,163840,3121152,2179072,2179072,3141632,2179072,2179072,2179072,3170304,2179072,2179072,3190784,3194880,2179072,914,0,0,0,0,0,0,3172,3173,0,0,0,0,0,0,0,0,0,665,0,0,668,0,0,0,0,914,0,2387968,2125824,2125824,2125824,2420736,2125824,2125824,2125824,2125824,2125824,2453504,2125824,2473984,2482176,2125824,2125824,2125824,2125824,2125824,2125824,2531328,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2605056,2125824,3190784,3194880,2125824,988,0,0,0,988,0,2387968,2125824,2125824,2125824,2420736,2125824,0,2125824,2125824,2125824,2125824,2125824,0,0,0,299,0,0,0,303,0,0,0,303,119198,73728,0,0,0,0,0,65536,0,3096576,2179072,2179072,2179072,2179072,2179072,2179072,2179072,3223552,914,0,2125824,2125824,2416640,2125824,2125824,2125824,2125824,2125824,2125824,2625536,2125824,2125824,2125824,2125824,2125824,2125824,2699264,2125824,2715648,2125824,2723840,2125824,2732032,2772992,2125824,3084288,2125824,3096576,2125824,2125824,2125824,2125824,2125824,2125824,2125824,3223552,988,0,2125824,2125824,2416640,225890,225890,225890,225890,225890,225890,225890,225741,225741,225741,225741,225741,225906,225741,225906,1,12290,3,0,0,0,0,0,0,0,90409,90409,90409,90409,0,94506,94506,90409,90409,94506,94506,94506,94506,94506,94506,94506,94506,94506,94506,94506,94506,94506,94506,94506,94506,1,2125824,237568,2125824,2125824,2125824,2125824,2125824,0,0,0,0,0,0,0,0,0,0,1222,0,0,0,0,0,249856,249856,249856,249856,249856,249856,249856,249856,249856,249856,249856,249856,249856,249856,249856,249856,0,0,0,0,0,0,0,0,0,217088,0,0,0,0,0,0,0,0,0,0,0,0,0,304,0,0,2125824,241664,2125824,2125824,2125824,2125824,2125824,0,0,0,0,0,0,0,0,0,0,1236,0,0,0,0,0,254414,254414,254414,254414,254414,254414,254414,254414,254414,254414,254414,254414,254414,254414,254414,254414,0,0,0,0,0,0,0,12290,0,0,0,2183168,0,0,270336,0,0,299,300,0,2134016,303,304,200704,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,687,2125824,0,2125824,2125824,2125824,2125824,2125824,0,0,180224,0,0,0,0,0,0,0,663,0,0,666,667,0,0,0,0,2940928,0,0,0,0,0,2748416,2879488,0,20480,0,0,0,0,0,0,0,679,0,0,0,0,0,0,0,0,0,1129,0,0,0,0,0,0,1,12290,2113826,0,0,0,0,0,0,296,0,0,0,296,0,0,0,0,0,0,3182,0,0,0,0,3187,0,0,0,0,0,0,0,69632,73728,0,0,0,0,0,65536,0,0,0,0,266240,0,0,0,0,0,0,0,0,0,0,0,266240,0,0,0,0,0,0,0,0,0,0,1,0,0,0,266240,0,0,0,0,0,0,0,0,0,0,0,0,0,2662400,0,2813952,12290,2113826,0,0,2183168,0,0,0,0,0,299,300,0,2134016,303,304,2125824,245760,0,0,2179072,2125824,2125824,2179072,2179072,2179072,2179072,2179072,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2584576,2125824,2125824,2125824,2125824,2125824,2617344,2125824,2125824,2125824,2125824,2125824,245760,2125824,2125824,2125824,2125824,2125824,0,0,0,0,0,0,0,0,0,0,1245,0,0,0,0,0,274432,274432,274432,274432,274432,274432,274432,0,0,0,0,0,274432,0,274432,1,12290,3,0,0,0,0,0,253952,0,0,0,253952,0,0,0,0,0,0,0,0,0,0,0,0,0,1155072,0,0,0,0,0,0,12290,3,78115,78115,293,0,0,0,0,0,299,300,0,0,303,304,563,563,587,587,587,587,0,2030,0,0,0,0,0,2032,0,0,0,0,0,0,3196,0,0,0,0,0,0,0,0,0,0,3186,0,0,0,3189,0,0,0,0,2034,0,0,0,0,0,2036,0,0,0,0,0,0,0,695,0,0,0,0,365,365,365,0,0,2485,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,266240,0,0,0,1678,0,0,0,0,0,0,0,0,0,0,0,0,338,0,0,0,0,0,0,0,1669,0,0,0,0,0,0,0,0,2114,0,0,0,0,0,0,3395,541,541,541,541,3399,541,541,541,541,541,541,1346,541,541,541,541,541,541,1356,541,541,12290,3,78115,78456,293,0,0,0,0,0,299,300,0,0,303,304,541,588,564,564,564,564,564,564,564,588,588,588,541,588,588,588,588,588,588,588,588,564,564,541,564,588,564,588,1,0,0,0,0,2775,0,0,0,0,0,0,0,0,0,0,0,0,163840,0,0,0,1,12290,3,78116,293,0,0,0,0,0,0,0,0,0,0,0,0,167936,0,0,0,282624,282624,282624,282624,282624,282624,282624,282624,282624,282624,282624,282624,282624,282624,282624,282624,1,0,0,0,0,0,282624,282624,282624,282624,282624,282624,282624,282624,282624,282624,0,0,282624,0,0,0,0,0,0,0,0,0,0,1600,1601,0,0,0,0,282624,282624,282624,0,282624,282624,282624,282624,282624,0,0,0,0,0,0,0,0,0,254414,254414,254414,254414,254414,254414,254414,254414,1,2981888,2396160,0,3153920,3180,0,0,0,0,0,0,0,2740224,0,0,0,0,0,0,679,751,0,0,0,0,0,0,0,0,0,1144,0,365,365,0,1147,0,0,0,0,0,286720,286720,0,286720,286720,286720,286720,286720,286720,286720,286720,286720,0,0,0,0,0,0,0,286720,286720,286720,286720,286720,286720,286720,286720,286720,286720,286720,286720,286720,286720,286720,286720,0,3108864,3198976,0,0,3043328,0,3149824,2936832,0,2760704,3305,2437120,0,0,0,0,0,0,680,0,0,0,0,0,0,0,0,0,300,0,0,0,0,0,0,0,0,0,0,2875392,0,0,0,3386,0,0,0,0,0,0,2834432,2940928,0,0,0,0,0,2748416,2879488,0,3386,0,0,0,0,0,0,0,709,0,0,0,0,0,0,0,0,0,2048,0,0,0,0,0,0,0,0,0,309,0,0,0,0,0,308,0,308,309,0,308,308,0,0,0,308,308,309,309,0,0,0,0,0,0,308,408,309,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,781,0,0,0,309,413,0,0,69632,73728,0,0,0,0,0,65536,0,0,0,0,0,783,0,802,0,0,0,0,541,847,541,541,541,541,541,2830,2831,541,541,541,541,2834,541,541,541,541,541,541,541,3521,541,3523,541,541,3525,541,563,563,0,0,432,0,0,0,0,308,449,463,463,463,463,463,463,463,463,463,463,463,463,463,463,463,463,463,463,463,463,489,489,463,489,489,489,489,489,489,489,514,489,489,489,489,489,489,489,489,489,489,489,489,489,489,489,534,489,489,489,489,489,542,565,542,565,542,542,565,542,589,565,565,565,565,565,565,565,589,589,589,542,589,589,589,589,589,589,589,589,565,565,542,565,589,565,589,1,0,0,674,0,0,0,0,0,0,0,0,0,0,0,0,0,323,324,0,0,704,0,0,0,0,0,0,0,711,0,0,0,0,0,0,0,742,0,0,0,0,742,0,748,0,0,0,736,0,0,0,0,0,0,0,0,0,0,0,747,0,0,0,0,0,792,663,841,0,0,0,0,541,845,541,541,541,541,541,2217,541,541,541,541,541,541,541,541,541,541,541,1802,541,541,541,541,0,0,0,0,645,0,0,0,0,0,0,0,0,0,0,0,0,172032,0,0,0,0,0,0,0,0,765,0,0,768,0,0,0,0,774,0,0,778,0,0,0,0,0,0,3562,0,3564,541,541,541,541,541,541,541,541,541,3219,541,541,541,541,541,3224,0,0,785,0,0,0,0,789,0,0,0,0,0,0,0,793,0,0,736,0,793,0,0,0,0,648,0,0,0,0,0,0,0,807,808,0,0,0,0,808,0,0,807,0,0,0,0,0,755,0,0,816,817,0,0,0,793,0,0,0,0,0,0,0,0,0,0,0,0,221184,0,0,0,0,0,0,648,0,0,0,0,0,834,789,0,0,0,0,0,0,0,2139,0,0,0,0,0,0,0,0,0,1712,0,0,0,0,0,0,838,839,789,789,0,0,0,0,789,736,789,0,541,541,849,853,563,964,563,967,563,563,981,563,563,0,587,587,587,996,1e3,587,0,0,0,0,0,0,0,0,3180,3448,0,0,0,0,0,0,0,2465,0,0,0,0,0,0,0,0,0,2152,0,0,0,0,0,0,1093,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1135,0,0,0,0,1152,0,0,0,0,1157,0,0,0,0,0,0,0,822,0,816,0,664,0,0,0,0,0,0,0,0,1201,0,0,0,0,0,0,0,0,0,0,0,0,221184,0,221184,0,0,0,1253,0,0,0,0,0,0,0,0,0,0,0,0,0,339,340,341,541,541,1342,541,541,541,541,541,541,541,541,541,541,541,541,541,541,2239,0,0,0,0,0,1596,0,0,0,0,0,0,0,0,0,0,0,0,233472,0,0,0,0,0,0,1640,0,0,0,0,0,0,0,0,0,0,0,0,354,355,356,357,1653,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1163,0,0,0,0,1669,0,0,0,0,0,0,1673,0,0,0,0,0,0,0,69632,73728,0,0,0,346,345,65536,344,0,1729,0,0,0,0,541,541,541,541,541,541,541,541,541,541,541,3327,541,541,1742,541,541,541,541,541,541,541,541,541,1755,541,541,541,541,541,541,541,2193,541,541,541,541,541,541,541,541,541,2557,541,541,541,541,541,541,541,541,541,1794,541,541,1797,541,541,541,541,541,541,541,541,541,541,1314,541,541,541,1318,541,541,1809,541,541,541,541,541,1814,541,541,541,541,541,541,541,1360,914,563,563,563,563,563,563,563,563,563,563,563,563,563,563,0,2328,1824,563,563,563,563,563,1831,563,563,563,563,563,1837,563,563,563,563,563,3093,563,563,563,563,563,563,563,563,563,3102,563,563,1892,563,563,563,563,563,563,563,563,563,563,1905,563,563,563,563,978,563,563,563,563,0,587,587,587,587,587,587,1997,587,587,587,587,587,587,587,587,587,1531,587,587,587,587,587,587,563,563,563,1910,563,563,563,563,563,563,563,26028,1920,587,587,587,0,1285,1469,1377,541,541,1339,541,541,563,563,1431,563,587,587,1927,587,587,587,587,587,1933,587,587,587,587,587,587,587,1529,587,587,587,587,587,587,587,587,1932,587,587,587,587,587,587,587,587,1494,587,587,587,587,587,587,587,587,587,1946,587,587,587,587,587,587,587,587,587,587,587,587,587,1513,587,587,563,563,2026,587,587,587,0,2030,0,0,0,0,0,2032,0,0,0,0,0,0,131072,0,131072,131072,131072,131072,0,131072,131072,131072,131072,131072,131072,131072,0,0,0,0,0,131072,0,131072,1,0,0,0,2042,0,0,0,0,0,0,0,0,0,0,0,0,365,365,365,0,0,2141,0,0,2148,0,0,0,0,0,0,0,0,0,0,0,0,237568,0,0,0,0,0,0,2140,541,541,541,541,541,541,541,541,541,541,541,2170,541,541,2173,541,541,541,541,541,541,2181,541,541,541,541,541,541,541,541,2841,541,541,541,541,541,541,541,541,1294,541,541,541,541,541,541,541,541,1327,541,541,541,1334,1336,541,541,541,541,2214,541,541,541,541,541,541,541,541,541,541,541,541,541,541,2535,541,563,2258,563,563,563,563,563,563,2266,563,563,563,563,563,563,563,983,563,0,587,587,587,587,1001,587,563,2300,563,563,563,563,563,563,563,563,563,563,563,563,563,563,587,587,587,2345,587,587,587,587,587,587,2353,587,587,587,587,587,587,587,1950,587,587,587,587,587,587,587,587,1468,587,587,587,587,587,587,587,587,2387,587,587,587,587,587,587,587,587,587,587,587,587,587,587,541,587,563,2414,541,541,541,541,563,563,563,563,587,587,587,587,2030,0,2032,0,2034,0,2036,0,0,2428,0,0,0,0,0,0,0,0,0,0,1713,0,0,0,0,0,2436,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1179,2449,0,0,0,0,0,2453,0,0,0,0,0,0,0,0,0,0,1726,0,0,0,0,0,0,0,0,0,2477,0,0,0,0,0,0,0,0,0,0,0,0,245760,0,0,0,0,0,2501,0,0,0,0,0,0,0,0,0,0,0,0,0,386,338,0,541,541,541,2539,541,541,541,541,541,541,541,541,541,541,541,541,541,2198,541,541,0,0,0,563,563,563,563,563,563,563,563,563,2595,563,563,563,563,563,3238,563,563,563,563,563,563,563,563,563,563,2880,563,563,563,563,563,587,587,587,2661,587,587,587,587,587,587,587,587,587,587,587,2669,587,587,587,587,2714,587,587,587,587,587,587,541,587,563,541,541,2417,2418,563,563,2421,2422,587,587,2425,2426,0,1563,0,0,0,2735,0,0,0,0,0,0,2740,0,0,0,0,0,0,0,1102,1101,0,0,0,0,0,0,0,0,1724,0,0,0,0,0,0,0,0,1172,0,0,0,0,0,0,0,0,1187,0,0,0,0,0,0,1104,0,0,0,0,0,2763,0,0,0,0,0,0,0,0,0,0,0,2431,2432,0,0,0,0,0,0,0,0,2792,2793,0,0,0,0,0,0,0,0,0,0,2049,0,0,0,0,0,541,541,541,541,2829,541,541,541,541,541,541,541,541,541,541,2836,563,563,563,563,2876,563,563,563,563,563,563,563,563,563,563,563,0,2329,587,587,587,2884,563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,1874,587,587,2933,587,587,587,587,587,587,587,587,587,587,587,587,587,1536,587,587,2955,541,2957,563,2959,587,0,0,0,0,0,0,0,0,0,0,0,0,0,0,541,541,541,541,541,541,541,587,3442,0,3444,0,0,0,0,0,3180,0,0,0,0,3452,0,0,0,0,0,796,0,0,0,0,0,0,0,0,0,0,0,0,796,0,0,0,0,3454,0,541,3457,541,3459,541,541,541,541,541,541,541,541,541,541,541,541,2585,0,0,0,563,587,3488,587,3490,587,587,587,587,587,587,587,587,587,587,587,1047,587,587,587,587,587,0,0,0,3505,0,0,0,0,0,0,0,3512,0,0,541,541,541,541,541,541,3462,541,541,541,541,541,541,541,541,541,3334,541,541,541,563,563,563,541,541,541,3517,541,541,541,541,541,541,541,541,541,541,563,563,563,563,563,563,563,563,563,563,3530,563,563,563,563,563,563,563,563,563,563,563,587,587,587,587,587,587,587,587,3544,587,587,587,587,587,587,587,587,587,587,587,0,0,0,0,541,541,541,541,563,563,310,311,312,0,0,0,0,0,0,0,0,0,0,0,0,0,669,0,0,0,0,0,421,0,0,0,0,450,0,0,0,0,0,0,0,0,304,304,304,304,0,304,304,304,0,0,0,0,450,450,421,450,450,450,450,450,450,450,450,450,450,450,450,450,450,533,450,533,533,533,450,533,533,533,533,450,543,566,543,566,543,543,566,543,590,566,566,566,566,566,566,566,590,590,590,543,590,590,590,590,590,590,590,590,566,566,616,621,590,621,627,1,960,563,563,563,563,563,563,563,563,0,587,587,587,587,587,587,587,3136,587,587,3138,587,587,587,587,587,0,0,0,0,1657,0,0,0,0,0,0,0,0,0,0,0,0,254414,0,0,0,1676,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1211,541,541,541,1810,541,541,541,541,541,541,541,541,541,541,541,1360,914,563,563,563,563,563,563,563,563,563,563,563,563,563,1378,0,0,2486,0,0,0,0,0,0,0,0,0,0,0,0,0,694,0,0,541,541,541,541,2528,541,541,541,541,2532,541,541,541,541,541,541,541,541,3218,541,541,541,541,541,541,541,541,2583,541,541,541,541,0,2586,0,0,0,0,563,563,563,563,563,563,2592,563,563,563,563,2596,563,0,587,587,587,587,587,78115,1079,0,0,0,0,0,0,0,0,0,225741,225741,225741,225741,225741,225741,225741,225741,225741,225741,225741,225741,225741,225741,225741,225741,0,0,0,0,0,0,0,2658,587,587,587,587,2662,587,587,587,587,587,587,587,587,587,587,2665,587,587,587,587,587,0,0,0,313,314,315,316,317,318,319,320,321,322,0,0,0,0,0,0,694,0,0,0,0,0,365,365,365,0,0,313,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2142208,0,0,316,0,0,0,0,0,0,0,0,0,0,0,0,0,730,0,0,0,423,431,433,422,431,0,313,431,451,464,464,464,464,464,464,464,464,464,464,464,464,464,464,464,464,464,464,464,485,490,490,501,490,490,490,490,490,490,490,490,516,516,529,529,530,530,530,530,530,530,530,530,530,530,530,516,530,530,530,530,530,544,567,544,567,544,544,567,544,591,567,567,567,567,567,567,567,591,591,591,613,591,591,591,591,591,591,591,614,615,615,613,615,614,615,614,1,734,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1238,0,0,0,0,767,0,0,0,0,0,0,0,0,0,0,0,0,266240,0,0,0,0,0,702,0,0,0,0,0,702,0,0,0,541,541,541,541,541,541,3322,541,541,541,541,541,541,541,541,1816,541,541,541,541,541,541,1360,563,563,563,968,563,563,563,563,563,0,587,587,587,587,587,587,587,3150,3151,3152,541,541,563,563,587,587,0,0,2963,0,0,0,0,0,0,0,0,3180,0,0,3389,0,0,0,0,0,1108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,308,309,0,1150,1108,0,0,0,0,0,0,0,0,0,0,0,0,0,1119,0,0,1212,0,0,0,0,0,0,0,0,0,0,0,0,0,1225,0,0,0,0,0,797,0,0,0,0,0,0,0,0,0,0,0,0,797,0,1360,914,563,563,1364,563,563,1368,563,563,563,563,563,563,563,563,985,0,587,587,587,587,587,587,1382,563,1387,563,563,1391,563,563,1394,563,563,563,563,563,563,563,984,563,0,587,587,587,587,587,1004,587,1460,587,587,587,587,587,587,587,587,1474,587,1479,587,587,1483,587,587,1486,587,587,587,587,587,587,587,587,587,587,587,587,587,1939,587,587,0,1692,0,1694,0,0,0,0,0,0,1701,0,0,0,0,0,0,0,2442,0,0,0,0,0,0,0,0,0,1173,0,0,0,0,0,0,541,541,1745,541,541,541,541,541,541,541,541,541,1757,541,541,541,541,541,541,2192,541,541,2195,541,541,541,541,541,541,541,1798,541,541,541,541,541,541,1806,541,541,1792,1793,541,541,541,541,541,541,541,541,541,541,541,541,541,541,2824,541,0,563,563,563,563,563,563,563,563,563,563,563,563,563,1840,563,0,587,587,587,587,587,78115,1079,0,0,1083,1087,0,0,1091,587,587,587,587,1948,587,587,587,587,587,587,587,587,587,587,587,1478,587,587,587,587,587,587,587,587,1961,587,587,587,587,587,587,587,587,587,587,587,1533,587,587,587,587,0,2034,0,2036,0,0,0,0,0,0,2430,0,0,0,0,0,0,0,2454,0,0,0,0,0,0,0,0,0,2429,0,0,0,0,0,0,0,0,0,2476,0,0,0,0,0,0,0,0,0,0,0,0,365,365,365,702,0,0,0,2502,2503,0,0,0,0,0,0,0,0,0,0,0,0,1147355,0,0,0,587,587,2700,587,587,587,587,587,587,587,587,587,587,587,587,587,2004,587,587,0,0,2802,0,0,0,0,0,0,0,2806,541,541,541,541,541,541,541,2204,541,541,541,541,541,541,541,541,541,2220,541,541,541,541,541,541,541,2956,563,2958,587,2960,0,0,0,0,0,2966,0,0,0,0,0,0,0,69632,73728,0,0,0,350,348,65536,0,0,0,0,2970,0,0,0,0,0,0,0,0,0,0,0,0,365,365,208896,0,3035,541,541,541,541,541,541,541,541,541,541,541,541,541,541,541,1807,541,541,3050,3051,541,541,541,541,541,541,541,541,541,541,541,541,541,2223,2224,541,563,3090,563,3092,563,563,563,563,563,563,563,563,563,563,563,563,1415,563,563,563,3117,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,1484,587,587,3132,587,3134,587,587,587,587,587,587,587,587,587,587,587,1937,1938,587,587,587,0,3192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,309,308,541,541,541,541,3228,541,541,541,541,563,563,563,563,563,563,563,563,563,945,563,563,563,563,587,3503,0,3504,0,0,0,0,0,0,0,0,0,0,0,541,541,541,541,2810,3515,541,3516,541,541,541,3520,541,541,541,541,541,541,541,563,3528,563,3529,563,563,563,3533,563,563,563,563,563,563,563,563,587,3542,587,3543,587,587,587,3547,587,587,587,587,587,587,587,587,0,0,0,0,3673,541,541,541,3675,563,563,3676,587,587,587,3678,0,0,541,541,563,563,587,587,0,541,541,3204,541,541,541,541,541,541,541,541,541,541,541,541,541,2238,2586,0,324,324,374,0,0,0,0,0,0,0,0,0,0,0,0,0,1133,0,0,0,0,434,374,0,439,445,0,452,465,465,465,465,465,465,465,465,465,465,465,465,465,465,465,465,465,465,465,465,491,491,502,491,491,491,491,491,491,491,491,517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,517,545,568,545,568,545,545,568,545,592,568,568,568,568,568,568,568,592,592,592,545,592,592,592,592,592,592,592,592,568,568,545,568,592,568,592,1,587,587,587,1019,587,587,587,587,587,587,587,587,587,587,587,587,1052,587,587,587,1122,0,1124,1125,0,0,0,1127,1128,0,0,0,0,0,0,0,0,334,0,0,0,0,0,334,0,0,0,1166,1167,0,0,0,0,0,0,0,0,0,0,0,0,400,0,0,0,0,0,1228,0,0,0,0,1233,0,0,0,0,0,0,0,0,0,365,300,0,0,0,0,0,0,0,0,0,1241,0,0,0,0,1244,0,1194,0,1113,0,1250,1127,0,0,0,0,0,0,0,0,0,541,541,1274,541,541,541,541,541,541,2203,541,541,541,541,541,541,541,541,541,541,1329,541,541,541,541,541,541,541,1322,541,541,1324,541,541,541,1328,541,541,541,541,541,541,541,541,3522,541,541,541,541,541,563,563,3068,563,563,563,563,563,563,563,563,2603,563,563,563,563,563,563,563,1360,914,563,563,1365,563,563,563,563,563,563,563,563,563,563,563,587,3427,587,587,3429,563,563,563,1405,563,563,563,563,563,563,563,1414,563,563,1416,563,0,587,587,587,1051,587,78115,1079,0,0,0,0,0,0,0,0,1134592,0,0,0,0,0,0,1134592,0,0,0,0,563,563,1420,563,563,563,563,563,563,563,563,563,563,563,563,563,1437,563,563,563,563,563,1444,563,563,563,563,563,26028,1360,988,587,587,1457,587,0,0,0,0,0,0,0,3447,3180,0,0,0,0,0,0,0,1237,0,0,541,541,1273,541,1276,541,0,0,0,1656,0,0,0,0,0,0,0,0,0,0,0,0,541,846,541,541,587,587,587,1993,587,587,587,587,587,587,587,587,587,587,587,587,1496,587,587,587,563,2025,587,587,587,2029,0,2030,0,0,0,0,0,2032,0,0,0,0,0,0,1134592,0,0,0,0,0,0,0,0,0,0,1134592,0,0,0,2034,0,0,0,0,0,2036,0,0,0,0,0,2039,0,2078,0,0,0,0,0,0,0,0,0,0,0,0,0,0,331,0,0,0,0,2092,0,0,0,0,0,0,0,0,0,0,0,0,643,0,0,0,541,2172,541,541,541,541,541,541,541,541,541,541,541,541,541,541,0,0,0,541,2188,541,541,541,541,541,541,541,541,541,541,541,541,541,541,0,2240,541,541,541,541,2229,541,2231,541,541,541,541,541,541,541,0,0,0,0,0,0,1146880,0,1146880,0,0,0,0,0,0,0,0,2617344,0,0,0,0,0,2789376,0,0,0,563,563,563,563,563,563,563,563,563,2253,563,563,563,563,0,0,0,0,0,0,587,2654,587,587,587,587,587,587,3135,587,587,587,587,587,587,587,587,587,1530,587,587,587,587,587,587,2257,563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,1889,2273,563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,2272,563,563,563,563,2316,563,2318,563,563,563,563,563,563,563,0,0,0,0,0,0,587,587,587,587,587,587,587,587,587,587,587,587,587,587,541,563,2344,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,1516,2360,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,1517,587,587,587,587,2403,587,2405,587,587,587,587,587,587,587,541,587,0,0,0,0,0,0,0,3508,0,0,0,0,0,0,541,541,541,541,541,541,3400,541,541,541,2499,0,0,0,0,0,2504,0,0,0,0,0,0,0,0,0,0,2086,2087,0,0,0,0,541,541,2526,2527,541,541,541,541,541,541,541,541,541,541,541,541,541,2237,0,0,541,541,2566,541,541,541,541,541,541,541,541,541,541,541,541,541,541,3046,541,0,0,0,563,563,563,2590,563,2591,563,563,563,563,563,563,563,1411,563,563,563,563,563,563,563,563,1429,563,563,563,563,563,563,563,563,1916,563,563,26028,1921,587,587,587,0,0,0,2761,0,0,0,0,0,0,0,0,0,0,0,0,674,0,0,0,541,541,2837,541,541,541,541,541,541,541,2843,541,541,541,541,541,541,541,2232,541,541,2235,2236,541,541,0,0,563,563,563,2885,563,563,563,563,563,563,563,2891,563,563,563,563,0,0,2329,0,0,0,587,587,587,587,587,587,587,587,587,587,2341,587,587,587,2920,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,1519,587,587,587,587,3373,587,587,541,541,563,563,587,587,0,0,0,0,0,0,0,0,0,2968,563,587,587,587,587,587,587,3493,587,587,587,587,587,587,587,587,1034,587,587,587,587,587,587,587,326,327,328,0,0,0,0,0,0,0,0,0,0,0,0,0,1161,0,0,0,0,0,325,373,328,372,0,0,0,0,0,0,0,0,0,0,2111,0,0,0,0,0,325,0,0,372,372,402,0,328,0,0,0,0,0,0,0,0,0,365,339,293,0,0,0,0,0,0,325,0,327,0,0,0,453,466,466,466,466,466,466,466,479,466,466,466,466,466,466,466,466,466,466,466,466,492,492,466,492,492,507,509,492,492,507,492,518,518,518,518,518,518,518,518,518,518,518,518,518,518,518,535,518,518,518,518,518,546,569,546,569,546,546,569,546,593,569,569,569,569,569,569,569,593,593,593,546,593,593,593,593,593,593,593,593,569,569,546,569,593,569,593,1,0,0,658,659,0,0,0,0,0,0,0,0,0,0,670,671,0,689,0,0,0,0,0,0,0,0,0,0,365,365,365,0,0,0,0,0,800,0,0,0,0,0,0,0,0,0,0,0,0,718,0,720,0,0,0,0,0,0,727,0,0,0,731,0,0,0,0,0,0,1159168,417,417,0,0,0,0,0,417,0,0,784,0,786,0,0,0,0,0,0,0,0,0,0,0,0,759,0,0,0,0,0,798,0,803,0,806,0,0,0,0,803,806,0,0,0,0,0,0,741,0,0,0,0,0,0,0,0,0,0,0,0,806,806,803,0,0,0,0,0,0,0,786,0,798,0,815,0,0,0,0,0,802,0,0,783,0,0,0,0,802,0,0,0,0,0,0,0,802,0,0,0,0,806,0,707,0,0,823,0,0,0,0,0,823,823,826,0,0,0,786,0,0,0,0,0,835,0,0,0,0,0,0,0,2480,0,0,0,0,0,0,0,0,0,1100,0,0,0,0,0,0,0,0,0,0,784,0,0,0,835,815,835,0,541,541,850,541,541,541,541,541,3052,541,541,541,541,541,541,541,541,3060,541,541,541,541,541,3217,541,541,541,541,541,541,541,3222,541,541,541,541,541,2529,541,541,541,541,541,541,541,541,541,541,541,3043,541,541,541,541,856,541,541,869,541,541,880,541,885,541,541,893,896,901,541,909,563,563,966,969,974,563,982,563,563,0,587,587,587,997,587,1003,587,587,1016,587,587,1027,587,1032,587,587,1040,1043,1048,587,1056,587,0,0,0,0,0,0,3507,0,0,0,0,0,0,0,541,541,541,541,541,3031,541,541,541,541,0,0,0,1110,0,0,0,0,0,0,0,1117,0,0,0,0,0,0,0,69632,73728,0,0,0,421,0,65536,0,0,1137,1138,0,0,0,0,1142,0,0,0,365,365,0,0,0,0,0,0,769,0,0,0,775,776,0,0,0,0,0,0,0,69632,73728,0,0,0,374,0,65536,0,0,1165,0,0,0,0,0,0,0,0,0,0,0,0,0,0,515,522,0,0,1182,741,0,0,0,1134,0,0,0,0,0,0,0,0,0,367,0,0,0,0,0,0,541,541,541,1281,541,541,541,541,541,541,1296,541,541,541,1301,541,541,541,541,541,3229,541,541,541,563,563,563,563,563,563,563,941,563,563,563,563,563,563,1360,914,563,563,563,563,563,563,563,563,563,563,1373,563,563,563,563,563,3249,563,3251,563,563,563,563,563,563,563,563,1852,563,563,563,563,563,563,563,563,563,563,1388,563,563,563,1393,563,563,563,563,563,563,563,563,1451,26028,1360,988,587,587,587,587,587,1485,587,587,587,587,587,587,587,587,587,587,587,587,587,1500,1540,587,587,0,541,587,563,541,541,541,541,541,563,563,563,563,563,563,3477,563,563,563,563,563,563,563,563,1396,563,563,563,563,563,563,563,0,0,1607,1608,1609,0,1611,1612,0,0,0,0,1617,0,0,0,0,0,0,770,0,0,773,0,0,777,0,0,0,0,0,0,796,0,0,0,0,0,541,541,541,541,541,541,563,563,563,563,563,563,933,563,563,947,563,563,563,563,0,0,1639,0,0,1642,0,1644,0,0,0,0,0,1650,1651,0,0,0,0,0,805,0,0,692,0,0,672,0,692,0,810,0,1667,0,0,1669,0,0,0,0,1671,1672,0,0,0,0,0,0,0,2491,2492,0,0,0,0,0,0,0,0,0,2686976,2736128,0,0,2531328,2707456,0,0,0,0,0,1708,0,0,1711,0,0,0,0,0,1715,0,0,0,0,0,0,2134016,0,0,0,0,0,0,0,0,1138688,0,1719,1720,0,0,0,0,0,0,0,0,0,0,0,0,1711,0,0,0,1731,1585,1585,1733,541,1735,541,1736,1737,541,1739,541,541,541,541,541,1310,541,541,541,541,541,541,541,1317,541,541,541,541,541,1748,541,541,541,541,541,541,541,541,541,1759,541,1743,541,541,541,541,541,541,541,541,541,1756,541,541,541,541,541,541,541,3333,541,541,541,541,541,563,563,563,922,926,563,563,563,563,563,563,952,563,957,1760,541,541,541,541,1764,541,1766,541,541,541,541,541,541,541,541,541,889,541,541,541,541,907,541,1774,1775,1777,541,541,541,541,541,541,541,1785,1786,1787,541,541,1790,1791,541,541,541,541,541,541,541,1799,541,541,541,1803,541,541,541,541,541,541,2530,541,541,541,541,541,541,541,541,541,541,1315,541,541,541,541,1320,541,541,541,541,1811,541,541,541,541,541,541,541,541,541,1822,1360,914,563,563,563,563,563,563,563,563,563,563,563,563,563,1379,0,1827,563,1829,563,1830,563,1832,563,1834,563,563,563,1838,563,563,563,563,1390,563,563,563,563,563,563,563,563,563,563,563,2652,0,587,587,587,563,1859,563,1861,563,563,563,563,563,563,563,563,1869,1870,1872,563,0,587,587,1042,587,587,78115,1079,0,0,0,0,0,0,0,0,307,307,307,0,0,0,0,0,1907,563,563,563,563,563,563,563,563,563,1918,26028,0,1923,587,1925,587,1926,587,1928,587,1930,587,587,587,1934,587,587,587,587,587,587,587,3366,587,587,587,587,3367,3368,587,587,587,587,587,1947,587,587,587,587,1951,587,587,587,587,1955,587,1957,587,587,1976,1977,1978,587,587,1981,1982,587,587,587,587,587,587,587,1999,2e3,587,587,587,587,587,587,587,2015,2016,2017,541,2019,541,541,563,2023,1990,587,587,587,1994,587,587,587,587,587,587,587,2003,587,587,587,0,1288,1472,1380,541,541,541,541,541,563,563,563,563,3475,563,563,563,563,563,563,563,563,563,563,2267,563,563,563,563,563,563,2024,563,1982,587,2028,587,0,2030,0,0,0,0,0,2032,0,0,0,0,0,0,2134016,0,0,0,0,0,0,0,746,0,0,0,0,0,2043,0,0,2046,2047,0,0,0,2051,0,0,0,0,0,0,800,0,0,0,0,0,0,0,800,0,0,0,0,541,541,541,541,2090,0,0,0,0,2094,0,0,0,0,0,0,0,0,0,0,0,2456,0,0,0,0,0,0,0,0,1669,0,0,0,0,0,0,0,2113,0,0,2116,0,0,2119,0,0,0,0,0,0,2126,0,2128,0,0,0,0,0,0,0,69632,73728,0,370,370,0,0,65536,370,0,0,0,0,2137,0,0,0,0,0,0,0,0,0,0,0,0,1159168,0,0,0,0,2047,0,2147,0,0,0,0,0,0,0,0,0,0,0,0,1103,1104,1105,1106,0,2158,0,0,541,541,541,541,541,541,541,541,541,541,541,541,541,3329,541,541,541,2174,541,2176,541,541,541,541,541,541,2184,541,2186,541,541,541,541,541,3332,541,541,541,541,541,541,541,563,563,563,3069,563,563,563,563,563,563,563,2212,541,541,541,541,541,541,2219,541,541,541,541,541,541,541,541,541,1312,541,541,541,541,541,541,563,563,2259,563,2261,563,563,563,563,563,563,2269,563,2271,563,563,563,563,1422,563,563,563,563,563,563,563,563,563,563,1438,587,587,2346,587,2348,587,587,587,587,587,587,2356,587,2358,587,587,0,0,0,3634,0,3636,541,541,541,541,541,541,541,563,563,921,563,563,563,563,940,944,950,563,955,563,563,2261,541,2416,541,541,563,2420,563,563,587,2424,587,587,2030,0,2032,0,0,0,2452,0,0,0,0,0,0,0,0,0,0,0,0,1132,0,0,0,0,0,2461,0,0,0,0,0,2466,0,2468,2469,0,0,0,0,0,0,0,69632,73728,0,420,420,0,0,65536,420,0,0,0,0,2488,0,0,0,0,0,0,0,0,0,0,0,0,2179072,2179072,2179072,2179072,0,0,0,0,2516,2468,0,0,0,0,0,2521,0,0,0,541,541,541,541,541,3321,541,541,541,3325,541,541,541,541,541,541,1749,541,541,541,541,541,541,541,541,541,541,2558,541,541,541,541,541,2563,541,541,541,2568,541,541,541,541,541,541,541,2575,541,541,541,541,541,541,2542,541,2544,541,541,541,541,541,541,541,541,563,3411,563,563,3413,563,563,563,541,541,541,541,2580,541,541,541,541,541,541,541,541,0,2586,0,0,0,0,0,812,0,809,792,0,0,814,0,667,0,788,0,0,0,563,563,563,563,563,563,563,563,2594,563,563,563,563,0,2652,0,0,0,0,587,587,587,587,587,587,587,587,587,587,587,587,2342,587,563,2624,563,563,563,563,2628,563,563,563,2633,563,563,563,563,563,563,2629,563,563,563,563,563,563,2636,563,563,563,563,2640,563,563,563,563,563,563,563,563,2646,563,563,563,563,0,2652,0,0,0,0,587,587,587,2656,587,2657,587,587,2660,587,587,587,587,587,587,587,587,587,587,587,587,587,2383,587,587,587,587,2672,587,2674,587,587,587,587,587,587,587,587,587,587,587,1970,587,587,587,587,587,2699,587,587,587,587,587,587,587,2706,587,587,587,587,587,587,587,3375,541,3376,563,3377,587,0,0,0,587,587,2712,587,587,587,587,587,587,587,587,541,587,563,541,541,541,541,563,563,2800,2801,0,0,0,0,0,0,0,0,0,541,541,541,541,541,541,541,541,541,3402,2992,0,0,0,0,0,0,0,0,0,0,0,2992,0,0,0,0,0,0,840,0,0,0,0,0,541,541,541,541,541,541,2166,541,541,541,541,541,0,3022,0,0,0,3025,541,541,541,541,541,541,3032,541,541,541,541,541,541,2570,541,541,541,541,2574,541,541,541,541,541,541,1286,541,541,541,541,541,541,541,541,541,541,1818,541,541,541,541,1360,541,541,3036,541,541,541,541,541,541,541,3042,541,541,541,541,541,541,541,2531,541,541,541,541,541,541,541,541,541,563,3230,563,563,563,3233,563,3048,541,541,541,541,541,541,541,541,541,541,3057,3059,541,541,541,541,541,541,2582,541,541,541,541,541,541,0,2586,0,3062,541,3064,3065,541,563,563,563,563,563,563,3072,563,563,563,563,563,1425,563,563,563,563,563,563,563,563,563,563,2889,563,563,563,563,563,563,563,3076,563,563,563,563,563,563,563,3082,563,563,563,563,563,3088,563,563,3091,563,563,563,563,563,563,563,563,3098,3100,563,563,563,563,563,3342,563,563,563,563,563,563,563,563,563,563,2645,563,563,563,563,563,563,563,3104,563,3106,3107,563,587,587,587,587,587,587,3114,587,587,587,0,1544,1545,1546,541,541,1548,541,541,563,563,1552,563,587,587,3118,587,587,587,587,587,587,587,3124,587,587,587,587,587,587,1998,587,587,587,587,587,587,587,587,587,3551,587,587,3553,587,0,0,3130,587,587,3133,587,587,587,587,587,587,587,587,3140,3142,587,587,0,0,3633,0,0,0,541,541,3638,541,541,541,3642,563,587,587,3146,587,3148,3149,587,541,587,563,541,3154,563,3156,587,3158,0,0,0,0,0,3181,0,3183,0,0,0,0,0,0,0,3190,0,0,0,3193,3194,0,0,0,0,0,0,0,0,0,0,0,0,2200252,2200252,2200252,0,563,563,563,563,3237,563,563,563,563,563,563,563,563,563,563,563,1400,563,563,563,563,563,563,563,3248,563,563,563,563,563,563,563,563,3256,563,563,563,563,563,3352,563,563,563,563,587,587,587,587,587,3358,563,563,563,587,587,587,3261,587,587,587,587,587,587,587,3266,587,0,0,0,0,0,3506,0,0,3509,0,0,0,0,0,541,541,541,541,3662,541,563,563,563,563,3666,563,0,3310,0,0,3313,0,0,0,0,0,0,0,0,0,0,0,0,2200253,151552,2200253,0,587,587,587,3372,587,587,587,541,541,563,563,587,587,0,0,0,0,0,0,0,0,2967,0,0,0,0,0,0,3383,3384,0,3180,0,0,0,0,0,3392,0,0,0,0,0,1097,0,0,0,0,0,0,0,0,0,0,331,382,384,0,0,0,563,3417,563,563,563,563,563,563,563,563,563,587,587,587,587,587,587,587,3115,587,587,587,587,587,587,3433,587,587,587,587,587,587,587,587,587,541,563,3472,563,3474,563,563,563,563,563,563,563,563,563,563,563,563,3243,563,563,563,3470,563,563,563,563,563,563,563,563,563,563,563,563,563,563,3485,563,563,563,563,3532,563,563,563,563,563,563,563,563,563,587,587,3110,587,587,587,587,587,587,587,587,587,587,587,3546,587,587,587,587,587,587,587,587,587,3555,3556,0,0,0,3559,0,0,0,0,0,3565,3566,3567,541,541,541,3570,541,3572,541,541,541,541,3577,3578,3579,563,563,563,3582,563,3584,563,0,587,587,1044,587,587,291,1079,0,0,1082,1086,0,0,1090,563,563,563,3589,3590,3591,3592,587,587,587,3595,587,3597,587,587,587,587,587,1464,587,587,587,1473,587,587,587,587,587,587,1949,587,587,587,587,587,587,587,587,587,2949,587,587,587,541,587,563,587,3602,0,0,0,0,0,0,0,0,0,0,541,541,541,541,541,541,1738,541,541,541,563,3644,563,563,563,3648,563,587,587,3650,587,587,587,3654,587,0,0,0,0,0,0,0,0,3180,0,3449,0,0,0,0,0,0,0,69632,73728,266240,0,0,0,0,65536,0,0,0,0,329,330,0,0,0,0,0,0,0,0,0,0,0,349,0,0,0,0,0,369,0,0,0,0,0,0,0,0,0,0,0,0,0,0,686,0,0,0,0,369,0,0,0,377,379,0,0,0,0,0,0,0,0,1099,0,0,0,0,0,0,0,0,1115,0,0,0,0,0,0,0,0,0,3185,0,0,0,0,0,0,0,0,412,0,0,0,412,69632,73728,0,369,369,0,424,65536,369,0,0,0,369,424,499,503,499,499,508,499,499,499,508,499,424,424,0,330,424,0,0,424,424,0,0,0,0,0,0,0,0,1156,0,0,0,0,0,0,0,0,664,0,0,0,0,0,0,0,0,680,681,0,0,0,0,0,0,424,424,424,424,424,424,424,424,424,424,424,424,424,424,424,424,547,570,547,570,547,547,570,547,594,570,570,570,570,570,570,570,594,594,594,547,594,594,594,594,594,594,594,594,570,570,547,570,594,570,594,1,587,587,587,1020,587,587,587,587,587,587,587,587,587,587,587,587,1954,587,587,587,0,0,1109,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1215,0,0,0,0,0,0,0,0,0,0,0,1226,541,1279,541,541,541,541,541,1291,541,541,541,541,541,541,541,541,541,1351,541,541,541,541,541,541,1360,914,563,563,563,563,563,563,563,563,1371,563,563,563,563,563,563,2643,563,563,563,563,563,563,563,563,563,1866,563,563,563,563,563,563,1383,563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,2286,587,587,1992,587,587,587,587,587,587,587,587,587,587,587,587,587,2411,541,587,563,563,3677,587,587,587,0,0,541,541,563,563,587,587,0,541,3203,541,541,541,3206,541,541,541,541,541,541,541,541,541,541,1313,541,541,541,541,541,425,425,0,0,425,440,0,425,425,467,467,467,467,467,467,467,467,467,467,467,467,467,467,467,467,467,467,467,467,493,493,467,493,493,493,493,493,493,493,493,493,493,493,493,493,493,493,493,548,571,548,571,548,548,571,548,595,571,571,571,571,571,571,571,595,595,595,548,595,595,595,595,595,595,595,595,571,571,548,571,595,571,595,1,0,1213,0,0,0,0,0,0,0,0,0,0,0,0,0,0,732,0,0,0,0,0,1695,0,0,0,0,0,0,0,0,0,0,0,360,0,0,0,0,0,0,0,0,2093,0,0,0,0,0,0,0,0,0,0,0,365,365,0,0,0,2157,0,0,0,541,541,541,541,541,541,541,541,541,541,541,541,3328,541,2201,541,541,541,541,541,541,541,541,541,541,541,541,541,541,541,2200,563,2415,541,541,541,2419,563,563,563,2423,587,587,587,0,0,0,0,0,0,541,541,541,541,541,541,541,563,3067,563,563,563,563,563,563,563,563,563,3253,563,563,563,563,563,563,0,2460,0,0,0,0,0,0,0,0,0,0,0,0,0,0,748,0,0,0,0,0,2791,0,0,0,0,0,0,0,0,0,0,0,365,365,1146,0,0,2943,587,587,587,587,587,587,587,587,587,587,587,587,541,587,563,541,541,0,0,0,0,2971,0,0,0,2975,0,0,0,0,0,2981,0,0,0,0,0,1128,0,0,0,0,0,1233,0,0,0,1265,0,0,0,2994,0,2996,0,0,0,0,0,0,0,0,3004,0,0,0,0,0,1169,0,1171,0,0,0,0,1176,0,0,0,0,0,0,1643,0,0,0,0,0,0,0,0,0,0,2520,0,0,0,0,541,0,0,0,0,3009,0,0,0,0,0,0,0,0,0,0,0,383,0,0,0,387,541,3063,541,541,541,3066,563,563,563,563,563,563,563,563,563,563,3083,563,563,563,563,563,563,563,3105,563,563,563,3108,587,587,587,587,587,587,587,587,587,1509,587,587,587,587,587,587,3144,587,587,3147,587,587,587,541,587,563,541,541,563,563,587,587,0,0,3295,0,0,0,0,0,0,0,0,2766,0,0,0,0,0,0,0,0,2151,0,0,0,0,0,0,0,0,2506,0,0,0,0,0,2512,0,0,0,0,0,0,3195,0,0,0,0,0,0,0,0,0,0,0,2782,0,0,0,0,541,541,541,541,3216,541,541,541,541,541,541,541,3221,541,3223,541,541,541,541,541,3408,541,541,3410,563,563,563,563,3414,563,563,563,563,1446,1447,563,563,563,26028,1360,988,587,587,587,587,587,587,3671,0,0,0,541,541,541,3674,563,563,563,563,563,587,587,3260,587,587,587,587,587,587,587,587,587,587,3274,587,587,587,587,587,587,3280,587,587,587,587,587,587,587,587,587,587,587,541,587,563,541,2722,563,3350,563,563,563,563,563,563,563,563,587,587,587,587,587,587,587,587,3655,587,587,587,587,3363,587,587,587,587,587,587,587,587,587,3369,587,0,0,0,541,587,563,541,541,541,541,541,563,563,563,563,563,3071,563,563,563,563,563,0,0,0,0,541,541,3660,3661,541,541,563,563,3664,3665,563,563,563,563,1423,563,563,1430,563,563,563,563,563,563,563,563,2631,563,563,563,563,563,563,563,587,587,3668,3669,587,587,0,0,0,0,541,541,541,541,563,563,563,924,928,931,563,939,563,563,563,954,956,959,0,0,690,691,0,0,0,0,696,0,0,0,365,365,365,0,0,0,0,0,1185,0,0,0,0,0,0,0,0,0,0,0,3180,0,0,0,0,0,0,829,0,0,0,0,0,0,0,0,0,758,0,0,0,0,0,0,758,0,0,0,0,0,758,758,910,541,563,563,563,563,927,563,563,563,563,563,563,563,563,563,1432,563,563,1436,563,563,563,983,0,587,587,587,587,1057,78115,1079,0,0,0,0,0,0,0,0,1220,0,0,0,0,0,0,0,0,0,282624,282624,282624,282624,282624,282624,282624,282624,587,1521,587,587,587,587,587,587,587,587,587,587,587,587,587,587,1514,587,0,0,0,1721,0,0,0,0,0,0,0,0,0,0,0,0,1193,0,0,0,0,2040,0,0,0,0,0,0,0,0,0,0,0,0,0,0,749,0,2171,541,541,541,541,541,541,541,541,541,541,541,541,541,541,541,2211,3288,541,3290,563,3292,587,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3514,468,468,468,486,494,494,486,494,494,494,494,494,494,494,494,519,527,527,527,527,527,527,527,527,527,527,527,527,527,527,527,536,527,527,527,527,527,549,572,549,572,549,549,572,549,596,572,572,572,572,572,572,572,596,596,596,549,596,596,596,596,596,596,596,596,572,572,549,572,596,572,596,1,795,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1652,0,818,0,0,0,795,0,0,818,0,0,0,0,0,818,818,0,0,0,0,795,0,0,0,0,0,0,836,791,0,0,836,857,541,865,541,541,541,541,541,541,541,541,541,541,541,541,541,541,3527,563,911,541,563,563,563,563,563,930,563,938,563,563,563,563,563,563,1850,563,563,563,563,563,563,563,563,563,0,587,587,587,587,587,587,587,1012,587,587,587,587,587,587,587,587,587,587,587,587,587,1058,984,0,587,587,587,1077,1058,78115,1079,0,0,0,0,0,0,0,0,1243,0,0,0,0,0,0,0,0,1259,0,0,0,1263,0,0,0,0,0,0,0,1139,1140,0,0,0,0,0,365,365,0,0,0,0,0,0,1113,0,0,0,0,0,0,0,0,0,0,2071,0,0,0,0,0,1180,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1705,1340,541,541,1344,541,541,541,541,541,1350,541,541,541,1357,541,541,541,541,541,1812,541,541,541,541,541,541,541,541,541,1360,1403,563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,2638,563,563,1442,563,563,563,1449,563,563,26028,1360,988,587,587,587,587,587,587,3272,587,587,587,587,587,587,587,587,3278,587,587,1487,587,587,587,587,587,587,587,1495,587,587,587,587,587,587,2365,587,587,587,587,587,587,587,587,587,2691,587,587,587,587,587,587,587,587,587,1524,587,587,1528,587,587,587,587,587,1534,587,587,587,587,587,1492,587,587,587,587,587,587,587,587,587,587,1510,587,587,587,587,587,1541,587,587,0,541,587,563,541,541,541,541,541,563,563,563,563,563,3476,563,563,563,3480,563,563,563,563,563,563,2863,563,563,2867,563,563,563,563,563,563,1409,563,563,1413,563,563,563,563,563,563,1448,563,563,26028,1360,988,587,587,587,587,0,0,0,1595,0,0,0,0,0,0,0,0,0,0,0,0,1223,0,0,0,0,0,1655,0,0,0,0,0,0,0,0,0,1664,0,0,0,0,0,0,1126,0,0,0,1130,1131,0,0,0,0,0,0,0,2818048,2846720,0,2916352,0,0,3002368,0,0,1718,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2053,1702,0,0,0,0,0,541,541,541,541,541,541,541,541,541,541,3326,541,541,541,563,563,563,1893,563,563,563,563,563,563,1901,563,563,563,563,563,563,2887,563,563,563,2890,563,2892,563,563,563,587,1944,587,587,587,587,587,587,587,587,587,587,587,587,587,587,1940,587,587,1974,587,587,587,587,1980,587,587,587,587,587,587,587,587,1989,2007,2009,587,587,587,587,587,541,587,563,541,541,541,541,563,563,563,563,587,587,587,587,2030,0,2032,0,0,2079,0,0,0,2082,0,0,0,0,0,2088,0,0,0,0,0,0,1141,0,1143,0,0,365,365,0,0,0,0,0,0,1154,0,0,0,0,0,1160,0,1162,0,2104,0,0,0,0,0,0,0,0,0,0,0,0,0,2115,0,0,0,0,0,1192,0,0,0,0,0,0,0,0,0,0,0,176128,176128,176128,176128,176128,176128,176128,0,0,563,563,563,563,563,563,2250,563,563,563,563,563,563,563,1851,563,563,563,563,1855,563,563,563,587,587,587,587,2349,587,587,587,587,587,587,587,587,587,587,587,1985,587,587,1988,587,2262,541,541,541,541,563,563,563,563,587,587,587,587,0,0,0,0,0,2732,0,2450,0,0,0,0,0,0,0,0,2455,0,0,2458,0,0,0,0,0,0,2134016,0,0,0,0,0,0,57344,0,0,0,0,0,0,2748,0,0,0,0,0,0,0,0,0,0,192972,192972,192972,192972,192972,192972,192972,0,0,0,0,2462,0,0,0,0,0,0,0,0,0,0,0,541,541,541,2809,541,2473,0,0,0,0,0,0,0,2481,0,0,0,2483,0,0,0,0,0,0,1170,0,0,0,0,0,0,0,0,0,0,2989,0,0,0,0,0,0,2500,0,0,0,0,0,0,0,0,0,0,2510,0,0,0,0,0,0,1186,0,0,0,1191,0,0,0,0,1107,0,0,0,0,0,0,0,0,0,0,0,758,0,0,0,0,0,0,0,2524,541,541,541,541,541,541,541,541,541,541,541,541,541,541,541,2536,541,541,2552,541,541,541,541,541,541,541,541,541,541,541,541,541,905,541,541,2564,541,541,541,541,541,541,2571,541,541,541,541,541,541,541,541,541,1768,541,541,541,541,541,541,541,2578,541,541,541,2581,541,541,541,541,541,541,541,0,0,0,0,0,0,1203,0,0,0,0,0,0,0,0,0,0,813,0,0,0,0,0,0,0,0,563,2588,563,563,563,563,563,563,563,563,563,563,563,1903,1904,563,563,563,2611,563,563,563,563,563,563,2616,563,563,563,563,563,563,563,2622,587,587,587,587,2702,587,587,587,587,587,587,587,587,587,587,2710,587,587,587,2713,587,587,587,587,587,587,587,2718,2719,2720,541,541,541,541,541,2177,541,541,541,541,541,541,541,541,541,541,541,541,2845,541,541,541,2758,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2103,0,2773,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1120,0,0,0,2789,0,0,0,0,2794,0,0,0,2796,0,0,0,0,0,0,0,69632,73728,316,317,317,422,423,65536,430,541,541,541,541,2814,541,541,541,541,541,541,541,541,541,541,541,541,1333,541,541,541,541,541,2848,541,541,541,541,541,541,0,0,563,563,563,2856,563,0,587,587,1047,587,587,78115,1079,0,0,0,0,0,0,0,0,1159168,365,0,0,0,0,0,0,563,563,563,563,2861,563,563,563,563,563,563,563,563,563,563,563,2294,563,563,563,563,563,563,563,563,2897,563,563,563,563,563,563,0,0,587,587,587,587,587,587,587,2338,587,587,587,587,587,587,587,3122,587,587,587,587,587,587,587,587,1036,587,587,587,587,1054,587,587,2905,587,587,587,587,587,2910,587,587,587,587,587,587,587,587,587,1935,587,587,587,587,1941,587,3006,0,0,0,0,3010,0,0,0,0,3015,0,0,0,0,0,0,0,2749,0,0,0,0,0,0,0,0,0,697,698,0,365,365,365,0,3191,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2145,3300,0,0,0,0,0,0,0,0,0,0,3180,0,0,0,0,0,0,0,69632,73728,163840,0,0,0,0,65536,0,563,563,563,3340,563,563,563,563,563,563,563,563,563,563,563,563,2283,563,563,563,563,563,563,3351,563,563,563,563,563,563,587,587,587,587,587,587,587,587,587,587,587,587,587,3359,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,1942,3370,587,587,587,587,587,587,541,541,563,563,587,587,0,0,0,0,3297,0,0,0,0,0,0,0,0,0,3394,0,541,541,541,541,541,541,541,541,541,541,541,541,3211,541,541,3486,587,587,587,587,587,587,587,587,3495,587,3497,3498,587,3500,587,0,0,0,541,587,563,541,541,541,904,541,563,563,563,977,3502,0,0,0,0,0,0,0,0,0,0,0,0,0,0,541,541,541,854,541,541,3612,541,3613,541,541,541,563,563,563,563,563,563,3619,563,0,996,1075,1041,587,587,78115,1079,0,0,1081,1085,0,0,1089,3620,563,563,563,563,587,587,587,587,587,587,3627,587,3628,587,587,0,3603,0,0,0,0,0,0,0,0,541,541,3610,541,563,563,587,587,587,587,0,0,541,541,563,563,587,587,3683,3684,3685,3686,0,541,563,587,0,541,563,587,0,541,563,587,0,0,0,0,0,0,0,0,3180,0,0,0,0,0,0,0,550,597,573,573,573,573,573,573,573,597,597,597,550,597,597,597,597,597,597,597,597,573,573,550,573,597,573,597,1,0,0,0,737,0,0,0,0,0,0,0,0,0,0,0,0,1237,0,0,0,0,0,2041,0,0,0,0,0,0,0,0,0,0,0,0,0,1194,1196,0,403,0,0,0,0,381,0,69632,73728,0,0,0,0,426,65536,0,0,0,0,0,1202,0,0,0,0,0,0,0,0,0,0,0,2444,2445,0,0,2448,426,426,0,0,426,0,446,426,426,469,469,469,476,469,469,469,469,469,469,469,469,469,476,469,469,469,469,469,469,469,469,483,469,495,495,469,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,495,538,551,574,551,574,551,551,574,551,598,574,574,574,574,574,574,574,598,598,598,551,598,598,598,598,598,598,598,598,574,574,551,574,598,574,598,1,0,0,0,0,660,661,0,0,0,0,0,0,0,0,0,0,0,3001,0,0,0,0,0,0,0,0,661,0,0,0,0,0,0,0,0,0,0,0,661,0,0,0,0,0,827,0,0,0,661,0,0,0,0,0,0,0,0,0,0,0,3176,0,0,0,0,0,0,0,729,0,742,661,0,0,0,0,0,541,844,541,541,541,541,541,2191,541,541,541,541,541,541,2197,541,2199,541,541,859,541,541,541,541,541,541,541,541,541,541,897,541,541,541,541,541,541,2817,541,2819,541,541,541,541,541,541,541,541,2572,541,541,541,541,541,541,541,541,1349,541,541,541,541,541,541,541,541,1752,541,541,541,541,541,541,541,541,1767,541,541,541,541,541,541,541,541,1782,541,541,541,541,541,541,541,541,1815,1817,541,541,541,541,541,1360,563,563,563,970,563,563,563,563,563,0,587,587,990,587,587,587,587,587,1526,587,587,587,587,587,587,587,587,587,587,1953,587,587,587,587,587,1006,587,587,587,587,587,587,587,587,587,587,1044,587,587,587,587,587,587,3285,587,587,587,587,587,587,541,587,563,1094,0,0,0,0,0,0,0,0,0,1101,1102,0,0,0,0,0,0,0,69632,73728,167936,0,0,0,0,65536,0,0,0,0,1229,0,0,0,0,0,0,0,0,0,0,0,0,1247,0,0,0,0,0,0,0,1102,0,0,0,0,1260,1261,0,0,1101,0,0,0,0,0,0,2134756,0,0,0,0,0,0,0,0,0,0,1116,0,0,0,0,0,541,1306,541,541,541,541,541,541,541,541,541,541,541,541,541,541,0,2241,1360,914,563,1363,563,563,563,563,563,563,563,563,563,563,563,1377,1384,563,563,563,563,563,563,563,563,563,1398,563,563,563,563,563,563,3079,563,563,563,563,563,563,563,563,563,0,587,587,989,587,587,587,1418,563,563,563,563,563,563,563,1431,563,563,563,563,563,563,563,1897,563,563,563,563,563,563,563,563,1395,563,563,563,563,563,563,563,587,587,1523,587,587,587,587,587,587,587,587,587,587,587,1537,587,0,0,0,541,587,563,541,541,541,1067,911,563,563,563,1072,563,587,587,1523,587,587,1079,0,0,0,0,0,0,0,0,0,0,2781,0,0,0,0,0,541,541,541,1746,1747,541,541,541,541,1754,541,541,541,541,541,541,541,1290,541,1295,541,541,1299,541,541,1302,541,541,541,541,1795,541,541,541,541,541,541,541,541,541,541,541,541,1335,541,541,541,1825,563,563,563,563,563,563,563,563,563,563,563,563,563,563,1841,1842,563,563,563,563,1849,563,563,563,563,563,563,563,563,563,563,3347,563,563,563,563,3348,1890,563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,2649,587,1945,587,587,587,587,587,587,587,587,587,587,587,587,587,587,2372,587,587,1959,587,587,587,587,587,587,587,587,587,587,587,587,587,587,2384,2385,587,587,587,587,2012,587,587,541,587,563,541,541,541,541,563,563,587,587,2961,0,0,2964,2965,0,0,0,0,0,0,0,2505,0,0,0,0,0,0,0,0,0,387,0,0,0,0,0,387,0,0,0,2054,0,2055,0,0,0,0,0,0,0,0,0,2064,541,541,541,541,2216,541,541,541,541,541,541,2221,541,541,541,541,541,541,1285,1292,541,541,541,541,541,541,541,541,541,1800,541,541,541,1805,541,541,541,2226,541,541,541,541,541,541,541,541,541,541,541,541,0,0,563,563,563,563,563,563,563,563,2302,563,563,563,563,563,563,2307,563,563,563,563,563,563,3080,563,563,563,563,563,563,563,563,563,1883,563,563,563,563,563,563,563,2313,563,563,563,563,563,563,563,563,563,563,563,563,0,0,587,587,587,587,587,587,2389,587,587,587,587,587,587,2394,587,587,587,587,587,587,2377,587,587,587,587,587,587,587,587,587,1952,587,587,587,587,1956,587,587,2400,587,587,587,587,587,587,587,587,587,587,587,587,541,587,0,0,0,541,587,563,541,541,895,541,541,563,563,968,563,0,587,587,587,587,587,78115,1079,0,0,1082,1086,0,0,1090,0,2437,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1178,0,587,2671,587,587,587,587,587,587,587,587,587,587,587,587,587,587,2931,587,0,0,0,2736,0,0,0,0,0,0,0,0,0,0,0,0,1588,1589,0,0,2787,0,0,0,0,0,0,0,0,0,0,0,2797,0,0,0,0,0,0,1204,0,0,0,0,0,0,0,0,0,0,1631,0,0,0,0,0,541,541,541,2813,541,541,541,541,541,541,2821,541,541,541,541,541,541,541,2555,541,541,541,541,541,541,541,2562,563,563,563,2860,563,563,563,563,563,563,2868,563,563,563,563,563,563,3094,563,563,3096,563,563,563,563,563,563,1880,1881,1882,563,563,1885,1886,563,563,563,0,0,3008,0,0,0,0,0,0,0,0,0,0,0,0,0,1197,0,0,541,541,3227,541,541,541,541,541,541,563,563,563,563,563,563,563,3073,563,563,563,3571,541,3573,541,541,541,563,563,563,563,563,563,563,3583,563,3585,0,0,0,0,541,3659,541,541,541,541,563,3663,563,563,563,563,563,1878,563,563,563,563,1884,563,563,563,563,563,563,2864,563,2866,563,563,563,563,563,563,563,3354,563,563,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,1057,587,3667,587,587,587,587,0,0,0,0,541,541,541,541,563,563,915,563,563,563,563,563,563,946,563,563,563,563,563,1427,563,563,563,563,563,563,563,563,563,563,3535,563,563,563,563,563,563,587,587,587,587,3112,587,587,587,587,3116,470,470,470,470,454,454,470,454,454,454,454,454,454,454,454,520,520,520,520,520,520,520,520,520,520,520,520,520,520,520,520,552,575,552,575,552,552,575,552,599,575,575,575,575,575,575,575,599,599,599,552,599,599,599,599,599,599,599,599,575,575,552,575,599,575,599,1,541,860,541,541,874,541,541,541,541,541,541,541,541,541,541,541,541,1770,541,541,541,1007,587,587,1021,587,587,587,587,587,587,587,587,587,587,587,587,1971,587,587,587,0,1123,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1184,1184,1251,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2156,0,0,0,1268,0,0,0,0,0,0,541,541,541,541,541,541,541,541,541,541,541,541,541,541,541,1360,541,541,541,1323,541,541,541,541,541,541,541,541,541,541,541,541,541,2534,541,541,541,1341,541,541,541,541,541,1348,541,541,541,541,541,541,541,541,541,2234,541,541,541,541,0,0,1440,563,563,563,563,563,563,563,563,26028,1360,988,587,587,587,587,587,587,3365,587,587,587,587,587,587,587,587,587,2936,587,587,587,2939,587,2941,587,587,587,587,587,1525,587,587,587,587,587,1532,587,587,587,587,587,587,2392,587,587,587,587,587,587,587,587,587,1472,587,587,587,587,1482,587,563,587,587,587,1557,587,1079,0,1561,0,0,0,1567,0,0,0,0,0,0,1218,1219,0,0,0,0,0,0,0,0,0,1235,0,0,0,0,0,0,1573,0,0,0,1579,0,0,0,0,0,0,0,0,0,0,0,662,0,0,0,0,0,0,0,0,0,0,0,541,541,541,1779,541,541,541,541,541,541,541,541,541,541,541,541,541,2548,541,541,563,1843,563,563,563,563,563,563,563,563,563,1854,563,563,563,563,563,1879,563,563,563,563,563,563,563,563,563,563,3344,563,563,563,563,563,563,563,563,1865,563,563,563,563,563,563,563,2065,2066,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1210,0,2117,0,0,2120,2121,0,0,0,0,0,2127,0,0,0,0,0,0,0,2765,0,0,0,0,0,0,0,0,0,550,573,550,573,550,550,573,541,2213,541,541,541,541,2218,541,541,541,541,541,541,541,541,541,541,2182,541,541,541,541,541,2299,563,563,563,563,2304,563,563,563,563,563,563,563,563,563,563,1917,563,26028,0,587,587,587,2386,587,587,587,587,2391,587,587,587,587,587,587,587,587,587,587,2001,587,587,587,587,587,2006,541,541,541,3037,541,541,541,541,541,541,541,541,541,541,541,541,541,2846,541,541,563,563,3077,563,563,563,563,563,563,563,563,563,563,563,563,563,1887,1888,563,587,587,587,3119,587,587,587,587,587,587,587,587,587,587,587,587,1986,587,587,587,563,563,3247,563,563,563,563,563,563,563,563,563,563,563,563,563,2296,563,563,587,0,0,0,3445,0,0,0,0,3180,0,0,0,0,0,0,0,1242,0,0,0,0,0,0,0,0,0,380,0,0,0,0,0,0,0,0,541,541,541,541,3460,541,541,541,541,541,541,541,541,541,541,2207,541,541,541,541,541,563,587,587,587,587,3491,587,587,587,587,587,587,587,587,587,587,2354,587,587,587,587,587,587,563,563,563,563,3623,587,587,587,587,587,587,587,587,587,587,587,2395,587,587,587,587,587,3631,0,0,0,0,0,0,541,541,541,541,541,541,541,563,563,920,563,563,563,563,563,563,949,951,563,563,563,563,563,3421,563,563,563,3425,563,587,587,587,587,587,587,587,587,587,587,587,587,587,587,3501,388,390,340,0,0,0,0,0,0,339,0,0,340,0,0,0,0,0,0,1598,0,0,0,0,0,0,0,0,1604,0,0,0,387,0,0,0,69632,73728,0,0,0,0,0,65536,0,0,0,0,0,1217,0,0,0,0,0,0,0,1224,0,0,0,0,0,347,0,0,0,0,0,0,0,0,0,0,0,3316,0,0,0,0,0,0,435,339,0,0,447,0,0,471,471,471,471,471,471,471,471,471,553,576,553,576,553,553,576,471,482,471,471,471,500,477,500,500,500,500,500,500,500,500,471,471,477,471,471,471,471,471,471,471,471,471,471,471,481,481,471,482,471,471,553,600,576,576,576,576,576,576,576,600,600,600,553,600,600,600,600,600,600,600,600,576,576,553,576,600,576,600,1,0,0,750,0,0,0,0,0,0,0,0,0,0,0,0,0,1603,0,0,0,0,0,0,663,0,788,0,0,0,0,0,0,0,792,0,0,0,0,0,1231,0,0,0,0,0,0,0,0,0,0,0,2153,0,0,0,0,0,0,0,801,0,0,0,0,0,809,0,0,0,0,706,0,0,0,0,0,0,0,0,715,0,717,0,828,0,0,0,663,831,0,788,0,0,0,0,0,837,0,0,0,0,0,1597,0,0,0,577536,0,0,1602,0,0,0,0,0,0,1257,0,0,0,0,0,0,0,0,0,0,2508,0,0,0,0,0,541,861,541,541,875,541,541,541,541,888,541,541,541,541,906,541,541,541,541,541,3519,541,541,541,541,541,541,541,541,563,563,563,923,563,929,563,563,942,563,563,953,563,958,961,563,563,563,563,979,563,563,563,0,587,587,991,587,587,587,587,587,1962,587,587,587,587,587,587,587,587,587,587,3287,587,587,587,541,587,563,1008,587,587,1022,587,587,587,587,1035,587,587,587,587,1053,587,587,587,587,587,2945,587,587,2948,587,587,2951,587,2952,2953,2954,0,0,0,0,1216,0,0,0,0,1221,0,0,0,0,0,0,0,1258,0,0,0,0,0,0,0,0,0,365,299,0,0,0,0,0,0,1144,0,0,1256,0,0,0,0,0,0,0,0,1235,0,0,0,0,0,0,2891776,0,0,0,0,0,2392064,2412544,0,0,0,0,0,0,2123,0,0,0,0,0,0,0,0,0,0,2727936,0,0,0,3084288,0,0,0,1267,0,0,0,0,0,0,0,541,541,541,541,541,541,541,541,541,1741,541,541,541,1309,541,541,541,541,541,541,541,541,541,541,541,541,541,3045,541,3047,563,587,587,1556,587,587,1079,0,0,0,0,0,0,0,0,0,0,3e3,0,0,0,0,0,1621,0,0,1624,0,1626,0,0,0,0,0,0,0,0,0,0,0,3198,3199,0,0,0,0,0,0,0,1722,0,0,0,0,0,0,0,0,0,0,0,683,684,685,0,0,541,541,541,541,1780,541,541,541,541,541,541,541,541,541,541,541,541,1820,541,541,1360,0,563,563,563,563,563,563,563,563,563,563,1836,563,563,563,563,563,2263,563,563,563,563,563,563,563,563,563,563,1433,563,563,563,563,563,1875,563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,2872,1943,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,2359,0,0,2135,0,0,0,0,0,0,0,0,0,0,0,0,0,1618,0,0,2146,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2484,0,0,0,0,541,541,541,2163,2164,541,541,541,541,541,541,541,541,2180,541,541,541,541,2185,541,541,541,541,541,2228,541,541,541,541,541,541,541,541,541,541,0,0,563,563,563,563,2857,0,0,563,563,563,2247,563,2249,563,563,563,563,563,563,563,563,2320,563,563,563,563,563,0,0,563,563,563,2315,563,563,563,563,563,563,563,563,563,563,0,0,988,587,587,587,587,0,0,587,587,587,2334,587,2336,587,587,587,587,587,587,587,587,1965,1966,1968,587,587,587,587,587,587,587,587,2402,587,587,587,587,587,587,587,587,587,587,541,587,0,0,0,541,587,563,541,541,897,541,541,563,563,970,563,0,997,587,1076,1048,587,78115,1079,0,0,0,0,0,0,0,0,458,1147355,1147355,1147355,1147355,1147355,1147355,1147355,1147355,1147355,1147355,1147355,1147355,1147355,1147355,1147355,1147355,0,0,2438,0,0,0,0,0,0,2443,0,0,0,2446,2447,0,0,0,0,0,1610,0,0,1613,0,0,0,0,0,0,0,0,1584,0,0,0,0,0,0,0,0,1683,0,0,0,0,0,0,0,0,334,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1134,0,0,0,0,2487,0,0,0,0,0,0,0,0,0,0,0,2498,0,0,0,2515,0,0,0,0,0,0,0,0,0,2523,0,541,541,541,541,541,3576,563,563,563,3580,563,563,563,563,563,563,2290,563,563,563,563,563,563,563,563,563,1899,563,563,563,563,563,1906,2537,2538,541,541,541,541,541,2543,541,2545,541,541,541,541,2549,541,541,541,541,541,3614,3615,541,563,563,563,563,563,563,563,563,3424,563,563,587,587,587,587,587,563,563,2598,563,563,2601,2602,563,563,563,563,563,2607,563,2609,563,0,999,1039,587,1050,587,78115,1079,0,0,0,0,0,0,0,0,3184,0,0,0,0,0,0,0,0,2750,0,0,0,0,0,0,0,0,0,2732032,0,0,0,0,0,0,563,563,563,2613,563,563,563,563,563,563,563,563,2619,563,563,563,563,563,3624,587,587,587,587,587,587,587,587,587,587,1967,587,587,587,1972,587,587,563,2639,563,563,563,563,563,563,563,563,563,563,563,563,563,563,1402,563,587,587,587,2673,587,2675,587,587,587,587,2679,587,587,587,587,587,587,2676,587,587,587,587,587,587,587,587,587,1469,1476,587,587,587,587,587,587,587,587,2685,587,587,587,587,587,587,587,587,2693,587,587,587,587,587,1979,587,587,587,587,587,587,587,587,587,587,2926,2927,587,587,587,587,2930,587,587,587,587,587,2701,587,587,587,587,2705,587,587,587,587,587,587,587,2378,2379,587,587,587,587,587,587,587,2406,587,587,2409,2410,587,587,2176,2348,0,2745,0,0,0,0,0,0,0,2751,2752,2753,0,0,0,0,0,0,0,69632,73728,172032,0,0,0,0,65536,0,2772,0,2774,0,0,0,0,2778,0,0,0,0,2783,0,0,2786,541,541,2828,541,541,541,541,541,541,541,541,541,541,541,541,541,1771,541,541,541,541,541,2838,541,541,541,541,541,541,541,541,541,541,541,541,541,3337,563,563,541,2847,541,541,2850,541,541,2853,541,0,0,2854,563,563,563,563,563,2277,563,563,2280,563,563,563,563,563,563,563,3081,563,563,563,563,563,563,563,563,3355,563,587,587,587,587,587,587,563,563,2875,563,563,563,563,563,563,563,563,563,563,563,563,563,2324,0,0,563,563,563,563,2886,563,563,563,563,563,563,563,563,563,563,563,2606,563,2608,563,563,563,563,563,2896,563,563,2899,563,563,2902,563,0,0,2903,587,587,587,587,587,3284,587,587,587,587,587,587,587,541,587,563,541,541,563,563,587,587,587,2921,587,587,2924,587,587,587,587,587,587,587,587,587,587,587,2666,587,587,587,587,0,0,0,0,0,2972,2973,0,0,0,0,2978,0,0,0,0,0,0,0,69632,73728,221184,0,0,0,0,65536,0,3021,0,0,3023,0,0,541,541,3028,541,541,541,541,541,541,541,541,2205,2206,541,541,541,541,541,541,0,0,3160,0,3162,0,0,0,3166,0,0,0,0,0,0,0,0,2518,0,0,0,0,0,0,541,541,541,541,3030,541,541,541,541,3034,3234,3235,563,563,563,563,3239,3240,563,563,563,563,563,3244,563,563,563,563,1445,563,563,563,563,26028,1360,988,587,1455,587,587,0,3632,0,0,0,0,541,541,541,541,541,3641,541,563,563,563,563,587,587,587,587,587,587,587,3263,3264,587,587,587,587,587,587,3435,587,587,587,587,587,587,587,541,563,3268,3269,587,587,587,587,587,3273,587,587,587,587,587,587,587,587,2393,587,587,587,587,587,587,587,3279,587,587,587,587,587,587,587,587,587,587,587,587,541,587,563,2721,541,0,0,0,3312,0,0,0,0,0,0,0,0,0,0,0,0,1633,0,0,0,541,3404,541,541,541,541,541,541,563,563,563,563,563,563,563,563,563,563,563,563,563,563,3419,563,563,563,563,563,563,563,587,587,587,587,587,3113,587,587,587,587,587,0,3443,0,0,3446,0,0,0,3180,0,0,0,0,0,0,0,1583,0,1585,0,0,0,0,0,0,0,1106,0,0,0,0,0,0,0,0,0,756,0,0,0,0,0,0,0,0,541,541,3458,541,541,541,541,3463,541,541,541,541,3468,541,541,541,541,872,541,541,541,541,541,541,541,541,541,541,541,541,1316,541,541,541,563,587,587,3489,587,587,587,587,3494,587,587,587,587,3499,587,587,587,587,587,3364,587,587,587,587,587,587,587,587,587,587,2664,587,587,2667,2668,587,587,563,563,3645,3646,563,563,563,587,587,587,3651,3652,587,587,587,0,541,587,563,541,541,541,541,541,563,563,563,563,587,587,587,587,0,0,0,2730,0,0,563,587,0,541,563,587,3691,3692,3693,3694,0,541,563,587,0,0,0,0,0,0,0,0,3180,0,0,0,0,0,3453,342,343,344,345,346,0,0,0,0,0,0,0,0,0,0,0,713,0,0,0,0,0,0,0,391,0,0,0,0,0,0,0,0,0,0,0,0,1674,0,0,0,345,345,0,346,345,0,344,345,455,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,472,487,496,496,504,496,506,496,496,506,506,496,506,521,521,521,521,521,521,521,521,521,521,521,521,521,521,521,521,554,577,554,577,554,554,577,554,601,577,577,577,577,577,577,577,601,601,601,554,601,601,601,601,601,601,601,601,577,577,554,577,601,577,601,1,656,657,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1590,1591,672,673,0,675,676,0,0,0,0,0,682,0,0,0,0,0,0,0,2804,0,0,0,541,2808,541,541,541,0,0,0,0,692,0,0,0,0,0,0,699,365,365,365,0,0,0,0,0,1658,0,0,0,0,0,0,0,0,0,0,0,3180,0,0,0,3308,0,719,0,721,0,723,0,0,0,0,0,0,0,0,0,733,0,0,0,0,646,752,753,754,0,0,0,0,0,760,761,0,0,0,0,0,1680,0,0,0,0,0,0,0,0,0,0,0,3180,0,3306,0,0,763,764,675,0,0,0,0,0,0,0,0,0,0,779,780,0,0,0,0,0,1696,1697,1698,1699,0,0,0,0,0,0,0,0,755,0,0,0,0,0,0,0,0,772,0,0,0,0,0,0,0,0,782,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1601,0,0,761,0,0,787,0,0,0,0,0,0,0,0,0,794,675,723,0,692,811,0,0,0,0,761,0,0,0,0,0,0,0,1591,0,0,0,0,0,0,0,0,0,1662,0,0,0,0,0,0,0,0,754,820,821,0,0,0,0,0,0,754,0,0,825,699,0,0,0,830,0,0,0,832,0,0,0,692,699,0,0,692,830,830,0,0,0,0,0,0,0,0,0,692,541,541,851,855,858,541,866,541,541,541,881,883,886,541,541,541,898,902,541,541,541,541,541,2541,541,541,541,541,541,541,541,541,541,541,541,541,3044,541,541,541,563,563,563,971,975,563,563,563,563,0,587,587,587,998,1002,1005,587,1013,587,587,587,1028,1030,1033,587,587,587,1045,1049,587,587,587,587,587,1995,587,587,587,587,587,2002,587,587,587,587,587,587,2946,587,587,587,587,587,587,541,587,563,1073,0,998,587,1045,1049,1078,78115,1079,0,0,0,0,0,0,0,0,2779,0,0,0,0,0,0,0,0,303,303,303,303,0,303,303,303,0,0,0,0,1168,0,0,0,0,0,0,0,0,0,0,0,729,0,0,0,0,0,0,1199,0,0,0,0,0,0,0,0,0,0,1209,0,0,0,0,0,0,2912256,0,3207168,2465792,0,0,2719744,0,0,0,0,0,0,541,541,541,3397,541,541,541,541,3401,541,0,0,1214,0,0,0,0,0,0,0,0,0,0,0,0,0,1634,0,0,0,0,1254,0,0,0,0,0,0,0,0,0,0,0,0,0,1665,0,0,1321,541,541,541,541,541,541,541,541,541,541,1331,541,541,1338,541,541,541,541,873,541,541,541,541,541,541,541,541,541,541,541,541,1332,541,541,541,563,563,1443,563,563,563,563,563,563,26028,1360,988,587,587,587,587,587,587,3548,587,3550,587,587,3552,587,587,0,0,0,0,0,0,541,541,541,3639,3640,541,541,563,1501,587,587,1505,587,587,587,587,587,587,587,587,587,587,1515,587,0,0,0,541,587,563,541,541,899,541,541,563,563,972,563,0,1074,587,587,1052,587,78115,1079,0,0,0,0,0,0,0,0,2445312,0,2842624,0,0,0,2637824,0,587,1522,587,587,587,587,587,587,587,587,587,587,1535,587,587,587,587,587,2013,587,541,587,563,541,541,541,541,563,563,563,563,587,587,587,587,0,0,0,0,0,0,1666,0,1668,0,0,0,1670,0,748,0,0,0,0,0,0,0,0,3174,0,0,0,0,0,0,0,0,791,0,0,0,0,0,0,0,0,833,0,0,0,0,0,0,808,0,0,1693,0,0,0,0,0,0,1700,0,0,0,0,0,0,0,1660,1661,0,0,0,0,0,0,0,0,710,0,0,0,0,0,0,0,0,726,0,0,0,0,0,0,0,0,0,274432,274432,274432,0,274432,274432,274432,541,541,1762,541,541,541,541,541,541,541,541,1769,541,541,541,1773,541,541,1778,541,541,541,541,541,541,541,541,541,541,541,541,541,1788,541,541,0,563,1828,563,563,563,563,563,563,563,1835,563,563,563,563,563,563,3250,563,563,563,563,563,563,563,563,563,2321,563,563,563,563,0,0,563,1908,563,563,563,563,563,563,563,563,563,26028,0,587,1924,587,0,0,0,541,587,563,541,541,900,541,541,563,563,973,563,563,563,563,2262,563,563,563,563,563,563,563,563,563,563,563,1434,563,563,563,563,587,587,587,1960,587,587,587,1964,587,587,1969,587,587,587,587,587,587,2688,587,587,587,587,587,587,2695,587,587,563,563,587,587,587,587,0,0,0,2031,0,1082,0,0,0,2033,0,1086,0,0,0,2035,0,1090,0,0,0,2037,0,1094,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1620,2587,0,1825,563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,2610,2650,563,563,563,0,0,0,2653,0,1921,587,587,587,587,587,587,587,3549,587,587,587,587,587,587,0,0,3672,0,541,541,541,541,563,563,0,0,2969,0,0,0,0,0,0,0,0,0,0,0,0,0,2102,0,0,0,0,0,3161,0,0,0,0,0,0,0,0,0,0,0,0,1703,0,0,0,0,0,3319,541,541,541,541,541,541,541,3324,541,541,541,541,541,541,541,2832,541,541,541,541,541,541,541,541,541,2573,541,541,541,541,541,541,587,587,3361,587,587,587,587,587,587,587,587,587,587,587,587,587,2709,587,587,3379,0,0,3382,0,0,0,0,3180,3387,0,0,0,0,0,0,0,1682,0,1684,0,0,0,0,0,0,0,1114,0,0,0,0,1118,0,0,1121,541,541,541,541,3407,541,541,541,563,563,563,3412,563,563,563,563,563,2289,563,563,563,563,563,563,563,563,563,563,2605,563,563,563,563,563,3416,563,563,563,563,563,3422,563,563,563,563,587,587,587,3428,587,0,0,0,541,587,563,850,541,1066,901,541,923,563,1071,974,587,587,587,3432,587,587,587,587,587,3438,587,587,587,587,541,563,563,563,563,2276,563,563,563,563,563,563,2282,563,2284,563,2287,563,587,587,587,587,587,3492,587,587,587,3496,587,587,587,587,587,587,2704,587,587,587,587,587,587,587,587,587,1470,587,587,587,587,587,587,0,0,3657,0,541,541,541,541,541,541,563,563,563,563,563,563,936,563,563,563,563,563,563,563,563,587,3687,3688,3689,3690,0,541,563,587,0,541,563,587,0,0,0,0,0,0,0,0,3180,0,0,3450,3451,0,0,389,0,0,0,393,389,0,0,0,0,0,0,0,0,0,0,0,122880,0,0,0,0,0,0,0,405,0,347,0,69632,73728,0,0,0,0,0,65536,0,0,0,0,0,1709,0,0,0,0,0,0,0,0,0,0,399,0,0,0,0,0,0,0,436,0,0,443,0,0,0,0,0,0,0,0,0,0,0,131072,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,522,522,522,522,522,0,0,0,0,0,0,0,0,0,522,522,522,522,522,522,522,522,522,555,578,555,578,555,555,578,555,602,578,578,578,578,578,578,578,602,602,602,555,602,602,602,602,602,602,602,602,578,578,617,622,602,622,628,1,0,0,0,751,0,0,0,0,0,0,0,0,0,0,0,0,2061,0,0,0,962,563,563,563,563,980,563,563,563,0,587,587,992,587,587,587,587,587,2350,587,587,587,587,587,587,587,587,587,587,1936,587,587,587,587,587,1107,0,0,0,0,1112,0,0,0,0,0,0,0,0,0,0,0,167936,167936,167936,167936,167936,167936,167936,1360,914,563,563,563,1366,563,563,563,563,563,563,563,563,563,1380,563,563,1404,563,563,563,563,563,563,563,563,563,563,563,563,563,2620,563,563,563,1441,563,563,563,563,563,563,563,26028,1360,988,587,587,587,1458,563,587,587,587,587,587,1079,0,1562,0,0,0,1568,0,0,0,0,0,0,1627,1628,1629,0,0,0,0,0,0,0,0,343,0,0,0,0,0,0,0,0,403,0,0,0,0,0,0,0,0,407,407,407,407,0,407,407,407,1574,0,0,0,1580,0,0,0,0,0,0,0,0,0,0,0,808,541,541,852,541,1605,0,0,0,0,0,0,0,0,0,0,0,0,0,1619,0,0,0,0,0,1723,0,0,0,0,0,0,0,0,0,0,0,2625536,0,2699264,2715648,0,1973,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,2373,563,563,587,587,587,587,0,0,1563,0,0,0,0,0,1569,0,1575,0,1581,0,0,0,0,0,0,0,0,0,0,0,1262,0,0,0,0,0,0,0,0,1575,0,0,0,0,0,1581,0,0,0,0,0,0,0,2974,0,0,0,0,0,0,0,0,0,365,0,253952,0,0,0,0,541,541,541,2190,541,541,541,541,2194,541,2196,541,541,541,541,541,541,541,3039,541,541,541,541,541,541,541,541,541,887,541,541,541,541,541,541,563,563,2275,563,563,563,563,2279,563,2281,563,563,563,563,563,563,1896,563,563,563,563,563,563,563,563,563,1397,1399,563,563,563,563,563,587,587,2362,587,587,587,587,2366,587,2368,587,587,587,587,587,587,1465,587,587,587,587,587,587,1480,587,587,0,0,0,0,0,2489,0,0,0,0,0,0,0,0,0,0,0,196608,0,0,0,0,563,563,2625,563,563,563,563,563,563,563,563,563,563,563,563,563,2648,563,563,0,0,0,0,3024,0,541,541,541,541,541,541,541,541,541,541,541,1330,541,541,541,541,0,3380,0,0,0,0,0,0,3180,0,0,0,0,3391,0,0,0,0,0,328,0,69632,73728,0,0,0,0,0,65536,0,3393,0,0,0,0,0,541,3396,541,541,3398,541,541,541,541,541,541,541,3040,541,541,541,541,541,541,541,541,541,1783,541,541,541,541,1789,541,0,3455,541,541,541,541,541,541,541,541,541,541,541,541,541,541,563,563,563,541,862,541,541,541,541,541,541,541,541,541,541,541,541,541,541,1319,541,541,912,563,563,563,563,563,563,935,563,563,563,563,563,563,563,2291,2292,563,563,563,563,563,563,563,2319,563,563,2322,2323,563,563,0,0,1009,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,2697,1059,0,0,0,541,587,563,541,541,541,541,541,563,563,563,563,563,2614,563,563,563,563,563,563,563,563,563,563,3649,587,587,587,587,587,587,587,0,1095,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2513,0,0,1623,0,0,0,0,0,0,0,0,0,0,0,0,0,2130,0,2132,1826,563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,3258,541,3215,541,541,541,541,541,541,541,541,541,541,541,541,541,541,1337,541,587,587,587,3271,587,587,587,587,587,587,587,587,587,587,587,587,2370,587,587,587,0,0,0,0,348,348,350,348,348,348,348,348,348,513,348,348,0,350,348,0,0,348,348,0,0,0,0,349,0,0,0,0,0,329,0,0,0,0,0,0,0,0,0,0,0,2509,0,0,0,0,348,348,348,348,348,348,348,348,348,348,348,348,348,348,348,348,556,579,556,579,556,556,579,556,603,579,579,579,579,579,579,579,603,603,603,556,603,603,603,603,603,603,603,603,579,579,556,579,603,579,603,1,0,0,0,0,722,0,724,0,0,0,0,0,0,0,0,0,299,0,0,0,0,0,0,0,0,0,0,739,0,0,0,0,0,0,0,0,0,0,0,836,541,541,541,541,0,0,0,766,0,0,0,771,0,0,0,0,0,0,0,0,0,1189,0,0,0,0,0,0,541,541,541,870,541,541,541,541,541,890,892,541,541,903,541,541,541,541,541,2569,541,541,541,541,541,541,541,541,541,541,541,541,2835,541,541,541,963,965,563,563,976,563,563,563,563,0,587,587,993,999,587,587,587,587,587,3374,587,541,541,563,563,587,587,0,0,0,0,0,0,3299,0,0,0,587,587,1017,587,587,587,587,587,1037,1039,587,587,1050,587,587,587,587,587,2364,587,587,2367,587,587,587,587,587,587,587,2677,587,587,587,587,587,587,2682,587,0,0,0,1151,0,1153,0,1155,0,0,0,0,0,0,0,0,0,1231,541,541,541,541,541,541,0,1181,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1636,0,0,1198,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1675,0,0,1266,0,0,0,0,0,0,0,1181,541,541,541,541,541,541,541,1326,541,541,541,541,541,541,541,1339,1305,1307,541,541,541,541,541,541,541,541,541,541,541,541,541,541,1358,541,541,541,1343,541,541,541,541,541,541,541,541,1354,1355,541,541,541,541,541,541,2840,541,541,541,541,541,541,541,541,541,541,3056,541,3058,541,541,541,1360,914,563,563,563,563,1367,563,563,563,563,563,563,563,563,563,3242,563,563,563,563,563,563,563,563,563,1421,563,563,563,563,563,563,563,1435,563,563,563,563,563,2627,563,563,563,563,563,563,2635,563,563,563,1459,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,2942,587,587,587,1489,1491,587,587,587,587,587,587,587,587,587,587,587,2707,2708,587,587,587,1554,587,1555,587,587,1558,1079,0,0,0,0,0,0,0,0,0,306,204800,204800,0,205106,204800,1,0,1677,0,0,1679,0,0,0,0,0,0,0,0,0,0,0,1159,0,0,0,0,541,541,541,541,1763,541,541,541,541,541,541,541,541,541,541,541,541,2208,541,541,541,0,563,563,563,563,563,563,563,1833,563,563,563,563,563,563,563,2879,563,563,563,563,563,563,563,563,2644,563,563,563,2647,563,563,563,1858,563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,1857,563,563,563,1909,563,563,563,563,1915,563,563,563,26028,0,587,587,587,587,587,2376,587,587,587,587,587,587,587,587,587,587,2717,541,587,563,541,541,587,587,587,587,1929,587,587,587,587,587,587,587,587,587,587,587,2938,587,587,587,587,587,1991,587,587,587,1996,587,587,587,587,587,587,587,587,2005,587,0,0,0,541,587,563,852,892,541,903,541,925,965,563,976,587,587,587,2011,587,587,587,541,587,563,541,541,541,541,563,563,916,563,563,563,932,563,563,563,563,563,563,563,1864,563,563,563,1868,563,563,1873,563,2077,0,0,0,0,0,0,0,0,2085,0,0,0,0,0,2089,0,0,2091,0,0,0,0,0,0,0,2099,0,0,0,0,0,0,0,3012,3013,0,0,0,0,3018,0,0,2133,2134,0,2136,0,0,0,0,0,0,0,0,0,0,2144,0,0,2149,2150,0,0,0,0,0,2154,0,0,0,0,0,0,0,2160,541,541,541,541,541,541,2167,541,541,541,541,541,541,1288,541,541,541,541,1298,541,541,541,541,541,541,1325,541,541,541,541,541,541,541,541,541,541,1801,541,541,541,541,541,2202,541,541,541,541,541,541,541,541,541,541,541,541,2209,541,541,541,541,541,2815,541,2818,541,541,541,541,2823,541,541,541,541,541,541,3409,541,563,563,563,563,563,563,563,563,3479,563,3481,3482,563,3484,563,541,541,541,2215,541,541,541,541,541,541,541,541,541,541,541,541,895,541,541,541,0,0,2244,563,563,563,563,563,563,563,2252,563,563,563,563,563,563,3534,563,3536,563,563,3538,563,563,587,587,563,563,2301,563,563,563,563,563,563,563,563,563,563,563,563,563,2893,563,563,0,0,2331,587,587,587,587,587,587,587,2339,587,587,587,587,587,587,2715,587,587,587,587,541,587,563,541,541,587,587,587,587,2363,587,587,587,587,587,587,2369,587,2371,587,2374,587,587,2388,587,587,587,587,587,587,587,587,587,587,587,587,587,2918,587,587,0,2474,0,0,0,0,0,0,0,0,0,2482,0,0,0,0,0,0,0,122880,122880,122880,122880,122880,0,122880,0,2105632,0,0,2514,0,0,0,0,0,0,0,0,0,2522,0,0,541,541,541,541,541,3461,541,541,541,3465,541,541,541,541,541,541,1287,541,541,541,541,541,541,541,541,541,541,2546,541,541,541,541,541,541,541,541,541,2540,541,541,541,541,541,541,541,541,541,541,541,541,2222,541,541,541,563,563,563,2599,563,563,563,563,563,2604,563,563,563,563,563,563,2278,563,563,563,563,563,563,563,563,563,2632,563,563,563,563,563,563,2670,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,3143,587,587,587,587,2686,587,587,587,587,587,587,587,587,587,587,587,3125,587,587,587,587,541,541,2723,563,563,563,2725,587,587,587,2727,2728,0,0,0,0,0,0,0,172032,172032,172032,172032,172032,172032,172032,172032,1,0,0,2746,0,2747,0,0,0,0,0,0,0,0,0,0,0,1175,0,0,0,0,0,0,0,0,2762,0,0,0,0,0,0,0,0,0,0,0,1192,0,1195,0,0,2811,541,2812,541,541,541,541,541,541,541,541,541,541,541,541,541,1804,541,541,541,541,541,2849,541,541,541,541,541,0,0,563,563,563,563,563,563,563,563,563,563,563,563,2255,563,2858,563,2859,563,563,563,563,563,563,563,563,563,563,563,563,563,3086,563,563,587,587,2907,587,2908,587,587,587,587,587,587,587,587,587,587,587,3139,587,3141,587,587,0,0,0,2983,0,0,0,0,0,0,0,0,0,0,0,0,2073,0,0,0,0,0,3381,0,0,0,0,0,3180,0,0,0,3390,0,0,0,0,0,0,1659,0,0,0,0,0,0,0,0,0,0,114688,0,241664,258048,0,0,3430,587,587,587,587,587,587,587,587,587,3439,587,587,587,541,563,563,563,563,2303,563,563,563,563,563,563,563,563,563,563,563,26028,0,587,587,587,541,541,541,541,3518,541,541,541,541,541,541,541,541,541,563,563,563,3232,563,563,563,563,563,563,3531,563,563,563,563,563,563,563,563,563,563,587,587,587,3357,587,587,587,587,587,3545,587,587,587,587,587,587,587,587,587,587,0,0,0,0,0,0,3637,541,541,541,541,541,541,3643,563,563,563,563,3647,563,563,587,587,587,587,587,3653,587,587,0,0,0,0,3635,0,541,541,541,541,541,541,541,563,2724,563,563,587,2726,587,587,0,0,0,0,0,0,0,0,3607,0,541,541,541,541,0,3656,0,3658,541,541,541,541,541,541,563,563,563,563,563,563,937,563,563,563,563,563,563,563,0,0,0,0,394,395,0,396,0,0,0,0,0,396,0,0,0,0,0,331,332,333,0,0,0,0,0,0,0,0,0,560,583,560,583,560,560,583,401,0,0,0,0,0,368,376,404,0,0,0,0,0,368,0,0,396,0,0,0,0,0,351,0,0,368,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2744,409,411,0,0,368,376,0,69632,73728,0,0,0,0,427,65536,0,0,0,0,0,2044,2045,0,0,0,0,0,0,0,0,0,361,0,0,0,0,0,361,427,427,437,0,427,0,411,427,456,0,0,0,0,0,0,0,0,106496,0,106496,0,0,0,0,106496,396,0,409,0,497,497,0,497,497,497,497,497,497,497,497,523,523,523,523,523,456,456,456,456,531,456,456,532,456,523,537,523,523,523,537,523,523,523,523,539,557,580,557,580,557,557,580,557,604,580,580,580,580,580,580,580,604,604,604,557,604,604,604,604,604,604,604,604,580,580,618,623,604,623,629,1,0,0,0,643,0,0,0,0,0,0,0,0,0,0,0,0,2101,0,0,0,783,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2757,0,0,0,802,0,0,0,0,0,0,0,0,0,0,0,0,2129,0,0,0,587,587,587,1023,1025,587,587,587,587,587,587,587,587,587,587,587,3275,587,587,587,587,0,0,0,0,1096,0,0,1098,0,0,0,0,0,0,0,0,0,1630,0,0,0,0,0,1636,0,0,0,0,1111,0,0,0,0,0,0,0,0,0,0,0,1207,0,0,0,0,1098,1227,0,0,0,0,0,0,1234,0,0,0,0,0,0,0,0,155648,0,0,0,0,0,0,0,0,1239,0,0,0,0,0,0,0,0,0,0,1239,1248,0,0,0,0,0,0,1681,0,0,0,0,0,0,1687,0,1689,0,0,0,0,1239,1269,1270,0,1239,0,541,541,541,541,541,541,541,3207,3208,541,541,541,541,3212,3213,1278,541,541,541,1282,541,541,1293,541,541,1297,541,541,541,541,541,541,541,3054,541,541,541,541,541,541,541,541,541,1784,541,541,541,541,541,541,1360,914,563,563,563,563,563,563,563,1370,563,563,563,1374,563,563,563,563,1847,563,563,563,563,563,563,563,563,563,563,563,2308,563,563,563,563,1385,563,563,1389,563,563,563,563,563,563,563,563,563,563,563,563,2295,563,563,563,563,563,563,1406,563,563,563,1410,563,563,563,563,563,563,563,563,2901,563,563,0,0,587,587,587,587,587,587,1462,587,587,587,1466,587,587,1477,587,587,1481,587,587,587,587,587,3434,587,3436,587,587,587,587,587,587,541,563,587,1502,587,587,587,587,587,587,587,587,587,587,587,587,587,587,3128,587,0,1622,0,0,0,0,0,0,0,0,0,0,0,0,1635,0,0,0,0,0,2067,0,0,0,0,0,0,0,0,0,2076,1637,0,0,0,1641,0,0,0,1645,0,0,0,1649,0,0,0,0,0,0,2056,0,2057,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1676,0,563,563,1844,563,563,563,563,563,563,563,563,563,563,563,563,563,3540,587,587,1958,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,3127,587,3129,587,587,2010,587,587,587,587,1749,1940,1844,541,541,541,541,563,563,917,563,563,563,934,563,563,948,563,563,563,563,563,1895,563,563,563,1900,563,563,563,563,563,563,1914,563,563,563,563,26028,0,587,587,587,0,2118,0,0,0,0,0,0,2125,0,0,0,0,0,0,0,0,184726,184932,184932,184932,0,184932,184932,184932,0,0,2159,0,541,541,2162,541,541,541,541,541,541,541,541,541,541,2833,541,541,541,541,541,541,541,2227,541,541,541,541,541,541,541,541,541,541,541,0,0,563,2855,563,563,563,0,0,563,563,2246,563,563,563,563,563,563,563,563,563,563,563,3255,563,563,563,563,563,563,2314,563,563,563,563,563,563,563,563,563,563,563,0,0,587,2904,587,0,0,587,587,2333,587,587,587,587,587,587,587,587,587,587,587,3440,587,587,541,563,587,587,587,587,2390,587,587,587,587,587,587,587,587,587,587,587,2928,587,587,587,587,587,587,587,587,2401,587,587,587,587,587,587,587,587,587,587,587,541,587,0,0,0,541,587,563,1064,541,541,905,541,1069,563,563,978,541,541,541,2567,541,541,541,541,541,541,541,541,541,541,541,541,900,541,541,541,2698,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,3277,587,587,0,2759,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1716,0,541,2827,541,541,541,541,541,541,541,541,541,541,541,541,541,541,1758,541,563,2874,563,563,563,563,563,563,563,563,563,563,563,563,563,563,2285,563,587,587,587,2923,587,587,587,587,587,587,587,587,587,587,587,587,2382,587,587,587,0,0,2993,0,0,0,0,0,0,0,0,0,0,0,0,0,2433,0,2435,3171,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2771,3202,541,541,541,541,541,541,541,541,541,541,541,541,541,541,541,2577,3225,541,541,541,541,541,541,541,541,563,563,563,563,563,563,563,2888,563,563,563,563,563,563,563,563,3241,563,563,563,563,563,563,563,587,587,587,3282,587,587,587,587,587,587,587,587,587,541,587,563,2018,541,541,541,2022,563,541,3289,563,3291,587,3293,3294,0,0,0,0,3298,0,0,0,0,0,0,0,1134592,0,365,0,0,0,1134592,0,0,0,1134592,1134592,0,0,1134592,0,0,1134592,0,0,0,3311,0,0,0,0,3315,0,0,0,0,0,0,0,0,0,1725,0,0,0,0,0,0,3318,0,541,541,541,3320,541,541,541,3323,541,541,541,541,541,541,541,1751,541,541,541,541,541,541,541,541,541,2586,0,563,563,563,563,563,3338,563,563,563,3341,563,563,563,563,563,563,563,563,563,563,563,26028,1921,587,587,587,587,3360,587,587,587,587,587,587,587,587,587,587,587,587,587,587,3554,0,0,3403,541,3405,541,541,541,541,541,563,563,563,563,563,563,563,563,563,563,3075,563,563,3418,563,3420,563,563,563,563,563,563,587,587,587,587,587,587,587,3596,587,3598,587,587,0,0,0,0,3560,0,0,0,0,541,541,541,541,541,541,541,541,541,2169,541,541,541,541,541,3574,541,541,563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,1417,3586,563,563,563,587,587,587,587,587,587,587,587,587,587,3599,587,0,0,0,853,1e3,926,849,1065,894,541,541,922,1070,967,563,0,587,587,587,587,587,78115,0,0,0,0,0,0,0,0,0,365,0,305,0,0,0,0,3611,541,541,541,541,541,541,541,563,563,3617,563,3618,563,563,563,563,587,587,587,587,3594,587,587,587,587,587,587,587,541,541,563,563,587,587,3378,0,0,410,356,0,0,0,0,0,69632,73728,0,0,0,0,0,65536,0,0,0,0,0,2122,0,0,0,0,0,0,0,0,0,0,304,304,0,0,0,0,0,0,354,0,0,0,356,0,0,473,473,473,473,473,473,473,478,473,473,473,473,473,473,473,473,473,473,473,478,473,484,473,0,0,473,0,0,0,0,0,0,0,0,524,528,528,528,528,473,473,473,473,473,473,473,478,473,528,524,528,528,528,524,528,528,528,528,540,558,581,558,581,558,558,581,558,605,581,581,581,581,581,581,581,605,605,605,558,605,605,605,605,605,605,605,605,581,581,619,624,605,624,630,1,0,0,0,0,644,0,0,0,0,0,0,0,0,0,0,0,1606,0,0,0,0,688,0,0,0,0,0,0,0,0,0,0,0,365,365,365,0,0,0,0,0,2138,0,0,0,0,0,0,0,0,0,0,0,2768,0,0,0,0,0,0,0,738,0,0,0,644,738,0,744,745,644,0,0,0,0,0,0,790,0,0,0,0,0,0,0,0,0,2058,0,0,0,0,0,0,0,0,799,0,804,0,0,0,0,0,0,804,0,0,0,0,0,644,0,0,0,799,0,804,0,790,0,819,0,0,0,665,0,0,0,0,819,0,0,0,0,0,0,0,2473984,2478080,0,0,0,0,0,0,0,0,0,2767,0,0,0,0,0,0,0,644,0,0,0,0,0,0,0,0,790,0,0,0,0,0,0,0,3165,0,0,0,0,0,0,0,0,0,541,563,541,563,541,541,563,0,0,790,790,0,644,0,0,790,804,842,0,541,848,541,541,541,541,541,2839,541,541,541,2842,541,2844,541,541,541,541,541,541,879,541,884,541,891,541,894,541,541,908,541,541,867,871,877,541,882,541,541,541,541,541,899,541,541,541,541,541,541,2852,541,541,0,0,563,563,563,563,563,563,563,563,563,563,563,563,563,2256,563,563,563,972,563,563,563,563,563,0,587,587,995,587,587,587,587,587,2687,587,587,587,587,587,587,587,587,587,587,2937,587,587,587,587,587,587,587,1014,1018,1024,587,1029,587,587,587,587,587,1046,587,587,587,587,587,1026,587,1031,587,1038,587,1041,587,587,1055,587,1149,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2799,0,0,0,1200,0,0,0,0,0,1205,0,0,0,0,0,0,0,1714,0,0,0,0,0,0,0,0,0,2140,2141,0,0,2143,0,0,1099,0,0,0,1230,0,1232,0,0,0,0,0,0,0,0,0,351,352,353,0,0,0,0,1240,0,0,0,0,0,0,0,0,0,0,1246,0,1249,1200,0,0,0,0,0,2427,0,0,0,0,0,0,0,0,0,0,336,337,0,0,0,0,1230,1252,0,1255,0,0,0,0,0,1130,0,0,0,0,1264,0,0,1149,1264,0,1271,541,541,541,541,1277,1360,914,1362,563,563,563,563,563,1369,563,563,563,563,1375,563,563,563,563,1862,563,563,563,563,563,563,563,563,563,563,563,3084,563,563,563,563,563,563,563,1407,563,563,563,563,1412,563,563,563,563,563,563,563,2900,563,563,563,0,0,587,587,587,563,1419,563,563,563,1426,1428,563,563,563,563,563,563,563,563,563,3346,563,563,563,563,563,563,587,587,1461,587,587,587,587,1467,587,587,587,587,587,587,587,587,2663,587,587,587,587,587,587,587,587,587,1488,587,587,587,587,587,587,587,587,587,587,1499,587,587,587,587,1463,587,587,587,587,587,1475,587,587,587,587,587,587,2014,541,587,563,1791,541,2020,541,1886,563,587,587,1504,587,587,587,587,587,587,587,587,1511,587,587,587,1518,1520,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,2396,2397,2398,587,587,1542,587,0,541,587,563,541,541,541,541,541,563,563,563,563,563,2862,563,2865,563,563,563,563,2870,563,563,563,563,587,587,587,587,587,1079,0,0,1563,0,0,0,1569,0,0,0,0,0,376,0,0,0,0,368,0,385,0,351,0,0,1575,0,0,0,1581,0,0,0,0,0,0,0,0,0,0,303,303,0,0,0,0,1592,1593,0,0,0,0,0,1599,0,0,0,0,0,0,0,0,0,2098,0,2100,0,0,0,0,0,1638,0,0,0,0,0,0,0,1646,1647,0,0,0,0,0,0,0,3197,0,0,0,0,0,0,3200,0,0,1654,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2038,0,1690,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3005,0,1706,1707,0,0,0,1710,0,0,0,0,0,1714,0,0,1717,0,0,1730,0,1732,1706,541,541,541,541,541,541,541,541,541,541,541,2547,541,541,541,541,541,1744,541,541,541,541,1750,541,541,541,541,541,541,541,541,541,541,3220,541,541,541,541,541,541,1761,541,541,541,541,1765,541,541,541,541,541,541,541,541,541,541,3335,541,541,563,563,563,541,1776,541,541,541,1781,541,541,541,541,541,541,541,541,541,541,541,2559,541,541,541,541,1808,541,541,541,541,541,541,541,541,541,541,541,541,541,541,1360,914,563,563,563,563,563,563,563,563,563,563,563,563,1376,563,0,587,587,1046,587,587,78115,1079,0,0,0,0,0,0,0,0,225890,225890,225890,225890,225741,225890,225890,225890,0,563,563,563,563,563,563,563,563,563,563,563,563,1839,563,563,563,563,1877,563,563,563,563,563,563,563,563,563,563,563,2869,563,563,563,563,563,563,1845,563,563,563,563,563,563,563,563,563,563,1856,563,563,563,563,1894,563,563,563,1898,563,563,563,563,563,563,563,1450,563,26028,1360,988,1454,587,587,587,563,563,1860,563,563,563,563,563,563,563,563,563,563,1871,563,563,563,563,1911,1913,563,563,563,563,563,26028,0,587,587,587,587,587,1506,587,587,1508,587,587,587,1512,587,587,587,0,1286,1470,1378,541,541,541,1549,541,563,563,563,1553,563,1876,563,563,563,563,563,563,563,563,563,563,563,563,563,563,2297,2298,563,563,587,2027,587,587,0,0,0,0,0,0,0,0,0,0,3511,0,3513,0,541,0,0,0,2080,2081,0,0,2083,2084,0,0,0,0,0,0,0,0,286720,0,0,0,0,0,0,0,0,0,286720,286720,0,286720,286720,1,0,0,0,2106,0,0,0,0,2109,2110,0,0,0,0,0,0,0,2069,0,0,0,0,0,0,0,0,0,541,564,541,564,541,541,564,541,541,541,541,2175,541,541,2179,541,541,541,2183,541,541,541,541,541,541,1347,541,541,541,541,541,541,541,541,541,563,563,3231,563,563,563,563,2225,541,541,541,541,2230,541,541,541,541,541,541,541,541,0,0,0,0,0,386,0,69632,73728,0,0,0,0,0,65536,0,2242,0,563,563,563,563,563,563,563,563,563,563,563,563,563,563,2325,0,563,563,563,2260,563,563,2264,563,563,563,2268,563,563,563,563,563,587,587,3625,587,3626,587,587,587,587,587,587,1493,587,587,587,587,587,587,587,587,587,2380,587,587,587,587,587,587,2312,563,563,563,563,2317,563,563,563,563,563,563,563,563,0,0,0,0,0,0,587,587,2655,587,587,587,2329,0,587,587,587,587,587,587,587,587,587,587,587,587,587,587,2680,587,587,587,587,587,587,2347,587,587,2351,587,587,587,2355,587,587,587,587,587,587,2925,587,587,587,587,587,587,587,587,587,1471,587,587,587,587,587,587,2399,587,587,587,587,2404,587,587,587,587,587,587,587,587,541,587,0,0,0,854,1001,927,541,541,541,541,910,563,563,563,563,563,1848,563,563,563,563,563,563,563,563,563,563,3097,563,3099,563,563,563,0,0,0,0,2439,0,0,0,0,0,0,0,0,0,0,0,1616,0,0,0,0,0,0,2475,0,0,0,2479,0,0,0,0,0,0,0,0,0,365,0,0,0,0,0,0,541,2525,541,541,541,541,541,541,541,541,541,541,2533,541,541,541,541,541,541,3053,541,541,3055,541,541,541,541,541,541,541,1311,541,541,541,541,541,541,541,541,541,1753,541,541,541,541,541,541,541,2551,541,541,2553,541,2554,541,541,541,541,541,541,541,2561,541,541,541,541,876,878,541,541,541,541,541,541,541,541,541,541,541,1353,541,541,541,541,541,2565,541,541,541,541,541,541,541,541,541,541,541,541,2576,541,541,541,541,1283,541,541,541,541,541,541,541,541,541,541,1304,0,0,0,563,563,2589,563,563,563,563,563,563,563,563,563,563,3537,563,563,3539,563,587,587,563,2597,563,563,563,563,563,563,563,563,563,563,563,563,563,563,2326,0,563,563,2612,563,563,563,2615,563,563,2617,563,2618,563,563,563,563,563,2877,2878,563,563,563,563,2881,563,563,563,563,563,1863,563,563,563,563,563,563,563,563,563,563,3356,587,587,587,587,587,563,563,563,563,2626,563,563,2630,563,563,563,563,563,563,563,563,3345,563,563,563,563,563,563,563,563,563,563,563,2641,2642,563,563,563,563,563,563,563,563,563,563,26028,1360,988,587,587,587,587,2683,587,2684,587,587,587,587,587,587,587,587,2692,587,587,2696,587,0,0,0,1061,1062,1063,851,541,898,902,1068,924,563,971,975,2733,2734,0,0,2737,2738,0,0,0,0,0,0,0,0,0,0,306,307,0,0,0,0,0,2788,0,2790,0,0,0,0,0,0,0,0,0,0,0,0,2457,0,0,0,0,0,0,0,2803,0,0,0,0,0,0,541,541,541,541,541,541,541,3033,541,541,2826,541,541,541,541,541,541,541,541,541,541,541,541,541,541,541,2825,2873,563,563,563,563,563,563,563,563,563,563,563,563,2883,563,563,563,563,1912,563,563,563,563,563,563,26028,0,587,587,587,587,587,2934,587,587,587,587,587,587,587,2940,587,587,587,587,2922,587,587,587,587,587,587,587,587,587,587,587,587,2932,0,2982,0,0,2984,0,0,0,0,0,0,0,0,0,0,0,1632,0,0,0,0,0,0,0,0,2995,0,0,2998,0,2999,0,0,0,0,0,0,0,2096,0,0,0,0,0,0,0,0,0,562,585,562,585,562,562,585,541,3049,541,541,541,541,541,541,541,541,541,541,541,541,541,3061,3089,563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,2621,563,3103,563,563,563,563,563,587,587,587,3111,587,587,587,587,587,587,1507,587,587,587,587,587,587,587,587,587,1983,1984,587,587,587,587,587,587,3131,587,587,587,587,587,587,587,587,587,587,587,587,587,587,2929,587,587,587,587,3145,587,587,587,587,587,541,587,563,541,541,563,563,587,587,0,2962,0,0,0,0,0,0,0,0,0,2507,0,0,0,0,0,0,0,0,0,0,0,3163,0,0,0,0,0,0,0,3169,0,0,0,0,0,438,0,0,0,0,0,0,0,0,0,0,0,2142,0,0,0,0,541,3226,541,541,541,541,541,541,541,563,563,563,563,563,563,563,3095,563,563,563,563,563,563,563,563,2306,563,563,563,563,563,563,563,563,563,3236,563,563,563,563,563,563,563,563,563,563,563,563,563,2309,2310,2311,563,563,3246,563,563,563,563,563,563,3252,563,3254,563,563,563,563,563,1392,563,563,563,563,563,563,563,563,563,563,1853,563,563,563,563,563,563,563,563,587,587,587,587,587,587,587,587,587,3265,587,587,587,587,587,2703,587,587,587,587,587,587,587,587,587,587,2950,587,587,541,587,563,587,587,3281,587,3283,587,587,587,587,587,587,587,587,541,587,563,3153,541,3155,563,3157,587,0,0,0,3301,0,0,0,0,0,0,0,3180,0,0,0,0,0,0,0,3014656,3207168,0,2691072,0,0,3215360,0,0,3309,0,0,0,0,0,3314,0,0,0,0,0,0,0,0,0,365,0,0,0,0,131072,131072,563,563,3339,563,563,563,3343,563,563,563,563,563,563,563,563,563,26028,1360,988,587,587,1456,587,587,587,587,3362,587,587,587,587,587,587,587,587,587,587,587,587,3126,587,587,587,587,587,3371,587,587,587,587,541,541,563,563,587,587,0,0,0,3296,0,0,0,0,0,0,3557,3558,0,0,0,0,0,0,0,541,541,541,3568,541,541,541,541,541,1284,541,541,541,541,541,541,541,541,541,1303,563,563,3588,563,587,587,587,3593,587,587,587,587,587,587,587,587,2690,587,587,587,587,2694,587,587,3601,587,0,0,0,0,0,3604,3605,3606,0,3608,541,541,541,541,541,541,1813,541,541,541,541,1819,541,541,541,1360,563,3621,3622,563,563,587,587,587,587,587,587,587,587,587,3629,3630,563,563,587,587,587,587,3679,0,541,3680,563,3681,587,3682,0,541,541,541,541,1345,541,541,541,541,541,541,541,541,541,541,541,541,2560,541,541,541,358,359,0,0,0,0,0,0,0,365,0,293,0,0,0,0,0,0,306,0,0,0,0,0,0,0,0,0,0,1174,0,0,0,0,0,0,0,0,392,0,0,0,0,0,0,0,0,0,0,0,0,2495,0,0,0,474,474,474,488,0,0,488,359,359,359,510,359,359,359,359,474,559,606,582,582,582,582,582,582,582,606,606,606,559,606,606,606,606,606,606,606,606,582,582,559,582,606,582,606,1,541,541,868,541,541,541,541,541,541,541,541,541,541,904,541,541,541,541,541,2851,541,541,541,0,0,563,563,563,563,563,563,563,563,563,563,2254,563,563,563,587,1015,587,587,587,587,587,587,587,587,587,587,1051,587,587,587,587,587,2909,587,587,587,587,587,587,2917,587,587,587,587,587,1527,587,587,587,587,587,587,587,587,1538,1539,1197,0,0,0,0,0,0,0,1197,0,0,0,0,0,0,0,0,1134592,0,0,1134592,0,0,0,0,0,0,0,0,0,0,0,0,0,2980,0,0,541,541,1280,541,541,541,1289,541,541,541,541,541,541,541,541,541,541,3524,541,541,3526,563,563,1360,914,563,563,563,563,563,563,563,563,563,1372,563,563,563,1381,587,587,1543,0,1289,1473,1381,541,541,541,541,541,563,563,563,563,563,2898,563,563,563,563,563,0,0,587,587,587,587,587,587,2337,587,587,587,587,587,587,587,2352,587,587,587,587,2357,587,587,587,563,587,587,587,587,587,1079,0,0,0,1564,0,0,0,1570,0,0,0,0,0,2440,0,0,0,0,0,0,0,0,0,0,0,2871296,0,0,2424832,0,0,0,1576,0,0,0,1582,0,0,0,0,0,0,0,0,0,365,0,0,0,0,155648,0,0,1606,0,0,0,0,0,0,0,1614,1615,0,0,0,0,0,0,0,3385,3180,0,0,0,0,0,0,0,0,2097,0,0,0,0,0,0,0,0,2070,0,0,0,0,2074,0,0,0,0,0,0,1625,0,0,0,0,0,0,0,0,0,0,0,1648,0,0,0,0,563,1891,563,563,563,563,563,563,563,563,1902,563,563,563,563,563,1408,563,563,563,563,563,563,563,563,563,563,1867,563,563,563,563,563,587,1975,587,587,587,587,587,587,587,587,587,587,587,1987,587,587,587,587,1490,587,587,587,587,587,587,587,587,587,587,587,2381,587,587,587,587,2008,587,587,587,587,587,587,541,587,563,541,541,541,541,563,563,918,563,563,563,563,563,563,563,563,563,563,563,2634,563,563,563,563,0,2243,563,563,563,563,563,563,563,563,563,563,563,563,563,563,2637,563,0,2330,587,587,587,587,587,587,587,587,587,587,587,587,587,587,3276,587,587,587,0,0,2451,0,0,0,0,0,0,0,0,0,0,0,0,0,2471,0,2472,0,0,0,563,563,563,563,563,563,563,2593,563,563,563,563,563,1424,563,563,563,563,563,563,563,563,563,563,2293,563,563,563,563,563,563,587,2659,587,587,587,587,587,587,587,587,587,587,587,587,587,587,2912,587,587,2916,587,587,587,587,0,0,0,0,0,2776,0,0,0,0,0,0,0,0,0,0,372,0,0,373,0,0,563,2895,563,563,563,563,563,563,563,563,563,0,0,587,587,587,587,2335,587,587,587,587,587,587,587,587,587,2947,587,587,587,587,587,541,587,563,587,2906,587,587,587,587,587,587,2913,587,2915,587,587,587,587,587,587,2935,587,587,587,587,587,587,587,587,587,2408,587,587,587,587,2177,2349,587,587,587,2944,587,587,587,587,587,587,587,587,587,541,587,563,563,563,563,563,563,563,587,587,587,541,587,587,587,0,541,587,563,541,1547,541,541,1550,563,1551,563,563,0,0,0,0,0,3561,0,0,0,541,541,541,541,541,541,541,541,3464,541,3466,3467,541,3469,541,541,541,541,3575,541,563,563,563,563,563,563,563,563,563,563,3423,563,563,563,3426,587,587,587,587,563,3587,563,563,587,587,587,587,587,587,587,587,587,587,587,3600,587,587,587,587,3670,587,0,0,0,0,541,541,541,541,563,563,919,925,563,563,563,563,943,563,563,563,563,563,563,3353,563,563,563,587,587,587,587,587,587,587,587,587,587,587,587,3267,0,0,360,0,0,0,0,0,0,365,0,293,0,0,0,0,0,0,331,0,0,0,0,0,0,0,331,0,0,69632,73728,0,419,419,0,0,65536,419,0,0,0,0,375,0,0,0,0,0,0,0,0,0,0,0,1663,0,0,0,0,0,0,360,0,0,0,0,0,0,0,0,0,0,0,0,0,2511,0,0,0,0,0,370,0,0,370,0,0,0,0,0,0,0,0,0,0,0,0,0,2496,0,0,560,607,583,583,583,583,583,583,583,607,607,607,560,607,607,607,607,607,607,607,607,583,583,560,583,607,583,607,1,541,863,541,541,541,541,541,541,541,541,541,541,541,541,541,541,1772,541,1010,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,3123,587,587,587,587,587,587,587,563,1386,563,563,563,563,563,563,563,563,563,563,563,563,563,563,2871,563,0,0,2760,0,0,0,0,0,0,0,0,0,0,0,0,0,2755,0,0,0,0,0,0,0,2985,0,0,0,0,0,0,0,0,0,0,406,0,0,0,0,0,0,0,0,0,3302,0,3303,0,0,0,0,3180,0,0,0,0,0,0,348,0,0,0,0,0,0,0,0,0,0,2801664,0,0,0,0,2142208,0,0,0,361,362,363,364,0,0,365,0,293,0,0,0,0,0,0,348,349,350,0,0,0,0,0,0,0,0,3180,0,3388,0,0,0,0,0,0,362,0,361,0,0,0,69632,73728,0,0,0,0,428,65536,0,0,0,0,0,2463,0,0,0,0,0,0,0,0,0,0,0,2807,541,541,541,541,428,428,0,0,428,0,362,428,457,0,0,0,0,0,0,0,0,1159168,0,1159168,0,0,0,0,1159168,0,0,0,0,498,498,0,505,505,505,505,511,512,505,505,525,525,525,525,525,457,457,457,457,457,457,457,457,457,525,525,525,525,525,525,525,525,525,561,584,561,584,561,561,584,561,608,584,584,584,584,584,584,584,608,608,608,561,608,608,608,608,608,608,608,608,584,584,620,625,608,625,631,1,563,563,563,973,563,563,563,563,563,0,587,587,587,587,587,587,1963,587,587,587,587,587,587,587,587,587,3137,587,587,587,587,587,587,587,0,2105,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2052,0,0,0,0,0,541,2161,541,541,541,541,541,541,541,541,541,541,541,3336,541,563,563,563,0,0,563,2245,563,563,563,563,563,563,563,563,563,563,563,563,2882,563,563,563,0,0,587,2332,587,587,587,587,587,587,587,587,587,587,587,587,3286,587,587,587,587,541,587,563,2550,541,541,541,541,541,541,541,541,541,541,541,541,541,541,541,2210,541,541,541,2579,541,541,541,541,541,541,541,541,541,541,0,0,0,0,0,0,2068,0,0,0,0,0,0,0,0,0,365,0,0,122880,122880,0,0,2711,587,587,587,587,587,587,587,587,587,587,541,587,563,541,541,541,2021,563,563,562,609,585,585,585,585,585,585,585,609,609,609,562,609,609,609,609,609,609,609,609,585,585,562,585,609,585,609,1,0,0,0,705,0,0,0,0,0,0,0,0,0,0,0,0,2742,0,0,0,0,735,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2075,0,541,864,541,541,541,541,541,541,541,541,541,541,541,541,541,541,2238,0,1011,587,587,587,587,587,587,587,587,587,587,587,587,587,587,587,2689,587,587,587,587,587,587,587,587,2716,587,587,587,541,587,563,541,541,1136,0,0,0,0,0,0,0,0,0,0,365,365,0,0,0,0,0,0,2095,0,0,0,0,0,0,0,0,0,0,2375680,0,0,0,0,0,587,1503,587,587,587,587,587,587,587,587,587,587,587,587,587,587,2911,587,2914,587,587,587,587,2919,587,563,587,587,587,587,587,1079,1560,0,0,0,1566,0,0,0,1572,0,0,0,1578,0,0,0,0,0,0,0,0,0,0,0,0,2754,0,0,0,563,563,563,563,2600,563,563,563,563,563,563,563,563,563,563,563,26028,1922,587,587,587,0,0,0,0,647,0,0,0,0,0,0,743,541,541,541,541,541,541,2178,541,541,541,541,541,541,541,541,541,0,2242,563,563,563,563,563,0,0,1594,0,0,0,0,0,0,0,0,0,0,0,0,0,2770,0,0,563,563,563,1846,563,563,563,563,563,563,563,563,563,563,563,563,3085,563,3087,563,2187,541,2189,541,541,541,541,541,541,541,541,541,541,541,541,541,1821,541,1360,0,0,563,563,563,563,2248,563,563,563,563,563,563,563,563,563,2305,563,563,563,563,563,563,563,563,563,0,587,587,994,587,587,587,563,2274,563,563,563,563,563,563,563,563,563,563,563,563,563,563,2894,563,587,2361,587,587,587,587,587,587,587,587,587,587,587,587,587,587,3121,587,587,587,587,587,587,587,587,563,563,541,563,587,563,587,1,2623,563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,3101,563,563,563,563,2651,0,0,0,0,0,0,587,587,587,587,587,587,587,587,587,2340,587,587,587,587,0,0,3179,0,0,0,0,0,0,0,0,0,0,0,0,0,2798,0,0,3245,563,563,563,563,563,563,563,563,563,563,563,563,563,563,563,3257,563,1134592,0,1134592,0,0,0,1134592,1135008,1135008,0,0,0,0,0,1135008,0,0,0,0,0,2478,0,0,0,0,0,0,0,0,0,0,0,3180,0,0,3307,0,1134592,0,1134592,1134592,0,0,0,0,1135203,1135203,1135203,1135203,1134592,1135203,1135203,1135203,1135203,1135203,1135203,1135203,0,1134592,1134592,1134592,1134592,1135203,1134592,1135203,1,0,0,2125824,2125824,2125824,2125824,2125824,2424832,2433024,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,0,0,988,2125824,2125824,2125824,2125824,1147355,1147355,1147355,1147355,458,458,1147355,458,458,458,458,458,458,458,458,1147406,1147406,1147406,1147406,1147406,1147406,1147406,1147406,1147406,1147406,1147406,1147406,1147406,1147406,1147406,1147406,0,0,0,0,0,0,0,0,458,0,0,0,0,0,1147355,1147355,1147355,1147406,1147406,1147355,1147406,1147406,1,12290,3,0,0,0,0,249856,0,0,0,249856,0,0,0,0,0,0,0,69632,73728,0,0,0,0,425,65536,0,1159168,0,0,1159168,0,1159168,1159168,0,1159168,1159168,0,1159168,1159168,1159168,1159168,1159168,1159168,1159168,1159168,1159168,1159168,1159168,1159168,1159168,1159168,1159168,1159168,1159168,1159168,1159168,0,1159168,1159168,0,1159168,1159168,1159168,1159168,1159168,1159168,1159168,1159168,1159168,0,0,0,0,0,0,0,0,0,1159168,0,0,1159168,1159168,1159168,1159168,1159168,1159168,1159168,1159168,1159168,1159168,1,12290,3,78115,293,0,0,0,0,0,0,0,0,0,0,0,0,131072,131072,0,0,1163264,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3170,0,913,2125824,2125824,2125824,2125824,2125824,2424832,2433024,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,2125824,0,0,1453,2125824,2125824,2125824,2125824,106496,0,106496,106496,0,106496,106496,106496,106496,106496,106496,106496,106496,106496,106496,106496,106496,106496,106496,106496,106496,0,0,0,106496,0,0,106496,106496,106496,106496,106496,106496,106496,106496,106496,0,0,0,0,0,0,0,0,0,0,0,2183168,0,0,0,0,0,0,0,0,2134016,0,0,0,0,0,0,0,0,0,0,541,541,541,1275,541,541,0,0,0,3117056,0,0,0,0,0,0,0,0,0,0,0,0,2979,0,0,0,0,3108864,3198976,0,0,3043328,0,3149824,2936832,0,2760704,0,2437120,0,0,0,0,0,0,2107,0,0,0,0,0,0,0,0,0,365,0,293,0,0,0,0,0,0,0,0,2875392,0,0,0,0,0,0,0,0,0,0,2834432],r.EXPECTED=[1039,1047,1048,1046,1042,1052,1056,1060,1064,1068,1446,1074,2948,2053,1092,1446,2490,1670,1213,1080,1084,1085,1446,1089,1446,1446,2818,1098,1103,1108,1187,1181,1181,1114,1118,1446,1933,1123,1446,1136,1098,1098,1204,1108,1108,1171,1181,1181,1130,1134,1446,1446,1140,1446,1147,1098,1152,1108,1108,1109,1181,1181,1182,1158,1446,1446,1238,1668,1098,1148,1108,1108,1206,1181,1181,1165,1446,3130,2162,1098,1099,1108,1177,1181,1215,1219,2143,1136,1098,1186,1110,1181,1191,3130,2153,1099,1108,1180,1217,2659,2819,1197,1173,1201,1104,1235,1210,1224,1154,1228,1232,1168,1243,1247,1251,1255,1259,1261,1266,1262,1270,1274,1278,1282,1286,1290,1220,1295,1890,1296,1446,1446,1446,1446,1375,2489,1446,1446,1446,2385,1446,1446,1446,1446,1446,1446,1446,1446,1076,1446,1446,1446,1446,2986,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1300,1304,1305,1309,1405,1315,1318,1322,1326,1330,1446,1446,1804,1334,2315,1338,2350,1142,1143,1342,1346,1446,1446,2834,1352,1362,1369,1446,1126,1446,2386,1379,1446,1384,1390,1446,2987,2588,1396,2688,1457,1446,1518,1446,1446,2269,1446,1446,1446,1402,1446,1441,1897,1409,1413,1446,1447,1419,1446,1447,1419,1446,1446,1193,1446,2988,3136,2482,1446,2617,1425,1446,1448,1431,1446,1918,1446,2648,1436,1457,1348,1457,1380,1440,1446,1445,3050,1452,1446,1456,1311,1446,1916,2325,1463,2125,1347,1472,2317,1909,1478,3010,2343,2076,2746,2758,1482,2765,2077,1799,1486,2744,1493,1358,1446,1446,2131,1446,2559,1386,1365,1497,1501,1505,1509,1515,2369,1569,2450,1522,2538,1526,1530,1536,2479,2088,1457,1971,1540,1544,1548,1552,1557,1446,2103,1446,1532,1446,2479,2082,1563,1568,2137,1573,1577,3026,1446,1446,2116,1446,1446,3027,1446,1586,1938,1584,2123,1647,1590,1432,1594,1446,2517,1600,1446,2517,1600,1446,2872,1606,1612,1616,1620,1626,1446,1239,1633,1446,1596,1640,3118,2782,1645,1651,1863,1446,1863,1446,1602,1446,2675,2173,1655,2685,1559,1866,2685,3124,1659,1665,2904,2903,3055,2673,1674,1678,3047,2266,2239,1682,1686,1690,1694,1698,2892,1702,1715,1719,1723,1727,1731,1446,2332,1773,1737,1744,1748,1751,1755,1758,1446,1772,2979,1777,1781,2506,1788,1792,1635,1636,1446,2668,2874,1796,1808,2784,1815,1819,1823,2304,1828,1446,2430,1446,1446,2334,1853,2583,1834,1843,1446,2069,1446,1446,1954,1446,1446,2070,1446,1446,1622,1608,1847,1851,1857,1641,1871,1446,2225,1956,1446,2225,1956,1446,2374,1885,1876,1811,1446,1883,1446,1947,1889,1446,1511,1446,1291,2287,1894,1901,1906,1446,1906,1446,1913,1446,1740,1922,1446,1932,1733,1446,1932,1830,1094,1732,1446,1937,2066,2439,2671,1945,1942,2455,1489,2323,1951,1709,1711,1629,1161,1962,1968,1977,1980,1984,1446,1119,1994,1999,2003,2007,2011,2015,2019,2023,1986,1872,2093,1928,2028,2032,2036,1802,2040,1446,1446,2044,1580,2050,2059,2063,2074,2046,1446,2024,2081,1446,2086,1446,1446,1988,2092,2097,2109,2113,1446,2120,1446,1446,2129,1446,1558,2135,1446,1446,2141,2535,2866,2147,1446,1990,1446,1446,3096,1446,1446,3096,1446,1446,1466,2151,2157,2204,1458,2161,1446,2914,1446,1446,1764,1446,3053,2166,2170,1446,2182,1446,2187,1446,2916,1957,2192,2202,2305,1446,2210,2496,1824,3112,2217,1761,1459,1558,2224,2229,2841,2969,2682,2815,2233,2248,2236,2243,1837,1839,2247,2252,2100,1446,1446,1446,1446,2918,1766,2256,2260,2273,2277,2281,2284,1446,2889,1902,2985,2524,2433,2299,2576,2212,2213,2303,1415,1457,2309,1958,2321,2329,1446,2976,1446,1398,1446,1553,2338,2342,2751,1446,2347,2503,2354,2358,1558,2363,1446,1995,2368,1446,1421,2364,2373,2733,2378,2383,2390,3044,1446,2715,1446,1446,1860,1446,1446,1860,2719,2733,2397,2176,2401,1946,2461,1446,1446,2405,1446,1473,2717,2413,2417,2427,2437,3061,1446,2105,1446,1973,2407,2443,2447,2454,2459,2379,1446,2465,2472,2476,2486,2511,2494,2701,2409,2500,2510,2516,2521,2528,2220,2532,2542,2546,2198,2312,2550,2554,2563,2567,2571,2575,1446,2580,2592,2596,2600,2604,2608,2612,2616,1446,2621,2393,1372,2628,2632,2636,2640,2652,3103,1446,2708,2468,2656,2665,2679,2692,1558,2699,1446,2705,1446,2998,2712,1446,2723,2624,1768,1879,3159,1446,2205,2727,1446,1468,2732,1446,2206,2982,1446,3004,2737,2741,3109,2750,1446,2755,1446,1446,2762,1446,1446,2762,2769,3037,2775,2420,2779,1446,2788,1446,1446,2795,1446,1427,2801,3020,2805,2646,1446,2812,1446,2809,1446,3067,2853,2823,2643,2183,2827,2863,2512,2832,2838,1707,1070,2359,2845,2851,2857,1964,1474,3084,2557,2878,2955,3090,2882,2293,2295,2886,2896,2900,2908,2912,1446,1446,1446,2922,2926,2930,2934,2938,2942,2946,1446,2055,2952,1355,2791,2178,2959,1867,2963,1784,2967,1446,2973,2423,2992,2996,3002,1446,2728,1446,1446,3008,1446,3014,3018,1446,3024,2188,3031,3147,1446,1446,2694,1446,1446,2847,1446,1446,2695,3035,1446,3041,3078,3141,3059,1446,1446,3065,1446,1446,3065,1446,1446,3071,1446,3075,1925,3153,1446,1446,3082,1446,1564,3088,1446,1661,3094,3100,2195,3116,1446,3122,1446,3128,1446,3134,1705,3140,2586,2797,1446,3145,2771,1392,3151,1446,3157,2290,2828,2661,2869,2422,3106,2860,2263,1446,1446,1446,1446,1446,1446,1446,1446,1446,1446,1473,3163,3166,3170,3182,3186,3182,3189,3181,3182,3182,3182,3182,3177,3173,3193,3182,3197,3201,3204,3210,3214,3216,3206,3220,3224,3228,3232,3235,3239,3243,3729,3929,3929,3246,3929,3929,5383,3929,3929,3300,3929,3261,3562,3273,4078,3734,3929,3929,3929,3277,3287,3294,4847,3929,3250,3929,3929,3344,3929,4873,4873,4873,4873,3266,4873,4873,3564,3564,3567,3564,3564,3564,3564,3267,3256,3305,3562,3568,3335,4081,3929,3929,3929,3323,4919,3377,4693,3929,3252,3722,3750,3365,3315,3269,3334,4080,3732,3929,3929,3559,4873,5799,4692,3929,3929,3688,3929,3929,3560,4873,4873,4873,4195,4873,4873,4873,4874,3564,3267,3264,3331,3339,3929,3342,3929,3738,3256,3367,3317,3321,3560,4873,3564,3309,3256,3256,3365,3371,3564,3564,3564,3567,3256,3256,3256,3256,3327,4195,3564,3564,3564,3310,3365,3359,3929,3929,3813,3929,3564,3564,3564,3364,3929,5741,3559,4873,4194,3564,3564,3268,3256,4193,4873,3266,3564,3310,3256,3256,3256,3366,3348,3929,3929,3929,3505,3383,3256,3373,3766,3256,3384,3929,4872,4874,3564,3268,3256,3257,3373,4694,3929,3929,3929,3355,3566,3256,3321,4194,3565,3311,3560,3563,3384,3561,3319,3360,3388,3390,4109,3394,3401,3405,3429,3429,3429,3429,3424,3430,3412,3416,3420,3428,3434,3438,3442,3397,3446,3450,3453,3457,3460,3463,3465,3469,3473,3408,3477,3481,3485,3696,3498,4473,3929,3929,3929,3512,3511,3929,3929,3929,3517,4964,4966,3929,3523,3527,3929,3929,3929,3752,3534,3543,3929,3929,3850,3854,3578,3582,3586,3589,3590,3594,3597,3601,3604,3608,3611,3614,3618,3622,3626,4965,3648,3636,5178,3647,5820,3654,4257,3659,3929,3669,4219,3694,3703,3929,5714,3525,3929,3929,3929,3770,3790,3929,5539,3707,3929,3342,5695,3904,3929,3289,3290,3906,3929,4658,4464,5227,4306,3936,3718,3726,3743,3929,3375,3631,3929,3548,5050,5064,3749,3929,3929,3929,3836,3758,3298,3929,3929,3915,3927,4893,3528,3929,3929,3921,4548,5744,4281,3929,3929,3932,5019,3929,5587,5178,3929,3553,3557,3572,5826,3929,3929,4530,3789,3794,3929,3929,3972,4899,3798,3806,3929,3929,3972,5040,3817,3826,3929,3929,3972,5490,3785,3929,3929,3929,3869,4728,4203,3770,3790,4142,3929,3929,3929,3894,4001,3929,3929,3929,3929,3252,3798,4127,4203,3850,3854,4139,3744,3929,3929,3929,3844,5313,5832,4137,4141,3929,3650,3929,3929,4854,4858,4140,3929,3929,3929,3930,5557,3873,3929,3929,3883,3929,5107,3929,5107,4780,3929,4781,5020,3929,3929,3738,5109,3929,3290,3904,3940,3947,3946,3942,3951,3955,3956,3956,3960,3962,3963,3962,3967,3971,3929,3929,4017,4021,4708,3978,3988,3929,3683,3781,3802,3995,4392,3929,5597,5363,3530,3929,4135,4005,4013,3929,3929,4065,4070,4026,3929,3929,4026,3375,3929,3929,4049,4056,4576,3997,5403,5596,3929,3856,4795,3529,3929,3929,3929,3931,4061,3929,3929,3929,3972,4199,3911,3929,3929,3929,3974,5170,3929,3929,4704,3929,4075,5320,4248,5165,3855,4657,4085,3929,3690,4699,5178,3978,3251,3929,3929,4101,3929,5319,4247,5772,5010,4113,3981,3929,3929,4164,4148,4148,4120,3929,3929,4165,4115,4709,4132,3929,3929,4247,4459,5170,3929,3929,4706,3879,4572,4576,5321,4249,4655,3929,3929,4274,3929,3972,4146,4150,3929,3735,3929,3735,4154,4158,3929,3929,4396,3929,3929,3982,3929,3929,3929,4029,4107,3929,4706,3929,4366,4574,4181,5320,5850,4644,4180,5319,4886,4217,4208,4673,3929,3929,4424,5855,3279,5321,4215,3929,3766,4873,4873,3563,3564,4228,3929,4451,4182,4233,4305,4240,4273,4435,4246,4434,4245,4708,4241,3929,3699,4502,3698,4255,5609,4272,5609,4272,3699,5199,5610,4273,4253,3281,4246,4270,3929,3809,3929,4549,3737,3929,3896,3929,5021,3770,4271,3771,4182,5163,5161,3929,3283,5762,3710,4279,4279,4211,4127,4128,4405,3712,4286,3929,3929,3929,4052,3929,5548,3754,4301,3929,3842,3574,4534,4651,5125,3745,4537,4310,4314,4318,4319,4323,4327,4333,4334,4331,4338,4339,4339,4340,3929,3844,4827,3929,3846,3929,3929,4905,3929,3376,5780,4202,3929,3929,3929,4235,4524,5352,5187,4364,4473,3342,4273,3929,3888,5737,4840,4356,4374,4378,4842,5051,4864,3929,4387,4491,3929,4413,3929,3892,5107,3929,3665,3929,3929,4681,3640,4265,4472,3929,4802,3929,4518,3670,4266,4421,3929,4204,4203,3929,4718,4428,4432,3929,3929,3929,4451,4440,4445,3929,3929,4450,4541,4470,3929,3343,3929,3897,3929,4294,3929,4296,3929,5616,3929,5461,4463,3929,5347,4362,5468,4800,3929,3929,4457,4461,5243,3929,4484,3929,3931,5074,3929,3972,4166,4116,3929,3929,3929,4035,4737,3929,3929,3929,4505,3929,5347,4495,3929,3972,5410,5415,4015,4019,3929,3929,4457,4490,4499,3929,3929,3929,4624,5347,3929,4801,3929,3997,3929,5743,4160,3929,3929,3929,4628,3929,5704,4529,3929,3998,5353,5435,3929,5703,4528,3929,4e3,3929,3929,3999,3528,4505,5352,4800,3929,4007,4653,3929,4009,3929,4642,5697,3929,3929,3929,4695,4052,3929,3929,3929,4708,4545,3929,3929,3301,4450,3929,3929,3929,4734,3929,5303,3342,3929,4030,4480,3929,3929,3929,4516,4994,3894,3929,3895,3929,3929,3351,3892,3737,3735,3929,4039,3929,3929,4086,5090,3895,5020,3895,3737,5022,3736,3737,4554,4556,3929,3929,4638,4794,3929,3929,4668,4806,4689,3929,3929,3929,4752,4504,3929,3929,5097,4566,4022,5334,4383,5691,4570,4582,4586,4590,4594,4598,4602,4605,4608,4612,4614,4618,4634,4632,4634,4621,3929,3929,3929,4757,4725,4816,3929,4648,4662,4666,5081,4672,3929,5344,4398,4352,4678,3929,3929,4678,4687,5178,3929,3929,4745,4749,4210,3929,4965,4768,5739,3929,3929,3322,5689,3899,5181,4703,5110,5214,4713,4722,3929,4051,3558,3929,4028,4478,4500,3929,5400,4741,3929,3929,4780,3929,4780,4762,3929,3929,3929,4821,4756,4761,3929,3929,4818,4822,4505,3863,3867,3929,3341,3341,3929,4766,4294,3929,3899,3929,4066,3929,3929,4087,5091,3767,5433,4817,4683,4716,3929,5809,3929,4091,4095,3751,3972,4773,4777,3929,4107,3929,3929,4137,4141,4786,4775,3929,3929,4820,3910,4788,4777,3929,3929,4828,3972,3322,4792,3929,3929,4847,3929,5432,4816,4833,4799,3929,5147,3929,3929,4872,4873,4966,4295,4304,4814,4826,3929,3929,3929,4871,4674,3929,4708,3897,5180,5433,4832,3929,4159,3929,3377,3299,3929,4503,4708,3929,4837,3929,3929,3929,4913,5207,3929,3929,3929,4965,3929,5148,3929,4008,3929,4408,3929,4172,3929,4172,3900,5432,3628,3929,3929,3929,4856,4860,3844,5313,3929,3929,4982,3929,5086,3768,5434,3630,3929,4174,3929,4562,5312,3929,3929,3929,5003,4502,5148,4878,4885,4293,3929,3929,4296,3929,4296,3929,4229,5198,5520,3928,3929,3928,3897,4293,3929,3898,3929,5228,3899,3898,3929,4296,3929,5547,3519,4911,3929,5584,4917,3769,3929,3929,3929,4240,4273,3929,3779,3800,3744,4923,4927,4934,4935,4930,4939,4943,4949,4953,4945,4957,4957,4958,4962,3929,4247,4511,3929,3972,5871,3929,3983,3929,5572,5591,3929,4731,4359,5861,5581,4990,3929,3929,3929,5111,4846,5503,4707,5051,3929,4263,4465,3929,4282,3929,3929,3860,3929,5742,3929,3929,3737,3929,3894,5322,3929,5e3,5007,3507,3929,4290,3929,3929,4449,3929,5018,3929,3929,3642,5026,3929,3929,3929,5177,4628,3929,3300,3929,4346,3674,3681,3547,3929,3539,5030,5034,3929,3929,3929,5337,5040,3822,3929,3929,3641,5042,3929,3929,3929,5368,3643,3929,3929,3929,5405,5793,3929,3929,3929,5453,4626,3377,5052,3929,3929,3929,3721,4501,4368,3929,3546,3490,5496,5308,5793,3929,3929,5485,4370,3929,3929,5068,3972,5073,4863,3929,3513,4450,5122,3375,5406,3842,3929,3655,5793,3929,3739,4707,5781,3929,3990,3929,3929,4006,3299,4452,4369,3929,4439,4444,3929,3895,4547,3886,3929,5078,3929,3929,5048,5304,3929,5095,3929,5486,5051,4451,4368,3929,4474,4050,4057,4293,4450,3929,3929,5228,3929,5453,3929,3929,5072,4862,3929,5101,3929,3512,5742,3929,5241,5105,4986,3751,5323,3296,4502,4381,3929,4486,4034,3929,3684,3783,3744,5062,3929,3929,4209,3929,3929,3929,3560,3929,5118,3929,3929,5111,4852,4515,4382,5129,3929,4502,4176,3929,4350,5314,3549,3929,5797,3929,3929,3929,5526,5795,3929,3929,3929,5603,5136,5144,5227,4451,4236,3929,4975,3676,5063,4465,3744,4042,4464,5152,3929,4507,3865,3929,4121,5622,4297,4174,3342,5169,3342,5169,4514,3537,4561,4558,3929,4559,4453,3929,5213,4466,3929,4520,3929,3929,5170,4045,5196,5187,5174,4560,5185,4558,5193,5203,5211,5218,5221,5222,5226,3929,3929,3929,5725,3929,5232,4690,3929,4524,5352,3677,3929,3929,3929,5771,3929,5740,3929,4274,4848,5238,5247,5773,5254,5251,4704,3918,5260,5266,5262,5268,5272,5276,5280,5284,5287,5291,5294,5293,5298,5302,3929,3929,3929,5742,5425,3929,4694,5050,3546,3490,3494,3929,5318,3929,5327,3923,4464,4390,5227,3929,5816,5331,5341,3929,5782,3744,3929,4547,3770,3929,4547,3929,3736,5322,3929,5189,3929,3929,5189,5361,5367,3374,3929,4693,3929,3929,3829,3929,5372,3929,5411,3929,4704,4292,3929,3892,3929,3929,4517,5713,4819,4170,3929,5416,3991,3929,4708,4852,3929,4186,4190,3929,3765,3775,3800,5841,5084,3929,3929,5111,5157,3753,5377,5381,3929,3929,5117,3929,3929,5388,3821,3929,4708,5234,4550,3929,5393,5392,3929,4751,5041,3744,3929,3929,5048,5036,3929,5373,5397,4693,3501,3929,3929,3929,5766,4862,3929,3929,3929,5789,5048,4769,3378,3492,5429,4705,5779,3929,4781,4779,3929,4505,5110,3876,3929,3929,3929,5791,3972,5439,3839,3929,4815,3929,4778,5514,5443,3839,3929,4815,3929,5108,5841,5843,3929,3929,5139,3929,5050,5457,3492,4485,5465,3770,3878,3929,4821,3929,3929,4417,3929,3929,5472,5477,3929,4881,3929,5701,5473,5482,3929,3929,5140,3929,5478,3929,5420,3877,3546,5494,3714,3632,3929,5514,5508,3929,4907,5500,3929,4890,4880,3929,4193,4873,4873,4195,5742,3379,5773,3631,5525,3929,3929,3929,5870,5524,3760,3896,3929,5819,4519,5513,3488,5530,5351,3929,4708,4846,4159,3929,3929,3929,5155,5159,5336,5518,3761,3929,3929,5512,5536,4519,4522,3989,3929,3929,3929,4913,5518,3929,4964,4293,5179,5352,3929,3929,4125,3929,3929,4247,4402,4086,3353,3929,5556,5570,3929,5570,5578,3983,3929,5573,3929,4971,3751,3929,4253,3929,4261,5594,4522,3929,5601,3984,3929,5574,3929,4978,4224,3929,3929,5608,5571,5607,5351,5349,3929,3929,3929,5206,4827,3929,3929,4897,4901,5733,5834,3662,4782,5757,3879,5132,5614,5467,5620,5626,5630,5634,5638,5642,5646,5650,5654,5658,5662,5666,5670,5673,5677,5681,5685,3929,3929,5256,4275,5756,3929,3972,3929,4996,3929,5561,5708,5718,3929,5722,5729,3929,3888,3998,5749,3929,3929,3929,5311,3929,5731,5753,5459,3929,5014,4985,3929,4344,4461,3929,3875,5420,3929,3878,3929,3929,3929,3736,4071,4506,3929,3766,4521,4967,3929,3929,3929,5387,3820,5761,4485,3929,3929,5424,4691,5113,3998,3929,3929,5435,3873,3929,5112,5770,4234,5849,3929,3929,3929,5447,3929,5732,5805,3929,3972,4093,4097,3929,3905,3929,4408,3670,5786,3929,3929,3929,5447,4693,4517,5803,5807,3929,5046,5056,3929,4434,4245,3929,3770,5321,3929,3649,3929,3929,4977,4223,3929,5830,3929,3929,5450,5042,4423,5838,3929,3929,5507,4159,4423,5838,4248,5847,4578,5805,3929,4548,3929,3929,5813,4423,5854,3929,3929,5552,5542,5859,3929,3929,3929,5564,3929,5786,4235,3929,3929,5566,4810,4103,5807,3990,3929,5059,5357,3929,4549,3929,3929,4549,5416,3929,4674,3929,4868,5532,3929,3929,3929,5710,3929,3831,3998,3929,3929,5712,4818,3973,5866,3929,3929,5739,3929,3972,5865,3929,3929,5745,3929,4964,3929,5180,4523,5824,3832,3929,3929,3929,5777,5545,4965,3929,4409,3929,3675,3738,3973,3547,3929,3929,5841,3929,6277,6502,5875,6282,5878,6547,6266,5881,6546,5889,6232,5882,6232,5892,6221,6267,5888,5883,5884,6232,6232,6232,6232,6414,5887,5883,6232,5891,6232,6232,5894,6232,6232,5922,5937,5949,5938,5939,5949,5944,5950,5944,5944,5940,5944,5941,5952,5941,5944,5946,5945,5946,5946,5946,5946,5947,5941,5948,5952,5948,5944,5942,5954,5956,5958,5962,5960,5959,5964,5966,5967,5971,5967,5968,5967,5969,5974,5973,5976,5978,6293,5998,5875,6282,5896,6871,6437,6282,6321,6282,6282,6282,5917,6456,6456,6456,6456,5991,5906,6379,6455,5990,6019,5991,5904,5904,5904,6456,6456,5926,5899,6456,6456,5997,6282,6408,6410,6282,5932,6282,5933,6464,6024,6282,6282,6379,5924,6282,6282,5924,6282,6362,6010,5984,6282,6003,6282,6362,6282,6282,6282,6004,6456,5906,6455,5990,5904,5902,6456,6456,6456,5906,6457,6019,6019,5904,5904,6456,6456,6282,6282,6282,5980,5917,6456,6456,6456,6455,5905,6456,6445,5926,5926,5926,5926,6032,6032,6008,5932,6282,6282,6282,6434,6024,6282,6019,5904,6456,6282,5896,6873,6282,6282,6282,6474,5903,6457,6019,5904,6456,6229,5904,6456,6456,6456,6018,6457,6019,5991,5905,5906,6282,6282,6282,5984,6282,6282,6282,5925,6543,5905,6456,6456,6456,6282,5905,6229,5905,6229,5905,6282,6650,6437,6043,6515,6056,6672,6088,6052,6515,6520,6054,6060,6058,6515,6515,6083,6528,6101,6761,6518,6521,6516,6517,6063,6065,6068,6061,6057,6515,6515,6519,6515,6070,6072,6066,6515,6515,6515,6515,6125,6522,6074,6515,6515,6076,6515,6523,6079,6082,6515,6081,6055,6091,6089,6090,6093,6114,6092,6113,6114,6114,6114,6114,6115,6117,6116,6117,6117,6118,6119,6120,6121,6121,6095,6097,6099,6122,6123,6124,6524,5900,6515,6518,6103,6108,6110,6104,6105,6109,6106,6112,6121,6127,6129,6282,5899,6282,5925,6463,6321,6282,6294,6006,6378,6282,6508,6282,6449,6646,6218,6604,6282,6524,6291,6282,6774,6282,6270,6282,6282,6282,6e3,6e3,6027,6161,6282,6282,5895,6375,6282,6312,6230,6366,6265,5876,6282,6282,6282,6015,6406,6282,6284,6027,6027,6137,6282,6282,6379,6281,6372,6028,6159,6282,5899,6282,6282,6282,6573,6282,6282,6467,6282,6311,6312,6372,6282,6282,6282,6019,6019,5904,5904,5904,5904,5905,6456,6456,6031,6154,6158,6282,6149,6273,6282,6163,6282,6677,6280,6166,6279,6682,6685,6501,6173,6175,6178,6178,6178,6178,6176,6181,6180,6181,6181,6183,6181,6185,6187,6188,6188,6188,6194,6193,6194,6193,6193,6189,6191,6190,6190,6196,6196,6198,6203,6202,6204,6208,6203,6205,6199,6200,6210,6206,6212,6282,6282,5896,6282,6282,6282,6512,6282,6150,6135,6320,6500,6163,6282,6282,6282,6026,6282,6026,6166,6282,6282,6282,6027,6221,6282,6505,6282,6282,6282,6032,6238,6282,6241,6282,5899,6451,6282,5913,6669,6401,6238,6282,6282,6282,6037,6245,6282,6282,6282,6040,6282,6282,6225,6248,6282,6282,5916,6722,6377,6247,6249,6282,6282,5924,6370,6252,6253,6282,6282,5932,6282,6282,6530,5924,6254,6282,6282,6254,6282,6322,6228,6282,5933,6378,6282,6378,6282,6452,6282,6432,6317,6282,5917,6086,6725,6727,6216,6086,6726,6450,6231,5926,5933,6008,6008,6008,6282,6282,6282,5918,6282,6282,6282,5923,6309,6683,6282,6282,6282,6148,6216,6308,6310,6282,6282,6282,6149,6282,5903,6397,6605,6282,6282,5933,5933,5933,6780,6282,6282,6282,6229,6282,6282,6282,5933,5924,6316,5917,6723,6377,5916,6722,6323,6448,6454,6216,6332,6436,6683,6282,5917,6328,6465,6450,6217,6231,6160,6436,6683,6328,6448,6454,6216,6610,6436,6683,6282,6221,6602,6310,6282,5984,5899,5925,6229,6435,6500,6281,6722,6013,6465,6450,6160,6603,6683,6282,6282,6231,6218,6310,6282,5984,6282,6283,6043,5914,6282,5933,6328,6465,6450,6647,6604,6282,6e3,6282,6282,6283,6277,6707,6733,6282,6722,6465,6230,6396,6282,6282,6282,6235,6686,6282,6708,6281,6282,6e3,6437,6362,6338,6279,6282,6282,6283,6444,6145,6683,6282,6282,5933,6003,6282,6282,6282,6006,6375,6465,6708,6282,6005,6282,6282,6287,6289,6282,6548,6282,6282,5933,6282,6282,6282,6137,6282,6282,6020,6282,6375,6282,6282,6282,6281,6471,6218,6683,6282,6282,6282,6370,5984,6282,6010,6795,5984,5899,6282,6282,6661,6282,6e3,6137,6282,6282,6282,6282,5896,5914,6704,6273,5928,6340,6344,6503,6348,6349,6349,6350,6355,6352,6349,6349,6349,6349,6354,6355,6355,6355,6356,6357,6357,6357,6357,6357,6358,6359,6359,6359,6359,6383,6360,6382,6382,6382,6361,6282,6282,6282,6283,6043,5903,5897,6485,6376,6395,6425,6282,6282,6282,6293,6291,6338,6282,6282,6282,6284,6282,6282,6345,6282,6282,6291,6282,6282,6282,6230,5876,6282,6407,6282,6282,6282,6286,6282,6282,6037,6411,6417,6282,6282,5979,5903,6470,6313,6647,6281,6282,6282,6408,6416,6418,6282,6282,5979,6525,6458,6342,6422,6282,6282,6282,6288,6282,6664,6731,6282,6012,6e3,6282,6012,6335,6310,5985,6504,6282,6282,6273,6470,6372,6273,6504,6385,6282,6282,6412,6257,6598,6600,6282,6411,6413,6597,6599,6599,6282,6282,6282,6291,6410,6282,6322,6451,5926,5926,6008,6008,6008,5932,6236,6282,6282,6282,6292,5982,6282,6283,6442,6050,6013,6609,6259,6424,6310,6282,5919,5920,6282,6282,6011,5916,6282,6664,6282,6282,6023,6437,6459,5983,6013,6594,6700,6437,6282,6424,6437,6282,6282,6235,6480,6481,6282,6282,6133,6282,6282,6485,6376,6647,6282,6016,6282,6282,5933,6330,6454,6217,6683,6282,6282,6484,5917,5929,6011,6608,6259,6425,6282,6486,5983,6013,6594,6786,6437,6282,6282,6282,6294,6282,6283,6484,5917,5983,6013,6531,6471,6282,6282,6146,6683,6282,6282,6155,6282,6282,6385,6282,6322,6282,6282,6275,6493,5917,5983,6324,6259,6729,6282,6019,6019,6019,5991,5904,6277,5903,6531,6011,6148,6282,6282,6282,6234,6531,6282,6282,6282,6322,6282,6133,6372,6505,6282,6230,6282,6282,6171,6756,6531,6046,6834,6437,6282,6282,6285,6530,5924,6282,6684,6282,6149,6282,6282,6282,6325,6285,6530,6045,6159,6024,6046,6386,6282,6282,6282,6372,6282,6294,6282,6530,6464,6386,6282,6282,6215,6224,5933,5924,6410,6282,6040,6282,6482,6282,6282,6282,6531,6536,6024,6282,6282,6282,6370,5987,6282,6535,6282,6282,6227,6282,6282,6282,6378,6378,6378,6282,6452,5994,6282,6282,6282,6394,6282,6282,6282,6404,6539,6333,6683,6282,6020,6282,6282,6282,6341,6282,6570,6300,6569,6301,6370,6545,6300,6302,6303,6303,6303,6303,6303,6304,6551,6554,6552,6561,6552,6555,6563,6564,6563,6563,6563,6563,6564,6556,6557,6557,6557,6557,6558,6372,6273,6282,6282,6243,6282,6509,6566,6282,6282,6271,6213,6282,6283,6568,6282,6021,6041,6282,6027,6282,6321,6282,6006,6282,6282,6027,6462,6282,6282,6282,6572,6282,6168,6282,6575,6510,6282,6029,6282,6282,6282,6588,5907,5909,5911,6282,6036,6282,6282,6388,6407,5908,5910,6282,6282,6272,6282,6526,6282,5916,6322,6282,6378,6282,6020,6282,6278,6282,6282,6394,5924,6278,6282,6283,6502,6365,6282,6579,6282,6282,6275,6525,5914,5992,6371,6048,6365,6367,6369,6282,6282,6277,6531,6046,6275,6583,5993,6047,6256,6256,6366,6368,6282,6282,6452,6e3,6282,6282,6282,6408,6282,6027,6282,6372,6526,6282,5899,6539,6664,6682,6282,6282,6282,6146,6282,6482,6282,6006,6451,6282,6282,6282,5985,6458,6342,6313,6136,6152,6282,6037,6378,6282,6282,6282,6421,6584,6020,6437,6683,6282,6027,6321,6282,6451,6646,6152,6282,6282,6282,6410,6282,6282,6282,6375,6282,6e3,6526,6322,6533,6682,6282,6408,6282,6282,6282,6505,6282,6282,6278,6282,6282,6282,6143,6371,6472,6282,6282,6282,6423,6539,6437,6683,6282,6040,6148,6040,6149,6273,6229,6682,6282,6470,6282,6282,6283,6282,6282,6282,6524,6548,5933,6282,5933,6282,6434,6410,6282,6282,6434,6537,6282,6664,6491,6866,5876,6482,6491,6282,6282,6283,6410,6282,6427,6282,6282,5980,6011,6276,6037,6285,6038,6590,6783,6607,6612,6620,6619,6620,6620,6616,6620,6620,6618,6622,6620,6614,6613,6624,6627,6626,6627,6627,6628,6630,6630,6634,6630,6632,6631,6630,6630,6630,6636,6638,6638,6637,6637,6640,6641,6282,6132,6282,6282,5895,5924,5984,6282,6640,6637,6640,6640,6640,6640,6505,5903,6644,6331,6649,6282,6282,6229,5879,6282,6527,6653,6148,6282,6137,5924,6282,6282,6282,6230,6281,6282,6282,6306,6402,6433,6346,6656,6658,6549,6282,6282,6283,6475,6423,6282,6282,6282,6437,6682,5912,6668,6400,6282,6157,6282,6282,5896,6451,5980,5917,6029,6221,6281,6282,6282,6524,6282,6282,6282,5930,6664,6282,6264,6683,6694,6282,6282,6282,6452,6282,6282,6282,6285,5897,6453,6654,6282,6346,6295,6282,6282,6283,6582,6297,6282,6681,6282,6164,6024,6282,6133,6451,6282,5988,6281,6285,5980,6458,6371,6263,6647,6281,6282,6676,6282,6676,6514,5903,6680,6465,6489,5995,6282,6282,6283,6496,6085,6282,6513,6525,6679,6688,6688,6399,6713,6281,6282,6286,6282,6037,6282,6282,6282,5899,6691,6497,6724,6488,6734,6282,6282,6282,6498,6282,6282,6282,6255,6282,6283,6691,6696,6724,6488,6698,6331,6222,6282,6282,6282,6431,6296,6282,6282,6282,6499,6282,6282,5903,6464,6231,6734,6696,6134,6733,6281,6693,6282,6282,6434,6282,6282,6282,6277,6525,6531,6471,6218,6231,6490,6282,6282,6282,6504,6548,6282,6283,6278,6282,6275,6710,6733,6282,6169,6282,6282,6509,6003,6712,6282,6282,6282,6508,5899,6702,6490,6282,6282,6283,6861,6854,6033,6858,6646,6218,6604,6282,6282,6282,6577,6286,6282,6394,6282,6229,6019,6019,6019,6019,5904,6286,6282,6137,6282,6229,6282,6292,6229,6282,6282,6372,6505,6282,6437,6683,6282,6229,6146,6265,6282,6283,6525,5927,6539,6729,6683,6282,6282,6650,6282,6282,6283,6863,6364,6024,6282,6282,6283,6869,6282,6362,6282,6362,6363,6010,6592,5925,6719,6591,6593,6718,6721,5934,5934,5935,6469,6736,5934,5934,5934,6736,6738,6742,6740,6739,6744,6746,6751,6751,6752,6753,6747,6748,6748,6748,6749,6751,6751,6751,6753,6753,6753,6753,6758,6754,6755,6282,6282,6285,6282,6282,6282,6014,6760,5981,6007,6728,6282,6763,6282,6282,6285,6496,6531,6282,6283,6768,6770,6282,6282,6282,6539,6392,6282,6282,6392,6027,6156,6282,6282,6293,6586,6282,6373,6281,6285,6507,5903,6470,6326,6505,6659,6282,6234,6229,5879,6283,6496,6703,6776,6704,6777,6282,6282,6282,6548,6282,5918,6025,6282,6282,6026,6282,6286,6505,6394,6282,6291,6370,6282,6370,6282,6496,6085,6831,6147,6603,6683,6282,6380,6282,6282,6370,6282,6282,6282,6003,6282,6294,6336,6e3,6282,6239,6846,6282,6260,6282,6282,6282,6642,6379,6282,6505,6336,6283,6702,6782,6319,6218,6604,6282,6785,5999,6282,6269,6663,6282,6140,6282,6282,6393,6282,5982,6724,6319,6218,6604,6539,6310,6282,6282,6375,6370,6375,6788,6320,6310,6e3,6e3,6282,6282,6375,6548,6282,6282,6282,6275,6084,6447,6282,6788,6429,6683,6282,6282,6664,6683,6282,6273,6541,6148,6282,6394,6e3,6282,6274,6282,6003,6318,6429,6683,6282,6275,5898,5915,6282,6282,6370,6370,6370,6664,6282,6683,6282,6410,6282,6699,6282,6275,5901,5982,6724,6291,6282,6282,6531,6689,6282,6282,6220,6282,6537,6282,6282,6282,6664,6146,6282,6282,6434,6281,6282,6282,6282,6020,6282,6006,6410,6408,6282,6027,6282,6282,6250,6843,6434,6410,6282,6434,6410,6282,6408,6282,6322,6282,6410,6410,6027,6282,6275,6702,6231,6490,6146,6282,6146,6282,6282,6282,6671,6146,6410,6408,6408,6409,6409,6409,6409,6409,6282,6282,6282,6682,6282,6282,6285,6039,6216,6221,6281,6286,6282,6282,6790,6543,6282,6505,6003,6282,6559,6282,6282,6559,6508,6792,6282,6077,6139,6282,6282,6379,6374,6793,6806,6798,6798,6801,6799,6798,6799,6798,6797,6803,6808,6807,6808,6805,6808,6809,6810,6813,6814,6815,6816,6815,6818,6811,6813,6811,6813,6820,6822,6822,6821,6821,6824,6824,6824,6824,6821,6824,6824,6828,6825,6826,6282,6282,6282,6683,6282,6282,6689,6439,6282,6277,6715,6282,6282,6282,6510,6035,6282,6282,6282,6684,6282,6282,6282,6233,6282,6716,6282,6580,6419,6282,6836,6282,6281,6282,6282,6283,6293,6337,6282,6838,6840,6282,6282,6666,6282,6143,6292,6282,6282,6292,6282,6282,6282,6378,6845,6282,6282,6845,6282,6487,6282,6282,6391,6391,6651,6282,6282,6282,6730,6512,6282,6282,6282,6830,6853,5931,6141,6428,6602,6604,6282,6282,6409,6410,6282,6852,6854,6856,6450,6002,6282,6001,6003,6282,6645,6231,6281,6282,6282,6674,6282,6167,6282,6282,6e3,6282,6e3,6034,6282,6282,6282,6848,6282,6394,6683,6282,6282,5933,6003,5933,6003,6282,6830,6645,6231,6222,6487,6282,6024,6282,6282,6693,6282,6282,6282,6464,6861,6854,6009,6377,6525,5931,6011,6465,6282,6830,5885,6282,6282,6702,5931,6319,6436,6683,5916,6282,6282,5925,6282,6282,6448,6282,6282,6931,6282,6282,6451,6282,6282,6282,6860,6044,6011,6465,6449,6647,6310,6282,6282,6142,6436,6683,6282,6282,6732,5924,5984,6861,5983,6377,6454,5982,6321,6282,6294,6138,6282,6461,6151,6437,6282,6282,6732,6772,6860,5983,6465,6151,6437,6282,6865,6282,6282,6282,6860,6337,6437,6282,6282,6466,6282,6144,6436,6282,6282,6282,6868,6219,6282,6282,6282,6468,6282,6282,6732,6282,5916,6262,6299,6282,5918,5918,5918,6378,6282,6282,6526,6282,6148,6282,6283,6293,6586,6292,6502,6437,6282,6282,6282,6294,6282,6292,6294,6282,6282,6474,5980,6293,6291,6282,6282,6292,6502,6282,6278,6294,6282,6278,6282,6282,6765,6282,6229,6362,6282,6230,6320,6500,6282,6505,6282,6292,6502,6282,6505,6233,6282,6282,6293,6282,6282,6282,6474,6478,6291,6278,6282,6282,6292,6531,6536,6875,6255,6282,6282,6476,6282,6006,6255,6282,6006,6390,6282,6314,6049,6282,6877,6878,6881,6375,6880,5930,6282,6532,6542,6883,6596,6258,6885,6596,6595,6595,6886,6889,6595,6888,6890,6889,6892,6897,6893,6894,6895,6899,6900,6905,6905,6901,6902,6912,6903,6902,6906,6905,6906,6905,6906,6907,6909,6908,6910,6914,6908,6908,6922,6922,6921,6922,6923,6916,6917,6918,6920,6926,6925,6928,6460,6371,6282,6282,6482,5932,6321,6285,6282,6282,6494,6371,6930,6282,6282,6282,6505,6494,6371,6130,6282,6282,6282,6505,6506,6282,6282,6282,6312,6933,6282,6505,6935,6282,6282,6937,6282,6282,6767,6769,6290,6282,6282,6282,6505,6692,6011,6313,6291,6233,6282,6282,6508,6282,6282,6282,5916,6030,6282,6423,6170,6282,6282,6170,6011,6372,6282,5916,6282,6282,5915,6451,6440,6282,6282,5918,6322,6283,6939,6446,6705,6447,6291,6282,6282,6294,6282,6282,6282,6438,6282,6282,6511,6282,6282,6282,6842,6149,6282,6149,6282,6282,6779,6007,6728,6310,6282,6282,6319,6310,6282,6282,6363,6282,6692,6011,6372,5916,6282,5915,6282,6282,6511,6268,6286,6282,5924,6282,6282,6833,6282,6279,6398,6282,6282,6014,6282,6282,6282,6601,6282,6439,5933,6133,6282,6148,6282,6255,6282,5914,5931,6705,6282,6282,6850,6282,6850,6282,6372,6282,6372,6282,6149,6282,6505,5914,5931,6291,6282,6282,5982,6585,6282,6282,6660,6291,6043,5914,6291,6282,6282,6283,6043,5899,6282,6282,1048576,1073741824,2147483648,1075838976,2097152,2147483648,4194560,4196352,-2143289344,-2143289344,4194304,2147483648,37748736,541065216,541065216,-2143289344,4198144,4196352,276901888,8540160,4194304,1,4,16,64,0,48,64,32,64,64,96,0,59,140224,5505024,-1887436800,0,63,64,128,0,64,256,0,110,110,8425488,4194304,1024,0,128,128,512,512,1024,1024,2048,0,256,256,257,37748736,742391808,742391808,775946240,-1371537408,775946240,4718592,775946240,775946240,171966464,171966464,775946240,239075328,-1405091840,-1371537408,239075328,171966464,64,4718592,2097216,4720640,541589504,4194368,4194368,541065280,541589504,4194400,-2143289280,4194368,-2143285440,-2143285408,-2143285408,-2109730976,775946336,776470528,-2143285408,776470528,775946304,775946304,-1908404384,775946304,-1908404384,2,8,32,128,1024,4096,0,260,8392704,0,1856,64,524288,64,896,8192,67108864,2147483648,96,262144,262144,8192,0,288,8388608,0,384,0,512,2048,2048,4096,4096,8192,8192,16384,0,520,520,96,524288,524288,0,2432,2048,268435456,0,24576,0,32768,32768,65536,1048576,128,2048,12288,0,12289,0,16384,16384,32768,0,1864,2,16,1024,98304,131072,262144,1048576,512,5120,2,536936448,80,528,528,2097168,2097168,268435472,524304,1048592,2097168,24,560,48,2097680,1048592,3145744,1048592,20,560,48,3146256,2097552,3146256,28,16,8192,2,2098064,163577856,17,21,112,128,3584,8192,2228784,-161430188,-161430188,-161429680,-161430188,-161429676,-161430188,-161298576,-160299088,-161298576,-161298572,-160774288,-160299084,146804757,146812949,146862101,146863389,146863389,148960541,-161429740,-161429676,146863421,148960541,146863389,-161429676,-160905388,-161429676,-161429676,-161429675,-161349072,-161349072,-161347728,-161347728,-161298572,-161298572,-160774284,-161298572,16,262160,-18860267,-160774284,-18729163,0,58368,159383552,0,65536,2097152,8388608,33554432,0,66048,0,77824,524288,33554432,1024,262144,2097152,16777216,67108864,0,131072,524288,134217728,2147483648,1,32768,196608,0,131328,131072,16777216,100663296,-1073741824,164096,0,131584,2621440,0,139264,0,150528,0,235712,16777216,1073774592,1226014816,100665360,-2046818288,100665360,100665360,-2044196848,1091799136,1091799136,1091803360,1091799136,1158908e3,1158908001,1192462432,1192462448,1192462448,1870638912,1870655296,1870638912,1200851056,1200851056,1091799393,1870655296,1870655296,1870655312,1870655316,1870655312,1870655312,1870638928,1870655316,1870655316,1870655317,1870655316,1879043952,1870655348,1870655316,1879027568,1879043952,1879043956,0,284672,229440,1048576,2097152,67108864,134217728,8,4194304,16777216,2147483648,1224736768,0,503616,2048,100663296,0,524288,2097152,4194304,4194304,0,40,0,44,-2046820352,0,605503,231488,1090519040,1157627904,1191182336,9437184,231744,52e4,7864320,1862270976,0,867391,1862270976,1862270976,16252928,0,1048576,4194304,25165824,25165824,33554432,8192,98304,1048576,8388608,134217728,268435456,4194432,3145728,0,24,0,29,0,32,1,2,2,4,0,2147483648,2147483648,0,0,1,0,2,0,3,240,19456,262144,0,4,8,0,6,0,7,150994944,0,1049088,1049088,12845065,12845065,147193865,128,6144,4194304,251658240,536870912,1073741824,32768,131072,1048576,4096,83886080,117440512,0,3145728,16777216,134217728,0,2048,8192,229376,0,2304,1536,8192,1536,65536,4194304,67108864,536870912,9216,33554432,262144,134217728,1073741824,50331649,9476,512,8192,134218240,1050624,0,5242880,1275208192,4194312,4194312,4194344,4194312,541065224,4203820,-869654016,-869654016,1279402504,1279402504,2143549415,2143549415,2143549423,0,8388608,4096,4194304,8388608,16777216,33554432,-1946157056,0,8192,131072,0,1792,0,1024,8192,65536,0,1536,2147483648,2143549423,2143549423,2143549415,1,16777216,268435456,512,139264,2760704,-872415232,0,19947520,0,33554432,67108864,1073741824,1073741824,262144,7340032,-2030043136,0,331776,300,4203520,4333568,1275068416,0,16777216,16777216,0,999,259072,4194304,4194432,999,29619200,2113929216,0,58720256,1007,1007,0,67108864,402653184,536870912,2048,1048576,16777216,536870912,300,0,83886080,0,2097152,134217728,536870912,0,49152,0,57344,102,384,6,96,128,3072,16384,65536,524288,1048576,0,4096,262144,524288,96,96,64,384,512,4096,65536,131072,1024,65536,262144,131072,32768,256,384,8192,33554432,2147483648,1,6,8,8388608,96,384,104,104,0,134217728,6,32,256,512,65536,7340032,50331648,0,8396800,4,32,384,4,64,1024,2097152,268435456,1073741824,8,262144,512,0,8,8,16,0,9,0,12,0,15,16,16,17,20,16,20,48,16,28,0,16,32,0,21,53,4,256,1024,524288,536870912,256,65536,16777216,1073741824,2048,524288,32,4100,1024,134217728,1049088,270532608,2097152,2097152,0,23,5505537,5587457,5591557,147202057,5587457,13894153,-1881791493,-1881791493,0,134218752,5587465,5587457,13894153,13894153,81003049,4456448,8388608,5505024,0,134348800,134348800,82432,0,142606336,5,86528,41,75497472,81920,0,184549376,2,56,64,2048,262144,536870912,2048,134217728,-2113929216,16777216,1073743872,268435968,229376,25165824,92274688,25165824,100663296,402653184,1610612736,0,100663296,134217728,805306368,1073741824,8388608,268567040,16384,229376,4194304,117440512,2113544,68423701,-2079059883,-2079059947,85200917,68423701,68423765,68489237,68423701,68423701,72618005,68423701,68425749,68423703,85200919,69488664,69488664,70537244,70537245,70537245,-2076946339,-2076946403,70537245,70537309,70539293,-2022351745,-2022351617,-2022351745,-2022351617,-2022351617,0,243269632,256,32768,1048576,33554432,134217728,-2113929216,0,268435456,49152,266240,1048576,67108864,-2080374784,-2080374784,268288,0,301989888,0,318767104,282624,0,536870912,28,3145728,192,351232,7340032,5,16,1049104,12,3145728,13,0,1073741825,192,3072,20480,0,1073741824,0,262144,2621440,-1073741824,20480,65536,268435456,14,32,512,131072,268435456,192,1024,64,32768,33554432,268435456,4,128,3840,16384,262144,128,2097152,1073741824,4,2097152,4,50331648,67108864,128,50331648,1073741824,128,268435968,268435968,268436032,256,1536,2048,16384,98304,393216,524288,268435456,536870912,9216,0,4194304,50331648,2147483648,256,536871168,-1879046336,-1879046334,-1879046326,-1879046334,1073744256,-1879046334,-1879046326,-1845491902,-1878784182,268444480,268436288,268436288,268436289,268444480,268444480,2100318149,2100318149,2100326341,0,1090519040,2100326341,2100326341,1,16,536936448,576,0,832,8192,1,4036,19939328,2080374784,0,1,1024,768,8192,16384,19922944,2080374784,1,128,4096,3584,16384,524288,8,33554432,402653184,2048,3145728,128,131072,268500992,4243456,4096,1048588,0,1258292224,1124073472,1124073472,1124073488,1124073474,1124073472,1392574464,1124073472,1073754113,12289,1124073472,12289,12289,1098920193,1132474625,1098920209,1132474625,1132474625,1124085761,1124085761,1124085777,1258304513,1124085761,1400975617,2132360255,2132622399,2132360255,2132622399,2132622399,2141011263,0,2140749119,2141011263,2,16384,3145728,12545,25165824,268435456,12305,13313,12561,0,78081,327155712,605247,1058013184,1073741824,867647,1066401792,0,1,12288,256,8388608,1,30,32,1024,2048,339968,327680,524288,1,14,16,14,1024,16384,4194304,134217728,1,12,1024,8,134217728,8,536870912,9437184,0,68157440,137363456,0,137363456,66,66,100680704,25165824,26214400,92274688,25165952,93323264,92274688,92274688,92274720,93323264,25165890,100721928,100721928,100787464,100721664,100721664,100853e3,100721928,125977600,125846528,125846528,125846560,125977600,125977600,127026176,281843,281843,1330419,281843,126895104,125846528,1330419,1330419,72633587,5524723,72633587,92556531,93605107,93605107,5524723,5524723,39079155,97799411,127290611,127290611,131484915,0,17408,33554432,1073741824,58624,0,124160,189696,148480,50331648,2,112],r.TOKEN=["(0)","PragmaContents","DirCommentContents","DirPIContents","CDataSection","Wildcard","EQName","URILiteral","IntegerLiteral","DecimalLiteral","DoubleLiteral","StringLiteral","PredefinedEntityRef","'\"\"'","EscapeApos","ElementContentChar","QuotAttrContentChar","AposAttrContentChar","PITarget","NCName","QName","S","S","CharRef","CommentContents","EOF","'!'","'!='","'\"'","'#'","'#)'","'$'","'%'","''''","'('","'(#'","'(:'","')'","'*'","'*'","'+'","','","'-'","'-->'","'.'","'..'","'/'","'//'","'/>'","':'","':)'","'::'","':='","';'","'<'","'<!--'","'</'","'<<'","'<='","'<?'","'='","'>'","'>='","'>>'","'?'","'?>'","'@'","'NaN'","'['","']'","'after'","'all'","'allowing'","'ancestor'","'ancestor-or-self'","'and'","'any'","'append'","'array'","'as'","'ascending'","'at'","'attribute'","'base-uri'","'before'","'boundary-space'","'break'","'by'","'case'","'cast'","'castable'","'catch'","'check'","'child'","'collation'","'collection'","'comment'","'constraint'","'construction'","'contains'","'content'","'context'","'continue'","'copy'","'copy-namespaces'","'count'","'decimal-format'","'decimal-separator'","'declare'","'default'","'delete'","'descendant'","'descendant-or-self'","'descending'","'diacritics'","'different'","'digit'","'distance'","'div'","'document'","'document-node'","'element'","'else'","'empty'","'empty-sequence'","'encoding'","'end'","'entire'","'eq'","'every'","'exactly'","'except'","'exit'","'external'","'first'","'following'","'following-sibling'","'for'","'foreach'","'foreign'","'from'","'ft-option'","'ftand'","'ftnot'","'ftor'","'function'","'ge'","'greatest'","'group'","'grouping-separator'","'gt'","'idiv'","'if'","'import'","'in'","'index'","'infinity'","'inherit'","'insensitive'","'insert'","'instance'","'integrity'","'intersect'","'into'","'is'","'item'","'json'","'json-item'","'key'","'language'","'last'","'lax'","'le'","'least'","'let'","'levels'","'loop'","'lowercase'","'lt'","'minus-sign'","'mod'","'modify'","'module'","'most'","'namespace'","'namespace-node'","'ne'","'next'","'no'","'no-inherit'","'no-preserve'","'node'","'nodes'","'not'","'object'","'occurs'","'of'","'on'","'only'","'option'","'or'","'order'","'ordered'","'ordering'","'paragraph'","'paragraphs'","'parent'","'pattern-separator'","'per-mille'","'percent'","'phrase'","'position'","'preceding'","'preceding-sibling'","'preserve'","'previous'","'processing-instruction'","'relationship'","'rename'","'replace'","'return'","'returning'","'revalidation'","'same'","'satisfies'","'schema'","'schema-attribute'","'schema-element'","'score'","'self'","'sensitive'","'sentence'","'sentences'","'skip'","'sliding'","'some'","'stable'","'start'","'stemming'","'stop'","'strict'","'strip'","'structured-item'","'switch'","'text'","'then'","'thesaurus'","'times'","'to'","'treat'","'try'","'tumbling'","'type'","'typeswitch'","'union'","'unique'","'unordered'","'updating'","'uppercase'","'using'","'validate'","'value'","'variable'","'version'","'weight'","'when'","'where'","'while'","'wildcards'","'window'","'with'","'without'","'word'","'words'","'xquery'","'zero-digit'","'{'","'{{'","'{|'","'|'","'||'","'|}'","'}'","'}}'"]},{}],11:[function(e,t,n){"use strict";n.TreeOps={flatten:function(e){var t=this,n="";if(!e)throw new Error("Invalid node found");return e.value===undefined?e.children.forEach(function(e){n+=t.flatten(e)}):n+=e.value,n},concat:function(e,t,n){var r=n?{}:e;n&&Object.keys(e).forEach(function(t){r[t]=e[t]});var i=Object.keys(t);return i.forEach(function(e){r[e]=t[e]}),r},removeParentPtr:function(e){e.getParent!==undefined&&delete e.getParent;for(var t in e.children){var n=e.children[t];this.removeParentPtr(n)}},inRange:function(e,t,n){if(e&&e.sl<=t.line&&t.line<=e.el){if(e.sl<t.line&&t.line<e.el)return!0;if(e.sl===t.line&&t.line<e.el)return e.sc<=t.col;if(e.sl===t.line&&e.el===t.line)return e.sc<=t.col&&t.col<=e.ec+(n?1:0);if(e.sl<t.line&&e.el===t.line)return t.col<=e.ec+(n?1:0)}},findNode:function(e,t){if(!e)return;var n=e.pos;if(this.inRange(n,t)===!0){for(var r in e.children){var i=e.children[r],s=this.findNode(i,t);if(s!==undefined)return s}return e}return},astAsXML:function(e,t){var n="";t=t?t:"",e.value&&(n+=t+"<"+e.name+">"+e.value+"</"+e.name+">\n"),n+=t+"<"+e.name+">\n";var r=this;return e.children.forEach(function(e){n+=r.astAsXML(e,t+"  ")}),n+=t+"</"+e.name+">\n",n}}},{}],12:[function(e,t,n){"use strict";var r=e("./parsers/JSONiqParser").JSONiqParser,i=e("./parsers/XQueryParser").XQueryParser,s=e("./parsers/JSONParseTreeHandler").JSONParseTreeHandler,o=e("./compiler/translator").Translator,u=e("./formatter/style_checker").StyleChecker,a=e("../lib/completion/completer"),f=n.createStaticContext=function(){var t=e("./compiler/static_context").StaticContext;return new t},l=function(e,t){return e?(Object.keys(t).forEach(function(n){e[n]===undefined&&(e[n]=t[n])}),e):t},c=function(e,t,n){var r=e.substring(0,t),i=e.substring(0,n),s=r.split("\n").length,o=t-r.lastIndexOf("\n"),u=i.split("\n").length,a=n-i.lastIndexOf("\n"),f={sl:s-1,sc:o-1,el:u-1,ec:a-1};return f};n.XQLint=function(e,t){t=t?t:{},t=l(t,{styleCheck:!1});var n;this.getAST=function(){return n};var h=[];this.getMarkers=function(){return h},this.getMarkers=function(e){var t=[];return h.forEach(function(n){(n.type===e||e===undefined)&&t.push(n)}),t},this.getErrors=function(){return this.getMarkers("error")},this.getWarnings=function(){return this.getMarkers("warning")},this.getCompletions=function(t){return a.complete(e,n,d,t)};var p=!1;this.hasSyntaxError=function(){return p};var d=t.staticContext?t.staticContext:f(),v=t.fileName?t.fileName:"",m=v.substring(v.length-".jq".length).indexOf(".jq")!==-1&&e.indexOf("xquery version")!==0||e.indexOf("jsoniq version")===0,g=new s(e),y=m?new r(e,g):new i(e,g);try{y.parse_XQuery()}catch(b){if(!(b instanceof y.ParseException))throw b;p=!0,g.closeParseTree();var w=c(e,b.getBegin(),b.getEnd()),E=y.getErrorMessage(b);w.sc===w.ec&&w.ec++,h.push({pos:w,type:"error",level:"error",message:E})}n=g.getParseTree(),t.styleCheck&&(h=h.concat((new u(n,e)).getMarkers()));var S=new o(d,n);h=h.concat(S.getMarkers())}},{"../lib/completion/completer":6,"./compiler/static_context":4,"./compiler/translator":5,"./formatter/style_checker":7,"./parsers/JSONParseTreeHandler":8,"./parsers/JSONiqParser":9,"./parsers/XQueryParser":10}]},{},[12])(12)}),ace.define("ace/mode/xquery_worker",["require","exports","module","ace/lib/oop","ace/worker/mirror","ace/mode/xquery/xqlint"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("../worker/mirror").Mirror,s=e("./xquery/xqlint"),o=s.XQLint,u=function(e){return function(t){var n=e,r=n[t],i={},s={};return r.functions.forEach(function(e){s[t+"#"+e.name+"#"+e.arity]={params:[]},e.parameters.forEach(function(n){s[t+"#"+e.name+"#"+e.arity].params.push("$"+n.name)})}),r.variables.forEach(function(e){var n=e.name.substring(e.name.indexOf(":")+1);i[t+"#"+n]={type:"VarDecl",annotations:[]}}),{variables:i,functions:s}}},a=t.XQueryWorker=function(e){i.call(this,e),this.setTimeout(200),this.opts={styleCheck:!1};var t=this;this.sender.on("complete",function(e){if(t.xqlint){var n={line:e.data.pos.row,col:e.data.pos.column},r=t.xqlint.getCompletions(n);t.sender.emit("complete",r)}}),this.sender.on("setAvailableModuleNamespaces",function(e){t.availableModuleNamespaces=e.data}),this.sender.on("setModuleResolver",function(e){t.moduleResolver=u(e.data)})};r.inherits(a,i),function(){this.onUpdate=function(){this.sender.emit("start");var e=this.doc.getValue(),t=s.createStaticContext();this.moduleResolver&&t.setModuleResolver(this.moduleResolver),this.availableModuleNamespaces&&(t.availableModuleNamespaces=this.availableModuleNamespaces);var n={styleCheck:this.styleCheck,staticContext:t};this.xqlint=new o(e,n),this.sender.emit("markers",this.xqlint.getMarkers())}}.call(a.prototype)}),ace.define("ace/lib/es5-shim",["require","exports","module"],function(e,t,n){function r(){}function w(e){try{return Object.defineProperty(e,"sentinel",{}),"sentinel"in e}catch(t){}}function H(e){return e=+e,e!==e?e=0:e!==0&&e!==1/0&&e!==-1/0&&(e=(e>0||-1)*Math.floor(Math.abs(e))),e}function B(e){var t=typeof e;return e===null||t==="undefined"||t==="boolean"||t==="number"||t==="string"}function j(e){var t,n,r;if(B(e))return e;n=e.valueOf;if(typeof n=="function"){t=n.call(e);if(B(t))return t}r=e.toString;if(typeof r=="function"){t=r.call(e);if(B(t))return t}throw new TypeError}Function.prototype.bind||(Function.prototype.bind=function(t){var n=this;if(typeof n!="function")throw new TypeError("Function.prototype.bind called on incompatible "+n);var i=u.call(arguments,1),s=function(){if(this instanceof s){var e=n.apply(this,i.concat(u.call(arguments)));return Object(e)===e?e:this}return n.apply(t,i.concat(u.call(arguments)))};return n.prototype&&(r.prototype=n.prototype,s.prototype=new r,r.prototype=null),s});var i=Function.prototype.call,s=Array.prototype,o=Object.prototype,u=s.slice,a=i.bind(o.toString),f=i.bind(o.hasOwnProperty),l,c,h,p,d;if(d=f(o,"__defineGetter__"))l=i.bind(o.__defineGetter__),c=i.bind(o.__defineSetter__),h=i.bind(o.__lookupGetter__),p=i.bind(o.__lookupSetter__);if([1,2].splice(0).length!=2)if(!function(){function e(e){var t=new Array(e+2);return t[0]=t[1]=0,t}var t=[],n;t.splice.apply(t,e(20)),t.splice.apply(t,e(26)),n=t.length,t.splice(5,0,"XXX"),n+1==t.length;if(n+1==t.length)return!0}())Array.prototype.splice=function(e,t){var n=this.length;e>0?e>n&&(e=n):e==void 0?e=0:e<0&&(e=Math.max(n+e,0)),e+t<n||(t=n-e);var r=this.slice(e,e+t),i=u.call(arguments,2),s=i.length;if(e===n)s&&this.push.apply(this,i);else{var o=Math.min(t,n-e),a=e+o,f=a+s-o,l=n-a,c=n-o;if(f<a)for(var h=0;h<l;++h)this[f+h]=this[a+h];else if(f>a)for(h=l;h--;)this[f+h]=this[a+h];if(s&&e===c)this.length=c,this.push.apply(this,i);else{this.length=c+s;for(h=0;h<s;++h)this[e+h]=i[h]}}return r};else{var v=Array.prototype.splice;Array.prototype.splice=function(e,t){return arguments.length?v.apply(this,[e===void 0?0:e,t===void 0?this.length-e:t].concat(u.call(arguments,2))):[]}}Array.isArray||(Array.isArray=function(t){return a(t)=="[object Array]"});var m=Object("a"),g=m[0]!="a"||!(0 in m);Array.prototype.forEach||(Array.prototype.forEach=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=arguments[1],s=-1,o=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError;while(++s<o)s in r&&t.call(i,r[s],s,n)}),Array.prototype.map||(Array.prototype.map=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=Array(i),o=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var u=0;u<i;u++)u in r&&(s[u]=t.call(o,r[u],u,n));return s}),Array.prototype.filter||(Array.prototype.filter=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=[],o,u=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var f=0;f<i;f++)f in r&&(o=r[f],t.call(u,o,f,n)&&s.push(o));return s}),Array.prototype.every||(Array.prototype.every=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&!t.call(s,r[o],o,n))return!1;return!0}),Array.prototype.some||(Array.prototype.some=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0,s=arguments[1];if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");for(var o=0;o<i;o++)if(o in r&&t.call(s,r[o],o,n))return!0;return!1}),Array.prototype.reduce||(Array.prototype.reduce=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduce of empty array with no initial value");var s=0,o;if(arguments.length>=2)o=arguments[1];else do{if(s in r){o=r[s++];break}if(++s>=i)throw new TypeError("reduce of empty array with no initial value")}while(!0);for(;s<i;s++)s in r&&(o=t.call(void 0,o,r[s],s,n));return o}),Array.prototype.reduceRight||(Array.prototype.reduceRight=function(t){var n=F(this),r=g&&a(this)=="[object String]"?this.split(""):n,i=r.length>>>0;if(a(t)!="[object Function]")throw new TypeError(t+" is not a function");if(!i&&arguments.length==1)throw new TypeError("reduceRight of empty array with no initial value");var s,o=i-1;if(arguments.length>=2)s=arguments[1];else do{if(o in r){s=r[o--];break}if(--o<0)throw new TypeError("reduceRight of empty array with no initial value")}while(!0);do o in this&&(s=t.call(void 0,s,r[o],o,n));while(o--);return s});if(!Array.prototype.indexOf||[0,1].indexOf(1,2)!=-1)Array.prototype.indexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=0;arguments.length>1&&(i=H(arguments[1])),i=i>=0?i:Math.max(0,r+i);for(;i<r;i++)if(i in n&&n[i]===t)return i;return-1};if(!Array.prototype.lastIndexOf||[0,1].lastIndexOf(0,-3)!=-1)Array.prototype.lastIndexOf=function(t){var n=g&&a(this)=="[object String]"?this.split(""):F(this),r=n.length>>>0;if(!r)return-1;var i=r-1;arguments.length>1&&(i=Math.min(i,H(arguments[1]))),i=i>=0?i:r-Math.abs(i);for(;i>=0;i--)if(i in n&&t===n[i])return i;return-1};Object.getPrototypeOf||(Object.getPrototypeOf=function(t){return t.__proto__||(t.constructor?t.constructor.prototype:o)});if(!Object.getOwnPropertyDescriptor){var y="Object.getOwnPropertyDescriptor called on a non-object: ";Object.getOwnPropertyDescriptor=function(t,n){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(y+t);if(!f(t,n))return;var r,i,s;r={enumerable:!0,configurable:!0};if(d){var u=t.__proto__;t.__proto__=o;var i=h(t,n),s=p(t,n);t.__proto__=u;if(i||s)return i&&(r.get=i),s&&(r.set=s),r}return r.value=t[n],r}}Object.getOwnPropertyNames||(Object.getOwnPropertyNames=function(t){return Object.keys(t)});if(!Object.create){var b;Object.prototype.__proto__===null?b=function(){return{__proto__:null}}:b=function(){var e={};for(var t in e)e[t]=null;return e.constructor=e.hasOwnProperty=e.propertyIsEnumerable=e.isPrototypeOf=e.toLocaleString=e.toString=e.valueOf=e.__proto__=null,e},Object.create=function(t,n){var r;if(t===null)r=b();else{if(typeof t!="object")throw new TypeError("typeof prototype["+typeof t+"] != 'object'");var i=function(){};i.prototype=t,r=new i,r.__proto__=t}return n!==void 0&&Object.defineProperties(r,n),r}}if(Object.defineProperty){var E=w({}),S=typeof document=="undefined"||w(document.createElement("div"));if(!E||!S)var x=Object.defineProperty}if(!Object.defineProperty||x){var T="Property description must be an object: ",N="Object.defineProperty called on non-object: ",C="getters & setters can not be defined on this javascript engine";Object.defineProperty=function(t,n,r){if(typeof t!="object"&&typeof t!="function"||t===null)throw new TypeError(N+t);if(typeof r!="object"&&typeof r!="function"||r===null)throw new TypeError(T+r);if(x)try{return x.call(Object,t,n,r)}catch(i){}if(f(r,"value"))if(d&&(h(t,n)||p(t,n))){var s=t.__proto__;t.__proto__=o,delete t[n],t[n]=r.value,t.__proto__=s}else t[n]=r.value;else{if(!d)throw new TypeError(C);f(r,"get")&&l(t,n,r.get),f(r,"set")&&c(t,n,r.set)}return t}}Object.defineProperties||(Object.defineProperties=function(t,n){for(var r in n)f(n,r)&&Object.defineProperty(t,r,n[r]);return t}),Object.seal||(Object.seal=function(t){return t}),Object.freeze||(Object.freeze=function(t){return t});try{Object.freeze(function(){})}catch(k){Object.freeze=function(t){return function(n){return typeof n=="function"?n:t(n)}}(Object.freeze)}Object.preventExtensions||(Object.preventExtensions=function(t){return t}),Object.isSealed||(Object.isSealed=function(t){return!1}),Object.isFrozen||(Object.isFrozen=function(t){return!1}),Object.isExtensible||(Object.isExtensible=function(t){if(Object(t)===t)throw new TypeError;var n="";while(f(t,n))n+="?";t[n]=!0;var r=f(t,n);return delete t[n],r});if(!Object.keys){var L=!0,A=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],O=A.length;for(var M in{toString:null})L=!1;Object.keys=function I(e){if(typeof e!="object"&&typeof e!="function"||e===null)throw new TypeError("Object.keys called on a non-object");var I=[];for(var t in e)f(e,t)&&I.push(t);if(L)for(var n=0,r=O;n<r;n++){var i=A[n];f(e,i)&&I.push(i)}return I}}Date.now||(Date.now=function(){return(new Date).getTime()});var _="	\n\f\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\ufeff";if(!String.prototype.trim||_.trim()){_="["+_+"]";var D=new RegExp("^"+_+_+"*"),P=new RegExp(_+_+"*$");String.prototype.trim=function(){return String(this).replace(D,"").replace(P,"")}}var F=function(e){if(e==null)throw new TypeError("can't convert "+e+" to object");return Object(e)}})
\ No newline at end of file
diff --git a/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/ui-ace.min.js b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/ui-ace.min.js
new file mode 100644
index 0000000..c69ced8
--- /dev/null
+++ b/themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/ui-ace.min.js
@@ -0,0 +1,7 @@
+/**
+ * angular-ui-ace - This directive allows you to add ACE editor elements.
+ * @version v0.2.3 - 2016-02-09
+ * @link http://angular-ui.github.com
+ * @license MIT
+ */
+"use strict";angular.module("ui.ace",[]).constant("uiAceConfig",{}).directive("uiAce",["uiAceConfig",function(a){if(angular.isUndefined(window.ace))throw new Error("ui-ace need ace to work... (o rly?)");var b=function(a,b,c){if(angular.isDefined(c.workerPath)){var d=window.ace.require("ace/config");d.set("workerPath",c.workerPath)}angular.isDefined(c.require)&&c.require.forEach(function(a){window.ace.require(a)}),angular.isDefined(c.showGutter)&&a.renderer.setShowGutter(c.showGutter),angular.isDefined(c.useWrapMode)&&b.setUseWrapMode(c.useWrapMode),angular.isDefined(c.showInvisibles)&&a.renderer.setShowInvisibles(c.showInvisibles),angular.isDefined(c.showIndentGuides)&&a.renderer.setDisplayIndentGuides(c.showIndentGuides),angular.isDefined(c.useSoftTabs)&&b.setUseSoftTabs(c.useSoftTabs),angular.isDefined(c.showPrintMargin)&&a.setShowPrintMargin(c.showPrintMargin),angular.isDefined(c.disableSearch)&&c.disableSearch&&a.commands.addCommands([{name:"unfind",bindKey:{win:"Ctrl-F",mac:"Command-F"},exec:function(){return!1},readOnly:!0}]),angular.isString(c.theme)&&a.setTheme("ace/theme/"+c.theme),angular.isString(c.mode)&&b.setMode("ace/mode/"+c.mode),angular.isDefined(c.firstLineNumber)&&(angular.isNumber(c.firstLineNumber)?b.setOption("firstLineNumber",c.firstLineNumber):angular.isFunction(c.firstLineNumber)&&b.setOption("firstLineNumber",c.firstLineNumber()));var e,f;if(angular.isDefined(c.advanced))for(e in c.advanced)f={name:e,value:c.advanced[e]},a.setOption(f.name,f.value);if(angular.isDefined(c.rendererOptions))for(e in c.rendererOptions)f={name:e,value:c.rendererOptions[e]},a.renderer.setOption(f.name,f.value);angular.forEach(c.callbacks,function(b){angular.isFunction(b)&&b(a)})};return{restrict:"EA",require:"?ngModel",link:function(c,d,e,f){var g,h,i=a.ace||{},j=angular.extend({},i,c.$eval(e.uiAce)),k=window.ace.edit(d[0]),l=k.getSession(),m=function(){var a=arguments[0],b=Array.prototype.slice.call(arguments,1);angular.isDefined(a)&&c.$evalAsync(function(){if(!angular.isFunction(a))throw new Error("ui-ace use a function as callback.");a(b)})},n={onChange:function(a){return function(b){var d=l.getValue();!f||d===f.$viewValue||c.$$phase||c.$root.$$phase||c.$evalAsync(function(){f.$setViewValue(d)}),m(a,b,k)}},onBlur:function(a){return function(){m(a,k)}}};e.$observe("readonly",function(a){k.setReadOnly(!!a||""===a)}),f&&(f.$formatters.push(function(a){if(angular.isUndefined(a)||null===a)return"";if(angular.isObject(a)||angular.isArray(a))throw new Error("ui-ace cannot use an object or an array as a model");return a}),f.$render=function(){l.setValue(f.$viewValue)});var o=function(a,d){a!==d&&(j=angular.extend({},i,c.$eval(e.uiAce)),j.callbacks=[j.onLoad],j.onLoad!==i.onLoad&&j.callbacks.unshift(i.onLoad),l.removeListener("change",g),g=n.onChange(j.onChange),l.on("change",g),k.removeListener("blur",h),h=n.onBlur(j.onBlur),k.on("blur",h),b(k,l,j))};c.$watch(e.uiAce,o,!0),o(i),d.on("$destroy",function(){k.session.$stopWorker(),k.destroy()}),c.$watch(function(){return[d[0].offsetWidth,d[0].offsetHeight]},function(){k.resize(),k.renderer.updateFull()},!0)}}}]);
\ No newline at end of file
diff --git a/util/embedded-ldap/pom.xml b/util/embedded-ldap/pom.xml
index 3b66403..6ec7893 100644
--- a/util/embedded-ldap/pom.xml
+++ b/util/embedded-ldap/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../../pom.xml</relativePath>
     </parent>
     <modelVersion>4.0.0</modelVersion>
diff --git a/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/LDAPEmbeddedServer.java b/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/LDAPEmbeddedServer.java
index 33e0820..1754b4c 100644
--- a/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/LDAPEmbeddedServer.java
+++ b/util/embedded-ldap/src/main/java/org/keycloak/util/ldap/LDAPEmbeddedServer.java
@@ -219,13 +219,15 @@ public class LDAPEmbeddedServer {
         ldapServer.setSearchBaseDn(this.baseDN);
 
         // Read the transports
-        Transport ldap = new TcpTransport(this.bindHost, this.bindPort, 3, 50);
+        Transport ldaps = new TcpTransport(this.bindHost, this.bindPort, 3, 50);
         if (enableSSL) {
-            ldap.setEnableSSL(true);
+            ldaps.setEnableSSL(true);
             ldapServer.setKeystoreFile(keystoreFile);
             ldapServer.setCertificatePassword(certPassword);
+            Transport ldap = new TcpTransport(this.bindHost, 10389, 3, 50);
+            ldapServer.addTransports( ldap );
         }
-        ldapServer.addTransports( ldap );
+        ldapServer.addTransports( ldaps );
 
         // Associate the DS to this LdapServer
         ldapServer.setDirectoryService( directoryService );

util/pom.xml 2(+1 -1)

diff --git a/util/pom.xml b/util/pom.xml
index 065f701..8b5f49d 100644
--- a/util/pom.xml
+++ b/util/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/wildfly/adduser/pom.xml b/wildfly/adduser/pom.xml
index e417c3c..f8ab0bf 100755
--- a/wildfly/adduser/pom.xml
+++ b/wildfly/adduser/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak</groupId>
         <artifactId>keycloak-wildfly-parent</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>keycloak-wildfly-adduser</artifactId>
diff --git a/wildfly/extensions/pom.xml b/wildfly/extensions/pom.xml
index a581cfe..c8da68d 100755
--- a/wildfly/extensions/pom.xml
+++ b/wildfly/extensions/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak</groupId>
         <artifactId>keycloak-wildfly-parent</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>keycloak-wildfly-extensions</artifactId>

wildfly/pom.xml 2(+1 -1)

diff --git a/wildfly/pom.xml b/wildfly/pom.xml
index efb8706..d37cb30 100755
--- a/wildfly/pom.xml
+++ b/wildfly/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>keycloak-parent</artifactId>
         <groupId>org.keycloak</groupId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <name>Keycloak WildFly Integration</name>
diff --git a/wildfly/server-subsystem/pom.xml b/wildfly/server-subsystem/pom.xml
index a98aa58..5601739 100755
--- a/wildfly/server-subsystem/pom.xml
+++ b/wildfly/server-subsystem/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.keycloak</groupId>
         <artifactId>keycloak-wildfly-parent</artifactId>
-        <version>2.0.0.CR1-SNAPSHOT</version>
+        <version>2.2.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>keycloak-wildfly-server-subsystem</artifactId>
@@ -78,6 +78,16 @@
             <artifactId>jboss-logging-processor</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-services</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-server-spi</artifactId>
+            <scope>provided</scope>
+        </dependency>
 
         <dependency>
             <groupId>org.wildfly.core</groupId>
diff --git a/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakProviderDependencyProcessor.java b/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakProviderDependencyProcessor.java
new file mode 100644
index 0000000..5a5936f
--- /dev/null
+++ b/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakProviderDependencyProcessor.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.subsystem.server.extension;
+
+import org.jboss.as.server.deployment.Attachments;
+import org.jboss.as.server.deployment.DeploymentPhaseContext;
+import org.jboss.as.server.deployment.DeploymentUnit;
+import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
+import org.jboss.as.server.deployment.DeploymentUnitProcessor;
+import org.jboss.as.server.deployment.module.ModuleDependency;
+import org.jboss.as.server.deployment.module.ModuleSpecification;
+import org.jboss.as.server.deployment.module.ResourceRoot;
+import org.jboss.logging.Logger;
+import org.jboss.modules.Module;
+import org.jboss.modules.ModuleIdentifier;
+import org.jboss.modules.ModuleLoader;
+import org.jboss.vfs.VirtualFile;
+import org.jboss.vfs.util.AbstractVirtualFileFilterWithAttributes;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class KeycloakProviderDependencyProcessor implements DeploymentUnitProcessor {
+    private static final ModuleIdentifier KEYCLOAK_COMMON = ModuleIdentifier.create("org.keycloak.keycloak-common");
+    private static final ModuleIdentifier KEYCLOAK_CORE = ModuleIdentifier.create("org.keycloak.keycloak-core");
+    private static final ModuleIdentifier KEYCLOAK_SERVER_SPI = ModuleIdentifier.create("org.keycloak.keycloak-server-spi");
+    private static final ModuleIdentifier KEYCLOAK_JPA = ModuleIdentifier.create("org.keycloak.keycloak-model-jpa");
+    private static final ModuleIdentifier JAXRS = ModuleIdentifier.create("javax.ws.rs.api");
+    private static final ModuleIdentifier RESTEASY = ModuleIdentifier.create("org.jboss.resteasy.resteasy-jaxrs");
+    private static final ModuleIdentifier APACHE = ModuleIdentifier.create("org.apache.httpcomponents");
+
+    private static final Logger logger = Logger.getLogger(KeycloakProviderDependencyProcessor.class);
+
+    @Override
+    public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
+        DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
+        KeycloakAdapterConfigService config = KeycloakAdapterConfigService.INSTANCE;
+        String deploymentName = deploymentUnit.getName();
+
+        if (config.isKeycloakServerDeployment(deploymentName)) {
+            return;
+        }
+
+        if (!isKeycloakProviderDeployment(deploymentUnit)) return;
+
+        final ModuleSpecification moduleSpecification = deploymentUnit.getAttachment(Attachments.MODULE_SPECIFICATION);
+        final ModuleLoader moduleLoader = Module.getBootModuleLoader();
+        moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_COMMON, false, false, false, false));
+        moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_CORE, false, false, false, false));
+        moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_SERVER_SPI, false, false, false, false));
+        moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, JAXRS, false, false, false, false));
+        moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, RESTEASY, false, false, false, false));
+        moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, APACHE, false, false, false, false));
+        moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_JPA, false, false, false, false));
+
+
+    }
+
+    public KeycloakProviderDependencyProcessor() {
+        super();
+    }
+
+    public static boolean isKeycloakProviderDeployment(DeploymentUnit du) {
+        final ResourceRoot resourceRoot = du.getAttachment(Attachments.DEPLOYMENT_ROOT);
+        if (resourceRoot == null) {
+            return false;
+        }
+        final VirtualFile deploymentRoot = resourceRoot.getRoot();
+        if (deploymentRoot == null || !deploymentRoot.exists()) {
+            return false;
+        }
+        VirtualFile services = deploymentRoot.getChild("META-INF/services");
+        if (!services.exists()) return false;
+        try {
+            List<VirtualFile> archives = services.getChildren(new AbstractVirtualFileFilterWithAttributes(){
+                @Override
+                public boolean accepts(VirtualFile file) {
+                    return file.getName().startsWith("org.keycloak");
+                }
+            });
+            return !archives.isEmpty();
+        } catch (IOException e) {
+
+        }
+        return false;
+    }
+
+    @Override
+    public void undeploy(DeploymentUnit context) {
+
+    }
+}
diff --git a/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakProviderDeploymentProcessor.java b/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakProviderDeploymentProcessor.java
new file mode 100644
index 0000000..c573754
--- /dev/null
+++ b/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakProviderDeploymentProcessor.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.keycloak.subsystem.server.extension;
+
+import org.jboss.as.server.deployment.AttachmentKey;
+import org.jboss.as.server.deployment.Attachments;
+import org.jboss.as.server.deployment.DeploymentPhaseContext;
+import org.jboss.as.server.deployment.DeploymentUnit;
+import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
+import org.jboss.as.server.deployment.DeploymentUnitProcessor;
+import org.jboss.as.server.deployment.module.ModuleDependency;
+import org.jboss.as.server.deployment.module.ModuleSpecification;
+import org.jboss.as.server.deployment.module.ResourceRoot;
+import org.jboss.logging.Logger;
+import org.jboss.modules.Module;
+import org.jboss.modules.ModuleIdentifier;
+import org.jboss.modules.ModuleLoader;
+import org.jboss.vfs.VirtualFile;
+import org.jboss.vfs.util.AbstractVirtualFileFilterWithAttributes;
+import org.keycloak.provider.ProviderManager;
+import org.keycloak.provider.ProviderManagerRegistry;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class KeycloakProviderDeploymentProcessor implements DeploymentUnitProcessor {
+
+    AttachmentKey<ProviderManager> ATTACHMENT_KEY = AttachmentKey.create(ProviderManager.class);
+
+    private static final Logger logger = Logger.getLogger(KeycloakProviderDeploymentProcessor.class);
+    @Override
+    public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
+        DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
+        KeycloakAdapterConfigService config = KeycloakAdapterConfigService.INSTANCE;
+        String deploymentName = deploymentUnit.getName();
+
+        if (config.isKeycloakServerDeployment(deploymentName)) {
+            return;
+        }
+
+        if (!KeycloakProviderDependencyProcessor.isKeycloakProviderDeployment(deploymentUnit)) return;
+
+        logger.infof("Deploying Keycloak provider: {0}", deploymentUnit.getName());
+        final Module module = deploymentUnit.getAttachment(Attachments.MODULE);
+        ProviderManager pm = new ProviderManager(module.getClassLoader());
+        ProviderManagerRegistry.SINGLETON.deploy(pm);
+        deploymentUnit.putAttachment(ATTACHMENT_KEY, pm);
+
+
+
+    }
+
+    public KeycloakProviderDeploymentProcessor() {
+        super();
+    }
+
+    @Override
+    public void undeploy(DeploymentUnit context) {
+        ProviderManager pm = context.getAttachment(ATTACHMENT_KEY);
+        if (pm != null) {
+            logger.infof("Undeploying Keycloak provider: {0}", context.getName());
+            ProviderManagerRegistry.SINGLETON.undeploy(pm);
+            context.removeAttachment(ATTACHMENT_KEY);
+        }
+    }
+}
diff --git a/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakServerDeploymentProcessor.java b/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakServerDeploymentProcessor.java
index 8b4840a..f99cab3 100755
--- a/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakServerDeploymentProcessor.java
+++ b/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakServerDeploymentProcessor.java
@@ -63,7 +63,7 @@ public class KeycloakServerDeploymentProcessor implements DeploymentUnitProcesso
             st.addDependency(cacheContainerService.append("offlineSessions"));
             st.addDependency(cacheContainerService.append("loginFailures"));
             st.addDependency(cacheContainerService.append("work"));
-            st.addDependency(cacheContainerService.append("realmVersions"));
+            st.addDependency(cacheContainerService.append("authorization"));;
         }
     }
 
diff --git a/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemAdd.java b/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemAdd.java
index a5d9e85..3c6dc34 100755
--- a/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemAdd.java
+++ b/wildfly/server-subsystem/src/main/java/org/keycloak/subsystem/server/extension/KeycloakSubsystemAdd.java
@@ -44,12 +44,22 @@ class KeycloakSubsystemAdd extends AbstractBoottimeAddStepHandler {
         context.addStep(new AbstractDeploymentChainStep() {
             @Override
             protected void execute(DeploymentProcessorTarget processorTarget) {
+                processorTarget.addDeploymentProcessor(SUBSYSTEM_NAME, Phase.DEPENDENCIES, 0, new KeycloakProviderDependencyProcessor());
+                processorTarget.addDeploymentProcessor(SUBSYSTEM_NAME,
+                        Phase.POST_MODULE, // PHASE
+                        Phase.POST_MODULE_VALIDATOR_FACTORY - 2, // PRIORITY
+                        new KeycloakProviderDeploymentProcessor());
                 processorTarget.addDeploymentProcessor(SUBSYSTEM_NAME,
                         Phase.POST_MODULE, // PHASE
                         Phase.POST_MODULE_VALIDATOR_FACTORY - 1, // PRIORITY
                         new KeycloakServerDeploymentProcessor());
             }
         }, OperationContext.Stage.RUNTIME);
+        context.addStep(new AbstractDeploymentChainStep() {
+            @Override
+            protected void execute(DeploymentProcessorTarget processorTarget) {
+            }
+        }, OperationContext.Stage.RUNTIME);
     }
 
     protected void populateModel(final OperationContext context, final ModelNode operation, final Resource resource) throws  OperationFailedException {
diff --git a/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-datasources.xml b/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-datasources.xml
index c823e4f..326fa7f 100755
--- a/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-datasources.xml
+++ b/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-datasources.xml
@@ -29,7 +29,7 @@
                     <password>sa</password>
                 </security>
             </datasource>
-            <datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true">
+            <datasource jndi-name="java:jboss/datasources/KeycloakDS" jta="false" pool-name="KeycloakDS" enabled="true" use-java-context="true">
                 <?KEYCLOAK_DS_CONNECTION_URL?>
                 <driver>h2</driver>
                 <security>
diff --git a/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan.xml b/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan.xml
index 837407a..bbc1a83 100755
--- a/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan.xml
+++ b/wildfly/server-subsystem/src/main/resources/subsystem-templates/keycloak-infinispan.xml
@@ -33,8 +33,8 @@
                 <local-cache name="offlineSessions"/>
                 <local-cache name="loginFailures"/>
                 <local-cache name="work"/>
-                <local-cache name="realmVersions">
-                    <transaction mode="BATCH" locking="PESSIMISTIC"/>
+                <local-cache name="authorization">
+                    <eviction max-entries="100" strategy="LRU"/>
                 </local-cache>
             </cache-container>
             <cache-container name="server" default-cache="default" module="org.wildfly.clustering.server">
@@ -95,10 +95,8 @@
                 <distributed-cache name="sessions" mode="SYNC" owners="1"/>
                 <distributed-cache name="offlineSessions" mode="SYNC" owners="1"/>
                 <distributed-cache name="loginFailures" mode="SYNC" owners="1"/>
+                <distributed-cache name="authorization" mode="SYNC" owners="1"/>
                 <replicated-cache name="work" mode="SYNC" />
-                <local-cache name="realmVersions">
-                    <transaction mode="BATCH" locking="PESSIMISTIC"/>
-                </local-cache>
             </cache-container>
             <cache-container name="server" aliases="singleton cluster" default-cache="default" module="org.wildfly.clustering.server">
                 <transport lock-timeout="60000"/>